Merge branch 'master' into compare-update-and-release-dates
@ -16,8 +16,8 @@ jobs:
|
||||
vmImage: windows-2019
|
||||
strategy:
|
||||
matrix:
|
||||
node_14.x:
|
||||
node_version: 14.x
|
||||
node:
|
||||
node_version: 16.x
|
||||
steps:
|
||||
- powershell: |
|
||||
$CI_BUILD_TAG = git describe --tags
|
||||
@ -64,8 +64,8 @@ jobs:
|
||||
vmImage: macOS-11
|
||||
strategy:
|
||||
matrix:
|
||||
node_14.x:
|
||||
node_version: 14.x
|
||||
node:
|
||||
node_version: 16.x
|
||||
steps:
|
||||
- script: CI_BUILD_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=CI_BUILD_TAG]$CI_BUILD_TAG"
|
||||
condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))"
|
||||
@ -94,9 +94,25 @@ jobs:
|
||||
GH_TOKEN: $(LENS_IDE_GH_TOKEN)
|
||||
displayName: Customize config
|
||||
|
||||
- script: make build
|
||||
- bash: |
|
||||
set -e
|
||||
|
||||
echo "Importing codesign certificate ..."
|
||||
echo $CSC_LINK | base64 -D > certificate.p12
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security set-keychain-settings -lut 21600 build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security import certificate.p12 -k build.keychain -P $CSC_KEY_PASSWORD -T /usr/bin/codesign -T /usr/bin/security -A
|
||||
security set-key-partition-list -S apple-tool:,apple: -k $KEYCHAIN_PASSWORD build.keychain
|
||||
|
||||
rm certificate.p12
|
||||
echo "Codesign certificate imported!"
|
||||
|
||||
make build
|
||||
condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))"
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: secretz
|
||||
APPLEID: $(APPLEID)
|
||||
APPLEIDPASS: $(APPLEIDPASS)
|
||||
CSC_LINK: $(CSC_LINK)
|
||||
@ -112,8 +128,8 @@ jobs:
|
||||
vmImage: ubuntu-18.04
|
||||
strategy:
|
||||
matrix:
|
||||
node_14.x:
|
||||
node_version: 14.x
|
||||
node:
|
||||
node_version: 16.x
|
||||
steps:
|
||||
- script: CI_BUILD_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=CI_BUILD_TAG]$CI_BUILD_TAG"
|
||||
condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))"
|
||||
|
||||
2
.github/workflows/check-docs.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'area/documentation') }}
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- name: Checkout Release from lens
|
||||
uses: actions/checkout@v2
|
||||
|
||||
4
.github/workflows/electronegativity.yml
vendored
@ -14,12 +14,12 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "14"
|
||||
node-version: "16"
|
||||
|
||||
- uses: doyensec/electronegativity-action@v1.1
|
||||
with:
|
||||
input: src/
|
||||
electron-version: "14.2.4"
|
||||
electron-version: "15.5.7"
|
||||
severity: medium
|
||||
|
||||
- name: Upload sarif
|
||||
|
||||
2
.github/workflows/linter.yml
vendored
@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- name: Checkout Release from lens
|
||||
uses: actions/checkout@v2
|
||||
|
||||
4
.github/workflows/main.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v2
|
||||
@ -46,7 +46,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
needs: verify-docs
|
||||
steps:
|
||||
- name: Set up Python 3.7
|
||||
|
||||
2
.github/workflows/mkdocs-manual.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v2
|
||||
|
||||
2
.github/workflows/publish-master-npm.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
${{ github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'area/extension') }}
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- name: Checkout Release
|
||||
uses: actions/checkout@v2
|
||||
|
||||
2
.github/workflows/publish-release-npm.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- name: Checkout Release
|
||||
uses: actions/checkout@v2
|
||||
|
||||
2
.github/workflows/test.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-18.04, macos-11, windows-2019]
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- name: Checkout Release from lens
|
||||
uses: actions/checkout@v2
|
||||
|
||||
2
.yarnrc
@ -1,3 +1,3 @@
|
||||
disturl "https://atom.io/download/electron"
|
||||
target "14.2.4"
|
||||
target "15.5.0"
|
||||
runtime "electron"
|
||||
|
||||
1
Makefile
@ -56,6 +56,7 @@ integration: build
|
||||
build: node_modules binaries/client
|
||||
yarn run npm:fix-build-version
|
||||
$(MAKE) build-extensions -B
|
||||
yarn run build:tray-icons
|
||||
yarn run compile
|
||||
ifeq "$(DETECTED_OS)" "Windows"
|
||||
# https://github.com/ukoloff/win-ca#clear-pem-folder-on-publish
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Lens Open Source Project (OpenLens)
|
||||
|
||||
[](https://github.com/lensapp/lens/actions/workflows/test.yml)
|
||||
[](https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI)
|
||||
[](https://join.slack.com/t/k8slens/shared_invite/zt-198iepl92-EPJsCckkJ~f887vWqJcgGA)
|
||||
|
||||
## The Repository
|
||||
|
||||
|
||||
@ -3,8 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { readFileSync } from "fs";
|
||||
import { ensureDirSync } from "fs-extra";
|
||||
import { ensureDir, readFile } from "fs-extra";
|
||||
import { JSDOM } from "jsdom";
|
||||
import path from "path";
|
||||
import sharp from "sharp";
|
||||
@ -12,39 +11,120 @@ import sharp from "sharp";
|
||||
const size = Number(process.env.OUTPUT_SIZE || "16");
|
||||
const outputFolder = process.env.OUTPUT_DIR || "./build/tray";
|
||||
const inputFile = process.env.INPUT_SVG_PATH || "./src/renderer/components/icon/logo-lens.svg";
|
||||
const noticeFile = process.env.NOTICE_SVG_PATH || "./src/renderer/components/icon/notice.svg";
|
||||
|
||||
const svgData = readFileSync(inputFile, { encoding: "utf-8" });
|
||||
const svgDom = new JSDOM(`<body>${svgData}</body>`);
|
||||
const svgRoot = svgDom.window.document.body.getElementsByTagName("svg")[0];
|
||||
async function ensureOutputFoler() {
|
||||
await ensureDir(outputFolder);
|
||||
}
|
||||
|
||||
svgRoot.innerHTML += `<style>* {fill: white !important;}</style>`;
|
||||
const lightTemplate = svgRoot.outerHTML;
|
||||
function getSvgStyling(colouring: "dark" | "light"): string {
|
||||
return `
|
||||
<style>
|
||||
ellipse {
|
||||
stroke: ${colouring === "dark" ? "white" : "black"} !important;
|
||||
}
|
||||
path, rect {
|
||||
fill: ${colouring === "dark" ? "white" : "black"} !important;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
|
||||
svgRoot.innerHTML += `<style>* {fill: black !important;}</style>`;
|
||||
type TargetSystems = "macos" | "windows-or-linux";
|
||||
|
||||
const darkTemplate = svgRoot.outerHTML;
|
||||
async function getBaseIconImage(system: TargetSystems) {
|
||||
const svgData = await readFile(inputFile, { encoding: "utf-8" });
|
||||
const dom = new JSDOM(`<body>${svgData}</body>`);
|
||||
const root = dom.window.document.body.getElementsByTagName("svg")[0];
|
||||
|
||||
console.log("Generating tray icon pngs");
|
||||
root.innerHTML += getSvgStyling(system === "macos" ? "light" : "dark");
|
||||
|
||||
ensureDirSync(outputFolder);
|
||||
return Buffer.from(root.outerHTML);
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
sharp(Buffer.from(lightTemplate))
|
||||
async function generateImage(image: Buffer, size: number, namePrefix: string) {
|
||||
sharp(image)
|
||||
.resize({ width: size, height: size })
|
||||
.png()
|
||||
.toFile(path.join(outputFolder, "trayIconDarkTemplate.png")),
|
||||
sharp(Buffer.from(lightTemplate))
|
||||
.resize({ width: size*2, height: size*2 })
|
||||
.png()
|
||||
.toFile(path.join(outputFolder, "trayIconDarkTemplate@2x.png")),
|
||||
sharp(Buffer.from(darkTemplate))
|
||||
.resize({ width: size, height: size })
|
||||
.png()
|
||||
.toFile(path.join(outputFolder, "trayIconTemplate.png")),
|
||||
sharp(Buffer.from(darkTemplate))
|
||||
.resize({ width: size*2, height: size*2 })
|
||||
.png()
|
||||
.toFile(path.join(outputFolder, "trayIconTemplate@2x.png")),
|
||||
])
|
||||
.then((resolutions) => console.log(`Generated ${resolutions.length} images`))
|
||||
.catch(console.error);
|
||||
.toFile(path.join(outputFolder, `${namePrefix}.png`));
|
||||
}
|
||||
|
||||
async function generateImages(image: Buffer, size: number, name: string) {
|
||||
await Promise.all([
|
||||
generateImage(image, size, name),
|
||||
generateImage(image, size*2, `${name}@2x`),
|
||||
generateImage(image, size*3, `${name}@3x`),
|
||||
generateImage(image, size*4, `${name}@4x`),
|
||||
]);
|
||||
}
|
||||
|
||||
async function generateUpdateAvailableImages(baseImage: Buffer, system: TargetSystems) {
|
||||
const noticeIconImage = await getNoticeIconImage(system);
|
||||
const circleBuffer = await sharp(Buffer.from(`
|
||||
<svg viewBox="0 0 64 64">
|
||||
<circle cx="32" cy="32" r="32" fill="black" />
|
||||
</svg>
|
||||
`))
|
||||
.toBuffer();
|
||||
|
||||
return sharp(baseImage)
|
||||
.resize({ width: 128, height: 128 })
|
||||
.composite([
|
||||
{
|
||||
input: circleBuffer,
|
||||
top: 64,
|
||||
left: 64,
|
||||
blend: "dest-out",
|
||||
},
|
||||
{
|
||||
input: (
|
||||
await sharp(noticeIconImage)
|
||||
.resize({
|
||||
width: 60,
|
||||
height: 60,
|
||||
})
|
||||
.toBuffer()
|
||||
),
|
||||
top: 66,
|
||||
left: 66,
|
||||
},
|
||||
])
|
||||
.toBuffer();
|
||||
}
|
||||
|
||||
async function getNoticeIconImage(system: TargetSystems) {
|
||||
const svgData = await readFile(noticeFile, { encoding: "utf-8" });
|
||||
const root = new JSDOM(svgData).window.document.getElementsByTagName("svg")[0];
|
||||
|
||||
root.innerHTML += getSvgStyling(system === "macos" ? "light" : "dark");
|
||||
|
||||
return Buffer.from(root.outerHTML);
|
||||
}
|
||||
|
||||
async function generateTrayIcons() {
|
||||
try {
|
||||
console.log("Generating tray icon pngs");
|
||||
await ensureOutputFoler();
|
||||
|
||||
const baseIconTemplateImage = await getBaseIconImage("macos");
|
||||
const updateAvailableTemplateImage = await generateUpdateAvailableImages(baseIconTemplateImage, "macos");
|
||||
const baseIconImage = await getBaseIconImage("windows-or-linux");
|
||||
const updateAvailableImage = await generateUpdateAvailableImages(baseIconImage, "windows-or-linux");
|
||||
|
||||
await Promise.all([
|
||||
// Templates are for macOS only
|
||||
generateImages(baseIconTemplateImage, size, "trayIconTemplate"),
|
||||
generateImages(updateAvailableTemplateImage, size, "trayIconUpdateAvailableTemplate"),
|
||||
|
||||
// Non-templates are for windows and linux
|
||||
generateImages(baseIconImage, size, "trayIcon"),
|
||||
generateImages(updateAvailableImage, size, "trayIconUpdateAvailable"),
|
||||
]);
|
||||
|
||||
console.log("Generated all images");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
generateTrayIcons();
|
||||
|
||||
|
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
|
Before Width: | Height: | Size: 724 B After Width: | Height: | Size: 724 B |
BIN
build/tray/trayIcon@3x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
build/tray/trayIcon@4x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
build/tray/trayIconTemplate@3x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
build/tray/trayIconTemplate@4x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
build/tray/trayIconUpdateAvailable.png
Normal file
|
After Width: | Height: | Size: 518 B |
BIN
build/tray/trayIconUpdateAvailable@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
build/tray/trayIconUpdateAvailable@3x.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
build/tray/trayIconUpdateAvailable@4x.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
build/tray/trayIconUpdateAvailableTemplate.png
Normal file
|
After Width: | Height: | Size: 466 B |
BIN
build/tray/trayIconUpdateAvailableTemplate@2x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
build/tray/trayIconUpdateAvailableTemplate@3x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
build/tray/trayIconUpdateAvailableTemplate@4x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
@ -79,7 +79,7 @@ Some of the most-important fields include:
|
||||
}
|
||||
```
|
||||
|
||||
## Webpack configuation
|
||||
## Webpack configuration
|
||||
|
||||
The following webpack `externals` are provided by `Lens` and must be used (when available) to make sure that the versions used are in sync.
|
||||
|
||||
|
||||
@ -224,7 +224,7 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
{
|
||||
id: "bonjour",
|
||||
components: {
|
||||
Page: () => <ExemplePage extension={this} />,
|
||||
Page: () => <ExamplePage extension={this} />,
|
||||
},
|
||||
},
|
||||
];
|
||||
@ -250,7 +250,7 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
target: { pageId: "bonjour" },
|
||||
title: "Bonjour le monde",
|
||||
components: {
|
||||
Icon: ExempleIcon,
|
||||
Icon: ExampleIcon,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@ -24,11 +24,6 @@ spec:
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
- matchExpressions:
|
||||
- key: beta.kubernetes.io/os
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
# <%- if config.node_selector -%>
|
||||
# nodeSelector:
|
||||
# <%- node_selector.to_h.each do |key, value| -%>
|
||||
|
||||
@ -30,11 +30,6 @@ spec:
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
- matchExpressions:
|
||||
- key: beta.kubernetes.io/os
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
|
||||
@ -23,11 +23,6 @@ spec:
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
- matchExpressions:
|
||||
- key: beta.kubernetes.io/os
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
serviceAccountName: kube-state-metrics
|
||||
containers:
|
||||
- name: kube-state-metrics
|
||||
|
||||
74
package.json
@ -52,7 +52,7 @@
|
||||
"sentryDsn": ""
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14 <15"
|
||||
"node": ">=16 <17"
|
||||
},
|
||||
"jest": {
|
||||
"collectCoverage": false,
|
||||
@ -72,6 +72,9 @@
|
||||
"<rootDir>/src/jest.setup.ts",
|
||||
"jest-canvas-mock"
|
||||
],
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/src/jest-after-env.setup.ts"
|
||||
],
|
||||
"globals": {
|
||||
"ts-jest": {
|
||||
"isolatedModules": true
|
||||
@ -225,22 +228,22 @@
|
||||
"filehound": "^1.17.6",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"got": "^11.8.3",
|
||||
"got": "^11.8.5",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"handlebars": "^4.7.7",
|
||||
"history": "^4.10.1",
|
||||
"http-proxy": "^1.18.1",
|
||||
"immer": "^9.0.12",
|
||||
"immer": "^9.0.14",
|
||||
"joi": "^17.6.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^16.7.0",
|
||||
"lodash": "^4.17.15",
|
||||
"mac-ca": "^1.0.6",
|
||||
"marked": "^4.0.15",
|
||||
"marked": "^4.0.16",
|
||||
"md5-file": "^5.0.0",
|
||||
"mobx": "^6.5.0",
|
||||
"mobx-observable-history": "^2.0.3",
|
||||
"mobx-react": "^7.3.0",
|
||||
"mobx-react": "^7.5.0",
|
||||
"mobx-utils": "^6.0.4",
|
||||
"mock-fs": "^5.1.2",
|
||||
"moment": "^2.29.3",
|
||||
@ -248,7 +251,7 @@
|
||||
"monaco-editor": "^0.29.1",
|
||||
"monaco-editor-webpack-plugin": "^5.0.0",
|
||||
"node-fetch": "lensapp/node-fetch#2.x",
|
||||
"node-pty": "^0.10.1",
|
||||
"node-pty": "^0.11.0-beta19",
|
||||
"npm": "^6.14.17",
|
||||
"p-limit": "^3.1.0",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
@ -276,14 +279,14 @@
|
||||
"winston": "^3.7.2",
|
||||
"winston-console-format": "^1.0.8",
|
||||
"winston-transport-browserconsole": "^1.0.5",
|
||||
"ws": "^8.5.0"
|
||||
"ws": "^8.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@async-fn/jest": "1.6.0",
|
||||
"@async-fn/jest": "1.6.1",
|
||||
"@material-ui/core": "^4.12.3",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.60",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
|
||||
"@sentry/types": "^6.19.7",
|
||||
"@testing-library/dom": "^7.31.2",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
@ -292,7 +295,7 @@
|
||||
"@types/byline": "^4.2.33",
|
||||
"@types/chart.js": "^2.9.36",
|
||||
"@types/circular-dependency-plugin": "5.0.5",
|
||||
"@types/cli-progress": "^3.9.2",
|
||||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/command-line-args": "^5.2.0",
|
||||
"@types/crypto-js": "^3.1.47",
|
||||
@ -311,7 +314,7 @@
|
||||
"@types/md5-file": "^4.0.2",
|
||||
"@types/mini-css-extract-plugin": "^2.4.0",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "14.18.17",
|
||||
"@types/node": "^16.11.39",
|
||||
"@types/node-fetch": "^2.6.1",
|
||||
"@types/npm": "^2.0.32",
|
||||
"@types/proper-lockfile": "^4.1.2",
|
||||
@ -321,7 +324,7 @@
|
||||
"@types/react-dom": "^17.0.16",
|
||||
"@types/react-router": "^5.1.18",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-table": "^7.7.11",
|
||||
"@types/react-table": "^7.7.12",
|
||||
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/readable-stream": "^2.3.13",
|
||||
@ -339,33 +342,33 @@
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"@types/webpack-dev-server": "^4.7.2",
|
||||
"@types/webpack-env": "^1.16.4",
|
||||
"@types/webpack-env": "^1.17.0",
|
||||
"@types/webpack-node-externals": "^2.5.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
||||
"@typescript-eslint/parser": "^5.17.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.27.1",
|
||||
"@typescript-eslint/parser": "^5.27.0",
|
||||
"ansi_up": "^5.1.0",
|
||||
"chart.js": "^2.9.4",
|
||||
"circular-dependency-plugin": "^5.2.2",
|
||||
"cli-progress": "^3.11.0",
|
||||
"cli-progress": "^3.11.1",
|
||||
"color": "^3.2.1",
|
||||
"command-line-args": "^5.2.1",
|
||||
"concurrently": "^7.1.0",
|
||||
"concurrently": "^7.2.1",
|
||||
"css-loader": "^6.7.1",
|
||||
"deepdash": "^5.3.9",
|
||||
"dompurify": "^2.3.6",
|
||||
"electron": "^14.2.9",
|
||||
"dompurify": "^2.3.8",
|
||||
"electron": "^15.5.7",
|
||||
"electron-builder": "^23.0.3",
|
||||
"electron-notarize": "^0.3.0",
|
||||
"esbuild": "^0.14.38",
|
||||
"esbuild-loader": "^2.18.0",
|
||||
"eslint": "^8.14.0",
|
||||
"esbuild-loader": "^2.19.0",
|
||||
"eslint": "^8.16.0",
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-react": "^7.30.0",
|
||||
"eslint-plugin-react-hooks": "^4.5.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"flex.box": "^3.4.4",
|
||||
"fork-ts-checker-webpack-plugin": "^6.5.0",
|
||||
"fork-ts-checker-webpack-plugin": "^6.5.2",
|
||||
"gunzip-maybe": "^1.4.2",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
@ -381,37 +384,36 @@
|
||||
"node-gyp": "7.1.2",
|
||||
"node-loader": "^2.0.0",
|
||||
"nodemon": "^2.0.16",
|
||||
"playwright": "^1.20.2",
|
||||
"postcss": "^8.4.12",
|
||||
"playwright": "^1.22.2",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-loader": "^6.2.1",
|
||||
"randomcolor": "^0.6.2",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-refresh": "^0.12.0",
|
||||
"react-refresh-typescript": "^2.0.4",
|
||||
"react-router-dom": "^5.3.1",
|
||||
"react-refresh": "^0.13.0",
|
||||
"react-refresh-typescript": "^2.0.5",
|
||||
"react-router-dom": "^5.3.3",
|
||||
"react-select": "^5.3.2",
|
||||
"react-select-event": "^5.5.0",
|
||||
"react-table": "^7.7.0",
|
||||
"react-table": "^7.8.0",
|
||||
"react-window": "^1.8.7",
|
||||
"sass": "^1.51.0",
|
||||
"sass": "^1.52.2",
|
||||
"sass-loader": "^12.6.0",
|
||||
"sharp": "^0.30.4",
|
||||
"sharp": "^0.30.6",
|
||||
"style-loader": "^3.3.1",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"tar-stream": "^2.2.0",
|
||||
"ts-jest": "26.5.6",
|
||||
"ts-loader": "^9.2.8",
|
||||
"ts-node": "^10.7.0",
|
||||
"type-fest": "^2.12.2",
|
||||
"type-fest": "^2.13.0",
|
||||
"typed-emitter": "^1.4.0",
|
||||
"typedoc": "0.22.15",
|
||||
"typedoc": "0.22.17",
|
||||
"typedoc-plugin-markdown": "^3.11.12",
|
||||
"typeface-roboto": "^1.1.13",
|
||||
"typescript": "^4.5.5",
|
||||
"typescript-plugin-css-modules": "^3.4.0",
|
||||
"webpack": "^5.72.0",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.9.0",
|
||||
"webpack-dev-server": "^4.9.1",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"xterm": "^4.18.0",
|
||||
"xterm-addon-fit": "^0.5.0"
|
||||
|
||||
@ -1,11 +1,20 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`extension special characters in page registrations renders 1`] = `<div />`;
|
||||
exports[`extension special characters in page registrations renders 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`extension special characters in page registrations when navigating to route with ID having special characters renders 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
Some page
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1,12 +1,21 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`navigate to extension page renders 1`] = `<div />`;
|
||||
exports[`navigate to extension page renders 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`navigate to extension page when extension navigates to child route renders 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
Child page
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -31,6 +40,9 @@ exports[`navigate to extension page when extension navigates to route with param
|
||||
Some button
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -55,6 +67,9 @@ exports[`navigate to extension page when extension navigates to route without pa
|
||||
Some button
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -79,5 +94,8 @@ exports[`navigate to extension page when extension navigates to route without pa
|
||||
Some button
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -8,6 +8,9 @@ exports[`navigating between routes given route with optional path parameters whe
|
||||
"someOtherParameter": "some-other-value"
|
||||
}
|
||||
</pre>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -16,5 +19,8 @@ exports[`navigating between routes given route without path parameters when navi
|
||||
<div>
|
||||
Some component
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`add-cluster - navigation using application menu renders 1`] = `<div />`;
|
||||
exports[`add-cluster - navigation using application menu renders 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`add-cluster - navigation using application menu when navigating to add cluster using application menu renders 1`] = `
|
||||
<div>
|
||||
@ -85,5 +91,8 @@ exports[`add-cluster - navigation using application menu when navigating to add
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -6,16 +6,17 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
|
||||
import React from "react";
|
||||
|
||||
// TODO: Make components free of side effects by making them deterministic
|
||||
jest.mock("../../renderer/components/tooltip/tooltip", () => ({
|
||||
Tooltip: () => null,
|
||||
}));
|
||||
|
||||
jest.mock("../../renderer/components/tooltip/withTooltip", () => ({
|
||||
withTooltip: (Target: any) => ({ tooltip, tooltipOverrideDisabled, ...props }: any) => <Target {...props} />,
|
||||
}));
|
||||
|
||||
jest.mock("../../renderer/components/monaco-editor/monaco-editor", () => ({
|
||||
MonacoEditor: () => null,
|
||||
}));
|
||||
@ -25,9 +26,7 @@ describe("add-cluster - navigation using application menu", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
applicationBuilder = getApplicationBuilder().beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(isAutoUpdateEnabledInjectable, () => () => false);
|
||||
});
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
@ -0,0 +1,536 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`installing update using tray when started renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update using tray when started when user checks for updates using tray renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Checking for updates...
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_16"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update using tray when started when user checks for updates using tray when new update is discovered renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Checking for updates...
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_115"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Download for version some-version started...
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_118"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update using tray when started when user checks for updates using tray when new update is discovered when download fails renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Checking for updates...
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_183"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Download for version some-version started...
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_186"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Download of update failed
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_191"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update using tray when started when user checks for updates using tray when new update is discovered when download succeeds renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Checking for updates...
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_266"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Download for version some-version started...
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_269"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
<div
|
||||
class="flex column gaps"
|
||||
data-testid="ask-boolean-some-irrelevant-random-id"
|
||||
>
|
||||
<b>
|
||||
Update Available
|
||||
</b>
|
||||
<p>
|
||||
Version some-version of Lens IDE is available and ready to be installed. Would you like to update now?
|
||||
|
||||
Lens should restart automatically, if it doesn't please restart manually. Installed extensions might require updating.
|
||||
</p>
|
||||
<div
|
||||
class="flex gaps row align-left box grow"
|
||||
>
|
||||
<button
|
||||
class="Button light"
|
||||
data-testid="ask-boolean-some-irrelevant-random-id-button-yes"
|
||||
type="button"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
class="Button active outlined"
|
||||
data-testid="ask-boolean-some-irrelevant-random-id-button-no"
|
||||
type="button"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-ask-boolean-for-some-irrelevant-random-id"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update using tray when started when user checks for updates using tray when no new update is discovered renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
Checking for updates...
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_59"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Animate opacity notification flex info enter"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
No new updates available
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-notification_62"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -0,0 +1,81 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`installing update when started renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update when started when user checks for updates renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update when started when user checks for updates when new update is discovered renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update when started when user checks for updates when new update is discovered when download fails renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update when started when user checks for updates when new update is discovered when download succeeds renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update when started when user checks for updates when new update is discovered when download succeeds when user answers not to install the update renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update when started when user checks for updates when new update is discovered when download succeeds when user answers to install the update renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`installing update when started when user checks for updates when no new update is discovered renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -0,0 +1,11 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`periodical checking of updates given updater is enabled and configuration exists, when started renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -0,0 +1,11 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`selection of update stability when started renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import selectedUpdateChannelInjectable from "../../common/application-update/selected-update-channel/selected-update-channel.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import appVersionInjectable from "../../common/get-configuration-file-model/app-version/app-version.injectable";
|
||||
import { updateChannels } from "../../common/application-update/update-channels";
|
||||
|
||||
describe("downgrading version update", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
|
||||
let mainDi: DiContainer;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
checkForPlatformUpdatesMock = asyncFn();
|
||||
|
||||
mainDi.override(
|
||||
checkForPlatformUpdatesInjectable,
|
||||
() => checkForPlatformUpdatesMock,
|
||||
);
|
||||
|
||||
mainDi.override(electronUpdaterIsActiveInjectable, () => true);
|
||||
mainDi.override(publishIsConfiguredInjectable, () => true);
|
||||
});
|
||||
|
||||
mainDi = applicationBuilder.dis.mainDi;
|
||||
});
|
||||
|
||||
[
|
||||
{
|
||||
updateChannel: updateChannels.latest,
|
||||
appVersion: "4.0.0-beta",
|
||||
downgradeIsAllowed: true,
|
||||
},
|
||||
{
|
||||
updateChannel: updateChannels.beta,
|
||||
appVersion: "4.0.0-beta",
|
||||
downgradeIsAllowed: false,
|
||||
},
|
||||
{
|
||||
updateChannel: updateChannels.beta,
|
||||
appVersion: "4.0.0-beta.1",
|
||||
downgradeIsAllowed: false,
|
||||
},
|
||||
{
|
||||
updateChannel: updateChannels.alpha,
|
||||
appVersion: "4.0.0-beta",
|
||||
downgradeIsAllowed: true,
|
||||
},
|
||||
{
|
||||
updateChannel: updateChannels.alpha,
|
||||
appVersion: "4.0.0-alpha",
|
||||
downgradeIsAllowed: false,
|
||||
},
|
||||
].forEach(({ appVersion, updateChannel, downgradeIsAllowed }) => {
|
||||
it(`given application version "${appVersion}" and update channel "${updateChannel.id}", when checking for updates, can${downgradeIsAllowed ? "": "not"} downgrade`, async () => {
|
||||
mainDi.override(appVersionInjectable, () => appVersion);
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
|
||||
|
||||
selectedUpdateChannel.setValue(updateChannel.id);
|
||||
|
||||
const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
|
||||
processCheckingForUpdates();
|
||||
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(expect.any(Object), { allowDowngrade: downgradeIsAllowed });
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,262 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import showApplicationWindowInjectable from "../../main/start-main-application/lens-window/show-application-window.injectable";
|
||||
import progressOfUpdateDownloadInjectable from "../../common/application-update/progress-of-update-download/progress-of-update-download.injectable";
|
||||
import type { TrayIconPaths } from "../../main/tray/tray-icon-path.injectable";
|
||||
import trayIconPathsInjectable from "../../main/tray/tray-icon-path.injectable";
|
||||
|
||||
describe("installing update using tray", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
|
||||
let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>;
|
||||
let showApplicationWindowMock: jest.Mock;
|
||||
let trayIconPaths: TrayIconPaths;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
checkForPlatformUpdatesMock = asyncFn();
|
||||
downloadPlatformUpdateMock = asyncFn();
|
||||
showApplicationWindowMock = jest.fn();
|
||||
|
||||
mainDi.override(showApplicationWindowInjectable, () => showApplicationWindowMock);
|
||||
|
||||
mainDi.override(
|
||||
checkForPlatformUpdatesInjectable,
|
||||
() => checkForPlatformUpdatesMock,
|
||||
);
|
||||
|
||||
mainDi.override(
|
||||
downloadPlatformUpdateInjectable,
|
||||
() => downloadPlatformUpdateMock,
|
||||
);
|
||||
|
||||
mainDi.override(electronUpdaterIsActiveInjectable, () => true);
|
||||
mainDi.override(publishIsConfiguredInjectable, () => true);
|
||||
trayIconPaths = mainDi.inject(trayIconPathsInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when started", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should use the normal tray icon", () => {
|
||||
expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal);
|
||||
});
|
||||
|
||||
it("user cannot install update yet", () => {
|
||||
expect(applicationBuilder.tray.get("install-update")).toBeNull();
|
||||
});
|
||||
|
||||
describe("when user checks for updates using tray", () => {
|
||||
let processCheckingForUpdatesPromise: Promise<void>;
|
||||
|
||||
beforeEach(async () => {
|
||||
processCheckingForUpdatesPromise = applicationBuilder.tray.click("check-for-updates");
|
||||
});
|
||||
|
||||
it("does not show application window yet", () => {
|
||||
expect(showApplicationWindowMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should still use the normal tray icon", () => {
|
||||
expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal);
|
||||
});
|
||||
|
||||
it("user cannot check for updates again", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("name of tray item for checking updates indicates that checking is happening", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.label?.get(),
|
||||
).toBe("Checking for updates...");
|
||||
});
|
||||
|
||||
it("user cannot install update yet", () => {
|
||||
expect(applicationBuilder.tray.get("install-update")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when no new update is discovered", () => {
|
||||
beforeEach(async () => {
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: false,
|
||||
});
|
||||
|
||||
await processCheckingForUpdatesPromise;
|
||||
});
|
||||
|
||||
it("shows application window", () => {
|
||||
expect(showApplicationWindowMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should still use the normal tray icon", () => {
|
||||
expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal);
|
||||
});
|
||||
|
||||
it("user cannot install update", () => {
|
||||
expect(applicationBuilder.tray.get("install-update")).toBeNull();
|
||||
});
|
||||
|
||||
it("user can check for updates again", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("name of tray item for checking updates no longer indicates that checking is happening", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.label?.get(),
|
||||
).toBe("Check for updates");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when new update is discovered", () => {
|
||||
beforeEach(async () => {
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: true,
|
||||
version: "some-version",
|
||||
});
|
||||
|
||||
await processCheckingForUpdatesPromise;
|
||||
});
|
||||
|
||||
it("shows application window", () => {
|
||||
expect(showApplicationWindowMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should use the update available icon", () => {
|
||||
expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.updateAvailable);
|
||||
});
|
||||
|
||||
it("user cannot check for updates again yet", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("name of tray item for checking updates indicates that downloading is happening", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.label?.get(),
|
||||
).toBe("Downloading update some-version (0%)...");
|
||||
});
|
||||
|
||||
it("when download progresses with decimals, percentage increases as integers", () => {
|
||||
const progressOfUpdateDownload = applicationBuilder.dis.mainDi.inject(
|
||||
progressOfUpdateDownloadInjectable,
|
||||
);
|
||||
|
||||
progressOfUpdateDownload.set({ percentage: 42.424242 });
|
||||
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.label?.get(),
|
||||
).toBe("Downloading update some-version (42%)...");
|
||||
});
|
||||
|
||||
it("user still cannot install update", () => {
|
||||
expect(applicationBuilder.tray.get("install-update")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when download fails", () => {
|
||||
beforeEach(async () => {
|
||||
await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: false });
|
||||
});
|
||||
|
||||
it("user cannot install update", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("install-update"),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("should revert to use the normal tray icon", () => {
|
||||
expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal);
|
||||
});
|
||||
|
||||
it("user can check for updates again", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("name of tray item for checking updates no longer indicates that downloading is happening", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.label?.get(),
|
||||
).toBe("Check for updates");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when download succeeds", () => {
|
||||
beforeEach(async () => {
|
||||
await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: true });
|
||||
});
|
||||
|
||||
it("user can install update", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("install-update")?.label?.get(),
|
||||
).toBe("Install update some-version");
|
||||
});
|
||||
|
||||
it("should use the update available icon", () => {
|
||||
expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.updateAvailable);
|
||||
});
|
||||
|
||||
it("user can check for updates again", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.enabled.get(),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("name of tray item for checking updates no longer indicates that downloading is happening", () => {
|
||||
expect(
|
||||
applicationBuilder.tray.get("check-for-updates")?.label?.get(),
|
||||
).toBe("Check for updates");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
225
src/behaviours/application-update/installing-update.test.ts
Normal file
@ -0,0 +1,225 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import quitAndInstallUpdateInjectable from "../../main/electron-app/features/quit-and-install-update.injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable";
|
||||
import type { AskBoolean } from "../../main/ask-boolean/ask-boolean.injectable";
|
||||
import askBooleanInjectable from "../../main/ask-boolean/ask-boolean.injectable";
|
||||
import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
|
||||
describe("installing update", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let quitAndInstallUpdateMock: jest.Mock;
|
||||
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
|
||||
let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>;
|
||||
let setUpdateOnQuitMock: jest.Mock;
|
||||
let showInfoNotificationMock: jest.Mock;
|
||||
let askBooleanMock: AsyncFnMock<AskBoolean>;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
|
||||
quitAndInstallUpdateMock = jest.fn();
|
||||
checkForPlatformUpdatesMock = asyncFn();
|
||||
downloadPlatformUpdateMock = asyncFn();
|
||||
setUpdateOnQuitMock = jest.fn();
|
||||
showInfoNotificationMock = jest.fn(() => () => {});
|
||||
askBooleanMock = asyncFn();
|
||||
|
||||
rendererDi.override(showInfoNotificationInjectable, () => showInfoNotificationMock);
|
||||
|
||||
mainDi.override(askBooleanInjectable, () => askBooleanMock);
|
||||
mainDi.override(setUpdateOnQuitInjectable, () => setUpdateOnQuitMock);
|
||||
|
||||
mainDi.override(
|
||||
checkForPlatformUpdatesInjectable,
|
||||
() => checkForPlatformUpdatesMock,
|
||||
);
|
||||
|
||||
mainDi.override(
|
||||
downloadPlatformUpdateInjectable,
|
||||
() => downloadPlatformUpdateMock,
|
||||
);
|
||||
|
||||
mainDi.override(
|
||||
quitAndInstallUpdateInjectable,
|
||||
() => quitAndInstallUpdateMock,
|
||||
);
|
||||
|
||||
mainDi.override(electronUpdaterIsActiveInjectable, () => true);
|
||||
mainDi.override(publishIsConfiguredInjectable, () => true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when started", () => {
|
||||
let rendered: RenderResult;
|
||||
let processCheckingForUpdates: () => Promise<void>;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
|
||||
processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when user checks for updates", () => {
|
||||
let processCheckingForUpdatesPromise: Promise<void>;
|
||||
|
||||
beforeEach(async () => {
|
||||
processCheckingForUpdatesPromise = processCheckingForUpdates();
|
||||
});
|
||||
|
||||
it("checks for updates", () => {
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
{ allowDowngrade: true },
|
||||
);
|
||||
});
|
||||
|
||||
it("notifies the user that checking for updates is happening", () => {
|
||||
expect(showInfoNotificationMock).toHaveBeenCalledWith("Checking for updates...");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when no new update is discovered", () => {
|
||||
beforeEach(async () => {
|
||||
showInfoNotificationMock.mockClear();
|
||||
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: false,
|
||||
});
|
||||
|
||||
await processCheckingForUpdatesPromise;
|
||||
});
|
||||
|
||||
it("notifies the user", () => {
|
||||
expect(showInfoNotificationMock).toHaveBeenCalledWith("No new updates available");
|
||||
});
|
||||
|
||||
it("does not start downloading update", () => {
|
||||
expect(downloadPlatformUpdateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when new update is discovered", () => {
|
||||
beforeEach(async () => {
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: true,
|
||||
version: "some-version",
|
||||
});
|
||||
|
||||
await processCheckingForUpdatesPromise;
|
||||
});
|
||||
|
||||
it("starts downloading the update", () => {
|
||||
expect(downloadPlatformUpdateMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("notifies the user that download is happening", () => {
|
||||
expect(showInfoNotificationMock).toHaveBeenCalledWith("Download for version some-version started...");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when download fails", () => {
|
||||
beforeEach(async () => {
|
||||
await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: false });
|
||||
});
|
||||
|
||||
it("does not quit and install update yet", () => {
|
||||
expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("notifies the user about failed download", () => {
|
||||
expect(showInfoNotificationMock).toHaveBeenCalledWith("Download of update failed");
|
||||
});
|
||||
|
||||
it("does not ask user to install update", () => {
|
||||
expect(askBooleanMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when download succeeds", () => {
|
||||
beforeEach(async () => {
|
||||
await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: true });
|
||||
});
|
||||
|
||||
it("does not quit and install update yet", () => {
|
||||
expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("asks user to install update immediately", () => {
|
||||
expect(askBooleanMock).toHaveBeenCalledWith({
|
||||
title: "Update Available",
|
||||
question:
|
||||
"Version some-version of Lens IDE is available and ready to be installed. Would you like to update now?\n\n" +
|
||||
"Lens should restart automatically, if it doesn't please restart manually. Installed extensions might require updating.",
|
||||
});
|
||||
});
|
||||
|
||||
describe("when user answers to install the update", () => {
|
||||
beforeEach(async () => {
|
||||
await askBooleanMock.resolve(true);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("quits application and installs the update", () => {
|
||||
expect(quitAndInstallUpdateMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when user answers not to install the update", () => {
|
||||
beforeEach(async () => {
|
||||
await askBooleanMock.resolve(false);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not quit application and install the update", () => {
|
||||
expect(quitAndInstallUpdateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import periodicalCheckForUpdatesInjectable from "../../main/application-update/periodical-check-for-updates/periodical-check-for-updates.injectable";
|
||||
|
||||
const ENOUGH_TIME = 1000 * 60 * 60 * 2;
|
||||
|
||||
describe("periodical checking of updates", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let processCheckingForUpdatesMock: AsyncFnMock<() => Promise<void>>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.unoverride(periodicalCheckForUpdatesInjectable);
|
||||
mainDi.permitSideEffects(periodicalCheckForUpdatesInjectable);
|
||||
|
||||
processCheckingForUpdatesMock = asyncFn();
|
||||
|
||||
mainDi.override(
|
||||
processCheckingForUpdatesInjectable,
|
||||
() => processCheckingForUpdatesMock,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given updater is enabled and configuration exists, when started", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(electronUpdaterIsActiveInjectable, () => true);
|
||||
mainDi.override(publishIsConfiguredInjectable, () => true);
|
||||
});
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("checks for updates", () => {
|
||||
expect(processCheckingForUpdatesMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("when just not enough time passes, does not check for updates again automatically yet", () => {
|
||||
processCheckingForUpdatesMock.mockClear();
|
||||
|
||||
jest.advanceTimersByTime(ENOUGH_TIME - 1);
|
||||
|
||||
expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("when just enough time passes, checks for updates again automatically", () => {
|
||||
processCheckingForUpdatesMock.mockClear();
|
||||
|
||||
jest.advanceTimersByTime(ENOUGH_TIME);
|
||||
|
||||
expect(processCheckingForUpdatesMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given updater is enabled but no configuration exist, when started", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(electronUpdaterIsActiveInjectable, () => true);
|
||||
mainDi.override(publishIsConfiguredInjectable, () => false);
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("does not check for updates", () => {
|
||||
expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("when time passes, never checks for updates", () => {
|
||||
jest.runOnlyPendingTimers();
|
||||
|
||||
expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given updater is not enabled but and configuration exist, when started", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(electronUpdaterIsActiveInjectable, () => false);
|
||||
mainDi.override(publishIsConfiguredInjectable, () => true);
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("does not check for updates", () => {
|
||||
expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("when time passes, never checks for updates", () => {
|
||||
jest.runOnlyPendingTimers();
|
||||
|
||||
expect(processCheckingForUpdatesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,331 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import quitAndInstallUpdateInjectable from "../../main/electron-app/features/quit-and-install-update.injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import electronUpdaterIsActiveInjectable from "../../main/electron-app/features/electron-updater-is-active.injectable";
|
||||
import publishIsConfiguredInjectable from "../../main/application-update/publish-is-configured.injectable";
|
||||
import type { CheckForPlatformUpdates } from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { UpdateChannel, UpdateChannelId } from "../../common/application-update/update-channels";
|
||||
import { updateChannels } from "../../common/application-update/update-channels";
|
||||
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
|
||||
import selectedUpdateChannelInjectable from "../../common/application-update/selected-update-channel/selected-update-channel.injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable";
|
||||
import type { AskBoolean } from "../../main/ask-boolean/ask-boolean.injectable";
|
||||
import askBooleanInjectable from "../../main/ask-boolean/ask-boolean.injectable";
|
||||
import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable";
|
||||
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
|
||||
import appVersionInjectable from "../../common/get-configuration-file-model/app-version/app-version.injectable";
|
||||
|
||||
describe("selection of update stability", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let quitAndInstallUpdateMock: jest.Mock;
|
||||
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
|
||||
let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>;
|
||||
let setUpdateOnQuitMock: jest.Mock;
|
||||
let showInfoNotificationMock: jest.Mock;
|
||||
let askBooleanMock: AsyncFnMock<AskBoolean>;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => {
|
||||
quitAndInstallUpdateMock = jest.fn();
|
||||
checkForPlatformUpdatesMock = asyncFn();
|
||||
downloadPlatformUpdateMock = asyncFn();
|
||||
setUpdateOnQuitMock = jest.fn();
|
||||
showInfoNotificationMock = jest.fn(() => () => {});
|
||||
askBooleanMock = asyncFn();
|
||||
|
||||
rendererDi.override(showInfoNotificationInjectable, () => showInfoNotificationMock);
|
||||
|
||||
mainDi.override(askBooleanInjectable, () => askBooleanMock);
|
||||
mainDi.override(setUpdateOnQuitInjectable, () => setUpdateOnQuitMock);
|
||||
|
||||
mainDi.override(
|
||||
checkForPlatformUpdatesInjectable,
|
||||
() => checkForPlatformUpdatesMock,
|
||||
);
|
||||
|
||||
mainDi.override(
|
||||
downloadPlatformUpdateInjectable,
|
||||
() => downloadPlatformUpdateMock,
|
||||
);
|
||||
|
||||
mainDi.override(
|
||||
quitAndInstallUpdateInjectable,
|
||||
() => quitAndInstallUpdateMock,
|
||||
);
|
||||
|
||||
mainDi.override(electronUpdaterIsActiveInjectable, () => true);
|
||||
mainDi.override(publishIsConfiguredInjectable, () => true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when started", () => {
|
||||
let rendered: RenderResult;
|
||||
let processCheckingForUpdates: () => Promise<void>;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
|
||||
processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('given update channel "alpha" is selected, when checking for updates', () => {
|
||||
let selectedUpdateChannel: {
|
||||
value: IComputedValue<UpdateChannel>;
|
||||
setValue: (channelId: UpdateChannelId) => void;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
selectedUpdateChannel = applicationBuilder.dis.mainDi.inject(
|
||||
selectedUpdateChannelInjectable,
|
||||
);
|
||||
|
||||
selectedUpdateChannel.setValue(updateChannels.alpha.id);
|
||||
|
||||
processCheckingForUpdates();
|
||||
});
|
||||
|
||||
it('checks updates from update channel "alpha"', () => {
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
|
||||
updateChannels.alpha,
|
||||
{ allowDowngrade: true },
|
||||
);
|
||||
});
|
||||
|
||||
it("when update is discovered, does not check update from other update channels", async () => {
|
||||
checkForPlatformUpdatesMock.mockClear();
|
||||
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: true,
|
||||
version: "some-version",
|
||||
});
|
||||
|
||||
expect(checkForPlatformUpdatesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when no update is discovered", () => {
|
||||
beforeEach(async () => {
|
||||
checkForPlatformUpdatesMock.mockClear();
|
||||
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('checks updates from update channel "beta"', () => {
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
|
||||
updateChannels.beta,
|
||||
{ allowDowngrade: true },
|
||||
);
|
||||
});
|
||||
|
||||
it("when update is discovered, does not check update from other update channels", async () => {
|
||||
checkForPlatformUpdatesMock.mockClear();
|
||||
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: true,
|
||||
version: "some-version",
|
||||
});
|
||||
|
||||
expect(checkForPlatformUpdatesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when no update is discovered again", () => {
|
||||
beforeEach(async () => {
|
||||
checkForPlatformUpdatesMock.mockClear();
|
||||
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('finally checks updates from update channel "latest"', () => {
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
|
||||
updateChannels.latest,
|
||||
{ allowDowngrade: true },
|
||||
);
|
||||
});
|
||||
|
||||
it("when update is discovered, does not check update from other update channels", async () => {
|
||||
checkForPlatformUpdatesMock.mockClear();
|
||||
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: true,
|
||||
version: "some-version",
|
||||
});
|
||||
|
||||
expect(checkForPlatformUpdatesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('given update channel "beta" is selected', () => {
|
||||
let selectedUpdateChannel: {
|
||||
value: IComputedValue<UpdateChannel>;
|
||||
setValue: (channelId: UpdateChannelId) => void;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
selectedUpdateChannel = applicationBuilder.dis.mainDi.inject(
|
||||
selectedUpdateChannelInjectable,
|
||||
);
|
||||
|
||||
selectedUpdateChannel.setValue(updateChannels.beta.id);
|
||||
});
|
||||
|
||||
describe("when checking for updates", () => {
|
||||
beforeEach(() => {
|
||||
processCheckingForUpdates();
|
||||
});
|
||||
|
||||
describe('when update from "beta" channel is discovered', () => {
|
||||
beforeEach(async () => {
|
||||
await checkForPlatformUpdatesMock.resolve({
|
||||
updateWasDiscovered: true,
|
||||
version: "some-beta-version",
|
||||
});
|
||||
});
|
||||
|
||||
describe("when update is downloaded", () => {
|
||||
beforeEach(async () => {
|
||||
await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: true });
|
||||
});
|
||||
|
||||
it("when user would close the application, installs the update", () => {
|
||||
expect(setUpdateOnQuitMock).toHaveBeenLastCalledWith(true);
|
||||
});
|
||||
|
||||
it('given user changes update channel to "latest", when user would close the application, does not install the update for not being stable enough', () => {
|
||||
selectedUpdateChannel.setValue(updateChannels.latest.id);
|
||||
|
||||
expect(setUpdateOnQuitMock).toHaveBeenLastCalledWith(false);
|
||||
});
|
||||
|
||||
it('given user changes update channel to "alpha", when user would close the application, installs the update for being stable enough', () => {
|
||||
selectedUpdateChannel.setValue(updateChannels.alpha.id);
|
||||
|
||||
expect(setUpdateOnQuitMock).toHaveBeenLastCalledWith(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("given valid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
// TODO: Switch to more natural way of setting initial value
|
||||
// TODO: UserStore is currently responsible for getting and setting initial value
|
||||
const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
|
||||
|
||||
selectedUpdateChannel.setValue(updateChannels.beta.id);
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
|
||||
processCheckingForUpdates();
|
||||
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.beta, expect.any(Object));
|
||||
});
|
||||
|
||||
it("given invalid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
// TODO: Switch to more natural way of setting initial value
|
||||
// TODO: UserStore is currently responsible for getting and setting initial value
|
||||
const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
|
||||
|
||||
selectedUpdateChannel.setValue("something-invalid" as UpdateChannelId);
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
|
||||
processCheckingForUpdates();
|
||||
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.latest, expect.any(Object));
|
||||
});
|
||||
|
||||
it('given no update channel selection is stored and currently using stable release, when user checks for updates, checks for updates from "latest" update channel by default', async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(appVersionInjectable, () => "1.0.0");
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
|
||||
processCheckingForUpdates();
|
||||
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(
|
||||
updateChannels.latest,
|
||||
{ allowDowngrade: true },
|
||||
);
|
||||
});
|
||||
|
||||
it('given no update channel selection is stored and currently using alpha release, when checking for updates, checks for updates from "alpha" channel', async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(appVersionInjectable, () => "1.0.0-alpha");
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
|
||||
processCheckingForUpdates();
|
||||
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.alpha, expect.any(Object));
|
||||
});
|
||||
|
||||
it('given no update channel selection is stored and currently using beta release, when checking for updates, checks for updates from "beta" channel', async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(appVersionInjectable, () => "1.0.0-beta");
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
|
||||
processCheckingForUpdates();
|
||||
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.beta, expect.any(Object));
|
||||
});
|
||||
|
||||
it("given update channel selection is stored and currently using prerelease, when checking for updates, checks for updates from stored channel", async () => {
|
||||
applicationBuilder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(appVersionInjectable, () => "1.0.0-alpha");
|
||||
|
||||
// TODO: Switch to more natural way of setting initial value
|
||||
// TODO: UserStore is currently responsible for getting and setting initial value
|
||||
const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
|
||||
|
||||
selectedUpdateChannel.setValue(updateChannels.beta.id);
|
||||
});
|
||||
|
||||
await applicationBuilder.render();
|
||||
|
||||
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable);
|
||||
|
||||
processCheckingForUpdates();
|
||||
|
||||
expect(checkForPlatformUpdatesMock).toHaveBeenCalledWith(updateChannels.beta, expect.any(Object));
|
||||
});
|
||||
});
|
||||
@ -328,6 +328,9 @@ exports[`cluster - order of sidebar items when rendered renders 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -723,5 +726,8 @@ exports[`cluster - order of sidebar items when rendered when parent is expanded
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -293,6 +293,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -589,6 +592,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -909,6 +915,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1234,6 +1243,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
|
||||
<div
|
||||
data-testid="some-child-page"
|
||||
/>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1534,6 +1546,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
|
||||
<div
|
||||
data-testid="some-child-page"
|
||||
/>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1854,6 +1869,9 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -2150,5 +2168,8 @@ exports[`cluster - sidebar and tab navigation for core given core registrations
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -293,6 +293,9 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -589,6 +592,9 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -929,6 +935,9 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1313,6 +1322,9 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1697,6 +1709,9 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -2036,6 +2051,9 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -2376,6 +2394,9 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -2672,5 +2693,8 @@ exports[`cluster - sidebar and tab navigation for extensions given extension wit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -261,6 +261,9 @@ exports[`cluster - visibility of sidebar items given kube resource for route is
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -573,5 +576,8 @@ exports[`cluster - visibility of sidebar items given kube resource for route is
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`extensions - navigation using application menu renders 1`] = `<div />`;
|
||||
exports[`extensions - navigation using application menu renders 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`extensions - navigation using application menu when navigating to extensions using application menu renders 1`] = `
|
||||
<div>
|
||||
@ -118,5 +124,8 @@ exports[`extensions - navigation using application menu when navigating to exten
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -6,12 +6,7 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
|
||||
import extensionsStoreInjectable from "../../extensions/extensions-store/extensions-store.injectable";
|
||||
import type { ExtensionsStore } from "../../extensions/extensions-store/extensions-store";
|
||||
import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
||||
import type { FileSystemProvisionerStore } from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store";
|
||||
import focusWindowInjectable from "../../renderer/ipc-channel-listeners/focus-window.injectable";
|
||||
import focusWindowInjectable from "../../renderer/navigation/focus-window.injectable";
|
||||
|
||||
// TODO: Make components free of side effects by making them deterministic
|
||||
jest.mock("../../renderer/components/input/input");
|
||||
@ -22,11 +17,7 @@ describe("extensions - navigation using application menu", () => {
|
||||
let focusWindowMock: jest.Mock;
|
||||
|
||||
beforeEach(async () => {
|
||||
applicationBuilder = getApplicationBuilder().beforeApplicationStart(({ mainDi, rendererDi }) => {
|
||||
mainDi.override(isAutoUpdateEnabledInjectable, () => () => false);
|
||||
rendererDi.override(extensionsStoreInjectable, () => ({}) as unknown as ExtensionsStore);
|
||||
rendererDi.override(fileSystemProvisionerStoreInjectable, () => ({}) as unknown as FileSystemProvisionerStore);
|
||||
|
||||
applicationBuilder = getApplicationBuilder().beforeApplicationStart(({ rendererDi }) => {
|
||||
focusWindowMock = jest.fn();
|
||||
|
||||
rendererDi.override(focusWindowInjectable, () => focusWindowMock);
|
||||
|
||||
@ -454,5 +454,8 @@ exports[`helm-charts - navigation to Helm charts when navigating to Helm charts
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -356,13 +356,12 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -370,7 +369,6 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -537,6 +535,9 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -679,6 +680,9 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -687,6 +691,9 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
<div>
|
||||
Some front page
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -695,6 +702,9 @@ exports[`preferences - closing-preferences given accessing preferences directly
|
||||
<div>
|
||||
Some front page
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1054,13 +1064,12 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -1068,7 +1077,6 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -1235,6 +1243,9 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1377,6 +1388,9 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1519,6 +1533,9 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1661,5 +1678,8 @@ exports[`preferences - closing-preferences given already in a page and then navi
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -199,6 +199,9 @@ exports[`preferences - navigation to application preferences given in some child
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -546,13 +549,12 @@ exports[`preferences - navigation to application preferences given in some child
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -560,7 +562,6 @@ exports[`preferences - navigation to application preferences given in some child
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -727,5 +728,8 @@ exports[`preferences - navigation to application preferences given in some child
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -344,13 +344,12 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -358,7 +357,6 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -525,6 +523,9 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -935,5 +936,8 @@ exports[`preferences - navigation to editor preferences given in preferences, wh
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -344,13 +344,12 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -358,7 +357,6 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -525,6 +523,9 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -884,13 +885,12 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -898,7 +898,6 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -1065,6 +1064,9 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1239,5 +1241,8 @@ exports[`preferences - navigation to extension specific preferences given in pre
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -344,13 +344,12 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -358,7 +357,6 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -525,6 +523,9 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -836,7 +837,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
class="flex gaps"
|
||||
>
|
||||
<div
|
||||
class="Select theme-lens box grow css-b62m3t-container"
|
||||
class="Select theme-lens box grow Select--is-disabled css-3iigni-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
@ -849,7 +850,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="Select__control css-1s2u09g-control"
|
||||
class="Select__control Select__control--is-disabled css-1insrsq-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
@ -861,7 +862,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
Repositories
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
class="Select__input-container css-jzldcf-Input"
|
||||
data-value=""
|
||||
>
|
||||
<input
|
||||
@ -873,6 +874,7 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="Select__input"
|
||||
disabled=""
|
||||
id="HelmRepoSelect"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
@ -886,8 +888,22 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
<div
|
||||
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||
>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="Select__indicator Select__loading-indicator css-at12u2-loadingIndicator"
|
||||
>
|
||||
<span
|
||||
class="css-1xtdfmb-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-zoievk-LoadingDot"
|
||||
/>
|
||||
<span
|
||||
class="css-x748d8-LoadingDot"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
|
||||
class="Select__indicator-separator css-109onse-indicatorSeparator"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
@ -920,13 +936,11 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
class="repos"
|
||||
>
|
||||
<div
|
||||
class="notice"
|
||||
class="pt-5 relative"
|
||||
>
|
||||
<div
|
||||
class="flex-grow text-center"
|
||||
>
|
||||
The repositories have not been added yet
|
||||
</div>
|
||||
class="Spinner singleColor center"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -969,5 +983,8 @@ exports[`preferences - navigation to kubernetes preferences given in preferences
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -344,13 +344,12 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -358,7 +357,6 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -525,6 +523,9 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -727,5 +728,8 @@ exports[`preferences - navigation to proxy preferences given in preferences, whe
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -185,6 +185,9 @@ exports[`preferences - navigation to telemetry preferences given URL for Sentry
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -532,13 +535,12 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -546,7 +548,6 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -713,6 +714,9 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1072,13 +1076,12 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -1086,7 +1089,6 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -1253,6 +1255,9 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1429,6 +1434,9 @@ exports[`preferences - navigation to telemetry preferences given in preferences,
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1568,5 +1576,8 @@ exports[`preferences - navigation to telemetry preferences given no URL for Sent
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -344,13 +344,12 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -358,7 +357,6 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -525,6 +523,9 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -770,6 +771,7 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
>
|
||||
<input
|
||||
class="input box grow"
|
||||
max="50"
|
||||
min="10"
|
||||
spellcheck="false"
|
||||
type="number"
|
||||
@ -789,22 +791,78 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Input theme round black"
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
>
|
||||
<label
|
||||
class="input-area flex gaps align-center"
|
||||
id=""
|
||||
>
|
||||
<input
|
||||
class="input box grow"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</label>
|
||||
<div
|
||||
class="input-info flex gaps"
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-2-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
aria-relevant="additions text"
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-2-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
data-value=""
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-2-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="Select__input"
|
||||
id="react-select-2-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||
>
|
||||
<span
|
||||
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="css-tj5bde-Svg"
|
||||
focusable="false"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
>
|
||||
<path
|
||||
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
@ -845,5 +903,8 @@ exports[`preferences - navigation to terminal preferences given in preferences,
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`preferences - navigation using application menu renders 1`] = `<div />`;
|
||||
exports[`preferences - navigation using application menu renders 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`preferences - navigation using application menu when navigating to preferences using application menu renders 1`] = `
|
||||
<div>
|
||||
@ -346,13 +352,12 @@ exports[`preferences - navigation using application menu when navigating to pref
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-update-channel-input-placeholder"
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Select...
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
@ -360,7 +365,6 @@ exports[`preferences - navigation using application menu when navigating to pref
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-update-channel-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
@ -527,5 +531,8 @@ exports[`preferences - navigation using application menu when navigating to pref
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -0,0 +1,542 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`show-about-using-tray renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`show-about-using-tray when navigating using tray renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="SettingLayout showNavigation Preferences"
|
||||
data-testid="application-preferences-page"
|
||||
>
|
||||
<nav
|
||||
class="sidebarRegion"
|
||||
>
|
||||
<div
|
||||
class="sidebar"
|
||||
>
|
||||
<div
|
||||
class="Tabs flex column"
|
||||
>
|
||||
<div
|
||||
class="header"
|
||||
>
|
||||
Preferences
|
||||
</div>
|
||||
<div
|
||||
class="Tab flex gaps align-center active"
|
||||
data-testid="tab-link-for-application"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="label"
|
||||
>
|
||||
App
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Tab flex gaps align-center"
|
||||
data-testid="tab-link-for-proxy"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="label"
|
||||
>
|
||||
Proxy
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Tab flex gaps align-center"
|
||||
data-testid="tab-link-for-kubernetes"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="label"
|
||||
>
|
||||
Kubernetes
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Tab flex gaps align-center"
|
||||
data-testid="tab-link-for-editor"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="label"
|
||||
>
|
||||
Editor
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Tab flex gaps align-center"
|
||||
data-testid="tab-link-for-terminal"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="label"
|
||||
>
|
||||
Terminal
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div
|
||||
class="contentRegion"
|
||||
id="ScrollSpyRoot"
|
||||
>
|
||||
<div
|
||||
class="content"
|
||||
>
|
||||
<section
|
||||
id="application"
|
||||
>
|
||||
<h2
|
||||
data-testid="application-header"
|
||||
>
|
||||
Application
|
||||
</h2>
|
||||
<section
|
||||
id="appearance"
|
||||
>
|
||||
<div
|
||||
class="SubTitle"
|
||||
>
|
||||
Theme
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-theme-input-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
aria-relevant="additions text"
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-theme-input-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
data-value=""
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-theme-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="Select__input"
|
||||
id="theme-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||
>
|
||||
<span
|
||||
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="css-tj5bde-Svg"
|
||||
focusable="false"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
>
|
||||
<path
|
||||
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<hr />
|
||||
<section
|
||||
id="extensionRegistryUrl"
|
||||
>
|
||||
<div
|
||||
class="SubTitle"
|
||||
>
|
||||
Extension Install Registry
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-extension-install-registry-input-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
aria-relevant="additions text"
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-extension-install-registry-input-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
data-value=""
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-extension-install-registry-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="Select__input"
|
||||
id="extension-install-registry-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||
>
|
||||
<span
|
||||
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="css-tj5bde-Svg"
|
||||
focusable="false"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
>
|
||||
<path
|
||||
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
class="mt-4 mb-5 leading-relaxed"
|
||||
>
|
||||
This setting is to change the registry URL for installing extensions by name.
|
||||
If you are unable to access the default registry (https://registry.npmjs.org) you can change it in your
|
||||
<b>
|
||||
.npmrc
|
||||
</b>
|
||||
file or in the input below.
|
||||
</p>
|
||||
<div
|
||||
class="Input theme round black disabled invalid"
|
||||
>
|
||||
<label
|
||||
class="input-area flex gaps align-center"
|
||||
id=""
|
||||
>
|
||||
<input
|
||||
class="input box grow"
|
||||
disabled=""
|
||||
placeholder="Custom Extension Registry URL..."
|
||||
spellcheck="false"
|
||||
value="some-custom-url"
|
||||
/>
|
||||
</label>
|
||||
<div
|
||||
class="input-info flex gaps"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<hr />
|
||||
<section
|
||||
id="other"
|
||||
>
|
||||
<div
|
||||
class="SubTitle"
|
||||
>
|
||||
Start-up
|
||||
|
||||
</div>
|
||||
<label
|
||||
class="Switch"
|
||||
data-testid="switch"
|
||||
>
|
||||
Automatically start Lens on login
|
||||
<input
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
</label>
|
||||
</section>
|
||||
<hr />
|
||||
<section
|
||||
id="update-channel"
|
||||
>
|
||||
<div
|
||||
class="SubTitle"
|
||||
>
|
||||
Update Channel
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-update-channel-input-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
aria-relevant="additions text"
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container Select__value-container--has-value css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__single-value css-qc6sy-singleValue"
|
||||
>
|
||||
Stable
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
data-value=""
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="Select__input"
|
||||
id="update-channel-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||
>
|
||||
<span
|
||||
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="css-tj5bde-Svg"
|
||||
focusable="false"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
>
|
||||
<path
|
||||
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<hr />
|
||||
<section
|
||||
id="locale"
|
||||
>
|
||||
<div
|
||||
class="SubTitle"
|
||||
>
|
||||
Locale Timezone
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="Select theme-lens css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-timezone-input-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
aria-relevant="additions text"
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="Select__control css-1s2u09g-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container css-319lph-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-14el2xx-placeholder"
|
||||
id="react-select-timezone-input-placeholder"
|
||||
>
|
||||
Select...
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-6j8wv5-Input"
|
||||
data-value=""
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-timezone-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="Select__input"
|
||||
id="timezone-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||
>
|
||||
<span
|
||||
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="css-tj5bde-Svg"
|
||||
focusable="false"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
>
|
||||
<path
|
||||
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
<div
|
||||
class="toolsRegion"
|
||||
>
|
||||
<div
|
||||
class="fixed top-[60px]"
|
||||
>
|
||||
<div
|
||||
data-testid="close-preferences"
|
||||
>
|
||||
<div
|
||||
aria-label="Close"
|
||||
class="closeButton"
|
||||
role="button"
|
||||
>
|
||||
<i
|
||||
class="Icon icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="esc"
|
||||
>
|
||||
ESC
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -5,17 +5,12 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import defaultShellInjectable from "../../renderer/components/+preferences/default-shell.injectable";
|
||||
|
||||
describe("preferences - navigation to terminal preferences", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(defaultShellInjectable, () => "some-default-shell");
|
||||
});
|
||||
});
|
||||
|
||||
describe("given in preferences, when rendered", () => {
|
||||
|
||||
44
src/behaviours/preferences/navigation-using-tray.test.ts
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
|
||||
describe("show-about-using-tray", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show application preferences page yet", () => {
|
||||
const actual = rendered.queryByTestId("application-preferences-page");
|
||||
|
||||
expect(actual).toBeNull();
|
||||
});
|
||||
|
||||
describe("when navigating using tray", () => {
|
||||
beforeEach(async () => {
|
||||
await applicationBuilder.tray.click("open-preferences");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows application preferences page", () => {
|
||||
const actual = rendered.getByTestId("application-preferences-page");
|
||||
|
||||
expect(actual).not.toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,6 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`welcome - navigation using application menu renders 1`] = `<div />`;
|
||||
exports[`welcome - navigation using application menu renders 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`welcome - navigation using application menu when navigating to welcome using application menu renders 1`] = `
|
||||
<div>
|
||||
@ -87,5 +93,8 @@ exports[`welcome - navigation using application menu when navigating to welcome
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -6,16 +6,13 @@
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import isAutoUpdateEnabledInjectable from "../../main/is-auto-update-enabled.injectable";
|
||||
|
||||
describe("welcome - navigation using application menu", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
applicationBuilder = getApplicationBuilder().beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(isAutoUpdateEnabledInjectable, () => () => false);
|
||||
});
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
@ -22,6 +22,9 @@ import getConfigurationFileModelInjectable from "../get-configuration-file-model
|
||||
import appVersionInjectable from "../get-configuration-file-model/app-version/app-version.injectable";
|
||||
import assert from "assert";
|
||||
import directoryForTempInjectable from "../app-paths/directory-for-temp/directory-for-temp.injectable";
|
||||
import kubectlBinaryNameInjectable from "../../main/kubectl/binary-name.injectable";
|
||||
import kubectlDownloadingNormalizedArchInjectable from "../../main/kubectl/normalized-arch.injectable";
|
||||
import normalizedPlatformInjectable from "../vars/normalized-platform.injectable";
|
||||
|
||||
console = new Console(stdout, stderr);
|
||||
|
||||
@ -84,6 +87,9 @@ describe("cluster-store", () => {
|
||||
|
||||
mainDi.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
mainDi.override(directoryForTempInjectable, () => "some-temp-directory");
|
||||
mainDi.override(kubectlBinaryNameInjectable, () => "kubectl");
|
||||
mainDi.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
|
||||
mainDi.override(normalizedPlatformInjectable, () => "darwin");
|
||||
|
||||
mainDi.permitSideEffects(getConfigurationFileModelInjectable);
|
||||
mainDi.permitSideEffects(appVersionInjectable);
|
||||
@ -363,6 +369,8 @@ users:
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
mainDi.override(appVersionInjectable, () => "3.6.0");
|
||||
|
||||
createCluster = mainDi.inject(createClusterInjectionToken);
|
||||
|
||||
clusterStore = mainDi.inject(clusterStoreInjectable);
|
||||
|
||||
@ -21,7 +21,7 @@ jest.mock("electron", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
import { UserStore } from "../user-store";
|
||||
import type { UserStore } from "../user-store";
|
||||
import { Console } from "console";
|
||||
import { SemVer } from "semver";
|
||||
import electron from "electron";
|
||||
@ -49,14 +49,15 @@ describe("user store tests", () => {
|
||||
|
||||
di.override(writeFileInjectable, () => () => Promise.resolve());
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
di.override(userStoreInjectable, () => UserStore.createInstance());
|
||||
|
||||
di.permitSideEffects(getConfigurationFileModelInjectable);
|
||||
|
||||
di.permitSideEffects(appVersionInjectable);
|
||||
di.permitSideEffects(userStoreInjectable);
|
||||
|
||||
di.unoverride(userStoreInjectable);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
UserStore.resetInstance();
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
@ -126,6 +127,8 @@ describe("user store tests", () => {
|
||||
},
|
||||
});
|
||||
|
||||
di.override(appVersionInjectable, () => "10.0.0");
|
||||
|
||||
userStore = di.inject(userStoreInjectable);
|
||||
});
|
||||
|
||||
|
||||
@ -4,12 +4,9 @@
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { PathName } from "./app-path-names";
|
||||
import { createChannel } from "../ipc-channel/create-channel/create-channel";
|
||||
|
||||
export type AppPaths = Record<PathName, string>;
|
||||
|
||||
export const appPathsInjectionToken = getInjectionToken<AppPaths>({ id: "app-paths-token" });
|
||||
|
||||
export const appPathsIpcChannel = createChannel<AppPaths>("app-paths");
|
||||
|
||||
|
||||
|
||||
22
src/common/app-paths/app-paths-channel.injectable.ts
Normal 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 type { AppPaths } from "./app-path-injection-token";
|
||||
import type { RequestChannel } from "../utils/channel/request-channel-injection-token";
|
||||
import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
|
||||
|
||||
export type AppPathsChannel = RequestChannel<void, AppPaths>;
|
||||
|
||||
const appPathsChannelInjectable = getInjectable({
|
||||
id: "app-paths-channel",
|
||||
|
||||
instantiate: (): AppPathsChannel => ({
|
||||
id: "app-paths",
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default appPathsChannelInjectable;
|
||||
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { baseBinariesDir } from "../../vars";
|
||||
|
||||
const directoryForBundledBinariesInjectable = getInjectable({
|
||||
id: "directory-for-bundled-binaries",
|
||||
instantiate: () => baseBinariesDir.get(),
|
||||
});
|
||||
|
||||
export default directoryForBundledBinariesInjectable;
|
||||
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MessageChannel } from "../utils/channel/message-channel-injection-token";
|
||||
import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
|
||||
|
||||
export type ApplicationUpdateStatusEventId =
|
||||
| "checking-for-updates"
|
||||
| "no-updates-available"
|
||||
| "download-for-update-started"
|
||||
| "download-for-update-failed";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
export type ApplicationUpdateStatusChannelMessage = { eventId: ApplicationUpdateStatusEventId; version?: string };
|
||||
export type ApplicationUpdateStatusChannel = MessageChannel<ApplicationUpdateStatusChannelMessage>;
|
||||
|
||||
const applicationUpdateStatusChannelInjectable = getInjectable({
|
||||
id: "application-update-status-channel",
|
||||
|
||||
instantiate: (): ApplicationUpdateStatusChannel => ({
|
||||
id: "application-update-status-channel",
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default applicationUpdateStatusChannelInjectable;
|
||||
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
|
||||
import type { UpdateChannel } from "../update-channels";
|
||||
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
|
||||
|
||||
const discoveredUpdateVersionInjectable = getInjectable({
|
||||
id: "discovered-update-version",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox<
|
||||
| { version: string; updateChannel: UpdateChannel }
|
||||
| null
|
||||
>(
|
||||
"discovered-update-version",
|
||||
null,
|
||||
);
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default discoveredUpdateVersionInjectable;
|
||||
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
|
||||
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
|
||||
|
||||
export interface ProgressOfDownload {
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
const progressOfUpdateDownloadInjectable = getInjectable({
|
||||
id: "progress-of-update-download-state",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox<ProgressOfDownload>("progress-of-update-download", { percentage: 0 });
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default progressOfUpdateDownloadInjectable;
|
||||
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { SemVer } from "semver";
|
||||
import appVersionInjectable from "../../get-configuration-file-model/app-version/app-version.injectable";
|
||||
import type { UpdateChannelId } from "../update-channels";
|
||||
import { updateChannels } from "../update-channels";
|
||||
|
||||
const defaultUpdateChannelInjectable = getInjectable({
|
||||
id: "default-update-channel",
|
||||
|
||||
instantiate: (di) => {
|
||||
const appVersion = di.inject(appVersionInjectable);
|
||||
|
||||
const currentReleaseChannel = new SemVer(appVersion).prerelease[0]?.toString() as UpdateChannelId;
|
||||
|
||||
if (currentReleaseChannel && updateChannels[currentReleaseChannel]) {
|
||||
return updateChannels[currentReleaseChannel];
|
||||
}
|
||||
|
||||
return updateChannels.latest;
|
||||
},
|
||||
});
|
||||
|
||||
export default defaultUpdateChannelInjectable;
|
||||
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { action, computed, observable } from "mobx";
|
||||
import type { UpdateChannel, UpdateChannelId } from "../update-channels";
|
||||
import { updateChannels } from "../update-channels";
|
||||
import defaultUpdateChannelInjectable from "./default-update-channel.injectable";
|
||||
|
||||
export interface SelectedUpdateChannel {
|
||||
value: IComputedValue<UpdateChannel>;
|
||||
setValue: (channelId?: UpdateChannelId) => void;
|
||||
}
|
||||
|
||||
const selectedUpdateChannelInjectable = getInjectable({
|
||||
id: "selected-update-channel",
|
||||
|
||||
instantiate: (di): SelectedUpdateChannel => {
|
||||
const defaultUpdateChannel = di.inject(defaultUpdateChannelInjectable);
|
||||
const state = observable.box(defaultUpdateChannel);
|
||||
|
||||
return {
|
||||
value: computed(() => state.get()),
|
||||
|
||||
setValue: action((channelId) => {
|
||||
const targetUpdateChannel =
|
||||
channelId && updateChannels[channelId]
|
||||
? updateChannels[channelId]
|
||||
: defaultUpdateChannel;
|
||||
|
||||
state.set(targetUpdateChannel);
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default selectedUpdateChannelInjectable;
|
||||
37
src/common/application-update/update-channels.ts
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
|
||||
export type UpdateChannelId = "alpha" | "beta" | "latest";
|
||||
|
||||
const latestChannel: UpdateChannel = {
|
||||
id: "latest",
|
||||
label: "Stable",
|
||||
moreStableUpdateChannel: null,
|
||||
};
|
||||
|
||||
const betaChannel: UpdateChannel = {
|
||||
id: "beta",
|
||||
label: "Beta",
|
||||
moreStableUpdateChannel: latestChannel,
|
||||
};
|
||||
|
||||
const alphaChannel: UpdateChannel = {
|
||||
id: "alpha",
|
||||
label: "Alpha",
|
||||
moreStableUpdateChannel: betaChannel,
|
||||
};
|
||||
|
||||
export const updateChannels: Record<UpdateChannelId, UpdateChannel> = {
|
||||
latest: latestChannel,
|
||||
beta: betaChannel,
|
||||
alpha: alphaChannel,
|
||||
};
|
||||
|
||||
export interface UpdateChannel {
|
||||
readonly id: UpdateChannelId;
|
||||
readonly label: string;
|
||||
readonly moreStableUpdateChannel: UpdateChannel | null;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
|
||||
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
|
||||
|
||||
const updateIsBeingDownloadedInjectable = getInjectable({
|
||||
id: "update-is-being-downloaded",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox("update-is-being-downloaded", false);
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default updateIsBeingDownloadedInjectable;
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import createSyncBoxInjectable from "../../utils/sync-box/create-sync-box.injectable";
|
||||
import { syncBoxInjectionToken } from "../../utils/sync-box/sync-box-injection-token";
|
||||
|
||||
const updatesAreBeingDiscoveredInjectable = getInjectable({
|
||||
id: "updates-are-being-discovered",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createSyncBox = di.inject(createSyncBoxInjectable);
|
||||
|
||||
return createSyncBox("updates-are-being-discovered", false);
|
||||
},
|
||||
|
||||
injectionToken: syncBoxInjectionToken,
|
||||
});
|
||||
|
||||
export default updatesAreBeingDiscoveredInjectable;
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MessageChannel } from "../utils/channel/message-channel-injection-token";
|
||||
import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
|
||||
|
||||
export type AskBooleanAnswerChannel = MessageChannel<{ id: string; value: boolean }>;
|
||||
|
||||
const askBooleanAnswerChannelInjectable = getInjectable({
|
||||
id: "ask-boolean-answer-channel",
|
||||
|
||||
instantiate: (): AskBooleanAnswerChannel => ({
|
||||
id: "ask-boolean-answer",
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default askBooleanAnswerChannelInjectable;
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MessageChannel } from "../utils/channel/message-channel-injection-token";
|
||||
import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
export type AskBooleanQuestionParameters = { id: string; title: string; question: string };
|
||||
export type AskBooleanQuestionChannel = MessageChannel<AskBooleanQuestionParameters>;
|
||||
|
||||
const askBooleanQuestionChannelInjectable = getInjectable({
|
||||
id: "ask-boolean-question-channel",
|
||||
|
||||
instantiate: (): AskBooleanQuestionChannel => ({
|
||||
id: "ask-boolean-question",
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default askBooleanQuestionChannelInjectable;
|
||||
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
||||
import type { MessageChannel } from "../utils/channel/message-channel-injection-token";
|
||||
import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
|
||||
|
||||
export type AppNavigationChannel = MessageChannel<string>;
|
||||
|
||||
const appNavigationChannelInjectable = getInjectable({
|
||||
id: "app-navigation-channel",
|
||||
|
||||
instantiate: (): AppNavigationChannel => ({
|
||||
id: IpcRendererNavigationEvents.NAVIGATE_IN_APP,
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default appNavigationChannelInjectable;
|
||||
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
||||
import type { MessageChannel } from "../utils/channel/message-channel-injection-token";
|
||||
import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
|
||||
|
||||
export type ClusterFrameNavigationChannel = MessageChannel<string>;
|
||||
|
||||
const clusterFrameNavigationChannelInjectable = getInjectable({
|
||||
id: "cluster-frame-navigation-channel",
|
||||
|
||||
instantiate: (): ClusterFrameNavigationChannel => ({
|
||||
id: IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER,
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterFrameNavigationChannelInjectable;
|
||||
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { createChannel } from "../ipc-channel/create-channel/create-channel";
|
||||
import { IpcRendererNavigationEvents } from "../../renderer/navigation/events";
|
||||
|
||||
export const appNavigationIpcChannel = createChannel<string>(IpcRendererNavigationEvents.NAVIGATE_IN_APP);
|
||||
export const clusterFrameNavigationIpcChannel = createChannel<string>(IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER);
|
||||
@ -3,12 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import packageInfo from "../../../../package.json";
|
||||
import packageJsonInjectable from "../../vars/package-json.injectable";
|
||||
|
||||
const appVersionInjectable = getInjectable({
|
||||
id: "app-version",
|
||||
instantiate: () => packageInfo.version,
|
||||
causesSideEffects: true,
|
||||
instantiate: (di) => di.inject(packageJsonInjectable).version,
|
||||
});
|
||||
|
||||
export default appVersionInjectable;
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { Channel } from "../channel";
|
||||
|
||||
export const createChannel = <Message>(name: string): Channel<Message> => ({
|
||||
name,
|
||||
_template: null as never,
|
||||
});
|
||||
@ -5,5 +5,4 @@
|
||||
|
||||
export * from "./ipc";
|
||||
export * from "./invalid-kubeconfig";
|
||||
export * from "./update-available";
|
||||
export * from "./type-enforced-ipc";
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { UpdateInfo } from "electron-updater";
|
||||
|
||||
export const UpdateAvailableChannel = "update-available";
|
||||
export const AutoUpdateChecking = "auto-update:checking";
|
||||
export const AutoUpdateNoUpdateAvailable = "auto-update:no-update";
|
||||
export const AutoUpdateQuitAndInstalledChannel = "auto-update:quit-and-install";
|
||||
export const AutoUpdateLogPrefix = "[UPDATE-CHECKER]";
|
||||
|
||||
export type UpdateAvailableFromMain = [backChannel: string, updateInfo: UpdateInfo];
|
||||
|
||||
export function areArgsUpdateAvailableFromMain(args: unknown[]): args is UpdateAvailableFromMain {
|
||||
if (args.length !== 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof args[0] !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof args[1] !== "object" || args[1] === null) {
|
||||
// TODO: improve this checking
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export type BackchannelArg = {
|
||||
doUpdate: false;
|
||||
} | {
|
||||
doUpdate: true;
|
||||
now: boolean;
|
||||
};
|
||||
|
||||
export type UpdateAvailableToBackchannel = [updateDecision: BackchannelArg];
|
||||
|
||||
export function areArgsUpdateAvailableToBackchannel(args: unknown[]): args is UpdateAvailableToBackchannel {
|
||||
if (args.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof args[0] !== "object" || args[0] === null) {
|
||||
// TODO: improve this checking
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -8,7 +8,61 @@ import { Node } from "../endpoints";
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
describe("Nodes tests", () => {
|
||||
describe("Node tests", () => {
|
||||
describe("isMasterNode()", () => {
|
||||
it("given a master node labelled before kubernetes 1.20, should return true", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"node-role.kubernetes.io/master": "NoSchedule",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.isMasterNode()).toBe(true);
|
||||
});
|
||||
|
||||
it("given a master node labelled after kubernetes 1.20, should return true", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"node-role.kubernetes.io/control-plane": "NoSchedule",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.isMasterNode()).toBe(true);
|
||||
});
|
||||
|
||||
it("given a non master node, should return false", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.isMasterNode()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getRoleLabels()", () => {
|
||||
it("should return empty string if labels is not present", () => {
|
||||
const node = new Node({
|
||||
@ -10,12 +10,14 @@ import type { BaseKubeObjectCondition, KubeObjectScope } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { DerivedKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { JSONSchemaProps } from "./types/json-schema-props";
|
||||
|
||||
interface AdditionalPrinterColumnsCommon {
|
||||
name: string;
|
||||
type: "integer" | "number" | "string" | "boolean" | "date";
|
||||
priority: number;
|
||||
description: string;
|
||||
priority?: number;
|
||||
format?: "int32" | "int64" | "float" | "double" | "byte" | "binary" | "date" | "date-time" | "password";
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & {
|
||||
@ -26,11 +28,15 @@ type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & {
|
||||
JSONPath: string;
|
||||
};
|
||||
|
||||
export interface CustomResourceValidation {
|
||||
openAPIV3Schema?: JSONSchemaProps;
|
||||
}
|
||||
|
||||
export interface CustomResourceDefinitionVersion {
|
||||
name: string;
|
||||
served: boolean;
|
||||
storage: boolean;
|
||||
schema?: object; // required in v1 but not present in v1beta
|
||||
schema?: CustomResourceValidation; // required in v1 but not present in v1beta
|
||||
additionalPrinterColumns?: AdditionalPrinterColumnsV1[];
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
import type { BaseKubeObjectCondition, KubeObjectScope } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { cpuUnitsToNumber, unitsToBytes } from "../../../renderer/utils";
|
||||
import { cpuUnitsToNumber, unitsToBytes, isObject } from "../../../renderer/utils";
|
||||
import type { MetricData } from "./metrics.api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
@ -69,6 +69,17 @@ export interface NodeCondition extends BaseKubeObjectCondition {
|
||||
lastHeartbeatTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* These role label prefixs are the ones that are for master nodes
|
||||
*
|
||||
* The `master` label has been deprecated in Kubernetes 1.20, and will be removed in 1.25 so we
|
||||
* have to also use the newer `control-plane` label
|
||||
*/
|
||||
const masterNodeLabels = [
|
||||
"master",
|
||||
"control-plane",
|
||||
];
|
||||
|
||||
/**
|
||||
* This regex is used in the `getRoleLabels()` method bellow, but placed here
|
||||
* as factoring out regexes is best practice.
|
||||
@ -189,15 +200,19 @@ export class Node extends KubeObject<NodeStatus, NodeSpec, KubeObjectScope.Clust
|
||||
return this.spec.taints || [];
|
||||
}
|
||||
|
||||
getRoleLabels(): string {
|
||||
isMasterNode(): boolean {
|
||||
return this.getRoleLabelItems()
|
||||
.some(roleLabel => masterNodeLabels.includes(roleLabel));
|
||||
}
|
||||
|
||||
getRoleLabelItems(): string[] {
|
||||
const { labels } = this.metadata;
|
||||
|
||||
if (!labels || typeof labels !== "object") {
|
||||
return "";
|
||||
}
|
||||
|
||||
const roleLabels: string[] = [];
|
||||
|
||||
if (!isObject(labels)) {
|
||||
return roleLabels;
|
||||
}
|
||||
|
||||
for (const labelKey of Object.keys(labels)) {
|
||||
const match = nodeRoleLabelKeyMatcher.match(labelKey);
|
||||
|
||||
@ -214,7 +229,11 @@ export class Node extends KubeObject<NodeStatus, NodeSpec, KubeObjectScope.Clust
|
||||
roleLabels.push(labels["node.kubernetes.io/role"]);
|
||||
}
|
||||
|
||||
return roleLabels.join(", ");
|
||||
return roleLabels;
|
||||
}
|
||||
|
||||
getRoleLabels(): string {
|
||||
return this.getRoleLabelItems().join(", ");
|
||||
}
|
||||
|
||||
getCpuCapacity() {
|
||||
|
||||
@ -294,8 +294,10 @@ export interface CephfsSource {
|
||||
secretRef?: SecretReference;
|
||||
/**
|
||||
* Whether the filesystem is used as readOnly.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readOnly: boolean;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface CinderSource {
|
||||
@ -445,46 +447,62 @@ export interface PortworxVolumeSource {
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface KeyToPath {
|
||||
key: string;
|
||||
path: string;
|
||||
mode?: number;
|
||||
}
|
||||
|
||||
export interface ConfigMapProjection {
|
||||
name: string;
|
||||
items?: KeyToPath[];
|
||||
optional?: boolean;
|
||||
}
|
||||
|
||||
export interface ObjectFieldSelector {
|
||||
fieldPath: string;
|
||||
apiVersion?: string;
|
||||
}
|
||||
|
||||
export interface ResourceFieldSelector {
|
||||
resource: string;
|
||||
containerName?: string;
|
||||
divisor?: string;
|
||||
}
|
||||
|
||||
export interface DownwardAPIVolumeFile {
|
||||
path: string;
|
||||
fieldRef?: ObjectFieldSelector;
|
||||
resourceFieldRef?: ResourceFieldSelector;
|
||||
mode?: number;
|
||||
}
|
||||
|
||||
export interface DownwardAPIProjection {
|
||||
items?: DownwardAPIVolumeFile[];
|
||||
}
|
||||
|
||||
export interface SecretProjection {
|
||||
name: string;
|
||||
items?: KeyToPath[];
|
||||
optional?: boolean;
|
||||
}
|
||||
|
||||
export interface ServiceAccountTokenProjection {
|
||||
audience?: string;
|
||||
expirationSeconds?: number;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface VolumeProjection {
|
||||
secret?: SecretProjection;
|
||||
downwardAPI?: DownwardAPIProjection;
|
||||
configMap?: ConfigMapProjection;
|
||||
serviceAccountToken?: ServiceAccountTokenProjection;
|
||||
}
|
||||
|
||||
export interface ProjectedSource {
|
||||
sources: {
|
||||
secret?: {
|
||||
name: string;
|
||||
items?: {
|
||||
key: string;
|
||||
path: string;
|
||||
mode?: number;
|
||||
}[];
|
||||
};
|
||||
downwardAPI?: {
|
||||
items?: {
|
||||
path: string;
|
||||
fieldRef?: {
|
||||
fieldPath: string;
|
||||
apiVersion?: string;
|
||||
};
|
||||
resourceFieldRef?: {
|
||||
resource: string;
|
||||
containerName?: string;
|
||||
};
|
||||
mode?: number;
|
||||
}[];
|
||||
};
|
||||
configMap?: {
|
||||
name: string;
|
||||
items?: {
|
||||
key: string;
|
||||
path: string;
|
||||
mode?: number;
|
||||
}[];
|
||||
optional?: boolean;
|
||||
};
|
||||
serviceAccountToken?: {
|
||||
audience?: string;
|
||||
expirationSeconds?: number;
|
||||
path: string;
|
||||
};
|
||||
}[];
|
||||
defaultMode: number;
|
||||
sources?: VolumeProjection[];
|
||||
defaultMode?: number;
|
||||
}
|
||||
|
||||
export interface QuobyteSource {
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface ExternalDocumentation {
|
||||
description?: string;
|
||||
url?: string;
|
||||
}
|
||||
93
src/common/k8s-api/endpoints/types/json-schema-props.ts
Normal file
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { JsonValue } from "type-fest";
|
||||
import type { ExternalDocumentation } from "./external-documentation";
|
||||
|
||||
export interface JSONSchemaProps {
|
||||
$ref?: string;
|
||||
$schema?: string;
|
||||
additionalItems?: JSONSchemaProps | boolean;
|
||||
additionalProperties?: JSONSchemaProps | boolean;
|
||||
allOf?: JSONSchemaProps[];
|
||||
anyOf?: JSONSchemaProps[];
|
||||
|
||||
/**
|
||||
* default is a default value for undefined object fields.
|
||||
* Defaulting is a beta feature under the CustomResourceDefaulting feature gate.
|
||||
* Defaulting requires spec.preserveUnknownFields to be false.
|
||||
*/
|
||||
_default?: object;
|
||||
|
||||
definitions?: Partial<Record<string, JSONSchemaProps>>;
|
||||
dependencies?: Partial<Record<string, object>>;
|
||||
description?: string;
|
||||
_enum?: object[];
|
||||
example?: JsonValue;
|
||||
|
||||
exclusiveMaximum?: boolean;
|
||||
exclusiveMinimum?: boolean;
|
||||
externalDocs?: ExternalDocumentation;
|
||||
|
||||
/**
|
||||
* format is an OpenAPI v3 format string.
|
||||
* Unknown formats are ignored.
|
||||
*
|
||||
* The following formats are validated:
|
||||
* - bsonobjectid: a bson object ID, i.e. a 24 characters hex string
|
||||
* - uri: an URI as parsed by Golang net/url.ParseRequestURI
|
||||
* - email: an email address as parsed by Golang net/mail.ParseAddress
|
||||
* - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
|
||||
* - ipv4: an IPv4 IP as parsed by Golang net.ParseIP
|
||||
* - ipv6: an IPv6 IP as parsed by Golang net.ParseIP
|
||||
* - cidr: a CIDR as parsed by Golang net.ParseCIDR
|
||||
* - mac: a MAC address as parsed by Golang net.ParseMAC
|
||||
* - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$
|
||||
* - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$
|
||||
* - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
|
||||
* - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
|
||||
* - isbn: an ISBN10 or ISBN13 number string like "0321751043" or "978-0321751041"
|
||||
* - isbn10: an ISBN10 number string like "0321751043"
|
||||
* - isbn13: an ISBN13 number string like "978-0321751041"
|
||||
* - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$ with any non digit characters mixed in
|
||||
* - ssn: a U.S. social security number following the regex ^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$
|
||||
* - hexcolor: an hexadecimal color code like "#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
|
||||
* - rgbcolor: an RGB color code like rgb like "rgb(255,255,2559"
|
||||
* - byte: base64 encoded binary data
|
||||
* - password: any kind of string
|
||||
* - date: a date string like "2006-01-02" as defined by full-date in RFC3339
|
||||
* - duration: a duration string like "22 ns" as parsed by Golang time.ParseDuration or compatible with Scala duration format
|
||||
* - datetime: a date time string like "2014-12-15T19:30:20.000Z" as defined by date-time in RFC3339.
|
||||
*/
|
||||
format?: string;
|
||||
|
||||
id?: string;
|
||||
items?: JSONSchemaProps | JSONSchemaProps[];
|
||||
maxItems?: number;
|
||||
maxLength?: number;
|
||||
maxProperties?: number;
|
||||
maximum?: number;
|
||||
minItems?: number;
|
||||
minLength?: number;
|
||||
minProperties?: number;
|
||||
minimum?: number;
|
||||
multipleOf?: number;
|
||||
not?: JSONSchemaProps;
|
||||
nullable?: boolean;
|
||||
oneOf?: JSONSchemaProps[];
|
||||
pattern?: string;
|
||||
patternProperties?: Partial<Record<string, JSONSchemaProps>>;
|
||||
properties?: Partial<Record<string, JSONSchemaProps>>;
|
||||
required?: Array<string>;
|
||||
title?: string;
|
||||
type?: string;
|
||||
uniqueItems?: boolean;
|
||||
x_kubernetes_embedded_resource?: boolean;
|
||||
x_kubernetes_int_or_string?: boolean;
|
||||
x_kubernetes_list_map_keys?: string[];
|
||||
x_kubernetes_list_type?: string;
|
||||
x_kubernetes_map_type?: string;
|
||||
x_kubernetes_preserve_unknown_fields?: boolean;
|
||||
}
|
||||
@ -169,6 +169,13 @@ export interface IRemoteKubeApiConfig {
|
||||
clientCertificateData?: string;
|
||||
clientKeyData?: string;
|
||||
};
|
||||
/**
|
||||
* Custom instance of https.agent to use for the requests
|
||||
*
|
||||
* @remarks the custom agent replaced default agent, options skipTLSVerify,
|
||||
* clientCertificateData, clientKeyData and caData are ignored.
|
||||
*/
|
||||
agent?: Agent;
|
||||
}
|
||||
|
||||
export function forCluster<
|
||||
@ -240,6 +247,10 @@ export function forRemoteCluster<
|
||||
reqInit.agent = new Agent(agentOptions);
|
||||
}
|
||||
|
||||
if (config.agent) {
|
||||
reqInit.agent = config.agent;
|
||||
}
|
||||
|
||||
const token = config.user.token;
|
||||
const request = new KubeJsonApi({
|
||||
serverAddress: config.cluster.server,
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Register custom protocols
|
||||
|
||||
import { protocol } from "electron";
|
||||
import path from "path";
|
||||
|
||||
export function registerFileProtocol(name: string, basePath: string) {
|
||||
protocol.registerFileProtocol(name, (request, callback) => {
|
||||
const filePath = request.url.replace(`${name}://`, "");
|
||||
const absPath = path.resolve(basePath, filePath);
|
||||
|
||||
callback({ path: absPath });
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MessageChannel } from "../utils/channel/message-channel-injection-token";
|
||||
import { messageChannelInjectionToken } from "../utils/channel/message-channel-injection-token";
|
||||
|
||||
export type RootFrameRenderedChannel = MessageChannel;
|
||||
|
||||
const rootFrameRenderedChannelInjectable = getInjectable({
|
||||
id: "root-frame-rendered-channel",
|
||||
|
||||
instantiate: (): RootFrameRenderedChannel => ({
|
||||
id: "root-frame-rendered",
|
||||
}),
|
||||
|
||||
injectionToken: messageChannelInjectionToken,
|
||||
});
|
||||
|
||||
export default rootFrameRenderedChannelInjectable;
|
||||
31
src/common/terminal/channels.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
|
||||
export enum TerminalChannels {
|
||||
STDIN = "stdin",
|
||||
STDOUT = "stdout",
|
||||
CONNECTED = "connected",
|
||||
RESIZE = "resize",
|
||||
PING = "ping",
|
||||
}
|
||||
|
||||
export type TerminalMessage = {
|
||||
type: TerminalChannels.STDIN;
|
||||
data: string;
|
||||
} | {
|
||||
type: TerminalChannels.STDOUT;
|
||||
data: string;
|
||||
} | {
|
||||
type: TerminalChannels.CONNECTED;
|
||||
} | {
|
||||
type: TerminalChannels.RESIZE;
|
||||
data: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
} | {
|
||||
type: TerminalChannels.PING;
|
||||
};
|
||||