mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
chore: Turn on @typescript-eslint/strict-boolean-expressions
- Fix some bugs about bad conditions Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
d3f45bfe49
commit
1675c56e59
599
package-lock.json
generated
599
package-lock.json
generated
@ -7539,7 +7539,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
|
||||
"integrity": "sha512-0VLab/pcLTLcfbxi6THSIMVYcw9hEUBGvjwwaGpW77mMgRXfGF+a76t7BxTGyLh1y68tBvrffp8UWnqvm76+yg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"postcss": "^8.0.0"
|
||||
}
|
||||
@ -7548,7 +7547,6 @@
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/postcss-modules-scope/-/postcss-modules-scope-3.0.1.tgz",
|
||||
"integrity": "sha512-LNkp3c4ML9EQj2dgslp4i80Jxj72YK3HjYzrTn6ftUVylW1zaKFGqrMlNIyqBmPWmIhZ/Y5r0Y4T49Hk1IuDUg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"postcss": "^8.0.0"
|
||||
}
|
||||
@ -11757,6 +11755,7 @@
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
@ -34819,10 +34818,11 @@
|
||||
"version": "6.5.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"typescript": "^4.9.3"
|
||||
"typescript": "^4.9.3",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@k8slens/eslint-config": "^6.5.0-alpha.3"
|
||||
}
|
||||
},
|
||||
"packages/infrastructure/webpack": {
|
||||
@ -38893,7 +38893,7 @@
|
||||
"typedoc": "^0.24.6",
|
||||
"typedoc-plugin-markdown": "^3.15.1",
|
||||
"typescript": "^4.9.5",
|
||||
"typescript-plugin-css-modules": "^3.4.0",
|
||||
"typescript-plugin-css-modules": "^5.0.1",
|
||||
"url-parse": "^1.5.10",
|
||||
"uuid": "^8.3.2",
|
||||
"webpack": "^5.81.0",
|
||||
@ -38910,6 +38910,78 @@
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": {
|
||||
"version": "16.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
|
||||
"dev": true
|
||||
},
|
||||
"stylus": {
|
||||
"version": "0.59.0",
|
||||
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz",
|
||||
"integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@adobe/css-tools": "^4.0.1",
|
||||
"debug": "^4.3.2",
|
||||
"glob": "^7.1.6",
|
||||
"sax": "~1.2.4",
|
||||
"source-map": "^0.7.3"
|
||||
}
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
|
||||
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"json5": "^2.2.2",
|
||||
"minimist": "^1.2.6",
|
||||
"strip-bom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"typescript-plugin-css-modules": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-5.0.1.tgz",
|
||||
"integrity": "sha512-hKXObfwfjx2/myRq4JeQ8D3xIWYTFqusi0hS/Aka7RFX1xQEoEkdOGDWyXNb8LmObawsUzbI30gQnZvqYXCrkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/postcss-modules-local-by-default": "^4.0.0",
|
||||
"@types/postcss-modules-scope": "^3.0.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"icss-utils": "^5.1.0",
|
||||
"less": "^4.1.3",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-load-config": "^3.1.4",
|
||||
"postcss-modules-extract-imports": "^3.0.0",
|
||||
"postcss-modules-local-by-default": "^4.0.0",
|
||||
"postcss-modules-scope": "^3.0.0",
|
||||
"reserved-words": "^0.1.2",
|
||||
"sass": "^1.58.3",
|
||||
"source-map-js": "^1.0.2",
|
||||
"stylus": "^0.59.0",
|
||||
"tsconfig-paths": "^4.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"postcss-load-config": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
|
||||
"integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lilconfig": "^2.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"xterm": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm/-/xterm-4.19.0.tgz",
|
||||
@ -38993,7 +39065,7 @@
|
||||
"typedoc": "^0.24.6",
|
||||
"typedoc-plugin-markdown": "^3.15.1",
|
||||
"typescript": "^4.9.5",
|
||||
"typescript-plugin-css-modules": "^4.1.1",
|
||||
"typescript-plugin-css-modules": "^5.0.1",
|
||||
"webpack": "^5.81.0",
|
||||
"webpack-cli": "^5.0.1"
|
||||
},
|
||||
@ -39086,9 +39158,9 @@
|
||||
}
|
||||
},
|
||||
"typescript-plugin-css-modules": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-4.2.3.tgz",
|
||||
"integrity": "sha512-jEEP2oUPOqR89QGgvPK2HSTZLkrCeKZQ9EwiNxm9VUcufUbNY1Tv053fPKRq6c13PMQjlBU3WrQjKN8u0j5Y6w==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-5.0.1.tgz",
|
||||
"integrity": "sha512-hKXObfwfjx2/myRq4JeQ8D3xIWYTFqusi0hS/Aka7RFX1xQEoEkdOGDWyXNb8LmObawsUzbI30gQnZvqYXCrkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/postcss-modules-local-by-default": "^4.0.0",
|
||||
@ -39642,7 +39714,75 @@
|
||||
"requires": {
|
||||
"@k8slens/eslint-config": "^6.5.0-alpha.2",
|
||||
"typescript": "^4.9.3",
|
||||
"typescript-plugin-css-modules": "^3.4.0"
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": {
|
||||
"version": "16.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
|
||||
},
|
||||
"strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="
|
||||
},
|
||||
"stylus": {
|
||||
"version": "0.59.0",
|
||||
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz",
|
||||
"integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==",
|
||||
"requires": {
|
||||
"@adobe/css-tools": "^4.0.1",
|
||||
"debug": "^4.3.2",
|
||||
"glob": "^7.1.6",
|
||||
"sax": "~1.2.4",
|
||||
"source-map": "^0.7.3"
|
||||
}
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
|
||||
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
|
||||
"requires": {
|
||||
"json5": "^2.2.2",
|
||||
"minimist": "^1.2.6",
|
||||
"strip-bom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"typescript-plugin-css-modules": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-5.0.1.tgz",
|
||||
"integrity": "sha512-hKXObfwfjx2/myRq4JeQ8D3xIWYTFqusi0hS/Aka7RFX1xQEoEkdOGDWyXNb8LmObawsUzbI30gQnZvqYXCrkA==",
|
||||
"requires": {
|
||||
"@types/postcss-modules-local-by-default": "^4.0.0",
|
||||
"@types/postcss-modules-scope": "^3.0.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"icss-utils": "^5.1.0",
|
||||
"less": "^4.1.3",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-load-config": "^3.1.4",
|
||||
"postcss-modules-extract-imports": "^3.0.0",
|
||||
"postcss-modules-local-by-default": "^4.0.0",
|
||||
"postcss-modules-scope": "^3.0.0",
|
||||
"reserved-words": "^0.1.2",
|
||||
"sass": "^1.58.3",
|
||||
"source-map-js": "^1.0.2",
|
||||
"stylus": "^0.59.0",
|
||||
"tsconfig-paths": "^4.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"postcss-load-config": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
|
||||
"integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
|
||||
"requires": {
|
||||
"lilconfig": "^2.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@k8slens/utilities": {
|
||||
@ -43423,7 +43563,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
|
||||
"integrity": "sha512-0VLab/pcLTLcfbxi6THSIMVYcw9hEUBGvjwwaGpW77mMgRXfGF+a76t7BxTGyLh1y68tBvrffp8UWnqvm76+yg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"postcss": "^8.0.0"
|
||||
}
|
||||
@ -43432,7 +43571,6 @@
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/postcss-modules-scope/-/postcss-modules-scope-3.0.1.tgz",
|
||||
"integrity": "sha512-LNkp3c4ML9EQj2dgslp4i80Jxj72YK3HjYzrTn6ftUVylW1zaKFGqrMlNIyqBmPWmIhZ/Y5r0Y4T49Hk1IuDUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"postcss": "^8.0.0"
|
||||
}
|
||||
@ -44785,11 +44923,6 @@
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
|
||||
},
|
||||
"atob": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
||||
},
|
||||
"atomically": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz",
|
||||
@ -46526,24 +46659,6 @@
|
||||
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
|
||||
"integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="
|
||||
},
|
||||
"css": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
|
||||
"integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"source-map": "^0.6.1",
|
||||
"source-map-resolve": "^0.5.2",
|
||||
"urix": "^0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-box-model": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
|
||||
@ -46568,14 +46683,6 @@
|
||||
"semver": "^7.3.8"
|
||||
}
|
||||
},
|
||||
"css-parse": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz",
|
||||
"integrity": "sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==",
|
||||
"requires": {
|
||||
"css": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
|
||||
@ -46589,15 +46696,6 @@
|
||||
"nth-check": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"css-selector-tokenizer": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
|
||||
"integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
|
||||
"requires": {
|
||||
"cssesc": "^3.0.0",
|
||||
"fastparse": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"css-vendor": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
|
||||
@ -46742,7 +46840,8 @@
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ=="
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||
"dev": true
|
||||
},
|
||||
"decompress-response": {
|
||||
"version": "6.0.0",
|
||||
@ -47239,7 +47338,8 @@
|
||||
"dotenv": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
|
||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
|
||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
|
||||
"dev": true
|
||||
},
|
||||
"dotenv-expand": {
|
||||
"version": "5.1.0",
|
||||
@ -48986,11 +49086,6 @@
|
||||
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
|
||||
"integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="
|
||||
},
|
||||
"fastparse": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
|
||||
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ=="
|
||||
},
|
||||
"fastq": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
|
||||
@ -49496,42 +49591,6 @@
|
||||
"wide-align": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"generic-names": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/generic-names/-/generic-names-1.0.3.tgz",
|
||||
"integrity": "sha512-b6OHfQuKasIKM9b6YPkX+KUj/TLBTx3B/1aT1T5F12FEuEqyFMdr59OMS53aoaSw8eVtapdqieX6lbg5opaOhA==",
|
||||
"requires": {
|
||||
"loader-utils": "^0.2.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"big.js": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
|
||||
"integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q=="
|
||||
},
|
||||
"emojis-list": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
|
||||
"integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng=="
|
||||
},
|
||||
"json5": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
|
||||
"integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw=="
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "0.2.17",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
|
||||
"integrity": "sha512-tiv66G0SmiOx+pLWMtGEkfSEejxvb6N6uRrQjfWJIT79W9GMpgKeCAmm9aVBKtd4WEgntciI8CsGqjpDoCWJug==",
|
||||
"requires": {
|
||||
"big.js": "^3.1.3",
|
||||
"emojis-list": "^2.0.0",
|
||||
"json5": "^0.5.0",
|
||||
"object-assign": "^4.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@ -57682,7 +57741,7 @@
|
||||
"type-fest": "^2.14.0",
|
||||
"typed-emitter": "^1.4.0",
|
||||
"typescript": "^4.9.5",
|
||||
"typescript-plugin-css-modules": "^4.1.1",
|
||||
"typescript-plugin-css-modules": "^5.0.1",
|
||||
"webpack": "^5.81.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.13.3",
|
||||
@ -57727,9 +57786,9 @@
|
||||
}
|
||||
},
|
||||
"typescript-plugin-css-modules": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-4.2.3.tgz",
|
||||
"integrity": "sha512-jEEP2oUPOqR89QGgvPK2HSTZLkrCeKZQ9EwiNxm9VUcufUbNY1Tv053fPKRq6c13PMQjlBU3WrQjKN8u0j5Y6w==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-5.0.1.tgz",
|
||||
"integrity": "sha512-hKXObfwfjx2/myRq4JeQ8D3xIWYTFqusi0hS/Aka7RFX1xQEoEkdOGDWyXNb8LmObawsUzbI30gQnZvqYXCrkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/postcss-modules-local-by-default": "^4.0.0",
|
||||
@ -58669,255 +58728,6 @@
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"postcss-filter-plugins": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-3.0.1.tgz",
|
||||
"integrity": "sha512-tRKbW4wWBEkSSFuJtamV2wkiV9rj6Yy7P3Y13+zaynlPEEZt8EgYKn3y/RBpMeIhNmHXFlSdzofml65hD5OafA==",
|
||||
"requires": {
|
||||
"postcss": "^6.0.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "6.0.23",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
|
||||
"integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.1",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^5.4.0"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"postcss-icss-keyframes": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-icss-keyframes/-/postcss-icss-keyframes-0.2.1.tgz",
|
||||
"integrity": "sha512-4m+hLY5TVqoTM198KKnzdNudyu1OvtqwD+8kVZ9PNiEO4+IfHYoyVvEXsOHjV8nZ1k6xowf+nY4HlUfZhOFvvw==",
|
||||
"requires": {
|
||||
"icss-utils": "^3.0.1",
|
||||
"postcss": "^6.0.2",
|
||||
"postcss-value-parser": "^3.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
|
||||
},
|
||||
"icss-utils": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-3.0.1.tgz",
|
||||
"integrity": "sha512-ANhVLoEfe0KoC9+z4yiTaXOneB49K6JIXdS+yAgH0NERELpdIT7kkj2XxUPuHafeHnn8umXnECSpsfk1RTaUew==",
|
||||
"requires": {
|
||||
"postcss": "^6.0.2"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"version": "6.0.23",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
|
||||
"integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.1",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^5.4.0"
|
||||
}
|
||||
},
|
||||
"postcss-value-parser": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"postcss-icss-selectors": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-icss-selectors/-/postcss-icss-selectors-2.0.3.tgz",
|
||||
"integrity": "sha512-dxFtq+wscbU9faJaH8kIi98vvCPDbt+qg1g9GoG0os1PY3UvgY1Y2G06iZrZb1iVC9cyFfafwSY1IS+IQpRQ4w==",
|
||||
"requires": {
|
||||
"css-selector-tokenizer": "^0.7.0",
|
||||
"generic-names": "^1.0.2",
|
||||
"icss-utils": "^3.0.1",
|
||||
"lodash": "^4.17.4",
|
||||
"postcss": "^6.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
|
||||
},
|
||||
"icss-utils": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-3.0.1.tgz",
|
||||
"integrity": "sha512-ANhVLoEfe0KoC9+z4yiTaXOneB49K6JIXdS+yAgH0NERELpdIT7kkj2XxUPuHafeHnn8umXnECSpsfk1RTaUew==",
|
||||
"requires": {
|
||||
"postcss": "^6.0.2"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"version": "6.0.23",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
|
||||
"integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.1",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^5.4.0"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"postcss-import": {
|
||||
"version": "15.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||
@ -60191,11 +60001,6 @@
|
||||
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
|
||||
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
|
||||
},
|
||||
"resolve-url": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||
"integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg=="
|
||||
},
|
||||
"resolve.exports": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
|
||||
@ -60966,18 +60771,6 @@
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
|
||||
},
|
||||
"source-map-resolve": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
|
||||
"integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
|
||||
"requires": {
|
||||
"atob": "^2.1.2",
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"resolve-url": "^0.2.1",
|
||||
"source-map-url": "^0.4.0",
|
||||
"urix": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
@ -60994,11 +60787,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"source-map-url": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
|
||||
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw=="
|
||||
},
|
||||
"spawn-command": {
|
||||
"version": "0.0.2-1",
|
||||
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
|
||||
@ -61494,41 +61282,6 @@
|
||||
"integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==",
|
||||
"dev": true
|
||||
},
|
||||
"stylus": {
|
||||
"version": "0.54.8",
|
||||
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz",
|
||||
"integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==",
|
||||
"requires": {
|
||||
"css-parse": "~2.0.0",
|
||||
"debug": "~3.1.0",
|
||||
"glob": "^7.1.6",
|
||||
"mkdirp": "~1.0.4",
|
||||
"safer-buffer": "^2.1.2",
|
||||
"sax": "~1.2.4",
|
||||
"semver": "^6.3.0",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"sucrase": {
|
||||
"version": "3.32.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
|
||||
@ -62629,37 +62382,6 @@
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g=="
|
||||
},
|
||||
"typescript-plugin-css-modules": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-plugin-css-modules/-/typescript-plugin-css-modules-3.4.0.tgz",
|
||||
"integrity": "sha512-2MdjfSg4MGex1csCWRUwKD+MpgnvcvLLr9bSAMemU/QYGqBsXdez0cc06H/fFhLtRoKJjXg6PSTur3Gy1Umhpw==",
|
||||
"requires": {
|
||||
"dotenv": "^10.0.0",
|
||||
"icss-utils": "^5.1.0",
|
||||
"less": "^4.1.1",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"postcss": "^8.3.0",
|
||||
"postcss-filter-plugins": "^3.0.1",
|
||||
"postcss-icss-keyframes": "^0.2.1",
|
||||
"postcss-icss-selectors": "^2.0.3",
|
||||
"postcss-load-config": "^3.0.1",
|
||||
"reserved-words": "^0.1.2",
|
||||
"sass": "^1.32.13",
|
||||
"stylus": "^0.54.8",
|
||||
"tsconfig-paths": "^3.9.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"postcss-load-config": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
|
||||
"integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
|
||||
"requires": {
|
||||
"lilconfig": "^2.0.5",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"typical": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
|
||||
@ -62815,11 +62537,6 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"urix": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
|
||||
"integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg=="
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
|
||||
@ -125,6 +125,7 @@ module.exports = {
|
||||
"no-constant-condition": ["error", {
|
||||
"checkLoops": false,
|
||||
}],
|
||||
"no-extra-boolean-cast": "off",
|
||||
"header/header": [2, "../../license-header"],
|
||||
"react/prop-types": "off",
|
||||
"no-invalid-this": "off",
|
||||
@ -136,6 +137,11 @@ module.exports = {
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": ["error", {
|
||||
"allowNullableString": true,
|
||||
"allowNullableBoolean": true,
|
||||
"allowNullableNumber": true,
|
||||
}],
|
||||
"no-restricted-imports": ["error", {
|
||||
"paths": [
|
||||
{
|
||||
|
||||
@ -3,27 +3,24 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
import type { AppPaths } from "./app-path-injection-token";
|
||||
|
||||
const appPathsStateInjectable = getInjectable({
|
||||
id: "app-paths-state",
|
||||
|
||||
instantiate: () => {
|
||||
let state: AppPaths;
|
||||
let state: AppPaths | undefined;
|
||||
|
||||
return {
|
||||
get: () =>{
|
||||
if (!state) {
|
||||
throw new Error("Tried to get app paths before state is setupped.");
|
||||
}
|
||||
assert(state, "Tried to get app paths before initialization");
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
set: (newState: AppPaths) => {
|
||||
if (state) {
|
||||
throw new Error("Tried to overwrite existing state of app paths.");
|
||||
}
|
||||
assert(!state, "Tried to overwrite existing state of app paths");
|
||||
|
||||
state = newState;
|
||||
},
|
||||
|
||||
@ -8,7 +8,7 @@ import type TypedEmitter from "typed-emitter";
|
||||
import { observable, makeObservable } from "mobx";
|
||||
import { once } from "lodash";
|
||||
import type { Disposer, StrictReactNode } from "@k8slens/utilities";
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import { isObject, iter } from "@k8slens/utilities";
|
||||
import type { CategoryColumnRegistration, TitleCellProps } from "../../renderer/components/catalog/custom-category-columns";
|
||||
import type { Literal, Metadata } from "../cluster-types";
|
||||
|
||||
@ -364,15 +364,15 @@ export abstract class CatalogEntity<
|
||||
constructor({ metadata, status, spec }: CatalogEntityData<Metadata, Status, Spec>) {
|
||||
makeObservable(this);
|
||||
|
||||
if (!metadata || typeof metadata !== "object") {
|
||||
if (!isObject(metadata)) {
|
||||
throw new TypeError("CatalogEntity's metadata must be a defined object");
|
||||
}
|
||||
|
||||
if (!status || typeof status !== "object") {
|
||||
if (!isObject(status)) {
|
||||
throw new TypeError("CatalogEntity's status must be a defined object");
|
||||
}
|
||||
|
||||
if (!spec || typeof spec !== "object") {
|
||||
if (!isObject(spec)) {
|
||||
throw new TypeError("CatalogEntity's spec must be a defined object");
|
||||
}
|
||||
|
||||
|
||||
@ -3,24 +3,21 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
import type { SelfSignedCert } from "selfsigned";
|
||||
|
||||
const lensProxyCertificateInjectable = getInjectable({
|
||||
id: "lens-proxy-certificate",
|
||||
instantiate: () => {
|
||||
let certState: SelfSignedCert;
|
||||
let certState: SelfSignedCert | undefined;
|
||||
const cert = {
|
||||
get: () => {
|
||||
if (!certState) {
|
||||
throw "certificate has not been set";
|
||||
}
|
||||
assert(certState, "certificate has not been set");
|
||||
|
||||
return certState;
|
||||
},
|
||||
set: (certificate: SelfSignedCert) => {
|
||||
if (certState) {
|
||||
throw "certificate has already been set";
|
||||
}
|
||||
assert(!certState, "certificate has already been set");
|
||||
|
||||
certState = certificate;
|
||||
},
|
||||
|
||||
@ -30,12 +30,14 @@ export function ipcMainHandle(channel: string, listener: (event: Electron.IpcMai
|
||||
}
|
||||
|
||||
export async function broadcastMessage(channel: string, ...args: unknown[]): Promise<void> {
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (ipcRenderer) {
|
||||
await ipcRenderer.invoke(broadcastMainChannel, channel, ...args.map(toJS));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (!webContents) {
|
||||
return;
|
||||
}
|
||||
@ -56,9 +58,9 @@ export async function broadcastMessage(channel: string, ...args: unknown[]): Pro
|
||||
);
|
||||
});
|
||||
|
||||
const views = webContents.getAllWebContents();
|
||||
const views = webContents.getAllWebContents() ?? [];
|
||||
|
||||
if (!views || !isArray(views) || views.length === 0) return;
|
||||
if (!isArray(views) || views.length === 0) return;
|
||||
|
||||
args = args.map(toJS);
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ import { autorun, action, observable } from "mobx";
|
||||
import type { KubeApi } from "@k8slens/kube-api";
|
||||
import type { KubeObject, ObjectReference } from "@k8slens/kube-object";
|
||||
import { parseKubeApi, createKubeApiURL } from "@k8slens/kube-api";
|
||||
import { getOrInsertWith, iter } from "@k8slens/utilities";
|
||||
import { getOrInsertWith, isDefined, iter } from "@k8slens/utilities";
|
||||
import type { CreateCustomResourceStore } from "./create-custom-resource-store.injectable";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@ -142,7 +142,7 @@ export class ApiManager {
|
||||
*/
|
||||
getStore<Store extends KubeObjectStore>(api: string | KubeApi): Store | undefined ;
|
||||
getStore(apiOrBase: string | KubeApi | undefined): KubeObjectStore | undefined {
|
||||
if (!apiOrBase) {
|
||||
if (!isDefined(apiOrBase) || apiOrBase === "") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ export class ApiManager {
|
||||
|
||||
const api = apiBase && this.getApi(apiBase);
|
||||
|
||||
if (!api) {
|
||||
if (!isDefined(api) || api === "") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import createKubeJsonApiInjectable from "./create-kube-json-api.injectable";
|
||||
import type { KubeApiOptions } from "@k8slens/kube-api";
|
||||
import { KubeApi } from "@k8slens/kube-api";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "@k8slens/kube-object";
|
||||
import { isDefined } from "@k8slens/utilities";
|
||||
|
||||
export interface CreateKubeApiForRemoteClusterConfig {
|
||||
cluster: {
|
||||
@ -92,7 +93,7 @@ const createKubeApiForRemoteClusterInjectable = getInjectable({
|
||||
serverAddress: config.cluster.server,
|
||||
apiBase: "",
|
||||
debug: isDevelopment,
|
||||
...(token ? {
|
||||
...(isDefined(token) ? {
|
||||
getRequestOptions: async () => ({
|
||||
headers: {
|
||||
"Authorization": `Bearer ${typeof token === "function" ? await token() : token}`,
|
||||
|
||||
@ -49,10 +49,10 @@ export function normalizeMetrics(metrics: MetricData | undefined | null, frames
|
||||
if (frames > 0) {
|
||||
// fill the gaps
|
||||
result.forEach(res => {
|
||||
if (!res.values || !res.values.length) return;
|
||||
if (!res.values.length) return;
|
||||
|
||||
let now = moment().startOf("minute").subtract(1, "minute").unix();
|
||||
let timestamp = res.values[0][0];
|
||||
let timestamp = res.values[0]?.[0] ?? 0;
|
||||
|
||||
while (timestamp <= now) {
|
||||
timestamp = moment.unix(timestamp).add(1, "minute").unix();
|
||||
@ -63,7 +63,7 @@ export function normalizeMetrics(metrics: MetricData | undefined | null, frames
|
||||
}
|
||||
|
||||
while (res.values.length < frames) {
|
||||
const timestamp = moment.unix(res.values[0][0]).subtract(1, "minute").unix();
|
||||
const timestamp = moment.unix(res.values[0]?.[0] ?? 0).subtract(1, "minute").unix();
|
||||
|
||||
if (!res.values.find((value) => value[0] === timestamp)) {
|
||||
res.values.unshift([timestamp, "0"]);
|
||||
@ -101,9 +101,11 @@ export function getItemMetrics<Keys extends string>(metrics: Partial<Record<Keys
|
||||
}
|
||||
const results = metrics[metric]?.data.result;
|
||||
const result = results?.find(res => Object.values(res.metric)[0] == itemName);
|
||||
const item = itemMetrics[metric];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
itemMetrics[metric]!.data.result = result ? [result] : [];
|
||||
if (item) {
|
||||
item.data.result = result ? [result] : [];
|
||||
}
|
||||
}
|
||||
|
||||
return itemMetrics;
|
||||
@ -114,7 +116,9 @@ export function getMetricLastPoints<Keys extends string>(metrics: Partial<Record
|
||||
object.entries(metrics)
|
||||
.map(([metricName, metric]) => {
|
||||
try {
|
||||
return [metricName, +metric.data.result[0].values.slice(-1)[0][1]] as const;
|
||||
const [value = [0, "0"]] = metric.data.result[0]?.values.slice(-1) ?? [];
|
||||
|
||||
return [metricName, +value[1]] as const;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -48,14 +48,8 @@ const requestMetricsInjectable = getInjectable({
|
||||
function requestMetrics<Keys extends string>(query: Record<Keys, Partial<Record<string, string>>>, params?: RequestMetricsParams): Promise<Record<Keys, MetricData>>;
|
||||
async function requestMetrics(metricsQuery: string | string[] | Partial<Record<string, Partial<Record<string, string>>>>, params: RequestMetricsParams = {}): Promise<MetricData | MetricData[] | Partial<Record<string, MetricData>>> {
|
||||
const { range = 3600, step = 60, namespace } = params;
|
||||
let { start, end } = params;
|
||||
|
||||
if (!start && !end) {
|
||||
const now = getSecondsFromUnixEpoch();
|
||||
|
||||
start = now - range;
|
||||
end = now;
|
||||
}
|
||||
const now = getSecondsFromUnixEpoch();
|
||||
const { start = now - range, end = now } = params;
|
||||
|
||||
return apiBase.post("/metrics", {
|
||||
data: metricsQuery,
|
||||
|
||||
@ -306,7 +306,7 @@ export class KubeObjectStore<
|
||||
}
|
||||
|
||||
protected resetOnError(error: unknown) {
|
||||
if (error) this.reset();
|
||||
if (Boolean(error)) this.reset();
|
||||
}
|
||||
|
||||
protected async loadItem(params: { name: string; namespace?: string }): Promise<K | null> {
|
||||
|
||||
@ -122,7 +122,7 @@ export abstract class LensProtocolRouter {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return countBy(b.path)["/"] - countBy(a.path)["/"];
|
||||
return (countBy(b.path)["/"] ?? 0) - (countBy(a.path)["/"] ?? 0);
|
||||
})[0] ?? null;
|
||||
}
|
||||
|
||||
@ -204,6 +204,7 @@ export abstract class LensProtocolRouter {
|
||||
const extension = extensionLoader.getInstanceByName(name) as LensExtension | undefined;
|
||||
|
||||
if (!extension) {
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but does not have a class for ${ipcRenderer ? "renderer" : "main"}`);
|
||||
|
||||
return name;
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export type KubeResource =
|
||||
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "leases" |
|
||||
"secrets" | "configmaps" | "ingresses" | "ingressclasses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" |
|
||||
"pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "replicationcontrollers" | "jobs" | "cronjobs" |
|
||||
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "verticalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" |
|
||||
"priorityclasses" | "runtimeclasses" |
|
||||
"roles" | "clusterroles" | "rolebindings" | "clusterrolebindings" | "serviceaccounts" | "mutatingwebhookconfigurations" | "validatingwebhookconfigurations";
|
||||
export type KubeResource = keyof typeof apiResourceRecord;
|
||||
|
||||
export interface KubeApiResource {
|
||||
kind: string;
|
||||
@ -35,7 +29,7 @@ export interface KubeApiResourceData {
|
||||
namespaced: boolean;
|
||||
}
|
||||
|
||||
export const apiResourceRecord: Record<KubeResource, KubeApiResourceData> = {
|
||||
export const apiResourceRecord = {
|
||||
clusterroles: {
|
||||
kind: "ClusterRole",
|
||||
group: "rbac.authorization.k8s.io",
|
||||
|
||||
@ -20,15 +20,16 @@ export function reactiveNow(interval?: number | "frame") {
|
||||
|
||||
// Note: This is the kludge until https://github.com/mobxjs/mobx-utils/issues/306 is fixed
|
||||
const synchronizationIsEnabled = !process.env.JEST_WORKER_ID;
|
||||
let ticker = tickers[interval];
|
||||
|
||||
if (!tickers[interval] || !synchronizationIsEnabled) {
|
||||
if (!ticker || !synchronizationIsEnabled) {
|
||||
if (typeof interval === "number")
|
||||
tickers[interval] = createIntervalTicker(interval);
|
||||
ticker = tickers[interval] = createIntervalTicker(interval);
|
||||
else
|
||||
tickers[interval] = createAnimationFrameTicker();
|
||||
ticker = tickers[interval] = createAnimationFrameTicker();
|
||||
}
|
||||
|
||||
return tickers[interval].current();
|
||||
return ticker.current();
|
||||
}
|
||||
|
||||
function createIntervalTicker(interval: number) {
|
||||
|
||||
@ -109,6 +109,7 @@ export class ExtensionDiscovery {
|
||||
* Initializes the class and setups the file watcher for added/removed local extensions.
|
||||
*/
|
||||
async init() {
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (ipcRenderer) {
|
||||
await this.initRenderer();
|
||||
} else {
|
||||
|
||||
@ -101,6 +101,7 @@ export class ExtensionLoader {
|
||||
));
|
||||
|
||||
async init() {
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (ipcMain) {
|
||||
await this.initMain();
|
||||
} else {
|
||||
@ -211,6 +212,7 @@ export class ExtensionLoader {
|
||||
}
|
||||
|
||||
broadcastExtensions() {
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
const channel = ipcRenderer
|
||||
? extensionLoaderFromRendererChannel
|
||||
: extensionLoaderFromMainChannel;
|
||||
|
||||
@ -145,7 +145,9 @@ export class LensRendererExtension extends LensExtension {
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
async isEnabledForCluster(cluster: KubernetesCluster): Promise<Boolean> {
|
||||
return Promise.resolve((void cluster) || true);
|
||||
void cluster;
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -146,10 +146,13 @@ export const logTabStore = Object.assign(
|
||||
createWorkloadTab: asLegacyGlobalFunctionForExtensionApi(createWorkloadLogsTabInjectable),
|
||||
renameTab: (tabId: string): void => {
|
||||
const { selectedPodId } = logTabStore.getData(tabId) ?? {};
|
||||
const pod = selectedPodId && podStore.getById(selectedPodId);
|
||||
|
||||
if (pod) {
|
||||
renameTab(tabId, `Pod ${pod.getName()}`);
|
||||
if (selectedPodId) {
|
||||
const pod = podStore.getById(selectedPodId);
|
||||
|
||||
if (pod) {
|
||||
renameTab(tabId, `Pod ${pod.getName()}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
tabs: undefined,
|
||||
|
||||
@ -38,12 +38,13 @@ import roleBindingApiInjectable from "../../common/k8s-api/endpoints/role-bindin
|
||||
import customResourceDefinitionApiInjectable from "../../common/k8s-api/endpoints/custom-resource-definition.api.injectable";
|
||||
import { shouldShowResourceInjectionToken } from "../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token";
|
||||
import requestMetricsInjectable from "../../common/k8s-api/endpoints/metrics.api/request-metrics.injectable";
|
||||
import { maybeGet } from "@k8slens/utilities";
|
||||
|
||||
export function isAllowedResource(resources: KubeResource | KubeResource[]) {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
return [resources].flat().every((resourceName) => {
|
||||
const resource = apiResourceRecord[resourceName];
|
||||
return [resources].flat().every((resourceName: string) => {
|
||||
const resource = maybeGet(apiResourceRecord, resourceName);
|
||||
|
||||
if (!resource) {
|
||||
return true;
|
||||
|
||||
@ -81,11 +81,12 @@ const toRecursedInjectablesFor = (logError: (errorMessage: string) => void) => {
|
||||
injectionToken: applicationMenuItemInjectionToken,
|
||||
}),
|
||||
|
||||
...((registration.submenu as MenuRegistration[])
|
||||
? (registration.submenu as MenuRegistration[]).flatMap(
|
||||
toRecursedInjectables(currentIdPath),
|
||||
)
|
||||
: []),
|
||||
...(
|
||||
registration.submenu
|
||||
? (registration.submenu as MenuRegistration[])
|
||||
.flatMap(toRecursedInjectables(currentIdPath))
|
||||
: []
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
@ -40,10 +40,11 @@ const NonInjectedUpdateButton = observer(({ warningLevel, update, id }: UpdateBu
|
||||
data-testid="update-button"
|
||||
data-warning-level={level}
|
||||
id={buttonId}
|
||||
className={cssNames(styles.updateButton, {
|
||||
[styles.warningHigh]: level === "high",
|
||||
[styles.warningMedium]: level === "medium",
|
||||
})}
|
||||
className={cssNames(
|
||||
styles.updateButton,
|
||||
level === "high" && styles.warningHigh,
|
||||
level === "medium" && styles.warningMedium,
|
||||
)}
|
||||
>
|
||||
Update
|
||||
<Icon material="arrow_drop_down" className={styles.icon}/>
|
||||
|
||||
@ -26,7 +26,7 @@ const selectedUpdateChannelInjectable = getInjectable({
|
||||
|
||||
setValue: action((channelId) => {
|
||||
const targetUpdateChannel =
|
||||
channelId && updateChannels[channelId]
|
||||
channelId && (channelId in updateChannels)
|
||||
? updateChannels[channelId]
|
||||
: defaultUpdateChannel;
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { isTruthy } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { globalAgent } from "https";
|
||||
import { requestSystemCAsInjectionToken } from "./request-system-cas-token";
|
||||
@ -34,7 +35,7 @@ const injectSystemCAsInjectable = getInjectable({
|
||||
return globalAgent.options.ca;
|
||||
}
|
||||
|
||||
if (globalAgent.options.ca) {
|
||||
if (isTruthy(globalAgent.options.ca)) {
|
||||
return [globalAgent.options.ca];
|
||||
}
|
||||
|
||||
|
||||
@ -73,13 +73,17 @@ const v500Beta10HotbarStoreMigrationInjectable = getInjectable({
|
||||
{
|
||||
// grab the default named hotbar or the first.
|
||||
const defaultHotbarIndex = Math.max(0, hotbars.findIndex(hotbar => hotbar.name === "default"));
|
||||
const [{ name, id, items }] = hotbars.splice(defaultHotbarIndex, 1);
|
||||
const [hotbar] = hotbars.splice(defaultHotbarIndex, 1);
|
||||
|
||||
workspaceHotbars.set("default", {
|
||||
name,
|
||||
id,
|
||||
items: items.filter(isDefined),
|
||||
});
|
||||
if (hotbar) {
|
||||
const { name, id, items } = hotbar;
|
||||
|
||||
workspaceHotbars.set("default", {
|
||||
name,
|
||||
id,
|
||||
items: items.filter(isDefined),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const cluster of clusters) {
|
||||
@ -130,7 +134,8 @@ const v500Beta10HotbarStoreMigrationInjectable = getInjectable({
|
||||
const defaultHotbarIndex = hotbars.findIndex(hotbar => hotbar.name === "default");
|
||||
|
||||
if (defaultHotbarIndex >= 0) {
|
||||
const defaultHotbar = createHotbar(hotbars[defaultHotbarIndex]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const defaultHotbar = createHotbar(hotbars[defaultHotbarIndex]!);
|
||||
|
||||
if (defaultHotbar.isFull()) {
|
||||
// making a new hotbar is less destructive if the first hotbar
|
||||
|
||||
@ -113,11 +113,10 @@ const registratorForPreferenceItemsInjectable = getInjectable({
|
||||
const items = extension.appPreferences.map((registration, i) => {
|
||||
const itemId = `${commonId}-item-${registration.id ?? i}`;
|
||||
|
||||
const itemIsInSpecialTab =
|
||||
registration.showInPreferencesTab &&
|
||||
["telemetry", "application"].includes(
|
||||
registration.showInPreferencesTab,
|
||||
);
|
||||
const itemIsInSpecialTab = (
|
||||
registration.showInPreferencesTab === "telemetry"
|
||||
|| registration.showInPreferencesTab === "application"
|
||||
);
|
||||
|
||||
return getInjectable({
|
||||
id: itemId,
|
||||
|
||||
@ -9,6 +9,7 @@ import type { LensRendererExtension } from "../../../../extensions/lens-renderer
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { topBarItemOnRightSideInjectionToken } from "../../../../renderer/components/layout/top-bar/top-bar-items/top-bar-item-injection-token";
|
||||
import { computed } from "mobx";
|
||||
import type { PartialDeep } from "type-fest";
|
||||
|
||||
const legacyExtensionApiRegistratorForTopBarItemsInjectable = getInjectable({
|
||||
id: "legacy-extension-api-registrator-for-top-bar-items",
|
||||
@ -19,7 +20,7 @@ const legacyExtensionApiRegistratorForTopBarItemsInjectable = getInjectable({
|
||||
return pipeline(
|
||||
extension.topBarItems,
|
||||
|
||||
reject((registration) => !registration?.components?.Item),
|
||||
reject((registration) => !(registration as PartialDeep<typeof registration>)?.components?.Item),
|
||||
|
||||
(validTopBarRegistrations) =>
|
||||
validTopBarRegistrations.map((registration, index) => {
|
||||
|
||||
@ -64,7 +64,7 @@ jest.mock("@k8slens/tooltip", () => ({
|
||||
void tooltipOverrideDisabled;
|
||||
const ResolvedTarget = Target as React.FunctionComponent<TargetProps>;
|
||||
|
||||
if (tooltip) {
|
||||
if (Boolean(tooltip)) {
|
||||
const testId = props["data-testid"] as string | undefined;
|
||||
|
||||
return (
|
||||
|
||||
@ -111,9 +111,7 @@ export const createClusterPrometheusHandler = (...args: [Dependencies, Cluster])
|
||||
break;
|
||||
|
||||
case "fulfilled":
|
||||
if (res.value) {
|
||||
return res.value;
|
||||
}
|
||||
return res.value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,6 +128,10 @@ export const createClusterPrometheusHandler = (...args: [Dependencies, Cluster])
|
||||
const prometheusPath = ensurePrometheusPath(service);
|
||||
const provider = ensurePrometheusProvider(service);
|
||||
|
||||
if (!provider) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { prometheusPath, provider };
|
||||
};
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ const clusterStoreSnapMigrationInjectable = getInjectable({
|
||||
}
|
||||
|
||||
logger.info("Migrating embedded kubeconfig paths");
|
||||
const storedClusters = (store.get("clusters") || []) as ClusterModel[];
|
||||
const storedClusters = (store.get("clusters") as (ClusterModel[] | undefined) ?? []);
|
||||
|
||||
if (!storedClusters.length) return;
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import * as yaml from "js-yaml";
|
||||
import { iter, put, sortBySemverVersion } from "@k8slens/utilities";
|
||||
import { isObject, iter, put, sortBySemverVersion } from "@k8slens/utilities";
|
||||
import type { HelmRepo } from "../../common/helm/helm-repo";
|
||||
import type { HelmChartManagerCache } from "./helm-chart-manager-cache.injectable";
|
||||
import type { Logger } from "@k8slens/logger";
|
||||
@ -71,11 +71,11 @@ export class HelmChartManager {
|
||||
const cacheFileStats = await this.dependencies.stat(this.repo.cacheFilePath);
|
||||
const data = yaml.load(cacheFile) as string | number | HelmCacheFile;
|
||||
|
||||
if (!data || typeof data !== "object" || typeof data.entries !== "object") {
|
||||
if (!isObject(data) || !isObject(data.entries)) {
|
||||
throw Object.assign(new TypeError("Helm Cache file does not parse correctly"), { file: this.repo.cacheFilePath, data });
|
||||
}
|
||||
|
||||
const normalized = normalizeHelmCharts(this.repo.name, data.entries);
|
||||
const normalized = normalizeHelmCharts(this.repo.name, data.entries as RepoHelmChartList);
|
||||
|
||||
return put(
|
||||
this.dependencies.cache,
|
||||
|
||||
@ -21,14 +21,17 @@ const getClusterForRequestInjectable = getInjectable({
|
||||
// lens-server is connecting to 127.0.0.1:<port>/<uid>
|
||||
if (req.url && req.headers.host.startsWith("127.0.0.1")) {
|
||||
const clusterId = req.url.split("/")[1];
|
||||
const cluster = getClusterById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
// we need to swap path prefix so that request is proxied to kube api
|
||||
req.url = req.url.replace(`/${clusterId}`, apiKubePrefix);
|
||||
if (clusterId) {
|
||||
const cluster = getClusterById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
// we need to swap path prefix so that request is proxied to kube api
|
||||
req.url = req.url.replace(`/${clusterId}`, apiKubePrefix);
|
||||
}
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
const clusterId = getClusterIdFromHost(req.headers.host);
|
||||
|
||||
@ -200,7 +200,7 @@ export class LensProxy {
|
||||
|
||||
this.dependencies.logger.error(`[LENS-PROXY]: http proxy errored for cluster: ${String(error)}`, { url: req.url });
|
||||
|
||||
if (target) {
|
||||
if (target !== undefined) {
|
||||
this.dependencies.logger.debug(`Failed proxy to target: ${JSON.stringify(target, null, 2)}`);
|
||||
|
||||
if (req.method === "GET" && (!res.statusCode || res.statusCode >= 500)) {
|
||||
@ -245,12 +245,10 @@ export class LensProxy {
|
||||
const kubeAuthProxyServer = this.dependencies.getKubeAuthProxyServer(cluster);
|
||||
const proxyTarget = await kubeAuthProxyServer.getApiTarget(isLongRunningRequest(req.url));
|
||||
|
||||
if (proxyTarget) {
|
||||
return this.dependencies.proxy.web(req, res, proxyTarget);
|
||||
}
|
||||
this.dependencies.proxy.web(req, res, proxyTarget);
|
||||
} else {
|
||||
res.setHeader("Content-Security-Policy", this.dependencies.contentSecurityPolicy);
|
||||
await this.dependencies.router.route(cluster, req, res);
|
||||
}
|
||||
|
||||
res.setHeader("Content-Security-Policy", this.dependencies.contentSecurityPolicy);
|
||||
await this.dependencies.router.route(cluster, req, res);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { chunk } from "lodash";
|
||||
import type { ConnectionOptions } from "tls";
|
||||
import { connect } from "tls";
|
||||
import url from "url";
|
||||
@ -13,6 +12,7 @@ import type { LensProxyApiRequest } from "../lens-proxy";
|
||||
import kubeAuthProxyServerInjectable from "../../cluster/kube-auth-proxy-server.injectable";
|
||||
import kubeAuthProxyCertificateInjectable from "../../kube-auth-proxy/kube-auth-proxy-certificate.injectable";
|
||||
import clusterApiUrlInjectable from "../../../features/cluster/connections/main/api-url.injectable";
|
||||
import { iter } from "@k8slens/utilities";
|
||||
|
||||
const skipRawHeaders = new Set(["Host", "Authorization"]);
|
||||
|
||||
@ -35,7 +35,7 @@ const kubeApiUpgradeRequestInjectable = getInjectable({
|
||||
proxySocket.write(`${req.method} ${pUrl.path ?? ""} HTTP/1.1\r\n`);
|
||||
proxySocket.write(`Host: ${clusterApiUrl.host}\r\n`);
|
||||
|
||||
for (const [key, value] of chunk(req.rawHeaders, 2)) {
|
||||
for (const [key, value] of iter.chunks(req.rawHeaders, 2)) {
|
||||
if (skipRawHeaders.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import type { InspectOptions } from "util";
|
||||
import { inspect } from "util";
|
||||
import { omit } from "lodash";
|
||||
import type { Format, TransformableInfo } from "logform";
|
||||
import { isObject, isTruthy } from "@k8slens/utilities";
|
||||
|
||||
// The following license was copied from https://github.com/duccio/winston-console-format/blob/master/LICENSE
|
||||
// This was modified to support formatting causes
|
||||
@ -116,9 +117,15 @@ export class ConsoleFormat implements Format {
|
||||
private _cause(source: unknown): string[] {
|
||||
const messages: string[] = [];
|
||||
|
||||
if (source instanceof Error && source.cause) {
|
||||
if (source instanceof Error && isTruthy(source.cause)) {
|
||||
messages.push("Cause:");
|
||||
messages.push(...this.getLines(omit(source.cause, "response")).map(l => ` ${l}`));
|
||||
|
||||
if (isObject(source.cause)) {
|
||||
messages.push(...this.getLines(omit(source.cause, "response")).map(l => ` ${l}`));
|
||||
} else {
|
||||
messages.push(...this.getLines(source.cause).map(l => ` ${l}`));
|
||||
}
|
||||
|
||||
messages.push(...this._cause(source.cause));
|
||||
}
|
||||
|
||||
|
||||
@ -7,22 +7,14 @@ import { matches } from "lodash/fp";
|
||||
import type { PrometheusProvider } from "./provider";
|
||||
import prometheusProvidersInjectable from "./providers.injectable";
|
||||
|
||||
export type GetPrometheusProviderByKind = (kind: string) => PrometheusProvider;
|
||||
export type GetPrometheusProviderByKind = (kind: string) => PrometheusProvider | undefined;
|
||||
|
||||
const getPrometheusProviderByKindInjectable = getInjectable({
|
||||
id: "get-prometheus-provider-by-kind",
|
||||
instantiate: (di): GetPrometheusProviderByKind => {
|
||||
const providers = di.inject(prometheusProvidersInjectable);
|
||||
|
||||
return (kind) => {
|
||||
const provider = providers.get().find(matches({ kind }));
|
||||
|
||||
if (!provider) {
|
||||
throw new Error(`Provider of kind "${kind}" does not exist`);
|
||||
}
|
||||
|
||||
return provider;
|
||||
};
|
||||
return (kind) => providers.get().find(matches({ kind }));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -6,11 +6,14 @@
|
||||
import type { PrometheusProvider } from "./provider";
|
||||
import { createPrometheusProvider, bytesSent, findFirstNamespacedService, prometheusProviderInjectionToken } from "./provider";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
|
||||
export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): PrometheusProvider["getQuery"] => (
|
||||
(opts, queryName) => {
|
||||
switch(opts.category) {
|
||||
case "cluster":
|
||||
assert(opts.nodes, 'Missing "nodes" option when "category" option is "cluster"');
|
||||
|
||||
switch (queryName) {
|
||||
case "memoryUsage":
|
||||
return `sum(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (component)`.replace(/_bytes/g, `_bytes{node=~"${opts.nodes}"}`);
|
||||
@ -69,6 +72,10 @@ export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }):
|
||||
}
|
||||
break;
|
||||
case "pods":
|
||||
assert(opts.pods, 'Missing "pods" option when "category" option is "pods"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "pods"');
|
||||
assert(opts.selector, 'Missing "selector" option when "category" option is "pods"');
|
||||
|
||||
switch (queryName) {
|
||||
case "cpuUsage":
|
||||
return `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${rateAccuracy}])) by (${opts.selector})`;
|
||||
@ -95,6 +102,9 @@ export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }):
|
||||
}
|
||||
break;
|
||||
case "pvc":
|
||||
assert(opts.pvc, 'Missing "pvc" option when "category" option is "pvc"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "pvc"');
|
||||
|
||||
switch (queryName) {
|
||||
case "diskUsage":
|
||||
return `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`;
|
||||
@ -103,6 +113,9 @@ export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }):
|
||||
}
|
||||
break;
|
||||
case "ingress":
|
||||
assert(opts.ingress, 'Missing "ingress" option when "category" option is "ingress"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "ingress"');
|
||||
|
||||
switch (queryName) {
|
||||
case "bytesSentSuccess":
|
||||
return bytesSent({
|
||||
@ -126,7 +139,7 @@ export const getHelmLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }):
|
||||
break;
|
||||
}
|
||||
|
||||
throw new Error(`Unknown queryName="${queryName}" for category="${opts.category}"`);
|
||||
throw new Error(`Unknown queryName="${queryName}" for category="${String(opts.category)}"`);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@ -6,11 +6,14 @@
|
||||
import { bytesSent, prometheusProviderInjectionToken, findNamespacedService, createPrometheusProvider } from "./provider";
|
||||
import type { PrometheusProvider } from "./provider";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
|
||||
export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): PrometheusProvider["getQuery"] => (
|
||||
(opts, queryName) => {
|
||||
switch(opts.category) {
|
||||
case "cluster":
|
||||
assert(opts.nodes, 'Missing "nodes" option when "category" option is "cluster"');
|
||||
|
||||
switch (queryName) {
|
||||
case "memoryUsage":
|
||||
return `sum(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_name)`.replace(/_bytes/g, `_bytes{kubernetes_node=~"${opts.nodes}"}`);
|
||||
@ -69,6 +72,10 @@ export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }):
|
||||
}
|
||||
break;
|
||||
case "pods":
|
||||
assert(opts.pods, 'Missing "pods" option when "category" option is "pods"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "pods"');
|
||||
assert(opts.selector, 'Missing "selector" option when "category" option is "pods"');
|
||||
|
||||
switch (queryName) {
|
||||
case "cpuUsage":
|
||||
return `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${rateAccuracy}])) by (${opts.selector})`;
|
||||
@ -95,6 +102,9 @@ export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }):
|
||||
}
|
||||
break;
|
||||
case "pvc":
|
||||
assert(opts.pvc, 'Missing "pvc" option when "category" option is "pvc"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "pvc"');
|
||||
|
||||
switch (queryName) {
|
||||
case "diskUsage":
|
||||
return `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`;
|
||||
@ -103,6 +113,9 @@ export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }):
|
||||
}
|
||||
break;
|
||||
case "ingress":
|
||||
assert(opts.ingress, 'Missing "ingress" option when "category" option is "ingress"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "ingress"');
|
||||
|
||||
switch (queryName) {
|
||||
case "bytesSentSuccess":
|
||||
return bytesSent({
|
||||
@ -126,7 +139,7 @@ export const getLensLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }):
|
||||
break;
|
||||
}
|
||||
|
||||
throw new Error(`Unknown queryName="${queryName}" for category="${opts.category}"`);
|
||||
throw new Error(`Unknown queryName="${queryName}" for category="${String(opts.category)}"`);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@ -6,11 +6,14 @@
|
||||
import type { PrometheusProvider } from "./provider";
|
||||
import { bytesSent, createPrometheusProvider, findFirstNamespacedService, prometheusProviderInjectionToken } from "./provider";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
|
||||
export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): PrometheusProvider["getQuery"] => (
|
||||
(opts, queryName) => {
|
||||
switch(opts.category) {
|
||||
case "cluster":
|
||||
assert(opts.nodes, 'Missing "nodes" option when "category" option is "cluster"');
|
||||
|
||||
switch (queryName) {
|
||||
case "memoryUsage":
|
||||
return `sum(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes))`.replace(/_bytes/g, `_bytes * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"}`);
|
||||
@ -69,6 +72,10 @@ export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string
|
||||
}
|
||||
break;
|
||||
case "pods":
|
||||
assert(opts.pods, 'Missing "pods" option when "category" option is "pods"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "pods"');
|
||||
assert(opts.selector, 'Missing "selector" option when "category" option is "pods"');
|
||||
|
||||
switch (queryName) {
|
||||
case "cpuUsage":
|
||||
return `sum(rate(container_cpu_usage_seconds_total{pod=~"${opts.pods}", namespace="${opts.namespace}"}[${rateAccuracy}])) by (${opts.selector})`;
|
||||
@ -95,6 +102,9 @@ export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string
|
||||
}
|
||||
break;
|
||||
case "pvc":
|
||||
assert(opts.pvc, 'Missing "pvc" option when "category" option is "pvc"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "pvc"');
|
||||
|
||||
switch (queryName) {
|
||||
case "diskUsage":
|
||||
return `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}", namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`;
|
||||
@ -103,6 +113,9 @@ export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string
|
||||
}
|
||||
break;
|
||||
case "ingress":
|
||||
assert(opts.ingress, 'Missing "ingress" option when "category" option is "ingress"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "ingress"');
|
||||
|
||||
switch (queryName) {
|
||||
case "bytesSentSuccess":
|
||||
return bytesSent({
|
||||
@ -126,7 +139,7 @@ export const getOperatorLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string
|
||||
break;
|
||||
}
|
||||
|
||||
throw new Error(`Unknown queryName="${queryName}" for category="${opts.category}"`);
|
||||
throw new Error(`Unknown queryName="${queryName}" for category="${String(opts.category)}"`);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@ -6,11 +6,14 @@
|
||||
import type { PrometheusProvider } from "./provider";
|
||||
import { bytesSent, createPrometheusProvider, findFirstNamespacedService, prometheusProviderInjectionToken } from "./provider";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
|
||||
export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: string }): PrometheusProvider["getQuery"] => (
|
||||
(opts, queryName) => {
|
||||
switch(opts.category) {
|
||||
case "cluster":
|
||||
assert(opts.nodes, 'Missing "nodes" option when "category" option is "cluster"');
|
||||
|
||||
switch (queryName) {
|
||||
case "memoryUsage":
|
||||
return `sum(node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_name)`.replace(/_bytes/g, `_bytes{node=~"${opts.nodes}"}`);
|
||||
@ -69,6 +72,10 @@ export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: stri
|
||||
}
|
||||
break;
|
||||
case "pods":
|
||||
assert(opts.pods, 'Missing "pods" option when "category" option is "pods"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "pods"');
|
||||
assert(opts.selector, 'Missing "selector" option when "category" option is "pods"');
|
||||
|
||||
switch (queryName) {
|
||||
case "cpuUsage":
|
||||
return `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${rateAccuracy}])) by (${opts.selector})`;
|
||||
@ -95,6 +102,9 @@ export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: stri
|
||||
}
|
||||
break;
|
||||
case "pvc":
|
||||
assert(opts.pvc, 'Missing "pvc" option when "category" option is "pvc"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "pvc"');
|
||||
|
||||
switch (queryName) {
|
||||
case "diskUsage":
|
||||
return `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}",namespace="${opts.namespace}"}) by (persistentvolumeclaim, namespace)`;
|
||||
@ -103,6 +113,9 @@ export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: stri
|
||||
}
|
||||
break;
|
||||
case "ingress":
|
||||
assert(opts.ingress, 'Missing "ingress" option when "category" option is "ingress"');
|
||||
assert(opts.namespace, 'Missing "namespace" option when "category" option is "ingress"');
|
||||
|
||||
switch (queryName) {
|
||||
case "bytesSentSuccess":
|
||||
return bytesSent({
|
||||
@ -126,7 +139,7 @@ export const getStacklightLikeQueryFor = ({ rateAccuracy }: { rateAccuracy: stri
|
||||
break;
|
||||
}
|
||||
|
||||
throw new Error(`Unknown queryName="${queryName}" for category="${opts.category}"`);
|
||||
throw new Error(`Unknown queryName="${queryName}" for category="${String(opts.category)}"`);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import type { LensExtension } from "../../../extensions/lens-extension";
|
||||
import { observable, when } from "mobx";
|
||||
import type { LensProtocolRouterDependencies, RouteAttempt } from "../../../common/protocol-handler";
|
||||
import { ProtocolHandlerInvalid } from "../../../common/protocol-handler";
|
||||
import { disposer, noop } from "@k8slens/utilities";
|
||||
import { disposer, isTruthy, noop } from "@k8slens/utilities";
|
||||
import type { BroadcastMessage } from "../../../common/ipc/broadcast-message.injectable";
|
||||
|
||||
export interface FallbackHandler {
|
||||
@ -79,7 +79,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter {
|
||||
await this._routeToExtension(url);
|
||||
}
|
||||
} catch (error) {
|
||||
void this.dependencies.broadcastMessage(ProtocolHandlerInvalid, error ? String(error) : "unknown error", rawUrl);
|
||||
void this.dependencies.broadcastMessage(ProtocolHandlerInvalid, isTruthy(error) ? String(error) : "unknown error", rawUrl);
|
||||
|
||||
if (error instanceof proto.RoutingError) {
|
||||
this.dependencies.logger.error(`${proto.LensProtocolRouter.LoggingPrefix}: ${String(error)}`, { url: error.url });
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { ServerResponse } from "http";
|
||||
import { loggerInjectionToken } from "@k8slens/logger";
|
||||
import { object } from "@k8slens/utilities";
|
||||
import { isDefined, object } from "@k8slens/utilities";
|
||||
import type { LensApiRequest, Route } from "./route";
|
||||
import { contentTypes } from "./router-content-types";
|
||||
|
||||
@ -34,7 +34,7 @@ const writeServerResponseFor = (serverResponse: ServerResponse) => ({
|
||||
if (content instanceof Buffer) {
|
||||
serverResponse.write(content);
|
||||
serverResponse.end();
|
||||
} else if (content) {
|
||||
} else if (isDefined(content)) {
|
||||
serverResponse.end(content);
|
||||
} else {
|
||||
serverResponse.end();
|
||||
@ -67,7 +67,7 @@ const createHandlerForRouteInjectable = getInjectable({
|
||||
} catch(error) {
|
||||
const mappedResult = contentTypes.txt.resultMapper({
|
||||
statusCode: 500,
|
||||
error: error ? String(error) : "unknown error",
|
||||
error: isDefined(error) ? String(error) : "unknown error",
|
||||
});
|
||||
|
||||
logger.error(`[ROUTER]: route ${route.path}, called with ${request.path}, threw an error`, error);
|
||||
|
||||
@ -54,7 +54,7 @@ export interface ClusterLensApiRequest<Path extends string> extends LensApiReque
|
||||
export interface LensApiResult<Response> {
|
||||
statusCode?: number;
|
||||
response?: Response;
|
||||
error?: unknown;
|
||||
error?: string | Error;
|
||||
contentType?: LensApiResultContentType;
|
||||
headers?: Partial<Record<string, string>>;
|
||||
proxy?: httpProxy;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { isDefined } from "@k8slens/utilities";
|
||||
import type { LensApiResult } from "./route";
|
||||
|
||||
export interface LensApiResultContentType {
|
||||
@ -14,19 +15,15 @@ export interface LensApiResultContentType {
|
||||
|
||||
const resultMapperFor =
|
||||
(contentType: string): LensApiResultContentType["resultMapper"] =>
|
||||
({ response, error, statusCode= error ? 400 : 200, headers = {}}) => ({
|
||||
({ response, error, statusCode = isDefined(error) ? 200 : 400, headers = {}}) => ({
|
||||
statusCode,
|
||||
content: error || response,
|
||||
content: isDefined(error) ? error : response,
|
||||
headers: { ...headers, "Content-Type": contentType },
|
||||
});
|
||||
|
||||
export type SupportedFileExtension = "json" | "txt" | "html" | "css" | "gif" | "jpg" | "png" | "svg" | "js" | "woff2" | "ttf";
|
||||
|
||||
export interface ContentTypes extends Record<SupportedFileExtension, LensApiResultContentType> {
|
||||
[key: string]: LensApiResultContentType | undefined;
|
||||
}
|
||||
|
||||
export const contentTypes: ContentTypes = {
|
||||
export const contentTypes: Record<SupportedFileExtension, LensApiResultContentType> = {
|
||||
json: {
|
||||
resultMapper: (result: LensApiResult<unknown>) => {
|
||||
const resultMapper = resultMapperFor("application/json");
|
||||
|
||||
@ -10,6 +10,7 @@ import type { LensApiRequest } from "../../router/route";
|
||||
import path from "path";
|
||||
import { contentTypes } from "../../router/router-content-types";
|
||||
import { prefixedLoggerInjectable } from "@k8slens/logger";
|
||||
import { maybeGet } from "@k8slens/utilities";
|
||||
|
||||
const prodStaticFileRouteHandlerInjectable = getInjectable({
|
||||
id: "prod-static-file-route-handler",
|
||||
@ -33,7 +34,7 @@ const prodStaticFileRouteHandlerInjectable = getInjectable({
|
||||
}
|
||||
|
||||
const fileExtension = path.extname(assetFilePath).slice(1);
|
||||
const contentType = contentTypes[fileExtension] || contentTypes.txt;
|
||||
const contentType = maybeGet(contentTypes, fileExtension) || contentTypes.txt;
|
||||
|
||||
try {
|
||||
return { response: await readFileBuffer(assetFilePath), contentType };
|
||||
|
||||
@ -16,6 +16,7 @@ import type { CreateKubeApi } from "../../../common/k8s-api/create-kube-api.inje
|
||||
import { initialNodeShellImage } from "../../../common/cluster-types";
|
||||
import type { LoadProxyKubeconfig } from "../../cluster/load-proxy-kubeconfig.injectable";
|
||||
import type { Pod } from "@k8slens/kube-object";
|
||||
import { isDefined } from "@k8slens/utilities";
|
||||
|
||||
export interface NodeShellSessionArgs extends ShellSessionArgs {
|
||||
nodeName: string;
|
||||
@ -67,7 +68,7 @@ export class NodeShellSession extends ShellSession {
|
||||
|
||||
this.send({
|
||||
type: TerminalChannels.STDOUT,
|
||||
data: `Error occurred: ${get(error, "response.body.message", error ? String(error) : "unknown error")}`,
|
||||
data: `Error occurred: ${get(error, "response.body.message", isDefined(error) ? String(error) : "unknown error")}`,
|
||||
});
|
||||
|
||||
throw new ShellOpenError(
|
||||
|
||||
@ -271,7 +271,7 @@ export abstract class ShellSession {
|
||||
}
|
||||
})
|
||||
.once("close", code => {
|
||||
this.dependencies.logger.info(`[SHELL-SESSION]: websocket for ${this.terminalId} closed with code=${WebSocketCloseEvent[code]}(${code})`, { cluster: this.cluster.getMeta() });
|
||||
this.dependencies.logger.info(`[SHELL-SESSION]: websocket for ${this.terminalId} closed with code=${String(WebSocketCloseEvent[code])}(${code})`, { cluster: this.cluster.getMeta() });
|
||||
|
||||
const stopShellSession = this.running
|
||||
&& (
|
||||
|
||||
@ -55,15 +55,11 @@ const toItemInjectablesFor = (extension: LensMainExtension, withErrorLoggingFor:
|
||||
separator: registration.type === "separator",
|
||||
|
||||
label: computed(() => {
|
||||
if (!registration.label) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (isString(registration.label)) {
|
||||
return registration.label;
|
||||
}
|
||||
|
||||
return registration.label.get();
|
||||
return registration.label?.get() ?? "";
|
||||
}),
|
||||
|
||||
tooltip: registration.toolTip,
|
||||
|
||||
@ -7,7 +7,7 @@ import { computed, observable, makeObservable, action, runInAction } from "mobx"
|
||||
import { ipcRendererOn } from "../../../../common/ipc";
|
||||
import type { CatalogCategory, CatalogEntity, CatalogEntityData, CatalogCategoryRegistry, CatalogEntityKindData } from "../../../../common/catalog";
|
||||
import type { Disposer } from "@k8slens/utilities";
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import { isDefined, isString, iter } from "@k8slens/utilities";
|
||||
import { once } from "lodash";
|
||||
import { CatalogRunEvent } from "../../../../common/catalog/catalog-run-event";
|
||||
import { ipcRenderer } from "electron";
|
||||
@ -60,7 +60,7 @@ export class CatalogEntityRegistry {
|
||||
// If the entity was not found but there are rawEntities to be processed,
|
||||
// try to process them and return the entity.
|
||||
// This might happen if an extension registered a new Catalog category.
|
||||
if (this.activeEntityId && !entity && this.rawEntities.length > 0) {
|
||||
if (this.activeEntityId.get() && !entity && this.rawEntities.length > 0) {
|
||||
this.processRawEntities();
|
||||
|
||||
return this.getActiveEntityById();
|
||||
@ -70,8 +70,8 @@ export class CatalogEntityRegistry {
|
||||
}
|
||||
|
||||
set activeEntity(raw: CatalogEntity | string | undefined) {
|
||||
if (raw) {
|
||||
const id = typeof raw === "string"
|
||||
if (isDefined(raw)) {
|
||||
const id = isString(raw)
|
||||
? raw
|
||||
: raw.getId();
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import type { ImgHTMLAttributes, MouseEventHandler } from "react";
|
||||
import React from "react";
|
||||
import randomColor from "randomcolor";
|
||||
import type { StrictReactNode } from "@k8slens/utilities";
|
||||
import { cssNames } from "@k8slens/utilities";
|
||||
import { isTruthy, cssNames } from "@k8slens/utilities";
|
||||
import { computeDefaultShortName } from "../../../common/catalog/helpers";
|
||||
|
||||
export interface AvatarProps {
|
||||
@ -44,11 +44,13 @@ export const Avatar = ({
|
||||
"data-testid": dataTestId,
|
||||
}: AvatarProps) => (
|
||||
<div
|
||||
className={cssNames(styles.Avatar, {
|
||||
[styles.circle]: variant == "circle",
|
||||
[styles.rounded]: variant == "rounded",
|
||||
[styles.disabled]: disabled,
|
||||
}, className)}
|
||||
className={cssNames(
|
||||
styles.Avatar,
|
||||
variant == "circle" && styles.circle,
|
||||
variant == "rounded" && styles.rounded,
|
||||
disabled && styles.disabled,
|
||||
className,
|
||||
)}
|
||||
style={{
|
||||
width: `${size}px`,
|
||||
height: `${size}px`,
|
||||
@ -62,14 +64,18 @@ export const Avatar = ({
|
||||
onClick={onClick}
|
||||
data-testid={dataTestId}
|
||||
>
|
||||
{src
|
||||
? (
|
||||
<img
|
||||
src={src}
|
||||
{...imgProps}
|
||||
alt={title}
|
||||
/>
|
||||
)
|
||||
: children || computeDefaultShortName(title)}
|
||||
{
|
||||
src
|
||||
? (
|
||||
<img
|
||||
src={src}
|
||||
{...imgProps}
|
||||
alt={title}
|
||||
/>
|
||||
)
|
||||
: isTruthy(children)
|
||||
? children
|
||||
: computeDefaultShortName(title)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -63,15 +63,17 @@ export const Badge = withTooltip(observer(({
|
||||
return (
|
||||
<div
|
||||
{...elemProps}
|
||||
className={cssNames(styles.badge, className, {
|
||||
[styles.small]: small,
|
||||
[styles.flat]: flat,
|
||||
[styles.clickable]: Boolean(elemProps.onClick) || isExpandable,
|
||||
[styles.interactive]: isExpandable,
|
||||
[styles.isExpanded]: isExpanded,
|
||||
[styles.disabled]: disabled,
|
||||
[styles.scrollable]: scrollable,
|
||||
})}
|
||||
className={cssNames(
|
||||
styles.badge,
|
||||
className,
|
||||
small && styles.small,
|
||||
flat && styles.flat,
|
||||
(Boolean(elemProps.onClick) || isExpandable) && styles.clickable,
|
||||
isExpandable && styles.interactive,
|
||||
isExpanded && styles.isExpanded,
|
||||
disabled && styles.disabled,
|
||||
scrollable && styles.scrollable,
|
||||
)}
|
||||
onMouseUp={onMouseUp}
|
||||
ref={elem}
|
||||
>
|
||||
|
||||
@ -11,9 +11,7 @@ import { observer } from "mobx-react";
|
||||
import { observable, action } from "mobx";
|
||||
import type { CatalogCategory, CatalogEntityAddMenu } from "../../api/catalog-entity";
|
||||
import { EventEmitter } from "events";
|
||||
import type { CatalogCategoryRegistry } from "../../../common/catalog";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
||||
import type { Navigate } from "../../navigation/navigate.injectable";
|
||||
import navigateInjectable from "../../navigation/navigate.injectable";
|
||||
|
||||
@ -24,7 +22,6 @@ export interface CatalogAddButtonProps {
|
||||
type CategoryId = string;
|
||||
|
||||
interface Dependencies {
|
||||
catalogCategoryRegistry: CatalogCategoryRegistry;
|
||||
navigate: Navigate;
|
||||
}
|
||||
|
||||
@ -43,19 +40,9 @@ class NonInjectedCatalogAddButton extends React.Component<CatalogAddButtonProps
|
||||
}
|
||||
}
|
||||
|
||||
get categories() {
|
||||
return this.props.catalogCategoryRegistry.filteredItems;
|
||||
}
|
||||
|
||||
updateMenuItems = action(() => {
|
||||
this.menuItems.clear();
|
||||
|
||||
if (this.props.category) {
|
||||
this.updateCategoryItems(this.props.category);
|
||||
} else {
|
||||
// Show menu items from all categories
|
||||
this.categories.forEach(this.updateCategoryItems);
|
||||
}
|
||||
this.updateCategoryItems(this.props.category);
|
||||
});
|
||||
|
||||
updateCategoryItems = action((category: CatalogCategory) => {
|
||||
@ -84,16 +71,13 @@ class NonInjectedCatalogAddButton extends React.Component<CatalogAddButtonProps
|
||||
|
||||
onButtonClick = () => {
|
||||
const defaultAction = this.items.find(item => item.defaultAction)?.onClick;
|
||||
const clickAction = defaultAction || (this.items.length === 1 ? this.items[0].onClick : null);
|
||||
const clickAction = defaultAction ?? this.items[0]?.onClick;
|
||||
|
||||
void clickAction?.();
|
||||
};
|
||||
|
||||
get items() {
|
||||
const { category } = this.props;
|
||||
|
||||
return category ? this.getCategoryFilteredItems(category) :
|
||||
this.categories.map(this.getCategoryFilteredItems).flat();
|
||||
return this.getCategoryFilteredItems(this.props.category);
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -136,7 +120,6 @@ class NonInjectedCatalogAddButton extends React.Component<CatalogAddButtonProps
|
||||
export const CatalogAddButton = withInjectables<Dependencies, CatalogAddButtonProps>(NonInjectedCatalogAddButton, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
catalogCategoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
||||
navigate: di.inject(navigateInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { isTruthy } from "@k8slens/utilities";
|
||||
import React from "react";
|
||||
import type { CatalogCategory } from "../../../common/catalog/catalog-entity";
|
||||
|
||||
@ -18,7 +19,7 @@ export const CatalogCategoryLabel = ({ category }: CatalogCategoryLabelProps) =>
|
||||
return (
|
||||
<div className="flex">
|
||||
<div>{category.metadata.name}</div>
|
||||
{badge ? (<div className="flex items-center">{badge}</div>) : null}
|
||||
{isTruthy(badge) ? (<div className="flex items-center">{badge}</div>) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -43,10 +43,6 @@ class NonInjectedCatalogEntityDrawerMenu<T extends CatalogEntity> extends React.
|
||||
}
|
||||
|
||||
getMenuItems(entity: T): React.ReactChild[] {
|
||||
if (!entity) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const items = this.menuItems
|
||||
.map(this.props.normalizeMenuItem)
|
||||
.filter(hasDefiniteField("icon"))
|
||||
|
||||
@ -15,22 +15,26 @@ const kubernetesClusterDetailsItemInjectable = getInjectable({
|
||||
kind: KubernetesCluster.kind,
|
||||
orderNumber: 40,
|
||||
components: {
|
||||
Details: ({ entity }) => (
|
||||
<>
|
||||
<DrawerTitle>Kubernetes Information</DrawerTitle>
|
||||
<div className="box grow EntityMetadata">
|
||||
<DrawerItem
|
||||
name="Distribution"
|
||||
data-testid={`kubernetes-distro-for-${entity.getId()}`}
|
||||
>
|
||||
{entity.metadata.distro || "unknown"}
|
||||
</DrawerItem>
|
||||
<DrawerItem name="Kubelet Version">
|
||||
{entity.metadata.kubeVersion || "unknown"}
|
||||
</DrawerItem>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
Details: ({ entity }) => {
|
||||
const kube = entity as KubernetesCluster;
|
||||
|
||||
return (
|
||||
<>
|
||||
<DrawerTitle>Kubernetes Information</DrawerTitle>
|
||||
<div className="box grow EntityMetadata">
|
||||
<DrawerItem
|
||||
name="Distribution"
|
||||
data-testid={`kubernetes-distro-for-${entity.getId()}`}
|
||||
>
|
||||
{kube.metadata.distro || "unknown"}
|
||||
</DrawerItem>
|
||||
<DrawerItem name="Kubelet Version">
|
||||
{kube.metadata.kubeVersion || "unknown"}
|
||||
</DrawerItem>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
},
|
||||
},
|
||||
}),
|
||||
injectionToken: catalogEntityDetailItemInjectionToken,
|
||||
|
||||
@ -137,7 +137,7 @@ const NonInjectedBarChart = observer(({
|
||||
typeof datasetIndex === "number"
|
||||
? {
|
||||
borderColor: "darkgray",
|
||||
backgroundColor: datasets[datasetIndex].borderColor as string,
|
||||
backgroundColor: datasets[datasetIndex]?.borderColor as string,
|
||||
}
|
||||
: {
|
||||
borderColor: "darkgray",
|
||||
@ -181,7 +181,7 @@ const tooltipCallbackWith = (precision: number): ChartTooltipCallback["label"] =
|
||||
return "";
|
||||
}
|
||||
|
||||
const { label, data } = datasets[datasetIndex];
|
||||
const { label, data } = datasets[datasetIndex] ?? {};
|
||||
|
||||
if (!label || !data) {
|
||||
return "<unknown>";
|
||||
|
||||
@ -36,7 +36,7 @@ const memoryLikeOptions: ChartOptions = {
|
||||
return "";
|
||||
}
|
||||
|
||||
const { label = "", data } = datasets[datasetIndex];
|
||||
const { label = "", data } = datasets[datasetIndex] ?? {};
|
||||
|
||||
if (!data) {
|
||||
return label;
|
||||
@ -78,7 +78,7 @@ export const metricTabOptions: Record<MetricsTab, ChartOptions> = {
|
||||
return "";
|
||||
}
|
||||
|
||||
const { label = "", data } = datasets[datasetIndex];
|
||||
const { label = "", data } = datasets[datasetIndex] ?? {};
|
||||
|
||||
if (!data) {
|
||||
return label;
|
||||
@ -106,7 +106,7 @@ export const metricTabOptions: Record<MetricsTab, ChartOptions> = {
|
||||
return "";
|
||||
}
|
||||
|
||||
const { label = "", data } = datasets[datasetIndex];
|
||||
const { label = "", data } = datasets[datasetIndex] ?? {};
|
||||
|
||||
if (!data) {
|
||||
return label;
|
||||
@ -134,7 +134,7 @@ export const metricTabOptions: Record<MetricsTab, ChartOptions> = {
|
||||
return "";
|
||||
}
|
||||
|
||||
const { label = "", data } = datasets[datasetIndex];
|
||||
const { label = "", data } = datasets[datasetIndex] ?? {};
|
||||
|
||||
if (!data) {
|
||||
return label;
|
||||
|
||||
@ -80,7 +80,7 @@ const NonInjectedPieChart = observer(({
|
||||
return false;
|
||||
}
|
||||
|
||||
const { data = [] } = datasets[datasetIndex];
|
||||
const { data = [] } = datasets[datasetIndex] ?? {};
|
||||
|
||||
if (datasets.length === 1) return true;
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
import "./checkbox.scss";
|
||||
import React from "react";
|
||||
import type { StrictReactNode } from "@k8slens/utilities";
|
||||
import { cssNames, noop } from "@k8slens/utilities";
|
||||
import { isTruthy, cssNames, noop } from "@k8slens/utilities";
|
||||
|
||||
export interface CheckboxProps {
|
||||
className?: string;
|
||||
@ -35,7 +35,7 @@ export function Checkbox({ label, inline, className, value, children, onChange =
|
||||
onChange={event => onChange(event.target.checked, event)}
|
||||
/>
|
||||
<i className="box flex align-center"/>
|
||||
{label ? <span className="label">{label}</span> : null}
|
||||
{isTruthy(label) ? <span className="label">{label}</span> : null}
|
||||
{children}
|
||||
</label>
|
||||
);
|
||||
|
||||
@ -16,7 +16,7 @@ import { TopBar } from "../layout/top-bar/top-bar";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
|
||||
import welcomeRouteInjectable from "../../../common/front-end-routing/routes/welcome/welcome-route.injectable";
|
||||
import { buildURL } from "@k8slens/utilities";
|
||||
import { buildURL, isDefined } from "@k8slens/utilities";
|
||||
import type { WatchForGeneralEntityNavigation } from "../../api/helpers/watch-for-general-entity-navigation.injectable";
|
||||
import watchForGeneralEntityNavigationInjectable from "../../api/helpers/watch-for-general-entity-navigation.injectable";
|
||||
import currentPathInjectable from "../../routes/current-path.injectable";
|
||||
@ -39,7 +39,7 @@ class NonInjectedClusterManager extends React.Component<Dependencies> {
|
||||
renderMainComponent() {
|
||||
const Component = this.props.currentRouteComponent.get();
|
||||
|
||||
if (Component) {
|
||||
if (isDefined(Component)) {
|
||||
return <Component />;
|
||||
}
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ class NonInjectedClusterPrometheusSetting extends React.Component<ClusterPrometh
|
||||
}
|
||||
|
||||
@computed get canEditPrometheusPath(): boolean {
|
||||
if (!this.selectedOption || this.selectedOption === autoDetectPrometheus) {
|
||||
if (this.selectedOption === autoDetectPrometheus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ class NonInjectedClusterPrometheusSetting extends React.Component<ClusterPrometh
|
||||
}
|
||||
|
||||
parsePrometheusPath = () => {
|
||||
if (!this.selectedOption || !this.path) {
|
||||
if (!this.path) {
|
||||
return undefined;
|
||||
}
|
||||
const parsed = this.path.split(/\/|:/, 3);
|
||||
|
||||
@ -14,7 +14,7 @@ import navigateToEntitySettingsInjectable from "../../../common/front-end-routin
|
||||
import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable";
|
||||
|
||||
export interface ClusterNoMetricsProps {
|
||||
className: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
|
||||
@ -212,9 +212,7 @@ function getInternalCommands(dependencies: Dependencies): CommandRegistration[]
|
||||
id: "entity.viewSettings",
|
||||
title: ({ entity }) => `${entity.kind}/${entity.getName()}: View Settings`,
|
||||
action: ({ entity }) => dependencies.navigateToEntitySettings(entity.getId()),
|
||||
isActive: ({ entity }) => (
|
||||
entity && dependencies.hasCatalogEntitySettingItems(entity)
|
||||
),
|
||||
isActive: ({ entity }) => dependencies.hasCatalogEntitySettingItems(entity),
|
||||
},
|
||||
{
|
||||
id: "cluster.openTerminal",
|
||||
|
||||
@ -54,7 +54,7 @@ class NonInjectedHorizontalPodAutoscalerDetails extends React.Component<KubeObje
|
||||
}
|
||||
|
||||
renderMetrics(hpa: HorizontalPodAutoscaler) {
|
||||
const renderName = (metric: HorizontalPodAutoscalerMetricSpec) => {
|
||||
const renderName = (metric: HorizontalPodAutoscalerMetricSpec | undefined) => {
|
||||
const metricName = getMetricName(metric);
|
||||
|
||||
switch (metric?.type) {
|
||||
@ -95,7 +95,7 @@ class NonInjectedHorizontalPodAutoscalerDetails extends React.Component<KubeObje
|
||||
this.props.getMetrics(hpa)
|
||||
.map((metrics, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell className="name">{renderName(hpa.getMetrics()[index])}</TableCell>
|
||||
<TableCell className="name">{renderName(hpa.getMetrics()?.[index])}</TableCell>
|
||||
<TableCell className="metrics">{metrics}</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
@ -107,10 +107,6 @@ class NonInjectedHorizontalPodAutoscalerDetails extends React.Component<KubeObje
|
||||
render() {
|
||||
const { object: hpa, apiManager, getDetailsUrl, logger } = this.props;
|
||||
|
||||
if (!hpa) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(hpa instanceof HorizontalPodAutoscaler)) {
|
||||
logger.error("[HpaDetails]: passed object that is not an instanceof HorizontalPodAutoscaler", hpa);
|
||||
|
||||
|
||||
@ -59,10 +59,6 @@ class NonInjectedLimitRangeDetails extends React.Component<KubeObjectDetailsProp
|
||||
render() {
|
||||
const { object: limitRange, logger } = this.props;
|
||||
|
||||
if (!limitRange) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(limitRange instanceof LimitRange)) {
|
||||
logger.error("[LimitRangeDetails]: passed object that is not an instanceof LimitRange", limitRange);
|
||||
|
||||
|
||||
@ -44,9 +44,7 @@ class NonInjectedConfigMapDetails extends React.Component<KubeObjectDetailsProps
|
||||
autorun(() => {
|
||||
const configMap = this.props.object as ConfigMap;
|
||||
|
||||
if (configMap) {
|
||||
this.data.replace(configMap.data); // refresh
|
||||
}
|
||||
this.data.replace(configMap.data); // refresh
|
||||
}),
|
||||
]);
|
||||
}
|
||||
@ -79,10 +77,6 @@ class NonInjectedConfigMapDetails extends React.Component<KubeObjectDetailsProps
|
||||
render() {
|
||||
const { object: configMap, logger } = this.props;
|
||||
|
||||
if (!configMap) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(configMap instanceof ConfigMap)) {
|
||||
logger.error("[ConfigMapDetails]: passed object that is not an instanceof ConfigMap", configMap);
|
||||
|
||||
|
||||
@ -144,13 +144,11 @@ export const WebhookConfig: React.FC<WebhookProps> = ({ webhook }) => {
|
||||
{" "}
|
||||
{rule.operations.join(", ")}
|
||||
</div>
|
||||
{rule.resources && (
|
||||
<div>
|
||||
Resources:
|
||||
{" "}
|
||||
{rule.resources.join(", ")}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
Resources:
|
||||
{" "}
|
||||
{rule.resources?.join(", ")}
|
||||
</div>
|
||||
{rule.scope && (
|
||||
<div>
|
||||
Scope:
|
||||
|
||||
@ -83,10 +83,6 @@ class NonInjectedResourceQuotaDetails extends React.Component<KubeObjectDetailsP
|
||||
render() {
|
||||
const { object: quota } = this.props;
|
||||
|
||||
if (!quota) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(quota instanceof ResourceQuota)) {
|
||||
this.props.logger.error("[ResourceQuotaDetails]: passed object that is not an instanceof ResourceQuota", quota);
|
||||
|
||||
|
||||
@ -48,10 +48,8 @@ class NonInjectedSecretDetails extends React.Component<KubeObjectDetailsProps &
|
||||
autorun(() => {
|
||||
const secret = this.props.object as Secret;
|
||||
|
||||
if (secret) {
|
||||
this.data = secret.data;
|
||||
this.revealSecret.clear();
|
||||
}
|
||||
this.data = secret.data;
|
||||
this.revealSecret.clear();
|
||||
}),
|
||||
]);
|
||||
}
|
||||
@ -145,10 +143,6 @@ class NonInjectedSecretDetails extends React.Component<KubeObjectDetailsProps &
|
||||
render() {
|
||||
const { object: secret, logger } = this.props;
|
||||
|
||||
if (!secret) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(secret instanceof Secret)) {
|
||||
logger.error("[SecretDetails]: passed object that is not an instanceof Secret", secret);
|
||||
|
||||
|
||||
@ -161,10 +161,6 @@ class NonInjectedVpaDetails extends React.Component<KubeObjectDetailsProps & Dep
|
||||
render() {
|
||||
const { object: vpa, apiManager, getDetailsUrl, logger } = this.props;
|
||||
|
||||
if (!vpa) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(vpa instanceof VerticalPodAutoscaler)) {
|
||||
logger.error("[VpaDetails]: passed object that is not an instanceof VerticalPodAutoscaler", vpa);
|
||||
|
||||
@ -186,10 +182,7 @@ class NonInjectedVpaDetails extends React.Component<KubeObjectDetailsProps & Dep
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerItem name="Recommender">
|
||||
{
|
||||
/* according to the spec there can be 0 or 1 recommenders, only */
|
||||
recommenders?.length ? recommenders[0].name : "default"
|
||||
}
|
||||
{recommenders?.[0]?.name ?? "default"}
|
||||
</DrawerItem>
|
||||
|
||||
{vpa.status && this.renderStatus(vpa, vpa.status)}
|
||||
|
||||
@ -28,10 +28,6 @@ class NonInjectedCustomResourceDefinitionDetails extends React.Component<KubeObj
|
||||
render() {
|
||||
const { object: crd } = this.props;
|
||||
|
||||
if (!crd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(crd instanceof CustomResourceDefinition)) {
|
||||
this.props.logger.error("[CustomResourceDefinitionDetails]: passed object that is not an instanceof CustomResourceDefinition", crd);
|
||||
|
||||
|
||||
@ -110,9 +110,9 @@ class NonInjectedCustomResourceDetails extends React.Component<CustomResourceDet
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props: { object, crd, logger }} = this;
|
||||
const { object, crd, logger } = this.props;
|
||||
|
||||
if (!object || !crd) {
|
||||
if (!crd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import type { CreateStorage } from "../../../utils/create-storage/create-storage
|
||||
import type { TabId } from "../dock/store";
|
||||
import autoBind from "auto-bind";
|
||||
import { toJS } from "../../../../common/utils";
|
||||
import { isTruthy } from "@k8slens/utilities";
|
||||
|
||||
export interface DockTabStoreOptions {
|
||||
autoInit?: boolean; // load data from storage when `storageKey` is provided and bind events, default: true
|
||||
@ -59,7 +60,7 @@ export class DockTabStore<T> {
|
||||
|
||||
findTabIdFromData(inspector: (val: T) => unknown): TabId | undefined {
|
||||
for (const [tabId, data] of this.data) {
|
||||
if (inspector(data)) {
|
||||
if (isTruthy(inspector(data))) {
|
||||
return tabId;
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,10 +78,6 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
|
||||
render() {
|
||||
const { className, moreActions, dockStore, active, isMac, ...tabProps } = this.props;
|
||||
|
||||
if (!tabProps.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
void dockStore;
|
||||
void active;
|
||||
void isMac;
|
||||
@ -94,9 +90,11 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
|
||||
<Tab
|
||||
{...tabProps}
|
||||
id={`tab-${id}`}
|
||||
className={cssNames(styles.DockTab, className, {
|
||||
[styles.pinned]: pinned,
|
||||
})}
|
||||
className={cssNames(
|
||||
styles.DockTab,
|
||||
className,
|
||||
pinned && styles.pinned,
|
||||
)}
|
||||
onContextMenu={() => this.menuVisible.set(true)}
|
||||
label={(
|
||||
<div className="flex align-center" onAuxClick={isMiddleClick(close)}>
|
||||
|
||||
@ -93,11 +93,11 @@ class NonInjectedDock extends React.Component<DockProps & Dependencies> {
|
||||
const currentIndex = tabs.indexOf(selectedTab);
|
||||
const nextIndex = currentIndex + direction;
|
||||
|
||||
// check if moving to the next or previous tab is possible.
|
||||
if (nextIndex >= tabs.length || nextIndex < 0) return;
|
||||
|
||||
const nextElement = tabs[nextIndex];
|
||||
|
||||
// check if moving to the next or previous tab is possible.
|
||||
if (!nextElement) return;
|
||||
|
||||
this.onChangeTab(nextElement);
|
||||
};
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import React, { Component } from "react";
|
||||
import { computed, observable, reaction, makeObservable } from "mobx";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import type { StrictReactNode } from "@k8slens/utilities";
|
||||
import { cssNames } from "@k8slens/utilities";
|
||||
import { cssNames, isTruthy } from "@k8slens/utilities";
|
||||
import { Button } from "@k8slens/button";
|
||||
import { Icon } from "@k8slens/icon";
|
||||
import { Spinner } from "../spinner";
|
||||
@ -90,7 +90,7 @@ class NonInjectedInfoPanel extends Component<InfoPanelProps & Dependencies> {
|
||||
try {
|
||||
const result = await this.props.submit?.();
|
||||
|
||||
if (showNotifications && result) {
|
||||
if (showNotifications && isTruthy(result)) {
|
||||
this.props.showSuccessNotification(result);
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ class NonInjectedInfoPanel extends Component<InfoPanelProps & Dependencies> {
|
||||
submitAndClose = async () => {
|
||||
const result = await this.submit();
|
||||
|
||||
if (result) {
|
||||
if (isTruthy(result)) {
|
||||
this.close();
|
||||
}
|
||||
};
|
||||
|
||||
@ -32,7 +32,7 @@ export const LogSearch = observer((props: PodLogSearchProps) => {
|
||||
const logs = tabData.showTimestamps
|
||||
? model.logs.get()
|
||||
: model.logsWithoutTimestamps.get();
|
||||
const jumpDisabled = !searchQuery || !occurrences.length;
|
||||
const jumpDisabled = !searchQuery.get() || !occurrences.length;
|
||||
|
||||
const setSearch = (query: string) => {
|
||||
searchStore.onSearch(logs, query);
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { when } from "mobx";
|
||||
import { loggerInjectionToken } from "@k8slens/logger";
|
||||
import { TerminalChannels } from "../../../../common/terminal/channels";
|
||||
import { waitUntilDefined, noop } from "@k8slens/utilities";
|
||||
import showSuccessNotificationInjectable from "../../notifications/show-success-notification.injectable";
|
||||
@ -40,7 +39,6 @@ const sendCommandInjectable = getInjectable({
|
||||
const selectTab = di.inject(selectDockTabInjectable);
|
||||
const getTerminalApi = di.inject(getTerminalApiInjectable);
|
||||
const showSuccessNotification = di.inject(showSuccessNotificationInjectable);
|
||||
const logger = di.inject(loggerInjectionToken);
|
||||
|
||||
return async (command: string, options: SendCommandOptions = {}): Promise<void> => {
|
||||
let tabId: string | undefined = options.tabId;
|
||||
@ -70,21 +68,14 @@ const sendCommandInjectable = getInjectable({
|
||||
await shellIsReady.catch(noop);
|
||||
clearTimeout(notifyVeryLong);
|
||||
|
||||
if (terminalApi) {
|
||||
if (options.enter) {
|
||||
command += "\r";
|
||||
}
|
||||
|
||||
terminalApi.sendMessage({
|
||||
type: TerminalChannels.STDIN,
|
||||
data: command,
|
||||
});
|
||||
} else {
|
||||
logger.warn(
|
||||
"The selected tab is does not have a connection. Cannot send command.",
|
||||
{ tabId, command },
|
||||
);
|
||||
if (options.enter) {
|
||||
command += "\r";
|
||||
}
|
||||
|
||||
terminalApi.sendMessage({
|
||||
type: TerminalChannels.STDIN,
|
||||
data: command,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -44,13 +44,11 @@ export class Terminal {
|
||||
protected readonly api: TerminalApi;
|
||||
|
||||
private get elem() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return this.xterm.element!;
|
||||
return this.xterm.element;
|
||||
}
|
||||
|
||||
private get viewport() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return this.elem.querySelector(".xterm-viewport")!;
|
||||
return this.elem?.querySelector(".xterm-viewport");
|
||||
}
|
||||
|
||||
attachTo(parentElem: HTMLElement) {
|
||||
@ -99,8 +97,10 @@ export class Terminal {
|
||||
const onDataHandler = this.xterm.onData(this.onData);
|
||||
const clearOnce = once(this.onClear);
|
||||
|
||||
this.viewport.addEventListener("scroll", this.onScroll);
|
||||
this.elem.addEventListener("contextmenu", this.onContextMenu);
|
||||
const { viewport, elem } = this;
|
||||
|
||||
viewport?.addEventListener("scroll", this.onScroll);
|
||||
elem?.addEventListener("contextmenu", this.onContextMenu);
|
||||
this.api.once("ready", clearOnce);
|
||||
this.api.once("connected", clearOnce);
|
||||
this.api.on("data", this.onApiData);
|
||||
@ -128,7 +128,8 @@ export class Terminal {
|
||||
() => this.fitAddon.dispose(),
|
||||
() => this.api.removeAllListeners(),
|
||||
() => window.removeEventListener("resize", this.onResize),
|
||||
() => this.elem.removeEventListener("contextmenu", this.onContextMenu),
|
||||
() => elem?.removeEventListener("contextmenu", this.onContextMenu),
|
||||
() => viewport?.removeEventListener("scroll", this.onScroll),
|
||||
this.xterm.onResize(({ cols, rows }) => {
|
||||
this.api.sendTerminalSize(cols, rows);
|
||||
}),
|
||||
@ -161,7 +162,7 @@ export class Terminal {
|
||||
};
|
||||
|
||||
onScroll = () => {
|
||||
this.scrollPos = this.viewport.scrollTop;
|
||||
this.scrollPos = this.viewport?.scrollTop ?? 0;
|
||||
};
|
||||
|
||||
onClear = () => {
|
||||
@ -176,7 +177,12 @@ export class Terminal {
|
||||
onActivate = () => {
|
||||
this.fit();
|
||||
setTimeout(() => this.focus(), 250); // delay used to prevent focus on active tab
|
||||
this.viewport.scrollTop = this.scrollPos; // restore last scroll position
|
||||
|
||||
const { viewport } = this;
|
||||
|
||||
if (viewport) {
|
||||
viewport.scrollTop = this.scrollPos; // restore last scroll position
|
||||
}
|
||||
};
|
||||
|
||||
onContextMenu = () => {
|
||||
|
||||
@ -10,7 +10,7 @@ import { Badge } from "../badge";
|
||||
import { KubeObject } from "@k8slens/kube-object";
|
||||
|
||||
export interface DrawerItemLabelsProps extends DrawerItemProps {
|
||||
labels: string[] | Partial<Record<string, string>>;
|
||||
labels?: string[] | Partial<Record<string, string>>;
|
||||
}
|
||||
|
||||
export function DrawerItemLabels(props: DrawerItemLabelsProps) {
|
||||
|
||||
@ -28,10 +28,12 @@ export interface DrawerTitleProps {
|
||||
export function DrawerTitle({ className, children, size = "title" }: DrawerTitleProps) {
|
||||
return (
|
||||
<div
|
||||
className={cssNames(styles.DrawerTitle, className, {
|
||||
[styles.title]: size === "title",
|
||||
[styles["sub-title"]]: size === "sub-title",
|
||||
})}
|
||||
className={cssNames(
|
||||
styles.DrawerTitle,
|
||||
className,
|
||||
size === "title" && styles.title,
|
||||
size === "sub-title" && styles["sub-title"],
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -36,10 +36,6 @@ const NonInjectedEventDetails = observer(({
|
||||
className,
|
||||
logger,
|
||||
}: Dependencies & KubeObjectDetailsProps) => {
|
||||
if (!event) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(event instanceof KubeEvent)) {
|
||||
logger.error("[EventDetails]: passed object that is not an instanceof KubeEvent", event);
|
||||
|
||||
|
||||
@ -43,10 +43,6 @@ class NonInjectedKubeEventDetails extends React.Component<KubeEventDetailsProps
|
||||
render() {
|
||||
const { object, eventStore } = this.props;
|
||||
|
||||
if (!object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(object instanceof KubeObject)) {
|
||||
this.props.logger.error("[KubeEventDetails]: passed object that is not an instanceof KubeObject", object);
|
||||
|
||||
@ -64,7 +60,7 @@ class NonInjectedKubeEventDetails extends React.Component<KubeEventDetailsProps
|
||||
<div className={styles.KubeEventDetails}>
|
||||
{events.map(event => (
|
||||
<div className={styles.event} key={event.getId()}>
|
||||
<div className={cssNames(styles.title, { [styles.warning]: event.isWarning() })}>
|
||||
<div className={cssNames(styles.title, event.isWarning() && styles.warning)}>
|
||||
{event.message}
|
||||
</div>
|
||||
<DrawerItem name="Source">
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { isObject } from "@k8slens/utilities";
|
||||
import { isObject, isTruthy } from "@k8slens/utilities";
|
||||
import React from "react";
|
||||
import { SemVer } from "semver";
|
||||
import URLParse from "url-parse";
|
||||
@ -76,8 +76,8 @@ const attemptInstallByInfoInjectable = getInjectable({
|
||||
return disposer();
|
||||
}
|
||||
|
||||
if (result.value.error || !isObject(result.value.versions)) {
|
||||
const message = result.value.error ? `: ${String(result.value.error)}` : "";
|
||||
if (isTruthy(result.value.error) || !isObject(result.value.versions)) {
|
||||
const message = isTruthy(result.value.error) ? `: ${String(result.value.error)}` : "";
|
||||
|
||||
showErrorNotification(`Failed to get registry information for extension${message}`);
|
||||
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { hasTypedProperty, isDefined } from "@k8slens/utilities";
|
||||
import { hasTypedProperty, isDefined, isObject } from "@k8slens/utilities";
|
||||
|
||||
export function getMessageFromError(error: unknown): string {
|
||||
if (!error || typeof error !== "object") {
|
||||
if (!isObject(error)) {
|
||||
return "an error has occurred";
|
||||
}
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ const NonInjectedInstalledExtensions = observer(({
|
||||
enableExtension,
|
||||
disableExtension,
|
||||
}: Dependencies) => {
|
||||
if (!extensionDiscovery.isLoaded) {
|
||||
if (!extensionDiscovery.isLoaded.get()) {
|
||||
return <div><Spinner center /></div>;
|
||||
}
|
||||
|
||||
@ -85,8 +85,8 @@ const NonInjectedInstalledExtensions = observer(({
|
||||
accessor: "extension",
|
||||
width: 200,
|
||||
sortType: (rowA, rowB) => { // Custom sorting for extension name
|
||||
const nameA = extensions[rowA.index].manifest.name;
|
||||
const nameB = extensions[rowB.index].manifest.name;
|
||||
const nameA = extensions[rowA.index]?.manifest.name ?? "";
|
||||
const nameB = extensions[rowB.index]?.manifest.name ?? "";
|
||||
|
||||
if (nameA > nameB) return -1;
|
||||
if (nameB > nameA) return 1;
|
||||
@ -126,7 +126,12 @@ const NonInjectedInstalledExtensions = observer(({
|
||||
),
|
||||
version,
|
||||
status: (
|
||||
<div className={cssNames({ [styles.enabled]: isEnabled, [styles.invalid]: !isCompatible })}>
|
||||
<div
|
||||
className={cssNames(
|
||||
isEnabled && styles.enabled,
|
||||
!isCompatible && styles.invalid,
|
||||
)}
|
||||
>
|
||||
{getStatus(extension)}
|
||||
</div>
|
||||
),
|
||||
|
||||
@ -25,7 +25,6 @@ import versionsOfSelectedHelmChartInjectable from "./details/versions-of-selecte
|
||||
import type { HelmChartDetailsVersionSelection } from "./details/versions/helm-chart-details-version-selection.injectable";
|
||||
import helmChartDetailsVersionSelectionInjectable from "./details/versions/helm-chart-details-version-selection.injectable";
|
||||
import assert from "assert";
|
||||
import autoBindReact from "auto-bind/react";
|
||||
|
||||
export interface HelmChartDetailsProps {
|
||||
hideDetails(): void;
|
||||
@ -47,15 +46,6 @@ interface Dependencies {
|
||||
|
||||
@observer
|
||||
class NonInjectedHelmChartDetails extends Component<HelmChartDetailsProps & Dependencies> {
|
||||
constructor(props: HelmChartDetailsProps & Dependencies) {
|
||||
super(props);
|
||||
autoBindReact(this);
|
||||
}
|
||||
|
||||
get chart() {
|
||||
return this.props.chart;
|
||||
}
|
||||
|
||||
install = () => {
|
||||
const chart = this.props.versionSelection.value.get();
|
||||
|
||||
@ -144,13 +134,13 @@ class NonInjectedHelmChartDetails extends Component<HelmChartDetailsProps & Depe
|
||||
const readmeIsLoading = this.props.readme.pending.get();
|
||||
const versionsAreLoading = this.props.versions.pending.get();
|
||||
|
||||
if (!this.chart || versionsAreLoading) {
|
||||
if (versionsAreLoading) {
|
||||
return <Spinner center data-testid="spinner-for-chart-details" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="box grow">
|
||||
{this.renderIntroduction(this.chart)}
|
||||
{this.renderIntroduction(this.props.chart)}
|
||||
|
||||
{readmeIsLoading ? (
|
||||
<Spinner center data-testid="spinner-for-chart-readme" />
|
||||
@ -162,12 +152,13 @@ class NonInjectedHelmChartDetails extends Component<HelmChartDetailsProps & Depe
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
className="HelmChartDetails"
|
||||
usePortal={true}
|
||||
open={!!this.chart}
|
||||
title={this.chart ? `Chart: ${this.chart.getFullName()}` : ""}
|
||||
usePortal
|
||||
open
|
||||
title={`Chart: ${this.props.chart.getFullName()}`}
|
||||
onClose={this.props.hideDetails}
|
||||
>
|
||||
{this.renderContent()}
|
||||
|
||||
@ -31,7 +31,7 @@ export const HelmChartIcon = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cssNames(styles.chartIcon, className, { [styles.imageNotLoaded]: !isImageLoaded })}
|
||||
className={cssNames(styles.chartIcon, className, !isImageLoaded && styles.imageNotLoaded)}
|
||||
data-testid="image-container"
|
||||
style={{
|
||||
backgroundImage: isImageLoaded ? backgroundImage : `url(${placeholderImageUrl})`,
|
||||
|
||||
@ -46,12 +46,9 @@ class NonInjectedHelmReleaseMenu extends React.Component<HelmReleaseMenuProps &
|
||||
renderContent() {
|
||||
const { release, toolbar } = this.props;
|
||||
|
||||
if (!release) return null;
|
||||
const hasRollback = release && release.getRevision() > 1;
|
||||
|
||||
return (
|
||||
<>
|
||||
{hasRollback && (
|
||||
{(release.getRevision() > 1) && (
|
||||
<MenuItem onClick={this.rollback}>
|
||||
<Icon
|
||||
material="history"
|
||||
|
||||
@ -69,10 +69,10 @@ class NonInjectedHotbarEntityIcon extends React.Component<HotbarEntityIconProps
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cssNames(styles.led, {
|
||||
// TODO: make it more generic
|
||||
[styles.online]: this.props.entity.status.phase === LensKubernetesClusterStatus.CONNECTED,
|
||||
})}
|
||||
className={cssNames(
|
||||
styles.led,
|
||||
(this.props.entity.status.phase === LensKubernetesClusterStatus.CONNECTED) && styles.online,
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -107,7 +107,6 @@ class NonInjectedHotbarEntityIcon extends React.Component<HotbarEntityIconProps
|
||||
className={className}
|
||||
active={this.isActive(entity)}
|
||||
onMenuOpen={() => this.onMenuOpen()}
|
||||
disabled={!entity}
|
||||
menuItems={this.menuItems}
|
||||
tooltip={(
|
||||
entity.metadata.source
|
||||
|
||||
@ -50,7 +50,7 @@ const NonInjectedHotbarIcon = observer(({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cssNames(styles.HotbarIcon, className, { [styles.contextMenuAvailable]: menuItems.length > 0 })}>
|
||||
<div className={cssNames(styles.HotbarIcon, className, (menuItems.length > 0 && styles.contextMenuAvailable))}>
|
||||
{tooltip && (
|
||||
<Tooltip targetId={id}>
|
||||
{tooltip}
|
||||
@ -61,7 +61,11 @@ const NonInjectedHotbarIcon = observer(({
|
||||
id={id}
|
||||
title={title}
|
||||
colorHash={source ? `${title}-${source}` : title}
|
||||
className={cssNames(styles.avatar, { [styles.active]: active, [styles.hasImage]: !!src })}
|
||||
className={cssNames(
|
||||
styles.avatar,
|
||||
active && styles.active,
|
||||
!!src && styles.hasImag,
|
||||
)}
|
||||
disabled={disabled}
|
||||
size={size}
|
||||
src={src}
|
||||
|
||||
@ -8,7 +8,7 @@ import "./input.scss";
|
||||
import type { DOMAttributes, InputHTMLAttributes, TextareaHTMLAttributes } from "react";
|
||||
import React from "react";
|
||||
import type { StrictReactNode, SingleOrMany } from "@k8slens/utilities";
|
||||
import { isReactNode, isString, isFunction, debouncePromise, isPromiseSettledFulfilled, cssNames } from "@k8slens/utilities";
|
||||
import { isReactNode, isFalsy, isTruthy, isString, isFunction, debouncePromise, isPromiseSettledFulfilled, cssNames } from "@k8slens/utilities";
|
||||
import { Icon } from "@k8slens/icon";
|
||||
import type { TooltipProps } from "@k8slens/tooltip";
|
||||
import { Tooltip } from "@k8slens/tooltip";
|
||||
@ -195,7 +195,13 @@ export class Input extends React.Component<InputProps, State> {
|
||||
|
||||
return undefined;
|
||||
} catch (error) {
|
||||
return this.getValidatorError(value, validator) || (error instanceof Error ? error.message : String(error));
|
||||
const validationError = this.getValidatorError(value, validator);
|
||||
|
||||
return isTruthy(validationError)
|
||||
? validationError
|
||||
: error instanceof Error
|
||||
? error.message
|
||||
: String(error);
|
||||
}
|
||||
})());
|
||||
}
|
||||
@ -327,7 +333,7 @@ export class Input extends React.Component<InputProps, State> {
|
||||
get showMaxLenIndicator() {
|
||||
const { maxLength, multiLine } = this.props;
|
||||
|
||||
return maxLength && multiLine;
|
||||
return Boolean(maxLength && multiLine);
|
||||
}
|
||||
|
||||
get isUncontrolled() {
|
||||
@ -440,12 +446,12 @@ export class Input extends React.Component<InputProps, State> {
|
||||
{errors.map((error, i) => <p key={i}>{error}</p>)}
|
||||
</div>
|
||||
);
|
||||
const componentId = id || showErrorsAsTooltip
|
||||
const componentId = id || isTruthy(showErrorsAsTooltip)
|
||||
? `input_tooltip_id_${uuid.v4()}`
|
||||
: undefined;
|
||||
let tooltipError: StrictReactNode;
|
||||
|
||||
if (showErrorsAsTooltip && showErrors) {
|
||||
if (isTruthy(showErrorsAsTooltip) && showErrors) {
|
||||
const tooltipProps = typeof showErrorsAsTooltip === "object" ? showErrorsAsTooltip : {};
|
||||
|
||||
tooltipProps.className = cssNames("InputTooltipError", tooltipProps.className);
|
||||
@ -473,7 +479,7 @@ export class Input extends React.Component<InputProps, State> {
|
||||
{contentRight}
|
||||
</label>
|
||||
<div className="input-info flex gaps">
|
||||
{!showErrorsAsTooltip && showErrors && errorsInfo}
|
||||
{(isFalsy(showErrorsAsTooltip) && showErrors) && errorsInfo}
|
||||
{this.showMaxLenIndicator && (
|
||||
<div className="maxLengthIndicator box right">
|
||||
{this.getValue().length}
|
||||
|
||||
@ -59,6 +59,10 @@ export function isAsyncValidator(validator: InputValidator): validator is AsyncI
|
||||
return typeof validator.debounce === "number";
|
||||
}
|
||||
|
||||
export function isSyncValidator(validator: InputValidator): validator is SyncInputValidator {
|
||||
return typeof validator.debounce !== "number";
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to create an {@link AsyncInputValidator}
|
||||
*/
|
||||
@ -106,7 +110,11 @@ export function unionInputValidatorsAsync(
|
||||
debounce: longestDebounce,
|
||||
validate: async (value, props) => {
|
||||
for (const validator of validators) {
|
||||
if (isAsyncValidator(validator)) {
|
||||
if (isSyncValidator(validator)) {
|
||||
if (validator.validate(value, props)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await validator.validate(value, props);
|
||||
|
||||
@ -114,10 +122,6 @@ export function unionInputValidatorsAsync(
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
} else {
|
||||
if (validator.validate(value, props)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import "./search-input.scss";
|
||||
|
||||
import React, { createRef } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { addWindowEventListener, cssNames, disposer } from "@k8slens/utilities";
|
||||
import { addWindowEventListener, cssNames, disposer, isTruthy } from "@k8slens/utilities";
|
||||
import { Icon } from "@k8slens/icon";
|
||||
import type { InputProps } from "./input";
|
||||
import { Input } from "./input";
|
||||
@ -86,7 +86,7 @@ class NonInjectedSearchInput extends React.Component<SearchInputProps & Dependen
|
||||
void bindGlobalFocusHotkey;
|
||||
void isMac;
|
||||
|
||||
if (showClearIcon && value) {
|
||||
if (showClearIcon && isTruthy(value)) {
|
||||
rightIcon = (
|
||||
<Icon
|
||||
small
|
||||
|
||||
@ -210,7 +210,7 @@ class NonInjectedItemListLayoutContent<
|
||||
const onConfirm = isFunction(removeItems)
|
||||
? () => removeItems.apply(store, [selectedItems])
|
||||
: isFunction(removeSelectedItems)
|
||||
? removeSelectedItems.bind(store)
|
||||
? () => removeSelectedItems.apply(store)
|
||||
: noop;
|
||||
|
||||
openConfirmDialog({
|
||||
@ -328,7 +328,7 @@ class NonInjectedItemListLayoutContent<
|
||||
{() => (
|
||||
<AddRemoveButtons
|
||||
onRemove={
|
||||
(store.removeItems || store.removeSelectedItems) && selectedItems.length > 0
|
||||
(Boolean(store.removeItems) || Boolean(store.removeSelectedItems)) && selectedItems.length > 0
|
||||
? () => this.removeItemsDialog(selectedItems)
|
||||
: undefined
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ import "./item-list-layout.scss";
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { IClassName, StrictReactNode } from "@k8slens/utilities";
|
||||
import { isFunction, cssNames, isDefined } from "@k8slens/utilities";
|
||||
import { isTruthy, isFunction, cssNames, isDefined } from "@k8slens/utilities";
|
||||
import type { ItemObject } from "@k8slens/list-layout";
|
||||
import type { Filter } from "./page-filters/store";
|
||||
import type { HeaderCustomizer, HeaderPlaceholders, ItemListStore, SearchFilter } from "./list-layout";
|
||||
@ -91,7 +91,7 @@ export class ItemListLayoutHeader<I extends ItemObject, PreLoadStores extends bo
|
||||
<div className={cssNames("header flex gaps align-center", headerClassName)}>
|
||||
{title}
|
||||
{
|
||||
info && (
|
||||
isTruthy(info) && (
|
||||
<div className="info-panel box grow">
|
||||
{info}
|
||||
</div>
|
||||
|
||||
@ -346,7 +346,7 @@ export const ItemListLayout = withInjectables<Dependencies, ItemListLayoutProps<
|
||||
}) as <I extends ItemObject, PreLoadStores extends boolean = true>(props: ItemListLayoutProps<I, PreLoadStores>) => React.ReactElement;
|
||||
|
||||
function applyFilters<I extends ItemObject>(filters: ItemsFilter<I>[], items: I[]): I[] {
|
||||
if (!filters || !filters.length) {
|
||||
if (!filters.length) {
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ const matchesApiFor = (api: SubscribableStore["api"]) => (column: GeneralKubeObj
|
||||
|
||||
const getLoadErrorMessage = (error: unknown): string => {
|
||||
if (error instanceof Error) {
|
||||
if (error.cause) {
|
||||
if (Boolean(error.cause)) {
|
||||
return `${error.message}: ${getLoadErrorMessage(error.cause)}`;
|
||||
}
|
||||
|
||||
@ -166,7 +166,19 @@ class NonInjectedKubeObjectListLayout<
|
||||
sortingCallbacks = {},
|
||||
...layoutProps
|
||||
} = this.props;
|
||||
const resourceName = this.props.resourceName || ResourceNames[ResourceKindMap[store.api.kind]] || store.api.kind;
|
||||
const resourceName = (() => {
|
||||
if (this.props.resourceName) {
|
||||
return this.props.resourceName;
|
||||
}
|
||||
|
||||
const kubeResource = ResourceKindMap[store.api.kind];
|
||||
|
||||
if (kubeResource) {
|
||||
return ResourceNames[kubeResource];
|
||||
}
|
||||
|
||||
return store.api.kind;
|
||||
})();
|
||||
const targetColumns = [
|
||||
...(columns ?? []),
|
||||
...generalColumns.filter(matchesApiFor(store.api)),
|
||||
|
||||
@ -51,7 +51,7 @@ class NonInjectedKubeObjectMenu<Kube extends KubeObject> extends React.Component
|
||||
private menuItems = observable.array<KubeObjectContextMenuItem>();
|
||||
|
||||
componentDidUpdate(prevProps: Readonly<KubeObjectMenuProps<Kube> & Dependencies>): void {
|
||||
if (prevProps.object !== this.props.object && this.props.object) {
|
||||
if (prevProps.object !== this.props.object) {
|
||||
this.emitOnContextMenuOpen(this.props.object);
|
||||
}
|
||||
}
|
||||
@ -199,11 +199,11 @@ class NonInjectedKubeObjectMenu<Kube extends KubeObject> extends React.Component
|
||||
id={`menu-actions-for-kube-object-menu-for-${object?.getId()}`}
|
||||
data-testid={`menu-actions-for-kube-object-menu-for-${object?.getId()}`}
|
||||
className={cssNames("KubeObjectMenu", className)}
|
||||
onOpen={object ? () => this.emitOnContextMenuOpen(object) : undefined}
|
||||
onOpen={() => this.emitOnContextMenuOpen(object)}
|
||||
{...menuProps}
|
||||
>
|
||||
{this.renderMenuItems()}
|
||||
{object && this.renderContextMenuItems(object)}
|
||||
{this.renderContextMenuItems(object)}
|
||||
</MenuActions>
|
||||
);
|
||||
}
|
||||
|
||||
@ -48,10 +48,6 @@ const NonInjectedKubeObjectMeta = observer((props : Dependencies & KubeObjectMet
|
||||
namespaceApi,
|
||||
} = props;
|
||||
|
||||
if (!object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(object instanceof KubeObject)) {
|
||||
logger.error("[KubeObjectMeta]: passed object that is not an instanceof KubeObject", object);
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import React from "react";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import type { StrictReactNode } from "@k8slens/utilities";
|
||||
import { cssNames } from "@k8slens/utilities";
|
||||
import { cssNames, isTruthy } from "@k8slens/utilities";
|
||||
import { Button } from "@k8slens/button";
|
||||
import type { DialogProps } from "../dialog";
|
||||
import { Dialog } from "../dialog";
|
||||
@ -54,7 +54,7 @@ class NonInjectedKubeConfigDialog extends React.Component<KubeConfigDialogProps
|
||||
};
|
||||
|
||||
renderContents = (data: KubeconfigDialogData) => (
|
||||
<Wizard header={<h5>{ data.title || "Kubeconfig File" }</h5>}>
|
||||
<Wizard header={<h5>{isTruthy(data.title) ? data.title : "Kubeconfig File" }</h5>}>
|
||||
<WizardStep
|
||||
customButtons={ (
|
||||
<div className="actions flex gaps">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user