mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into feature/navigate-back-ui-button
This commit is contained in:
commit
528ca6bf44
5
.github/PULL_REQUEST_TEMPLATE/default.md
vendored
5
.github/PULL_REQUEST_TEMPLATE/default.md
vendored
@ -1,5 +0,0 @@
|
||||
Fixes #
|
||||
|
||||
**Description of changes:**
|
||||
|
||||
-
|
||||
16
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
16
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<!--
|
||||
All PRs must be labelled with one of the following labels:
|
||||
- enhancement
|
||||
- bug
|
||||
- chore
|
||||
- area/ci
|
||||
- area/tests
|
||||
- area/documentaion
|
||||
- dependencies
|
||||
-->
|
||||
|
||||
Fixes #
|
||||
|
||||
**Description of changes:**
|
||||
|
||||
-
|
||||
13
.github/PULL_REQUEST_TEMPLATE/release.md
vendored
13
.github/PULL_REQUEST_TEMPLATE/release.md
vendored
@ -1,13 +0,0 @@
|
||||
## Changes since v
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
*
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
|
||||
*
|
||||
|
||||
## 🧰 Maintenance
|
||||
|
||||
*
|
||||
1
.github/release-drafter.yml
vendored
1
.github/release-drafter.yml
vendored
@ -14,6 +14,7 @@ categories:
|
||||
- 'area/ci'
|
||||
- 'area/tests'
|
||||
- 'dependencies'
|
||||
- 'area/documentation'
|
||||
|
||||
template: |
|
||||
## Changes since $PREVIOUS_TAG
|
||||
|
||||
2
.github/workflows/license-header.yml
vendored
2
.github/workflows/license-header.yml
vendored
@ -14,6 +14,8 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Golang
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.15.1'
|
||||
- name: Install addlicense
|
||||
run: |
|
||||
export PATH=${PATH}:`go env GOPATH`/bin
|
||||
|
||||
13
.github/workflows/require-type-labels.yml
vendored
Normal file
13
.github/workflows/require-type-labels.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
name: Require Release Category Labels
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, labeled, unlabeled, synchronize]
|
||||
jobs:
|
||||
label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: mheap/github-action-required-labels@v1
|
||||
with:
|
||||
mode: exactly
|
||||
count: 1
|
||||
labels: "enhancement, bug, chore, area/ci, area/tests, dependencies, area/documentation"
|
||||
@ -19,14 +19,17 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
Object.defineProperty(window, "requestIdleCallback", {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation(callback => callback()),
|
||||
});
|
||||
/**
|
||||
* Mock the global window variable
|
||||
*/
|
||||
export function mockWindow() {
|
||||
Object.defineProperty(window, "requestIdleCallback", {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation(callback => callback()),
|
||||
});
|
||||
|
||||
Object.defineProperty(window, "cancelIdleCallback", {
|
||||
writable: true,
|
||||
value: jest.fn(),
|
||||
});
|
||||
|
||||
export default {};
|
||||
Object.defineProperty(window, "cancelIdleCallback", {
|
||||
writable: true,
|
||||
value: jest.fn(),
|
||||
});
|
||||
}
|
||||
|
||||
227
extensions/kube-object-event-status/package-lock.json
generated
227
extensions/kube-object-event-status/package-lock.json
generated
@ -11,7 +11,8 @@
|
||||
"@material-ui/core": "*",
|
||||
"@types/node": "*",
|
||||
"@types/react-select": "*",
|
||||
"conf": "^7.0.1"
|
||||
"conf": "^7.0.1",
|
||||
"typed-emitter": "^1.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
@ -675,6 +676,12 @@
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
|
||||
"dev": true
|
||||
},
|
||||
"typed-emitter": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-1.3.1.tgz",
|
||||
"integrity": "sha512-2h7utWyXgd2R2u2IuL8B4yu1gqMxbgUj2VS/MGVbFhEVQNJKXoQQoS5CBMh+eW31zFeSmDfEQ3qQf4xy5SlPVQ==",
|
||||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@ -919,9 +926,9 @@
|
||||
}
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
|
||||
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -972,9 +979,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -1026,9 +1033,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"base": {
|
||||
@ -1087,9 +1094,9 @@
|
||||
}
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dev": true
|
||||
},
|
||||
"big.js": {
|
||||
@ -1099,9 +1106,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
|
||||
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -1122,9 +1129,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
|
||||
"integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
|
||||
"integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
@ -1190,21 +1197,13 @@
|
||||
}
|
||||
},
|
||||
"browserify-rsa": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
|
||||
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
|
||||
"integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bn.js": "^4.1.0",
|
||||
"bn.js": "^5.0.0",
|
||||
"randombytes": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"browserify-sign": {
|
||||
@ -1264,9 +1263,9 @@
|
||||
}
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"buffer-xor": {
|
||||
@ -1333,20 +1332,20 @@
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
|
||||
"integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.1",
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.1.2",
|
||||
"glob-parent": "~5.1.0",
|
||||
"fsevents": "~2.3.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.5.0"
|
||||
"readdirp": "~3.6.0"
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
@ -1356,13 +1355,10 @@
|
||||
"dev": true
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
|
||||
"integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||
"integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
|
||||
"dev": true
|
||||
},
|
||||
"cipher-base": {
|
||||
"version": "1.0.4",
|
||||
@ -1507,9 +1503,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -1644,9 +1640,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -1767,9 +1763,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"events": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
|
||||
"integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"evp_bytestokey": {
|
||||
@ -2011,9 +2007,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
|
||||
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -2024,9 +2020,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"version": "7.1.7",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
|
||||
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
@ -2038,9 +2034,9 @@
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
|
||||
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -2483,9 +2479,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -2819,9 +2815,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"pbkdf2": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
|
||||
"integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
|
||||
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"create-hash": "^1.1.2",
|
||||
@ -2897,9 +2893,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -2990,9 +2986,9 @@
|
||||
}
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
|
||||
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -3017,9 +3013,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"repeat-element": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
|
||||
"integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
|
||||
"integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
|
||||
"dev": true
|
||||
},
|
||||
"repeat-string": {
|
||||
@ -3305,9 +3301,9 @@
|
||||
}
|
||||
},
|
||||
"source-map-url": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
|
||||
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
|
||||
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
|
||||
"dev": true
|
||||
},
|
||||
"split-string": {
|
||||
@ -3535,12 +3531,6 @@
|
||||
"semver": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"dev": true
|
||||
},
|
||||
"tty-browserify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||
@ -3637,9 +3627,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
|
||||
"integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
@ -3705,21 +3695,21 @@
|
||||
"dev": true
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz",
|
||||
"integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==",
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
|
||||
"integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": "^3.4.1",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"neo-async": "^2.5.0",
|
||||
"watchpack-chokidar2": "^2.0.0"
|
||||
"watchpack-chokidar2": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"watchpack-chokidar2": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz",
|
||||
"integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
|
||||
"integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -3947,9 +3937,9 @@
|
||||
}
|
||||
},
|
||||
"webpack": {
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz",
|
||||
"integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==",
|
||||
"version": "4.46.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz",
|
||||
"integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.9.0",
|
||||
@ -3960,7 +3950,7 @@
|
||||
"ajv": "^6.10.2",
|
||||
"ajv-keywords": "^3.4.1",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^4.3.0",
|
||||
"enhanced-resolve": "^4.5.0",
|
||||
"eslint-scope": "^4.0.3",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
"loader-runner": "^2.4.0",
|
||||
@ -4006,6 +3996,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
|
||||
"integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"memory-fs": "^0.5.0",
|
||||
"tapable": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"memory-fs": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
|
||||
"integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"errno": "^0.1.3",
|
||||
"readable-stream": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||
@ -4132,9 +4145,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
|
||||
"integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
|
||||
@ -20,6 +20,6 @@
|
||||
"@k8slens/extensions": "file:../../src/extensions/npm/extensions",
|
||||
"ts-loader": "^8.0.4",
|
||||
"typescript": "^4.3.2",
|
||||
"webpack": "^4.44.2"
|
||||
"webpack": "^4.46.0"
|
||||
}
|
||||
}
|
||||
|
||||
170
extensions/node-menu/package-lock.json
generated
170
extensions/node-menu/package-lock.json
generated
@ -631,7 +631,8 @@
|
||||
"@material-ui/core": "*",
|
||||
"@types/node": "*",
|
||||
"@types/react-select": "*",
|
||||
"conf": "^7.0.1"
|
||||
"conf": "^7.0.1",
|
||||
"typed-emitter": "^1.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
@ -1295,6 +1296,12 @@
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
|
||||
"dev": true
|
||||
},
|
||||
"typed-emitter": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-1.3.1.tgz",
|
||||
"integrity": "sha512-2h7utWyXgd2R2u2IuL8B4yu1gqMxbgUj2VS/MGVbFhEVQNJKXoQQoS5CBMh+eW31zFeSmDfEQ3qQf4xy5SlPVQ==",
|
||||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@ -1785,9 +1792,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -2016,9 +2023,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
|
||||
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -2039,9 +2046,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
|
||||
"integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
|
||||
"integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
@ -2113,21 +2120,13 @@
|
||||
}
|
||||
},
|
||||
"browserify-rsa": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
|
||||
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
|
||||
"integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bn.js": "^4.1.0",
|
||||
"bn.js": "^5.0.0",
|
||||
"randombytes": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"browserify-sign": {
|
||||
@ -2308,26 +2307,37 @@
|
||||
"dev": true
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
|
||||
"integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.1",
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.1.2",
|
||||
"glob-parent": "~5.1.0",
|
||||
"fsevents": "~2.3.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.5.0"
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
|
||||
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
@ -2340,13 +2350,10 @@
|
||||
"dev": true
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
|
||||
"integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||
"integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
|
||||
"dev": true
|
||||
},
|
||||
"ci-info": {
|
||||
"version": "2.0.0",
|
||||
@ -2555,9 +2562,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -2790,9 +2797,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -2986,9 +2993,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"events": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
|
||||
"integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"evp_bytestokey": {
|
||||
@ -3455,9 +3462,9 @@
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
|
||||
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -4819,9 +4826,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -5362,9 +5369,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"pbkdf2": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
|
||||
"integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
|
||||
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"create-hash": "^1.1.2",
|
||||
@ -5489,9 +5496,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -5625,9 +5632,9 @@
|
||||
}
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
|
||||
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -6750,12 +6757,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"dev": true
|
||||
},
|
||||
"tty-browserify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||
@ -7287,9 +7288,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"webpack": {
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz",
|
||||
"integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==",
|
||||
"version": "4.46.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz",
|
||||
"integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.9.0",
|
||||
@ -7300,7 +7301,7 @@
|
||||
"ajv": "^6.10.2",
|
||||
"ajv-keywords": "^3.4.1",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^4.3.0",
|
||||
"enhanced-resolve": "^4.5.0",
|
||||
"eslint-scope": "^4.0.3",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
"loader-runner": "^2.4.0",
|
||||
@ -7352,6 +7353,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
|
||||
"integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"memory-fs": "^0.5.0",
|
||||
"tapable": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"memory-fs": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
|
||||
"integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"errno": "^0.1.3",
|
||||
"readable-stream": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||
|
||||
@ -21,6 +21,6 @@
|
||||
"jest": "^26.6.3",
|
||||
"ts-loader": "^8.0.4",
|
||||
"typescript": "^4.3.2",
|
||||
"webpack": "^4.44.2"
|
||||
"webpack": "^4.46.0"
|
||||
}
|
||||
}
|
||||
|
||||
170
extensions/pod-menu/package-lock.json
generated
170
extensions/pod-menu/package-lock.json
generated
@ -631,7 +631,8 @@
|
||||
"@material-ui/core": "*",
|
||||
"@types/node": "*",
|
||||
"@types/react-select": "*",
|
||||
"conf": "^7.0.1"
|
||||
"conf": "^7.0.1",
|
||||
"typed-emitter": "^1.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
@ -1248,6 +1249,12 @@
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
|
||||
"dev": true
|
||||
},
|
||||
"typed-emitter": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-1.3.1.tgz",
|
||||
"integrity": "sha512-2h7utWyXgd2R2u2IuL8B4yu1gqMxbgUj2VS/MGVbFhEVQNJKXoQQoS5CBMh+eW31zFeSmDfEQ3qQf4xy5SlPVQ==",
|
||||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@ -1738,9 +1745,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -1969,9 +1976,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
|
||||
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -1992,9 +1999,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
|
||||
"integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
|
||||
"integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
@ -2066,21 +2073,13 @@
|
||||
}
|
||||
},
|
||||
"browserify-rsa": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
|
||||
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
|
||||
"integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bn.js": "^4.1.0",
|
||||
"bn.js": "^5.0.0",
|
||||
"randombytes": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"browserify-sign": {
|
||||
@ -2261,26 +2260,37 @@
|
||||
"dev": true
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
|
||||
"integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.1",
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.1.2",
|
||||
"glob-parent": "~5.1.0",
|
||||
"fsevents": "~2.3.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.5.0"
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
|
||||
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
@ -2293,13 +2303,10 @@
|
||||
"dev": true
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
|
||||
"integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||
"integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
|
||||
"dev": true
|
||||
},
|
||||
"ci-info": {
|
||||
"version": "2.0.0",
|
||||
@ -2508,9 +2515,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -2743,9 +2750,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -2939,9 +2946,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"events": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
|
||||
"integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"evp_bytestokey": {
|
||||
@ -3408,9 +3415,9 @@
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
|
||||
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -4772,9 +4779,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -5315,9 +5322,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"pbkdf2": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
|
||||
"integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
|
||||
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"create-hash": "^1.1.2",
|
||||
@ -5442,9 +5449,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -5578,9 +5585,9 @@
|
||||
}
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
|
||||
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@ -6703,12 +6710,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"dev": true
|
||||
},
|
||||
"tty-browserify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||
@ -7240,9 +7241,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"webpack": {
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz",
|
||||
"integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==",
|
||||
"version": "4.46.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz",
|
||||
"integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.9.0",
|
||||
@ -7253,7 +7254,7 @@
|
||||
"ajv": "^6.10.2",
|
||||
"ajv-keywords": "^3.4.1",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^4.3.0",
|
||||
"enhanced-resolve": "^4.5.0",
|
||||
"eslint-scope": "^4.0.3",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
"loader-runner": "^2.4.0",
|
||||
@ -7305,6 +7306,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
|
||||
"integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"memory-fs": "^0.5.0",
|
||||
"tapable": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"memory-fs": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
|
||||
"integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"errno": "^0.1.3",
|
||||
"readable-stream": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||
|
||||
@ -21,6 +21,6 @@
|
||||
"jest": "^26.6.3",
|
||||
"ts-loader": "^8.0.4",
|
||||
"typescript": "^4.3.2",
|
||||
"webpack": "^4.44.2"
|
||||
"webpack": "^4.46.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ import * as utils from "../helpers/utils";
|
||||
import { listHelmRepositories } from "../helpers/utils";
|
||||
import { fail } from "assert";
|
||||
|
||||
jest.setTimeout(60000);
|
||||
jest.setTimeout(2 * 60 * 1000); // 2 minutes so that we can get better errors from spectron
|
||||
|
||||
// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below)
|
||||
describe("Lens integration tests", () => {
|
||||
@ -38,14 +38,10 @@ describe("Lens integration tests", () => {
|
||||
|
||||
describe("app start", () => {
|
||||
utils.beforeAllWrapped(async () => {
|
||||
app = await utils.appStart();
|
||||
app = await utils.setup();
|
||||
});
|
||||
|
||||
utils.afterAllWrapped(async () => {
|
||||
if (app?.isRunning()) {
|
||||
await utils.tearDown(app);
|
||||
}
|
||||
});
|
||||
utils.afterAllWrapped(() => utils.tearDown(app));
|
||||
|
||||
it('shows "add cluster"', async () => {
|
||||
await app.electron.ipcRenderer.send("test-menu-item-click", "File", "Add Cluster");
|
||||
|
||||
@ -33,7 +33,7 @@ import * as util from "util";
|
||||
|
||||
export const promiseExec = util.promisify(exec);
|
||||
|
||||
jest.setTimeout(60000);
|
||||
jest.setTimeout(2 * 60 * 1000); // 2 minutes so that we can get better errors from spectron
|
||||
|
||||
// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below)
|
||||
describe("Lens cluster pages", () => {
|
||||
@ -41,38 +41,36 @@ describe("Lens cluster pages", () => {
|
||||
const BACKSPACE = "\uE003";
|
||||
let app: Application;
|
||||
const ready = minikubeReady(TEST_NAMESPACE);
|
||||
let clusterAdded = false;
|
||||
|
||||
utils.describeIf(ready)("test common pages", () => {
|
||||
let clusterAdded = false;
|
||||
const addCluster = async () => {
|
||||
await app.client.waitUntilTextExists("div", "Catalog");
|
||||
await waitForMinikubeDashboard(app);
|
||||
await app.client.click('a[href="/nodes"]');
|
||||
await app.client.waitUntilTextExists("div.TableCell", "Ready");
|
||||
};
|
||||
|
||||
const appStartAddCluster = async () => {
|
||||
app = await utils.appStart();
|
||||
await addCluster();
|
||||
clusterAdded = true;
|
||||
};
|
||||
|
||||
const tearDown = async () => {
|
||||
await utils.tearDown(app);
|
||||
clusterAdded = false;
|
||||
};
|
||||
|
||||
describe("cluster add", () => {
|
||||
utils.beforeAllWrapped(async () => {
|
||||
app = await utils.appStart();
|
||||
app = await utils.setup();
|
||||
});
|
||||
|
||||
utils.afterAllWrapped(tearDown);
|
||||
utils.afterAllWrapped(() => utils.tearDown(app));
|
||||
|
||||
it("allows to add a cluster", async () => {
|
||||
await addCluster();
|
||||
clusterAdded = true;
|
||||
});
|
||||
});
|
||||
|
||||
const appStartAddCluster = async () => {
|
||||
if (clusterAdded) {
|
||||
app = await utils.setup();
|
||||
await addCluster();
|
||||
}
|
||||
};
|
||||
|
||||
function getSidebarSelectors(itemId: string) {
|
||||
const root = `.SidebarItem[data-test-id="${itemId}"]`;
|
||||
|
||||
@ -84,7 +82,7 @@ describe("Lens cluster pages", () => {
|
||||
|
||||
describe("cluster pages", () => {
|
||||
utils.beforeAllWrapped(appStartAddCluster);
|
||||
utils.afterAllWrapped(tearDown);
|
||||
utils.afterAllWrapped(() => utils.tearDown(app));
|
||||
|
||||
const tests: {
|
||||
drawer?: string
|
||||
@ -369,7 +367,7 @@ describe("Lens cluster pages", () => {
|
||||
|
||||
describe("viewing pod logs", () => {
|
||||
utils.beforeEachWrapped(appStartAddCluster);
|
||||
utils.afterEachWrapped(tearDown);
|
||||
utils.afterEachWrapped(() => utils.tearDown(app));
|
||||
|
||||
it(`shows a log for a pod`, async () => {
|
||||
expect(clusterAdded).toBe(true);
|
||||
@ -397,7 +395,6 @@ describe("Lens cluster pages", () => {
|
||||
// Open logs tab in dock
|
||||
await app.client.click(".list .TableRow:first-child");
|
||||
await app.client.waitForVisible(".Drawer");
|
||||
|
||||
const logsButton = "ul.KubeObjectMenu li.MenuItem i.Icon span[data-icon-name='subject']";
|
||||
|
||||
await app.client.waitForVisible(logsButton);
|
||||
@ -419,7 +416,7 @@ describe("Lens cluster pages", () => {
|
||||
|
||||
describe("cluster operations", () => {
|
||||
utils.beforeEachWrapped(appStartAddCluster);
|
||||
utils.afterEachWrapped(tearDown);
|
||||
utils.afterEachWrapped(() => utils.tearDown(app));
|
||||
|
||||
it("shows default namespace", async () => {
|
||||
expect(clusterAdded).toBe(true);
|
||||
|
||||
@ -22,21 +22,17 @@
|
||||
import type { Application } from "spectron";
|
||||
import * as utils from "../helpers/utils";
|
||||
|
||||
jest.setTimeout(60000);
|
||||
jest.setTimeout(2 * 60 * 1000); // 2 minutes so that we can get better errors from spectron
|
||||
|
||||
describe("Lens command palette", () => {
|
||||
let app: Application;
|
||||
|
||||
describe("menu", () => {
|
||||
utils.beforeAllWrapped(async () => {
|
||||
app = await utils.appStart();
|
||||
app = await utils.setup();
|
||||
});
|
||||
|
||||
utils.afterAllWrapped(async () => {
|
||||
if (app?.isRunning()) {
|
||||
await utils.tearDown(app);
|
||||
}
|
||||
});
|
||||
utils.afterAllWrapped(() => utils.tearDown(app));
|
||||
|
||||
it("opens command dialog from menu", async () => {
|
||||
await app.electron.ipcRenderer.send("test-menu-item-click", "View", "Command Palette...");
|
||||
|
||||
@ -69,24 +69,20 @@ export function describeIf(condition: boolean) {
|
||||
return condition ? describe : describe.skip;
|
||||
}
|
||||
|
||||
export function setup(): Application {
|
||||
return new Application({
|
||||
path: AppPaths[process.platform], // path to electron app
|
||||
args: [],
|
||||
startTimeout: 30000,
|
||||
waitTimeout: 60000,
|
||||
env: {
|
||||
CICD: "true"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const keys = {
|
||||
backspace: "\uE003"
|
||||
};
|
||||
|
||||
export async function appStart() {
|
||||
const app = setup();
|
||||
export async function setup(): Promise<Application> {
|
||||
const app = new Application({
|
||||
path: AppPaths[process.platform], // path to electron app
|
||||
args: [],
|
||||
startTimeout: 60000,
|
||||
waitTimeout: 10000,
|
||||
env: {
|
||||
CICD: "true"
|
||||
}
|
||||
});
|
||||
|
||||
await app.start();
|
||||
// Wait for splash screen to be closed
|
||||
|
||||
29
package.json
29
package.json
@ -48,7 +48,7 @@
|
||||
"postversion": "git push --set-upstream ${GIT_REMOTE:-origin} release/v$npm_package_version"
|
||||
},
|
||||
"config": {
|
||||
"bundledKubectlVersion": "1.18.15",
|
||||
"bundledKubectlVersion": "1.21.2",
|
||||
"bundledHelmVersion": "3.5.4",
|
||||
"sentryDsn": ""
|
||||
},
|
||||
@ -185,7 +185,7 @@
|
||||
"@hapi/subtext": "^7.0.3",
|
||||
"@kubernetes/client-node": "^0.14.3",
|
||||
"@sentry/electron": "^2.5.0",
|
||||
"@sentry/integrations": "^6.8.0",
|
||||
"@sentry/integrations": "^6.10.0",
|
||||
"abort-controller": "^3.0.0",
|
||||
"array-move": "^3.0.1",
|
||||
"auto-bind": "^4.0.0",
|
||||
@ -202,6 +202,7 @@
|
||||
"electron-window-state": "^5.0.3",
|
||||
"filehound": "^1.17.4",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"handlebars": "^4.7.7",
|
||||
"http-proxy": "^1.18.1",
|
||||
@ -220,7 +221,8 @@
|
||||
"mock-fs": "^4.14.0",
|
||||
"moment": "^2.29.1",
|
||||
"moment-timezone": "^0.5.33",
|
||||
"node-pty": "^0.9.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"node-pty": "^0.10.1",
|
||||
"npm": "^6.14.8",
|
||||
"openid-client": "^3.15.2",
|
||||
"p-limit": "^3.1.0",
|
||||
@ -237,19 +239,20 @@
|
||||
"serializr": "^2.0.3",
|
||||
"shell-env": "^3.0.1",
|
||||
"spdy": "^4.0.2",
|
||||
"tar": "^6.0.5",
|
||||
"tar": "^6.1.4",
|
||||
"tcp-port-used": "^1.0.1",
|
||||
"tempy": "^0.5.0",
|
||||
"url-parse": "^1.5.1",
|
||||
"uuid": "^8.3.2",
|
||||
"win-ca": "^3.2.0",
|
||||
"winston": "^3.2.1",
|
||||
"winston": "^3.3.3",
|
||||
"winston-console-format": "^1.0.8",
|
||||
"winston-transport-browserconsole": "^1.0.5",
|
||||
"ws": "^7.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emeraldpay/hashicon-react": "^0.4.0",
|
||||
"@material-ui/core": "^4.11.4",
|
||||
"@material-ui/core": "^4.12.3",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
|
||||
@ -260,16 +263,17 @@
|
||||
"@types/byline": "^4.2.32",
|
||||
"@types/chart.js": "^2.9.21",
|
||||
"@types/circular-dependency-plugin": "^5.0.1",
|
||||
"@types/color": "^3.0.1",
|
||||
"@types/color": "^3.0.2",
|
||||
"@types/crypto-js": "^3.1.47",
|
||||
"@types/dompurify": "^2.0.2",
|
||||
"@types/electron-devtools-installer": "^2.2.0",
|
||||
"@types/electron-window-state": "^2.0.34",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
"@types/glob-to-regexp": "^0.4.1",
|
||||
"@types/hapi": "^18.0.6",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/html-webpack-plugin": "^3.2.3",
|
||||
"@types/http-proxy": "^1.17.5",
|
||||
"@types/http-proxy": "^1.17.7",
|
||||
"@types/jest": "^26.0.22",
|
||||
"@types/js-yaml": "^3.12.4",
|
||||
"@types/jsdom": "^16.2.4",
|
||||
@ -281,6 +285,7 @@
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/module-alias": "^2.0.0",
|
||||
"@types/node": "12.20",
|
||||
"@types/node-fetch": "^2.5.12",
|
||||
"@types/npm": "^2.0.31",
|
||||
"@types/progress-bar-webpack-plugin": "^2.1.2",
|
||||
"@types/proper-lockfile": "^4.1.1",
|
||||
@ -302,6 +307,7 @@
|
||||
"@types/tar": "^4.0.5",
|
||||
"@types/tcp-port-used": "^1.0.0",
|
||||
"@types/tempy": "^0.3.0",
|
||||
"@types/triple-beam": "^1.3.2",
|
||||
"@types/url-parse": "^1.4.3",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@types/webdriverio": "^4.13.0",
|
||||
@ -309,11 +315,11 @@
|
||||
"@types/webpack-dev-server": "^3.11.1",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"@types/webpack-node-externals": "^1.7.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.14.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
||||
"@typescript-eslint/parser": "^4.0.0",
|
||||
"ace-builds": "^1.4.12",
|
||||
"ansi_up": "^5.0.0",
|
||||
"chart.js": "^2.9.3",
|
||||
"chart.js": "^2.9.4",
|
||||
"circular-dependency-plugin": "^5.2.2",
|
||||
"color": "^3.1.2",
|
||||
"concurrently": "^5.2.0",
|
||||
@ -346,9 +352,8 @@
|
||||
"node-loader": "^1.0.3",
|
||||
"node-sass": "^4.14.1",
|
||||
"nodemon": "^2.0.12",
|
||||
"open": "^7.3.1",
|
||||
"patch-package": "^6.2.2",
|
||||
"postcss": "^8.2.14",
|
||||
"postcss": "^8.3.6",
|
||||
"postcss-loader": "4.0.3",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"progress-bar-webpack-plugin": "^2.1.0",
|
||||
|
||||
@ -25,9 +25,11 @@ import yaml from "js-yaml";
|
||||
import path from "path";
|
||||
import fse from "fs-extra";
|
||||
import { Cluster } from "../../main/cluster";
|
||||
import { ClusterId, ClusterStore, getClusterIdFromHost } from "../cluster-store";
|
||||
import { ClusterStore } from "../cluster-store";
|
||||
import { Console } from "console";
|
||||
import { stdout, stderr } from "process";
|
||||
import type { ClusterId } from "../cluster-types";
|
||||
import { getCustomKubeConfigPath } from "../utils";
|
||||
|
||||
console = new Console(stdout, stderr);
|
||||
|
||||
@ -57,7 +59,7 @@ users:
|
||||
`;
|
||||
|
||||
function embed(clusterId: ClusterId, contents: any): string {
|
||||
const absPath = ClusterStore.getCustomKubeConfigPath(clusterId);
|
||||
const absPath = getCustomKubeConfigPath(clusterId);
|
||||
|
||||
fse.ensureDirSync(path.dirname(absPath));
|
||||
fse.writeFileSync(absPath, contents, { encoding: "utf-8", mode: 0o600 });
|
||||
@ -550,27 +552,3 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
|
||||
expect(icon.startsWith("data:;base64,")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getClusterIdFromHost", () => {
|
||||
const clusterFakeId = "fe540901-0bd6-4f6c-b472-bce1559d7c4a";
|
||||
|
||||
it("should return undefined for non cluster frame hosts", () => {
|
||||
expect(getClusterIdFromHost("localhost:45345")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return ClusterId for cluster frame hosts", () => {
|
||||
expect(getClusterIdFromHost(`${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
});
|
||||
|
||||
it("should return ClusterId for cluster frame hosts with additional subdomains", () => {
|
||||
expect(getClusterIdFromHost(`abc.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.vwx.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.vwx.yz.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
});
|
||||
});
|
||||
|
||||
@ -19,7 +19,9 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { anyObject } from "jest-mock-extended";
|
||||
import mockFs from "mock-fs";
|
||||
import logger from "../../main/logger";
|
||||
import { ClusterStore } from "../cluster-store";
|
||||
import { HotbarStore } from "../hotbar-store";
|
||||
|
||||
@ -187,7 +189,7 @@ describe("HotbarStore", () => {
|
||||
hotbarStore.removeFromHotbar("catalog-entity");
|
||||
const items = hotbarStore.getActive().items.filter(Boolean);
|
||||
|
||||
expect(items.length).toEqual(0);
|
||||
expect(items).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it("does nothing if removing with invalid uid", () => {
|
||||
@ -245,6 +247,43 @@ describe("HotbarStore", () => {
|
||||
expect(items.slice(0, 4)).toEqual(["catalog-entity", "minikube", "aws", "test"]);
|
||||
});
|
||||
|
||||
it("logs an error if cellIndex is out of bounds", () => {
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.add({ name: "hottest", id: "hottest" });
|
||||
hotbarStore.activeHotbarId = "hottest";
|
||||
|
||||
const { error } = logger;
|
||||
const mocked = jest.fn();
|
||||
|
||||
logger.error = mocked;
|
||||
|
||||
hotbarStore.addToHotbar(testCluster, -1);
|
||||
expect(mocked).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
|
||||
|
||||
hotbarStore.addToHotbar(testCluster, 12);
|
||||
expect(mocked).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
|
||||
|
||||
hotbarStore.addToHotbar(testCluster, 13);
|
||||
expect(mocked).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject());
|
||||
|
||||
logger.error = error;
|
||||
});
|
||||
|
||||
it("throws an error if getId is invalid or returns not a string", () => {
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
expect(() => hotbarStore.addToHotbar({} as any)).toThrowError(TypeError);
|
||||
expect(() => hotbarStore.addToHotbar({ getId: () => true } as any)).toThrowError(TypeError);
|
||||
});
|
||||
|
||||
it("throws an error if getName is invalid or returns not a string", () => {
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
expect(() => hotbarStore.addToHotbar({ getId: () => "" } as any)).toThrowError(TypeError);
|
||||
expect(() => hotbarStore.addToHotbar({ getId: () => "", getName: () => 4 } as any)).toThrowError(TypeError);
|
||||
});
|
||||
|
||||
it("does nothing when item moved to same cell", () => {
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
|
||||
@ -28,6 +28,8 @@ import { getAppVersion, Singleton, toJS, Disposer } from "./utils";
|
||||
import logger from "../main/logger";
|
||||
import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc";
|
||||
import isEqual from "lodash/isEqual";
|
||||
import { isTestEnv } from "./vars";
|
||||
import { kebabCase } from "lodash";
|
||||
|
||||
export interface BaseStoreParams<T> extends ConfOptions<T> {
|
||||
syncOptions?: IReactionOptions;
|
||||
@ -59,12 +61,14 @@ export abstract class BaseStore<T> extends Singleton {
|
||||
const res: any = this.fromStore(this.storeConfig.store);
|
||||
|
||||
if (res instanceof Promise || (typeof res === "object" && res && typeof res.then === "function")) {
|
||||
console.error(`${this.name} extends BaseStore<T>'s fromStore method returns a Promise or promise-like object. This is an error and must be fixed.`);
|
||||
console.error(`${this.constructor.name} extends BaseStore<T>'s fromStore method returns a Promise or promise-like object. This is an error and must be fixed.`);
|
||||
}
|
||||
|
||||
this.enableSync();
|
||||
|
||||
logger.info(`[STORE]: LOADED from ${this.path}`);
|
||||
if (!isTestEnv) {
|
||||
logger.info(`[${kebabCase(this.constructor.name).toUpperCase()}]: LOADED from ${this.path}`);
|
||||
}
|
||||
}
|
||||
|
||||
get name() {
|
||||
|
||||
@ -19,119 +19,26 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import path from "path";
|
||||
import { app, ipcMain, ipcRenderer, remote, webFrame } from "electron";
|
||||
import { ipcMain, ipcRenderer, webFrame } from "electron";
|
||||
import { action, comparer, computed, makeObservable, observable, reaction } from "mobx";
|
||||
import { BaseStore } from "./base-store";
|
||||
import { Cluster, ClusterState } from "../main/cluster";
|
||||
import { Cluster } from "../main/cluster";
|
||||
import migrations from "../migrations/cluster-store";
|
||||
import * as uuid from "uuid";
|
||||
import logger from "../main/logger";
|
||||
import { appEventBus } from "./event-bus";
|
||||
import { ipcMainHandle, ipcMainOn, ipcRendererOn, requestMain } from "./ipc";
|
||||
import { disposer, toJS } from "./utils";
|
||||
|
||||
export interface ClusterIconUpload {
|
||||
clusterId: string;
|
||||
name: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface ClusterMetadata {
|
||||
[key: string]: string | number | boolean | object;
|
||||
}
|
||||
|
||||
export type ClusterPrometheusMetadata = {
|
||||
success?: boolean;
|
||||
provider?: string;
|
||||
autoDetected?: boolean;
|
||||
};
|
||||
import type { ClusterModel, ClusterId, ClusterState } from "./cluster-types";
|
||||
|
||||
export interface ClusterStoreModel {
|
||||
clusters?: ClusterModel[];
|
||||
}
|
||||
|
||||
export type ClusterId = string;
|
||||
|
||||
export interface UpdateClusterModel extends Omit<ClusterModel, "id"> {
|
||||
id?: ClusterId;
|
||||
}
|
||||
|
||||
export interface ClusterModel {
|
||||
/** Unique id for a cluster */
|
||||
id: ClusterId;
|
||||
|
||||
/** Path to cluster kubeconfig */
|
||||
kubeConfigPath: string;
|
||||
|
||||
/**
|
||||
* Workspace id
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
workspace?: string;
|
||||
|
||||
/**
|
||||
* @deprecated this is used only for hotbar migrations from 4.2.X
|
||||
*/
|
||||
workspaces?: string[];
|
||||
|
||||
/** User context in kubeconfig */
|
||||
contextName: string;
|
||||
|
||||
/** Preferences */
|
||||
preferences?: ClusterPreferences;
|
||||
|
||||
/** Metadata */
|
||||
metadata?: ClusterMetadata;
|
||||
|
||||
/**
|
||||
* Labels for the catalog entity
|
||||
*/
|
||||
labels?: Record<string, string>;
|
||||
|
||||
/** List of accessible namespaces */
|
||||
accessibleNamespaces?: string[];
|
||||
}
|
||||
|
||||
export interface ClusterPreferences extends ClusterPrometheusPreferences {
|
||||
terminalCWD?: string;
|
||||
clusterName?: string;
|
||||
iconOrder?: number;
|
||||
icon?: string;
|
||||
httpsProxy?: string;
|
||||
hiddenMetrics?: string[];
|
||||
nodeShellImage?: string;
|
||||
imagePullSecret?: string;
|
||||
}
|
||||
|
||||
export interface ClusterPrometheusPreferences {
|
||||
prometheus?: {
|
||||
namespace: string;
|
||||
service: string;
|
||||
port: number;
|
||||
prefix: string;
|
||||
};
|
||||
prometheusProvider?: {
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
const initialStates = "cluster:states";
|
||||
|
||||
export const initialNodeShellImage = "docker.io/alpine:3.13";
|
||||
|
||||
export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
private static StateChannel = "cluster:state";
|
||||
|
||||
static get storedKubeConfigFolder(): string {
|
||||
return path.resolve((app ?? remote.app).getPath("userData"), "kubeconfigs");
|
||||
}
|
||||
|
||||
static getCustomKubeConfigPath(clusterId: ClusterId = uuid.v4()): string {
|
||||
return path.resolve(ClusterStore.storedKubeConfigFolder, clusterId);
|
||||
}
|
||||
|
||||
clusters = observable.map<ClusterId, Cluster>();
|
||||
removedClusters = observable.map<ClusterId, Cluster>();
|
||||
|
||||
@ -272,22 +179,3 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getClusterIdFromHost(host: string): ClusterId | undefined {
|
||||
// e.g host == "%clusterId.localhost:45345"
|
||||
const subDomains = host.split(":")[0].split(".");
|
||||
|
||||
return subDomains.slice(-2, -1)[0]; // ClusterId or undefined
|
||||
}
|
||||
|
||||
export function getClusterFrameUrl(clusterId: ClusterId) {
|
||||
return `//${clusterId}.${location.host}`;
|
||||
}
|
||||
|
||||
export function getHostedClusterId() {
|
||||
return getClusterIdFromHost(location.host);
|
||||
}
|
||||
|
||||
export function getHostedCluster(): Cluster {
|
||||
return ClusterStore.getInstance().getById(getHostedClusterId());
|
||||
}
|
||||
|
||||
180
src/common/cluster-types.ts
Normal file
180
src/common/cluster-types.ts
Normal file
@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JSON serializable metadata type
|
||||
*/
|
||||
export type ClusterMetadata = Record<string, string | number | boolean | object>;
|
||||
|
||||
/**
|
||||
* Metadata for cluster's prometheus settings
|
||||
*/
|
||||
export interface ClusterPrometheusMetadata {
|
||||
success?: boolean;
|
||||
provider?: string;
|
||||
autoDetected?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A ClusterId is an opaque string
|
||||
*/
|
||||
export type ClusterId = string;
|
||||
|
||||
/**
|
||||
* The fields that are used for updating a cluster instance
|
||||
*/
|
||||
export type UpdateClusterModel = Omit<ClusterModel, "id">;
|
||||
|
||||
/**
|
||||
* The model for passing cluster data around, including to disk
|
||||
*/
|
||||
export interface ClusterModel {
|
||||
/** Unique id for a cluster */
|
||||
id: ClusterId;
|
||||
|
||||
/** Path to cluster kubeconfig */
|
||||
kubeConfigPath: string;
|
||||
|
||||
/**
|
||||
* Workspace id
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
workspace?: string;
|
||||
|
||||
/**
|
||||
* @deprecated this is used only for hotbar migrations from 4.2.X
|
||||
*/
|
||||
workspaces?: string[];
|
||||
|
||||
/** User context in kubeconfig */
|
||||
contextName: string;
|
||||
|
||||
/** Preferences */
|
||||
preferences?: ClusterPreferences;
|
||||
|
||||
/** Metadata */
|
||||
metadata?: ClusterMetadata;
|
||||
|
||||
/** List of accessible namespaces */
|
||||
accessibleNamespaces?: string[];
|
||||
|
||||
/**
|
||||
* Labels for the catalog entity
|
||||
*/
|
||||
labels?: Record<string, string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The complete set of cluster settings or preferences
|
||||
*/
|
||||
export interface ClusterPreferences extends ClusterPrometheusPreferences {
|
||||
terminalCWD?: string;
|
||||
clusterName?: string;
|
||||
iconOrder?: number;
|
||||
icon?: string;
|
||||
httpsProxy?: string;
|
||||
hiddenMetrics?: string[];
|
||||
nodeShellImage?: string;
|
||||
imagePullSecret?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A cluster's prometheus settings (a subset of cluster settings)
|
||||
*/
|
||||
export interface ClusterPrometheusPreferences {
|
||||
prometheus?: {
|
||||
namespace: string;
|
||||
service: string;
|
||||
port: number;
|
||||
prefix: string;
|
||||
};
|
||||
prometheusProvider?: {
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The options for the status of connection attempts to a cluster
|
||||
*/
|
||||
export enum ClusterStatus {
|
||||
AccessGranted = 2,
|
||||
AccessDenied = 1,
|
||||
Offline = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* The OpenLens known static metadata keys
|
||||
*/
|
||||
export enum ClusterMetadataKey {
|
||||
VERSION = "version",
|
||||
CLUSTER_ID = "id",
|
||||
DISTRIBUTION = "distribution",
|
||||
NODES_COUNT = "nodes",
|
||||
LAST_SEEN = "lastSeen",
|
||||
PROMETHEUS = "prometheus"
|
||||
}
|
||||
|
||||
/**
|
||||
* A shorthand enum for resource types that have metrics attached to them via OpenLens metrics stack
|
||||
*/
|
||||
export enum ClusterMetricsResourceType {
|
||||
Cluster = "Cluster",
|
||||
Node = "Node",
|
||||
Pod = "Pod",
|
||||
Deployment = "Deployment",
|
||||
StatefulSet = "StatefulSet",
|
||||
Container = "Container",
|
||||
Ingress = "Ingress",
|
||||
VolumeClaim = "VolumeClaim",
|
||||
ReplicaSet = "ReplicaSet",
|
||||
DaemonSet = "DaemonSet",
|
||||
Job = "Job",
|
||||
Namespace = "Namespace",
|
||||
}
|
||||
|
||||
/**
|
||||
* The default node shell image
|
||||
*/
|
||||
export const initialNodeShellImage = "docker.io/alpine:3.13";
|
||||
|
||||
/**
|
||||
* The arguments for requesting to refresh a cluster's metadata
|
||||
*/
|
||||
export interface ClusterRefreshOptions {
|
||||
refreshMetadata?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* The data representing a cluster's state, for passing between main and renderer
|
||||
*/
|
||||
export interface ClusterState {
|
||||
apiUrl: string;
|
||||
online: boolean;
|
||||
disconnected: boolean;
|
||||
accessible: boolean;
|
||||
ready: boolean;
|
||||
failureReason: string;
|
||||
isAdmin: boolean;
|
||||
allowedNamespaces: string[]
|
||||
allowedResources: string[]
|
||||
isGlobalWatchEnabled: boolean;
|
||||
}
|
||||
@ -22,38 +22,18 @@
|
||||
import { action, comparer, observable, makeObservable } from "mobx";
|
||||
import { BaseStore } from "./base-store";
|
||||
import migrations from "../migrations/hotbar-store";
|
||||
import * as uuid from "uuid";
|
||||
import isNull from "lodash/isNull";
|
||||
import { toJS } from "./utils";
|
||||
import { CatalogEntity } from "./catalog";
|
||||
import { catalogEntity } from "../main/catalog-sources/general";
|
||||
|
||||
export interface HotbarItem {
|
||||
entity: {
|
||||
uid: string;
|
||||
name?: string;
|
||||
source?: string;
|
||||
};
|
||||
params?: {
|
||||
[key: string]: string;
|
||||
}
|
||||
}
|
||||
|
||||
export type Hotbar = Required<HotbarCreateOptions>;
|
||||
|
||||
export interface HotbarCreateOptions {
|
||||
id?: string;
|
||||
name: string;
|
||||
items?: (HotbarItem | null)[];
|
||||
}
|
||||
import logger from "../main/logger";
|
||||
import { broadcastMessage, HotbarTooManyItems } from "./ipc";
|
||||
import { defaultHotbarCells, getEmptyHotbar, Hotbar, HotbarCreateOptions } from "./hotbar-types";
|
||||
|
||||
export interface HotbarStoreModel {
|
||||
hotbars: Hotbar[];
|
||||
activeHotbarId: string;
|
||||
}
|
||||
|
||||
export const defaultHotbarCells = 12; // Number is chosen to easy hit any item with keyboard
|
||||
|
||||
export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
@observable hotbars: Hotbar[] = [];
|
||||
@observable private _activeHotbarId: string;
|
||||
@ -89,22 +69,22 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
return this.hotbarIndex(this.activeHotbarId);
|
||||
}
|
||||
|
||||
static getInitialItems() {
|
||||
return [...Array.from(Array(defaultHotbarCells).fill(null))];
|
||||
}
|
||||
|
||||
@action
|
||||
protected fromStore(data: Partial<HotbarStoreModel> = {}) {
|
||||
if (!data.hotbars || !data.hotbars.length) {
|
||||
this.hotbars = [{
|
||||
id: uuid.v4(),
|
||||
name: "Default",
|
||||
items: this.defaultHotbarInitialItems,
|
||||
}];
|
||||
const hotbar = getEmptyHotbar("Default");
|
||||
const { metadata: { uid, name, source } } = catalogEntity;
|
||||
const initialItem = { entity: { uid, name, source } };
|
||||
|
||||
hotbar.items[0] = initialItem;
|
||||
|
||||
this.hotbars = [hotbar];
|
||||
} else {
|
||||
this.hotbars = data.hotbars;
|
||||
}
|
||||
|
||||
this.hotbars.forEach(ensureExactHotbarItemLength);
|
||||
|
||||
if (data.activeHotbarId) {
|
||||
if (this.getById(data.activeHotbarId)) {
|
||||
this.activeHotbarId = data.activeHotbarId;
|
||||
@ -116,14 +96,13 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
}
|
||||
}
|
||||
|
||||
get defaultHotbarInitialItems() {
|
||||
const { metadata: { uid, name, source } } = catalogEntity;
|
||||
const initialItem = { entity: { uid, name, source }};
|
||||
toJSON(): HotbarStoreModel {
|
||||
const model: HotbarStoreModel = {
|
||||
hotbars: this.hotbars,
|
||||
activeHotbarId: this.activeHotbarId
|
||||
};
|
||||
|
||||
return [
|
||||
initialItem,
|
||||
...Array.from(Array(defaultHotbarCells - 1).fill(null))
|
||||
];
|
||||
return toJS(model);
|
||||
}
|
||||
|
||||
getActive() {
|
||||
@ -140,16 +119,12 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
|
||||
@action
|
||||
add(data: HotbarCreateOptions, { setActive = false } = {}) {
|
||||
const {
|
||||
id = uuid.v4(),
|
||||
items = HotbarStore.getInitialItems(),
|
||||
name,
|
||||
} = data;
|
||||
const hotbar = getEmptyHotbar(data.name, data.id);
|
||||
|
||||
this.hotbars.push({ id, name, items });
|
||||
this.hotbars.push(hotbar);
|
||||
|
||||
if (setActive) {
|
||||
this._activeHotbarId = id;
|
||||
this._activeHotbarId = hotbar.id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,39 +151,52 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
}
|
||||
|
||||
@action
|
||||
addToHotbar(item: CatalogEntity, cellIndex = -1) {
|
||||
addToHotbar(item: CatalogEntity, cellIndex?: number) {
|
||||
const hotbar = this.getActive();
|
||||
const uid = item.metadata?.uid;
|
||||
const name = item.metadata?.name;
|
||||
|
||||
if (typeof uid !== "string") {
|
||||
throw new TypeError("CatalogEntity.metadata.uid must be a string");
|
||||
}
|
||||
|
||||
if (typeof name !== "string") {
|
||||
throw new TypeError("CatalogEntity.metadata.name must be a string");
|
||||
}
|
||||
|
||||
const newItem = { entity: {
|
||||
uid: item.metadata.uid,
|
||||
name: item.metadata.name,
|
||||
source: item.metadata.source
|
||||
uid,
|
||||
name,
|
||||
source: item.metadata.source,
|
||||
}};
|
||||
|
||||
if (hotbar.items.find(i => i?.entity.uid === item.metadata.uid)) {
|
||||
|
||||
if (hotbar.items.find(i => i?.entity.uid === uid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cellIndex == -1) {
|
||||
if (cellIndex === undefined) {
|
||||
// Add item to empty cell
|
||||
const emptyCellIndex = hotbar.items.findIndex(isNull);
|
||||
const emptyCellIndex = hotbar.items.indexOf(null);
|
||||
|
||||
if (emptyCellIndex != -1) {
|
||||
hotbar.items[emptyCellIndex] = newItem;
|
||||
} else {
|
||||
// Add new item to the end of list
|
||||
hotbar.items.push(newItem);
|
||||
broadcastMessage(HotbarTooManyItems);
|
||||
}
|
||||
} else {
|
||||
} else if (0 <= cellIndex && cellIndex < hotbar.items.length) {
|
||||
hotbar.items[cellIndex] = newItem;
|
||||
} else {
|
||||
logger.error(`[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range`, { entityId: uid, hotbarId: hotbar.id, cellIndex, });
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
removeFromHotbar(uid: string): void {
|
||||
const hotbar = this.getActive();
|
||||
const index = hotbar.items.findIndex((i) => i?.entity.uid === uid);
|
||||
const index = hotbar.items.findIndex(item => item?.entity.uid === uid);
|
||||
|
||||
if (index == -1) {
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -222,13 +210,10 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
*/
|
||||
@action
|
||||
removeAllHotbarItems(uid: string) {
|
||||
const undoItems: [Hotbar, number, HotbarItem][] = [];
|
||||
|
||||
for (const hotbar of this.hotbars) {
|
||||
const index = hotbar.items.findIndex((i) => i?.entity.uid === uid);
|
||||
|
||||
if (index >= 0) {
|
||||
undoItems.push([hotbar, index, hotbar.items[index]]);
|
||||
hotbar.items[index] = null;
|
||||
}
|
||||
}
|
||||
@ -289,13 +274,33 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
|
||||
hotbarStore.activeHotbarId = hotbarStore.hotbars[index].id;
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(): HotbarStoreModel {
|
||||
const model: HotbarStoreModel = {
|
||||
hotbars: this.hotbars,
|
||||
activeHotbarId: this.activeHotbarId
|
||||
};
|
||||
/**
|
||||
* This function ensures that there are always exactly `defaultHotbarCells`
|
||||
* worth of items in the hotbar.
|
||||
* @param hotbar The hotbar to modify
|
||||
*/
|
||||
function ensureExactHotbarItemLength(hotbar: Hotbar) {
|
||||
if (hotbar.items.length === defaultHotbarCells) {
|
||||
// if we already have `defaultHotbarCells` then we are good to stop
|
||||
return;
|
||||
}
|
||||
|
||||
return toJS(model);
|
||||
// otherwise, keep adding empty entries until full
|
||||
while (hotbar.items.length < defaultHotbarCells) {
|
||||
hotbar.items.push(null);
|
||||
}
|
||||
|
||||
// if for some reason the hotbar was overfilled before, remove as many entries
|
||||
// as needed, but prefer empty slots and items at the end first.
|
||||
while (hotbar.items.length > defaultHotbarCells) {
|
||||
const lastNull = hotbar.items.lastIndexOf(null);
|
||||
|
||||
if (lastNull >= 0) {
|
||||
hotbar.items.splice(lastNull, 1);
|
||||
} else {
|
||||
hotbar.items.length = defaultHotbarCells;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
src/common/hotbar-types.ts
Normal file
52
src/common/hotbar-types.ts
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import * as uuid from "uuid";
|
||||
import type { Tuple } from "./utils";
|
||||
|
||||
export interface HotbarItem {
|
||||
entity: {
|
||||
uid: string;
|
||||
name?: string;
|
||||
source?: string;
|
||||
};
|
||||
params?: {
|
||||
[key: string]: string;
|
||||
}
|
||||
}
|
||||
|
||||
export type Hotbar = Required<HotbarCreateOptions>;
|
||||
|
||||
export interface HotbarCreateOptions {
|
||||
id?: string;
|
||||
name: string;
|
||||
items?: Tuple<HotbarItem | null, typeof defaultHotbarCells>;
|
||||
}
|
||||
|
||||
export const defaultHotbarCells = 12; // Number is chosen to easy hit any item with keyboard
|
||||
|
||||
export function getEmptyHotbar(name: string, id: string = uuid.v4()): Hotbar {
|
||||
return {
|
||||
id,
|
||||
items: Array(defaultHotbarCells).fill(null) as Tuple<HotbarItem | null, typeof defaultHotbarCells>,
|
||||
name,
|
||||
};
|
||||
}
|
||||
22
src/common/ipc/hotbar.ts
Normal file
22
src/common/ipc/hotbar.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export const HotbarTooManyItems = "hotbar:too-many-items";
|
||||
@ -24,3 +24,4 @@ export * from "./invalid-kubeconfig";
|
||||
export * from "./update-available.ipc";
|
||||
export * from "./cluster.ipc";
|
||||
export * from "./type-enforced-ipc";
|
||||
export * from "./hotbar";
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { ingressStore } from "../../components/+network-ingresses/ingress.store";
|
||||
import { ingressStore } from "../../../renderer/components/+network-ingresses/ingress.store";
|
||||
import { apiManager } from "../api-manager";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
@ -20,12 +20,22 @@
|
||||
*/
|
||||
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeJsonApi } from "../kube-json-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
describe("KubeApi", () => {
|
||||
let request: KubeJsonApi;
|
||||
|
||||
beforeEach(() => {
|
||||
request = new KubeJsonApi({
|
||||
serverAddress: `http://127.0.0.1:9999`,
|
||||
apiBase: "/api-kube"
|
||||
});
|
||||
});
|
||||
|
||||
it("uses url from apiBase if apiBase contains the resource", async () => {
|
||||
(fetch as any).mockResponse(async (request: any) => {
|
||||
if (request.url === "/api-kube/apis/networking.k8s.io/v1") {
|
||||
if (request.url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
@ -33,7 +43,7 @@ describe("KubeApi", () => {
|
||||
}] as any[]
|
||||
})
|
||||
};
|
||||
} else if (request.url === "/api-kube/apis/extensions/v1beta1") {
|
||||
} else if (request.url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
|
||||
// Even if the old API contains ingresses, KubeApi should prefer the apiBase url
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
@ -54,6 +64,7 @@ describe("KubeApi", () => {
|
||||
const apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||
const kubeApi = new KubeApi({
|
||||
request,
|
||||
objectConstructor: KubeObject,
|
||||
apiBase,
|
||||
fallbackApiBases: [fallbackApiBase],
|
||||
@ -67,13 +78,13 @@ describe("KubeApi", () => {
|
||||
|
||||
it("uses url from fallbackApiBases if apiBase lacks the resource", async () => {
|
||||
(fetch as any).mockResponse(async (request: any) => {
|
||||
if (request.url === "/api-kube/apis/networking.k8s.io/v1") {
|
||||
if (request.url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [] as any[]
|
||||
})
|
||||
};
|
||||
} else if (request.url === "/api-kube/apis/extensions/v1beta1") {
|
||||
} else if (request.url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
@ -93,6 +104,7 @@ describe("KubeApi", () => {
|
||||
const apiBase = "apis/networking.k8s.io/v1/ingresses";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||
const kubeApi = new KubeApi({
|
||||
request,
|
||||
objectConstructor: KubeObject,
|
||||
apiBase,
|
||||
fallbackApiBases: [fallbackApiBase],
|
||||
@ -19,12 +19,13 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import type { KubeObjectStore } from "../kube-object.store";
|
||||
import type { KubeObjectStore } from "./kube-object.store";
|
||||
|
||||
import { action, observable, makeObservable } from "mobx";
|
||||
import { autoBind, iter } from "../utils";
|
||||
import { KubeApi, parseKubeApi } from "./kube-api";
|
||||
import type { KubeApi } from "./kube-api";
|
||||
import type { KubeObject } from "./kube-object";
|
||||
import { IKubeObjectRef, parseKubeApi, createKubeApiURL } from "./kube-api-parse";
|
||||
|
||||
export class ApiManager {
|
||||
private apis = observable.map<string, KubeApi<KubeObject>>();
|
||||
@ -48,6 +49,8 @@ export class ApiManager {
|
||||
}
|
||||
|
||||
registerApi(apiBase: string, api: KubeApi<KubeObject>) {
|
||||
if (!api.apiBase) return;
|
||||
|
||||
if (!this.apis.has(apiBase)) {
|
||||
this.stores.forEach((store) => {
|
||||
if (store.api === api) {
|
||||
@ -83,14 +86,53 @@ export class ApiManager {
|
||||
|
||||
@action
|
||||
registerStore(store: KubeObjectStore<KubeObject>, apis: KubeApi<KubeObject>[] = [store.api]) {
|
||||
apis.forEach(api => {
|
||||
this.stores.set(api.apiBase, store);
|
||||
apis.filter(Boolean).forEach(api => {
|
||||
if (api.apiBase) this.stores.set(api.apiBase, store);
|
||||
});
|
||||
}
|
||||
|
||||
getStore<S extends KubeObjectStore<KubeObject>>(api: string | KubeApi<KubeObject>): S | undefined {
|
||||
return this.stores.get(this.resolveApi(api)?.apiBase) as S;
|
||||
}
|
||||
|
||||
lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string {
|
||||
const {
|
||||
kind, apiVersion, name,
|
||||
namespace = parentObject.getNs()
|
||||
} = ref;
|
||||
|
||||
if (!kind) return "";
|
||||
|
||||
// search in registered apis by 'kind' & 'apiVersion'
|
||||
const api = this.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion);
|
||||
|
||||
if (api) {
|
||||
return api.getUrl({ namespace, name });
|
||||
}
|
||||
|
||||
// lookup api by generated resource link
|
||||
const apiPrefixes = ["/apis", "/api"];
|
||||
const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`;
|
||||
|
||||
for (const apiPrefix of apiPrefixes) {
|
||||
const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource });
|
||||
|
||||
if (this.getApi(apiLink)) {
|
||||
return apiLink;
|
||||
}
|
||||
}
|
||||
|
||||
// resolve by kind only (hpa's might use refs to older versions of resources for example)
|
||||
const apiByKind = this.getApi(api => api.kind === kind);
|
||||
|
||||
if (apiByKind) {
|
||||
return apiByKind.getUrl({ name, namespace });
|
||||
}
|
||||
|
||||
// otherwise generate link with default prefix
|
||||
// resource still might exists in k8s, but api is not registered in the app
|
||||
return createKubeApiURL({ apiVersion, name, namespace, resource });
|
||||
}
|
||||
}
|
||||
|
||||
export const apiManager = new ApiManager();
|
||||
28
src/common/k8s-api/cluster-context.ts
Normal file
28
src/common/k8s-api/cluster-context.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import type { Cluster } from "../../main/cluster";
|
||||
|
||||
export interface ClusterContext {
|
||||
cluster?: Cluster;
|
||||
allNamespaces: string[]; // available / allowed namespaces from cluster.ts
|
||||
contextNamespaces: string[]; // selected by user (see: namespace-select.tsx)
|
||||
}
|
||||
@ -18,6 +18,7 @@
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
@ -53,6 +54,17 @@ export class ClusterRoleBinding extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const clusterRoleBindingApi = new KubeApi({
|
||||
objectConstructor: ClusterRoleBinding,
|
||||
});
|
||||
/**
|
||||
* Only available within kubernetes cluster pages
|
||||
*/
|
||||
let clusterRoleBindingApi: KubeApi<ClusterRoleBinding>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
clusterRoleBindingApi = new KubeApi({
|
||||
objectConstructor: ClusterRoleBinding,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
clusterRoleBindingApi
|
||||
};
|
||||
@ -19,6 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
@ -41,6 +42,17 @@ export class ClusterRole extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const clusterRoleApi = new KubeApi({
|
||||
objectConstructor: ClusterRole,
|
||||
});
|
||||
/**
|
||||
* Only available within kubernetes cluster pages
|
||||
*/
|
||||
let clusterRoleApi: KubeApi<ClusterRole>;
|
||||
|
||||
if (isClusterPageContext()) { // initialize automatically only when within a cluster iframe/context
|
||||
clusterRoleApi = new KubeApi({
|
||||
objectConstructor: ClusterRole,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
clusterRoleApi
|
||||
};
|
||||
@ -22,6 +22,7 @@
|
||||
import { IMetrics, IMetricsReqParams, metricsApi } from "./metrics.api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class ClusterApi extends KubeApi<Cluster> {
|
||||
static kind = "Cluster";
|
||||
@ -122,6 +123,17 @@ export class Cluster extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const clusterApi = new ClusterApi({
|
||||
objectConstructor: Cluster,
|
||||
});
|
||||
/**
|
||||
* Only available within kubernetes cluster pages
|
||||
*/
|
||||
let clusterApi: ClusterApi;
|
||||
|
||||
if (isClusterPageContext()) { // initialize automatically only when within a cluster iframe/context
|
||||
clusterApi = new ClusterApi({
|
||||
objectConstructor: Cluster,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
clusterApi
|
||||
};
|
||||
@ -22,7 +22,8 @@
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { autoBind } from "../../../common/utils";
|
||||
import { autoBind } from "../../utils";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface ConfigMap {
|
||||
data: {
|
||||
@ -47,6 +48,17 @@ export class ConfigMap extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const configMapApi = new KubeApi({
|
||||
objectConstructor: ConfigMap,
|
||||
});
|
||||
/**
|
||||
* Only available within kubernetes cluster pages
|
||||
*/
|
||||
let configMapApi: KubeApi<ConfigMap>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
configMapApi = new KubeApi({
|
||||
objectConstructor: ConfigMap,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
configMapApi
|
||||
};
|
||||
@ -21,7 +21,8 @@
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { crdResourcesURL } from "../../../common/routes";
|
||||
import { crdResourcesURL } from "../../routes";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
type AdditionalPrinterColumnsCommon = {
|
||||
name: string;
|
||||
@ -174,7 +175,18 @@ export class CustomResourceDefinition extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const crdApi = new KubeApi<CustomResourceDefinition>({
|
||||
objectConstructor: CustomResourceDefinition,
|
||||
checkPreferredVersion: true,
|
||||
});
|
||||
/**
|
||||
* Only available within kubernetes cluster pages
|
||||
*/
|
||||
let crdApi: KubeApi<CustomResourceDefinition>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
crdApi = new KubeApi<CustomResourceDefinition>({
|
||||
objectConstructor: CustomResourceDefinition,
|
||||
checkPreferredVersion: true,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
crdApi
|
||||
};
|
||||
@ -26,6 +26,7 @@ import { formatDuration } from "../../utils/formatDuration";
|
||||
import { autoBind } from "../../utils";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class CronJobApi extends KubeApi<CronJob> {
|
||||
suspend(params: { namespace: string; name: string }) {
|
||||
@ -140,6 +141,17 @@ export class CronJob extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const cronJobApi = new CronJobApi({
|
||||
objectConstructor: CronJob,
|
||||
});
|
||||
/**
|
||||
* Only available within kubernetes cluster pages
|
||||
*/
|
||||
let cronJobApi: CronJobApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
cronJobApi = new CronJobApi({
|
||||
objectConstructor: CronJob,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
cronJobApi
|
||||
};
|
||||
@ -26,6 +26,7 @@ import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { IPodContainer, IPodMetrics } from "./pods.api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class DaemonSet extends WorkloadKubeObject {
|
||||
static kind = "DaemonSet";
|
||||
@ -116,6 +117,17 @@ export function getMetricsForDaemonSets(daemonsets: DaemonSet[], namespace: stri
|
||||
});
|
||||
}
|
||||
|
||||
export const daemonSetApi = new DaemonSetApi({
|
||||
objectConstructor: DaemonSet,
|
||||
});
|
||||
/**
|
||||
* Only available within kubernetes cluster pages
|
||||
*/
|
||||
let daemonSetApi: DaemonSetApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
daemonSetApi = new DaemonSetApi({
|
||||
objectConstructor: DaemonSet,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
daemonSetApi
|
||||
};
|
||||
@ -27,6 +27,7 @@ import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { IPodMetrics } from "./pods.api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class DeploymentApi extends KubeApi<Deployment> {
|
||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||
@ -232,6 +233,14 @@ export class Deployment extends WorkloadKubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const deploymentApi = new DeploymentApi({
|
||||
objectConstructor: Deployment,
|
||||
});
|
||||
let deploymentApi: DeploymentApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
deploymentApi = new DeploymentApi({
|
||||
objectConstructor: Deployment,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
deploymentApi
|
||||
};
|
||||
@ -24,6 +24,7 @@ import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { get } from "lodash";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface IEndpointPort {
|
||||
name?: string;
|
||||
@ -149,6 +150,14 @@ export class Endpoint extends KubeObject {
|
||||
|
||||
}
|
||||
|
||||
export const endpointApi = new KubeApi({
|
||||
objectConstructor: Endpoint,
|
||||
});
|
||||
let endpointApi: KubeApi<Endpoint>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
endpointApi = new KubeApi<Endpoint>({
|
||||
objectConstructor: Endpoint,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
endpointApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import moment from "moment";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { formatDuration } from "../../utils/formatDuration";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface KubeEvent {
|
||||
involvedObject: {
|
||||
@ -77,6 +78,14 @@ export class KubeEvent extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const eventApi = new KubeApi({
|
||||
objectConstructor: KubeEvent,
|
||||
});
|
||||
let eventApi: KubeApi<KubeEvent>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
eventApi = new KubeApi<KubeEvent>({
|
||||
objectConstructor: KubeEvent,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
eventApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import { compile } from "path-to-regexp";
|
||||
import { apiBase } from "../index";
|
||||
import { stringify } from "querystring";
|
||||
import { autoBind } from "../../utils";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
|
||||
export type RepoHelmChartList = Record<string, HelmChart[]>;
|
||||
export type HelmChartList = Record<string, RepoHelmChartList>;
|
||||
@ -23,11 +23,11 @@ import jsYaml from "js-yaml";
|
||||
import { autoBind, formatDuration } from "../../utils";
|
||||
import capitalize from "lodash/capitalize";
|
||||
import { apiBase } from "../index";
|
||||
import { helmChartStore } from "../../components/+apps-helm-charts/helm-chart.store";
|
||||
import { helmChartStore } from "../../../renderer/components/+apps-helm-charts/helm-chart.store";
|
||||
import type { ItemObject } from "../../item.store";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { JsonApiData } from "../json-api";
|
||||
import { buildURLPositional } from "../../../common/utils/buildUrl";
|
||||
import { buildURLPositional } from "../../utils/buildUrl";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
|
||||
interface IReleasePayload {
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export enum HpaMetricType {
|
||||
Resource = "Resource",
|
||||
@ -163,6 +164,14 @@ export class HorizontalPodAutoscaler extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const hpaApi = new KubeApi({
|
||||
objectConstructor: HorizontalPodAutoscaler,
|
||||
});
|
||||
let hpaApi: KubeApi<HorizontalPodAutoscaler>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
hpaApi = new KubeApi<HorizontalPodAutoscaler>({
|
||||
objectConstructor: HorizontalPodAutoscaler,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
hpaApi
|
||||
};
|
||||
@ -24,6 +24,7 @@ import { autoBind } from "../../utils";
|
||||
import { IMetrics, metricsApi } from "./metrics.api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class IngressApi extends KubeApi<Ingress> {
|
||||
}
|
||||
@ -203,10 +204,17 @@ export class Ingress extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const ingressApi = new IngressApi({
|
||||
objectConstructor: Ingress,
|
||||
// Add fallback for Kubernetes <1.19
|
||||
checkPreferredVersion: true,
|
||||
fallbackApiBases: ["/apis/extensions/v1beta1/ingresses"],
|
||||
logStuff: true
|
||||
} as any);
|
||||
let ingressApi: IngressApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
ingressApi = new IngressApi({
|
||||
objectConstructor: Ingress,
|
||||
// Add fallback for Kubernetes <1.19
|
||||
checkPreferredVersion: true,
|
||||
fallbackApiBases: ["/apis/extensions/v1beta1/ingresses"],
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
ingressApi
|
||||
};
|
||||
@ -27,6 +27,7 @@ import { metricsApi } from "./metrics.api";
|
||||
import type { JsonApiParams } from "../json-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { IPodContainer, IPodMetrics } from "./pods.api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class Job extends WorkloadKubeObject {
|
||||
static kind = "Job";
|
||||
@ -148,6 +149,14 @@ export function getMetricsForJobs(jobs: Job[], namespace: string, selector = "")
|
||||
});
|
||||
}
|
||||
|
||||
export const jobApi = new JobApi({
|
||||
objectConstructor: Job,
|
||||
});
|
||||
let jobApi: JobApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
jobApi = new JobApi({
|
||||
objectConstructor: Job,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
jobApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { autoBind } from "../../utils";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export enum LimitType {
|
||||
CONTAINER = "Container",
|
||||
@ -80,6 +81,14 @@ export class LimitRange extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const limitRangeApi = new KubeApi({
|
||||
objectConstructor: LimitRange,
|
||||
});
|
||||
let limitRangeApi: KubeApi<LimitRange>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
limitRangeApi = new KubeApi<LimitRange>({
|
||||
objectConstructor: LimitRange,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
limitRangeApi
|
||||
};
|
||||
@ -21,10 +21,11 @@
|
||||
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { autoBind } from "../../utils";
|
||||
import { autoBind } from "../../../renderer/utils";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { IPodMetrics } from "./pods.api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export enum NamespaceStatus {
|
||||
ACTIVE = "Active",
|
||||
@ -69,6 +70,14 @@ export function getMetricsForNamespace(namespace: string, selector = ""): Promis
|
||||
});
|
||||
}
|
||||
|
||||
export const namespacesApi = new NamespaceApi({
|
||||
objectConstructor: Namespace,
|
||||
});
|
||||
let namespacesApi: NamespaceApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
namespacesApi = new NamespaceApi({
|
||||
objectConstructor: Namespace,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
namespacesApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import { KubeObject } from "../kube-object";
|
||||
import { autoBind } from "../../utils";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface IPolicyIpBlock {
|
||||
cidr: string;
|
||||
@ -96,6 +97,14 @@ export class NetworkPolicy extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const networkPolicyApi = new KubeApi({
|
||||
objectConstructor: NetworkPolicy,
|
||||
});
|
||||
let networkPolicyApi: KubeApi<NetworkPolicy>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
networkPolicyApi = new KubeApi<NetworkPolicy>({
|
||||
objectConstructor: NetworkPolicy,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
networkPolicyApi
|
||||
};
|
||||
@ -20,10 +20,11 @@
|
||||
*/
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { autoBind, cpuUnitsToNumber, unitsToBytes } from "../../utils";
|
||||
import { autoBind, cpuUnitsToNumber, unitsToBytes } from "../../../renderer/utils";
|
||||
import { IMetrics, metricsApi } from "./metrics.api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class NodesApi extends KubeApi<Node> {
|
||||
}
|
||||
@ -225,6 +226,14 @@ export class Node extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const nodesApi = new NodesApi({
|
||||
objectConstructor: Node,
|
||||
});
|
||||
let nodesApi: NodesApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
nodesApi = new NodesApi({
|
||||
objectConstructor: Node,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
nodesApi
|
||||
};
|
||||
@ -25,6 +25,7 @@ import { IMetrics, metricsApi } from "./metrics.api";
|
||||
import type { Pod } from "./pods.api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
|
||||
}
|
||||
@ -116,6 +117,14 @@ export class PersistentVolumeClaim extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const pvcApi = new PersistentVolumeClaimsApi({
|
||||
objectConstructor: PersistentVolumeClaim,
|
||||
});
|
||||
let pvcApi: PersistentVolumeClaimsApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
pvcApi = new PersistentVolumeClaimsApi({
|
||||
objectConstructor: PersistentVolumeClaim,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
pvcApi
|
||||
};
|
||||
@ -20,10 +20,10 @@
|
||||
*/
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { unitsToBytes } from "../../utils/convertMemory";
|
||||
import { autoBind } from "../../utils";
|
||||
import { autoBind, unitsToBytes } from "../../utils";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface PersistentVolume {
|
||||
spec: {
|
||||
@ -102,6 +102,14 @@ export class PersistentVolume extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const persistentVolumeApi = new KubeApi({
|
||||
objectConstructor: PersistentVolume,
|
||||
});
|
||||
let persistentVolumeApi: KubeApi<PersistentVolume>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
persistentVolumeApi = new KubeApi({
|
||||
objectConstructor: PersistentVolume,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
persistentVolumeApi
|
||||
};
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface PodMetrics {
|
||||
timestamp: string;
|
||||
@ -40,6 +41,14 @@ export class PodMetrics extends KubeObject {
|
||||
static apiBase = "/apis/metrics.k8s.io/v1beta1/pods";
|
||||
}
|
||||
|
||||
export const podMetricsApi = new KubeApi({
|
||||
objectConstructor: PodMetrics,
|
||||
});
|
||||
let podMetricsApi: KubeApi<PodMetrics>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
podMetricsApi = new KubeApi<PodMetrics>({
|
||||
objectConstructor: PodMetrics,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
podMetricsApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import { autoBind } from "../../utils";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface PodDisruptionBudget {
|
||||
spec: {
|
||||
@ -72,6 +73,14 @@ export class PodDisruptionBudget extends KubeObject {
|
||||
|
||||
}
|
||||
|
||||
export const pdbApi = new KubeApi({
|
||||
objectConstructor: PodDisruptionBudget,
|
||||
});
|
||||
let pdbApi: KubeApi<PodDisruptionBudget>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
pdbApi = new KubeApi({
|
||||
objectConstructor: PodDisruptionBudget,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
pdbApi
|
||||
};
|
||||
@ -24,6 +24,7 @@ import { autoBind } from "../../utils";
|
||||
import { IMetrics, metricsApi } from "./metrics.api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class PodsApi extends KubeApi<Pod> {
|
||||
async getLogs(params: { namespace: string; name: string }, query?: IPodLogsQuery): Promise<string> {
|
||||
@ -502,6 +503,14 @@ export class Pod extends WorkloadKubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const podsApi = new PodsApi({
|
||||
objectConstructor: Pod,
|
||||
});
|
||||
let podsApi: PodsApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
podsApi = new PodsApi({
|
||||
objectConstructor: Pod,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
podsApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import { autoBind } from "../../utils";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface PodSecurityPolicy {
|
||||
spec: {
|
||||
@ -117,6 +118,14 @@ export class PodSecurityPolicy extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const pspApi = new KubeApi({
|
||||
objectConstructor: PodSecurityPolicy,
|
||||
});
|
||||
let pspApi: KubeApi<PodSecurityPolicy>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
pspApi = new KubeApi({
|
||||
objectConstructor: PodSecurityPolicy,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
pspApi
|
||||
};
|
||||
@ -20,12 +20,13 @@
|
||||
*/
|
||||
|
||||
import get from "lodash/get";
|
||||
import { autoBind } from "../../utils";
|
||||
import { autoBind } from "../../../renderer/utils";
|
||||
import { WorkloadKubeObject } from "../workload-kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { IPodContainer, IPodMetrics, Pod } from "./pods.api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||
@ -123,6 +124,14 @@ export class ReplicaSet extends WorkloadKubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const replicaSetApi = new ReplicaSetApi({
|
||||
objectConstructor: ReplicaSet,
|
||||
});
|
||||
let replicaSetApi: ReplicaSetApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
replicaSetApi = new ReplicaSetApi({
|
||||
objectConstructor: ReplicaSet,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
replicaSetApi
|
||||
};
|
||||
@ -20,35 +20,21 @@
|
||||
*/
|
||||
|
||||
import jsYaml from "js-yaml";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { apiBase } from "../index";
|
||||
import { apiManager } from "../api-manager";
|
||||
|
||||
export const resourceApplierApi = {
|
||||
annotations: [
|
||||
"kubectl.kubernetes.io/last-applied-configuration"
|
||||
],
|
||||
|
||||
async update<K extends KubeObject>(resource: object | string): Promise<K | null> {
|
||||
async update(resource: object | string): Promise<KubeJsonApiData | null> {
|
||||
if (typeof resource === "string") {
|
||||
resource = jsYaml.safeLoad(resource);
|
||||
}
|
||||
|
||||
return apiBase
|
||||
.post<KubeJsonApiData[]>("/stack", { data: resource })
|
||||
.then(data => {
|
||||
const items = data.map(obj => {
|
||||
const api = apiManager.getApiByKind(obj.kind, obj.apiVersion);
|
||||
const [data = null] = await apiBase.post<KubeJsonApiData[]>("/stack", { data: resource });
|
||||
|
||||
if (api) {
|
||||
return new api.objectConstructor(obj);
|
||||
} else {
|
||||
return new KubeObject(obj);
|
||||
}
|
||||
});
|
||||
|
||||
return items[0] as K ?? null;
|
||||
});
|
||||
return data;
|
||||
}
|
||||
};
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface IResourceQuotaValues {
|
||||
[quota: string]: string;
|
||||
@ -80,6 +81,14 @@ export class ResourceQuota extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const resourceQuotaApi = new KubeApi({
|
||||
objectConstructor: ResourceQuota,
|
||||
});
|
||||
let resourceQuotaApi: KubeApi<ResourceQuota>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
resourceQuotaApi = new KubeApi<ResourceQuota>({
|
||||
objectConstructor: ResourceQuota,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
resourceQuotaApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import { autoBind } from "../../utils";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export type RoleBindingSubjectKind = "Group" | "ServiceAccount" | "User";
|
||||
|
||||
@ -61,6 +62,14 @@ export class RoleBinding extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const roleBindingApi = new KubeApi({
|
||||
objectConstructor: RoleBinding,
|
||||
});
|
||||
let roleBindingApi: KubeApi<RoleBinding>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
roleBindingApi = new KubeApi({
|
||||
objectConstructor: RoleBinding,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
roleBindingApi
|
||||
};
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface Role {
|
||||
rules: {
|
||||
@ -41,6 +42,14 @@ export class Role extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const roleApi = new KubeApi({
|
||||
objectConstructor: Role,
|
||||
});
|
||||
let roleApi: KubeApi<Role>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
roleApi = new KubeApi<Role>({
|
||||
objectConstructor: Role,
|
||||
});
|
||||
}
|
||||
|
||||
export{
|
||||
roleApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import { KubeObject } from "../kube-object";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { autoBind } from "../../utils";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export enum SecretType {
|
||||
Opaque = "Opaque",
|
||||
@ -69,6 +70,14 @@ export class Secret extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const secretsApi = new KubeApi({
|
||||
objectConstructor: Secret,
|
||||
});
|
||||
let secretsApi: KubeApi<Secret>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
secretsApi = new KubeApi({
|
||||
objectConstructor: Secret,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
secretsApi
|
||||
};
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class SelfSubjectRulesReviewApi extends KubeApi<SelfSubjectRulesReview> {
|
||||
create({ namespace = "default" }): Promise<SelfSubjectRulesReview> {
|
||||
@ -86,6 +87,15 @@ export class SelfSubjectRulesReview extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const selfSubjectRulesReviewApi = new SelfSubjectRulesReviewApi({
|
||||
objectConstructor: SelfSubjectRulesReview,
|
||||
});
|
||||
let selfSubjectRulesReviewApi: SelfSubjectRulesReviewApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
selfSubjectRulesReviewApi = new SelfSubjectRulesReviewApi({
|
||||
objectConstructor: SelfSubjectRulesReview,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
selfSubjectRulesReviewApi
|
||||
};
|
||||
|
||||
@ -23,6 +23,7 @@ import { autoBind } from "../../utils";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface ServiceAccount {
|
||||
secrets?: {
|
||||
@ -52,6 +53,14 @@ export class ServiceAccount extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const serviceAccountsApi = new KubeApi<ServiceAccount>({
|
||||
objectConstructor: ServiceAccount,
|
||||
});
|
||||
let serviceAccountsApi: KubeApi<ServiceAccount>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
serviceAccountsApi = new KubeApi<ServiceAccount>({
|
||||
objectConstructor: ServiceAccount,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
serviceAccountsApi
|
||||
};
|
||||
@ -19,10 +19,11 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { autoBind } from "../../utils";
|
||||
import { autoBind } from "../../../renderer/utils";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface ServicePort {
|
||||
name?: string;
|
||||
@ -143,6 +144,14 @@ export class Service extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const serviceApi = new KubeApi({
|
||||
objectConstructor: Service,
|
||||
});
|
||||
let serviceApi: KubeApi<Service>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
serviceApi = new KubeApi<Service>({
|
||||
objectConstructor: Service,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
serviceApi
|
||||
};
|
||||
@ -26,6 +26,7 @@ import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { IPodContainer, IPodMetrics } from "./pods.api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export class StatefulSetApi extends KubeApi<StatefulSet> {
|
||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||
@ -149,6 +150,14 @@ export class StatefulSet extends WorkloadKubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const statefulSetApi = new StatefulSetApi({
|
||||
objectConstructor: StatefulSet,
|
||||
});
|
||||
let statefulSetApi: StatefulSetApi;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
statefulSetApi = new StatefulSetApi({
|
||||
objectConstructor: StatefulSet,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
statefulSetApi
|
||||
};
|
||||
@ -23,6 +23,7 @@ import { autoBind } from "../../utils";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
||||
|
||||
export interface StorageClass {
|
||||
provisioner: string; // e.g. "storage.k8s.io/v1"
|
||||
@ -62,6 +63,14 @@ export class StorageClass extends KubeObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const storageClassApi = new KubeApi({
|
||||
objectConstructor: StorageClass,
|
||||
});
|
||||
let storageClassApi: KubeApi<StorageClass>;
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
storageClassApi = new KubeApi({
|
||||
objectConstructor: StorageClass,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
storageClassApi
|
||||
};
|
||||
67
src/common/k8s-api/index.ts
Normal file
67
src/common/k8s-api/index.ts
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { JsonApi } from "./json-api";
|
||||
import { KubeJsonApi } from "./kube-json-api";
|
||||
import { apiKubePrefix, apiPrefix, isDebugging, isDevelopment } from "../../common/vars";
|
||||
import { isClusterPageContext } from "../utils/cluster-id-url-parsing";
|
||||
|
||||
let apiBase: JsonApi;
|
||||
let apiKube: KubeJsonApi;
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
apiBase = new JsonApi({
|
||||
serverAddress: `http://127.0.0.1:${process.env.LENS_PROXY_PORT}`,
|
||||
apiBase: apiPrefix,
|
||||
debug: isDevelopment || isDebugging,
|
||||
}, {
|
||||
headers: {
|
||||
"Host": `localhost:${process.env.LENS_PROXY_PORT}`
|
||||
}
|
||||
});
|
||||
} else {
|
||||
apiBase = new JsonApi({
|
||||
serverAddress: `http://127.0.0.1:${window.location.port}`,
|
||||
apiBase: apiPrefix,
|
||||
debug: isDevelopment || isDebugging,
|
||||
}, {
|
||||
headers: {
|
||||
"Host": window.location.host
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isClusterPageContext()) {
|
||||
apiKube = new KubeJsonApi({
|
||||
serverAddress: `http://127.0.0.1:${window.location.port}`,
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDevelopment
|
||||
}, {
|
||||
headers: {
|
||||
"Host": window.location.host
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
apiBase,
|
||||
apiKube
|
||||
};
|
||||
@ -21,9 +21,11 @@
|
||||
|
||||
// Base http-service / json-api class
|
||||
|
||||
import { merge } from "lodash";
|
||||
import fetch, { Response, RequestInit } from "node-fetch";
|
||||
import { stringify } from "querystring";
|
||||
import { EventEmitter } from "../../common/event-emitter";
|
||||
import { randomBytes } from "crypto";
|
||||
import logger from "../../common/logger";
|
||||
|
||||
export interface JsonApiData {
|
||||
}
|
||||
@ -49,9 +51,9 @@ export interface JsonApiLog {
|
||||
|
||||
export interface JsonApiConfig {
|
||||
apiBase: string;
|
||||
serverAddress: string;
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
static reqInitDefault: RequestInit = {
|
||||
headers: {
|
||||
@ -63,9 +65,9 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
debug: false
|
||||
};
|
||||
|
||||
constructor(protected config: JsonApiConfig, protected reqInit?: RequestInit) {
|
||||
constructor(public readonly config: JsonApiConfig, protected reqInit?: RequestInit) {
|
||||
this.config = Object.assign({}, JsonApi.configDefault, config);
|
||||
this.reqInit = Object.assign({}, JsonApi.reqInitDefault, reqInit);
|
||||
this.reqInit = merge({}, JsonApi.reqInitDefault, reqInit);
|
||||
this.parseResponse = this.parseResponse.bind(this);
|
||||
}
|
||||
|
||||
@ -77,10 +79,8 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
}
|
||||
|
||||
getResponse(path: string, params?: P, init: RequestInit = {}): Promise<Response> {
|
||||
const reqPath = `${this.config.apiBase}${path}`;
|
||||
const subdomain = randomBytes(2).toString("hex");
|
||||
let reqUrl = `http://${subdomain}.${window.location.host}${reqPath}`; // hack around browser connection limits (chromium allows 6 per domain)
|
||||
const reqInit: RequestInit = { ...init };
|
||||
let reqUrl = `${this.config.serverAddress}${this.config.apiBase}${path}`;
|
||||
const reqInit: RequestInit = merge({}, this.reqInit, init);
|
||||
const { query } = params || {} as P;
|
||||
|
||||
if (!reqInit.method) {
|
||||
@ -95,7 +95,7 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
|
||||
this.writeLog({
|
||||
method: reqInit.method.toUpperCase(),
|
||||
reqUrl: reqPath,
|
||||
reqUrl,
|
||||
reqInit,
|
||||
});
|
||||
|
||||
@ -119,8 +119,8 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
}
|
||||
|
||||
protected async request<D>(path: string, params?: P, init: RequestInit = {}) {
|
||||
let reqUrl = this.config.apiBase + path;
|
||||
const reqInit: RequestInit = { ...this.reqInit, ...init };
|
||||
let reqUrl = `${this.config.serverAddress}${this.config.apiBase}${path}`;
|
||||
const reqInit: RequestInit = merge({}, this.reqInit, init);
|
||||
const { data, query } = params || {} as P;
|
||||
|
||||
if (data && !reqInit.body) {
|
||||
@ -192,13 +192,9 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
}
|
||||
|
||||
protected writeLog(log: JsonApiLog) {
|
||||
if (!this.config.debug) return;
|
||||
const { method, reqUrl, ...params } = log;
|
||||
let textStyle = "font-weight: bold;";
|
||||
|
||||
if (params.data) textStyle += "background: green; color: white;";
|
||||
if (params.error) textStyle += "background: red; color: white;";
|
||||
console.log(`%c${method} ${reqUrl}`, textStyle, params);
|
||||
logger.info(`[JSON-API] request ${method} ${reqUrl}`, params);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,10 +21,8 @@
|
||||
|
||||
// Parse kube-api path and get api-version, group, etc.
|
||||
|
||||
import type { KubeObject } from "./kube-object";
|
||||
import { splitArray } from "../../common/utils";
|
||||
import { apiManager } from "./api-manager";
|
||||
import { isDebugging } from "../../common/vars";
|
||||
import { splitArray } from "../utils";
|
||||
import { isDebugging } from "../vars";
|
||||
import logger from "../../main/logger";
|
||||
import { inspect } from "util";
|
||||
|
||||
@ -68,7 +66,7 @@ export function parseKubeApi(path: string): IKubeApiParsed {
|
||||
}
|
||||
|
||||
function _parseKubeApi(path: string): IKubeApiParsed {
|
||||
const apiPath = new URL(path, location.origin).pathname;
|
||||
const apiPath = new URL(path, "http://localhost").pathname;
|
||||
const [, prefix, ...parts] = apiPath.split("/");
|
||||
const apiPrefix = `/${prefix}`;
|
||||
const [left, right, namespaced] = splitArray(parts, "namespaces");
|
||||
@ -159,42 +157,3 @@ export function createKubeApiURL(ref: IKubeApiLinkRef): string {
|
||||
.filter(v => v)
|
||||
.join("/");
|
||||
}
|
||||
|
||||
export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string {
|
||||
const {
|
||||
kind, apiVersion, name,
|
||||
namespace = parentObject.getNs()
|
||||
} = ref;
|
||||
|
||||
if (!kind) return "";
|
||||
|
||||
// search in registered apis by 'kind' & 'apiVersion'
|
||||
const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion);
|
||||
|
||||
if (api) {
|
||||
return api.getUrl({ namespace, name });
|
||||
}
|
||||
|
||||
// lookup api by generated resource link
|
||||
const apiPrefixes = ["/apis", "/api"];
|
||||
const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`;
|
||||
|
||||
for (const apiPrefix of apiPrefixes) {
|
||||
const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource });
|
||||
|
||||
if (apiManager.getApi(apiLink)) {
|
||||
return apiLink;
|
||||
}
|
||||
}
|
||||
|
||||
// resolve by kind only (hpa's might use refs to older versions of resources for example)
|
||||
const apiByKind = apiManager.getApi(api => api.kind === kind);
|
||||
|
||||
if (apiByKind) {
|
||||
return apiByKind.getUrl({ name, namespace });
|
||||
}
|
||||
|
||||
// otherwise generate link with default prefix
|
||||
// resource still might exists in k8s, but api is not registered in the app
|
||||
return createKubeApiURL({ apiVersion, name, namespace, resource });
|
||||
}
|
||||
@ -23,17 +23,18 @@
|
||||
|
||||
import merge from "lodash/merge";
|
||||
import { stringify } from "querystring";
|
||||
import { apiKubePrefix, isDevelopment, isTestEnv } from "../../common/vars";
|
||||
import { apiKubePrefix, isDevelopment } from "../../common/vars";
|
||||
import logger from "../../main/logger";
|
||||
import { apiManager } from "./api-manager";
|
||||
import { apiKube } from "./index";
|
||||
import { apiBase, apiKube } from "./index";
|
||||
import { createKubeApiURL, parseKubeApi } from "./kube-api-parse";
|
||||
import { KubeObjectConstructor, KubeObject, KubeStatus } from "./kube-object";
|
||||
import byline from "byline";
|
||||
import type { IKubeWatchEvent } from "./kube-watch-api";
|
||||
import { ReadableWebToNodeStream } from "../utils/readableStream";
|
||||
import { KubeJsonApi, KubeJsonApiData } from "./kube-json-api";
|
||||
import { noop } from "../utils";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
import AbortController from "abort-controller";
|
||||
|
||||
export interface IKubeApiOptions<T extends KubeObject> {
|
||||
/**
|
||||
@ -56,11 +57,6 @@ export interface IKubeApiOptions<T extends KubeObject> {
|
||||
checkPreferredVersion?: boolean;
|
||||
}
|
||||
|
||||
export interface KubeApiListOptions {
|
||||
namespace?: string;
|
||||
reqInit?: RequestInit;
|
||||
}
|
||||
|
||||
export interface IKubeApiQueryParams {
|
||||
watch?: boolean | number;
|
||||
resourceVersion?: string;
|
||||
@ -101,11 +97,12 @@ export interface IKubeApiCluster {
|
||||
|
||||
export function forCluster<T extends KubeObject>(cluster: IKubeApiCluster, kubeClass: KubeObjectConstructor<T>): KubeApi<T> {
|
||||
const request = new KubeJsonApi({
|
||||
serverAddress: apiBase.config.serverAddress,
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDevelopment,
|
||||
}, {
|
||||
headers: {
|
||||
"X-Cluster-ID": cluster.metadata.uid
|
||||
"Host": apiBase.config.serverAddress
|
||||
}
|
||||
});
|
||||
|
||||
@ -173,7 +170,6 @@ export class KubeApi<T extends KubeObject> {
|
||||
this.request = request;
|
||||
this.objectConstructor = objectConstructor;
|
||||
|
||||
this.checkPreferredVersion();
|
||||
this.parseResponse = this.parseResponse.bind(this);
|
||||
apiManager.registerApi(apiBase, this);
|
||||
}
|
||||
@ -206,18 +202,9 @@ export class KubeApi<T extends KubeObject> {
|
||||
}
|
||||
} catch (error) {
|
||||
// Exception is ignored as we can try the next url
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid throwing in tests
|
||||
if (isTestEnv) {
|
||||
return {
|
||||
apiPrefix: this.apiPrefix,
|
||||
apiGroup: this.apiGroup
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Can't find working API for the Kubernetes resource ${this.apiResource}`);
|
||||
}
|
||||
|
||||
@ -440,7 +427,7 @@ export class KubeApi<T extends KubeObject> {
|
||||
});
|
||||
|
||||
const watchUrl = this.getWatchUrl(namespace);
|
||||
const responsePromise = this.request.getResponse(watchUrl, null, { signal });
|
||||
const responsePromise = this.request.getResponse(watchUrl, null, { signal, timeout: 600_000 });
|
||||
|
||||
responsePromise
|
||||
.then(response => {
|
||||
@ -448,10 +435,8 @@ export class KubeApi<T extends KubeObject> {
|
||||
return callback(null, response);
|
||||
}
|
||||
|
||||
const nodeStream = new ReadableWebToNodeStream(response.body);
|
||||
|
||||
["end", "close", "error"].forEach((eventName) => {
|
||||
nodeStream.on(eventName, () => {
|
||||
response.body.on(eventName, () => {
|
||||
if (errorReceived) return; // kubernetes errors should be handled in a callback
|
||||
|
||||
clearTimeout(timedRetry);
|
||||
@ -461,7 +446,7 @@ export class KubeApi<T extends KubeObject> {
|
||||
});
|
||||
});
|
||||
|
||||
byline(nodeStream).on("data", (line) => {
|
||||
byline(response.body).on("data", (line) => {
|
||||
try {
|
||||
const event: IKubeWatchEvent<KubeJsonApiData> = JSON.parse(line);
|
||||
|
||||
@ -479,7 +464,7 @@ export class KubeApi<T extends KubeObject> {
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
if (error instanceof DOMException) return; // AbortController rejects, we can ignore it
|
||||
if (error?.type === "aborted") return; // AbortController rejects, we can ignore it
|
||||
|
||||
callback(null, error);
|
||||
});
|
||||
@ -506,5 +491,3 @@ export class KubeApi<T extends KubeObject> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export * from "./kube-api-parse";
|
||||
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
import { JsonApi, JsonApiData, JsonApiError } from "./json-api";
|
||||
import type { Response } from "node-fetch";
|
||||
|
||||
export interface KubeJsonApiListMetadata {
|
||||
resourceVersion: string;
|
||||
@ -79,3 +80,4 @@ export class KubeJsonApi extends JsonApi<KubeJsonApiData> {
|
||||
return super.parseError(error, res);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,17 +19,19 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import type { ClusterContext } from "./components/context";
|
||||
import type { ClusterContext } from "./cluster-context";
|
||||
|
||||
import { action, computed, makeObservable, observable, reaction, when } from "mobx";
|
||||
import { autoBind, noop, rejectPromiseBy } from "./utils";
|
||||
import { KubeObject, KubeStatus } from "./api/kube-object";
|
||||
import type { IKubeWatchEvent } from "./api/kube-watch-api";
|
||||
import { ItemStore } from "./item.store";
|
||||
import { apiManager } from "./api/api-manager";
|
||||
import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi, parseKubeApi } from "./api/kube-api";
|
||||
import type { KubeJsonApiData } from "./api/kube-json-api";
|
||||
import { Notifications } from "./components/notifications";
|
||||
import { autoBind, noop, rejectPromiseBy } from "../utils";
|
||||
import { KubeObject, KubeStatus } from "./kube-object";
|
||||
import type { IKubeWatchEvent } from "./kube-watch-api";
|
||||
import { ItemStore } from "../item.store";
|
||||
import { apiManager } from "./api-manager";
|
||||
import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi } from "./kube-api";
|
||||
import { parseKubeApi } from "./kube-api-parse";
|
||||
import type { KubeJsonApiData } from "./kube-json-api";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
import AbortController from "abort-controller";
|
||||
|
||||
export interface KubeObjectStoreLoadingParams<K extends KubeObject> {
|
||||
namespaces: string[];
|
||||
@ -192,9 +194,6 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
|
||||
|
||||
return items;
|
||||
} catch (error) {
|
||||
if (error.message) {
|
||||
Notifications.error(error.message);
|
||||
}
|
||||
console.warn("[KubeObjectStore] loadAll failed", this.api.apiBase, error);
|
||||
this.resetOnError(error);
|
||||
this.failedLoading = true;
|
||||
@ -279,7 +278,8 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
|
||||
}
|
||||
|
||||
async update(item: T, data: Partial<T>): Promise<T> {
|
||||
const newItem = await item.update(data);
|
||||
const rawItem = await item.update(data);
|
||||
const newItem = new this.api.objectConstructor(rawItem);
|
||||
|
||||
ensureObjectSelfLink(this.api, newItem);
|
||||
|
||||
@ -346,7 +346,7 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
|
||||
const { signal } = abortController;
|
||||
|
||||
const callback = (data: IKubeWatchEvent<T>, error: any) => {
|
||||
if (!this.isLoaded || error instanceof DOMException) return;
|
||||
if (!this.isLoaded || error?.type === "aborted") return;
|
||||
|
||||
if (error instanceof Response) {
|
||||
if (error.status === 404 || error.status === 401) {
|
||||
@ -86,6 +86,16 @@ export class KubeStatus {
|
||||
}
|
||||
}
|
||||
|
||||
export interface KubeObjectStatus {
|
||||
conditions?: {
|
||||
lastTransitionTime: string;
|
||||
message: string;
|
||||
reason: string;
|
||||
status: string;
|
||||
type?: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export type KubeMetaField = keyof KubeObjectMetadata;
|
||||
|
||||
export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata, Status = any, Spec = any> implements ItemObject {
|
||||
@ -277,14 +287,14 @@ export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata
|
||||
}
|
||||
|
||||
// use unified resource-applier api for updating all k8s objects
|
||||
async update<K extends KubeObject>(data: Partial<K>): Promise<K> {
|
||||
async update(data: Partial<this>): Promise<KubeJsonApiData | null> {
|
||||
for (const field of KubeObject.nonEditableFields) {
|
||||
if (!_.isEqual(_.get(this, field), _.get(data, field))) {
|
||||
throw new Error(`Failed to update Kube Object: ${field} has been modified`);
|
||||
}
|
||||
}
|
||||
|
||||
return resourceApplierApi.update<K>({
|
||||
return resourceApplierApi.update({
|
||||
...this.toPlainObject(),
|
||||
...data,
|
||||
});
|
||||
@ -22,15 +22,15 @@
|
||||
// Kubernetes watch-api client
|
||||
// API: https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams
|
||||
|
||||
import type { KubeObjectStore } from "../kube-object.store";
|
||||
import type { ClusterContext } from "../components/context";
|
||||
import type { KubeObjectStore } from "./kube-object.store";
|
||||
import type { ClusterContext } from "./cluster-context";
|
||||
|
||||
import plimit from "p-limit";
|
||||
import { comparer, observable, reaction, makeObservable } from "mobx";
|
||||
import { autoBind, Disposer, noop } from "../utils";
|
||||
import type { KubeApi } from "./kube-api";
|
||||
import type { KubeJsonApiData } from "./kube-json-api";
|
||||
import { isDebugging, isProduction } from "../../common/vars";
|
||||
import { isDebugging, isProduction } from "../vars";
|
||||
import type { KubeObject } from "./kube-object";
|
||||
|
||||
export interface IKubeWatchEvent<T extends KubeJsonApiData> {
|
||||
81
src/common/logger.ts
Normal file
81
src/common/logger.ts
Normal file
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { app, ipcMain, remote } from "electron";
|
||||
import winston from "winston";
|
||||
import { consoleFormat } from "winston-console-format";
|
||||
import { isDebugging, isTestEnv } from "./vars";
|
||||
import BrowserConsole from "winston-transport-browserconsole";
|
||||
|
||||
|
||||
const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info";
|
||||
let consoleOptions: winston.transports.ConsoleTransportOptions;
|
||||
|
||||
if (ipcMain) {
|
||||
consoleOptions = {
|
||||
handleExceptions: false,
|
||||
level: logLevel,
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize({ level: true, message: false}),
|
||||
winston.format.padLevels(),
|
||||
winston.format.ms(),
|
||||
consoleFormat({
|
||||
showMeta: true,
|
||||
inspectOptions: {
|
||||
depth: 4,
|
||||
colors: true,
|
||||
maxArrayLength: 10,
|
||||
breakLength: 120,
|
||||
compact: Infinity,
|
||||
},
|
||||
})
|
||||
)
|
||||
};
|
||||
} else {
|
||||
consoleOptions = {
|
||||
handleExceptions: false,
|
||||
level: logLevel,
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize({ level: true, message: false}),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
const fileOptions: winston.transports.FileTransportOptions = {
|
||||
handleExceptions: false,
|
||||
level: logLevel,
|
||||
filename: "lens.log",
|
||||
dirname: (app ?? remote?.app)?.getPath("logs"),
|
||||
maxsize: 16 * 1024,
|
||||
maxFiles: 16,
|
||||
tailable: true,
|
||||
};
|
||||
const logger = winston.createLogger({
|
||||
format: winston.format.combine(
|
||||
winston.format.simple()
|
||||
),
|
||||
transports: [
|
||||
ipcMain ? new winston.transports.Console(consoleOptions) : new BrowserConsole(),
|
||||
...(isTestEnv ? [] : [new winston.transports.File(fileOptions)]),
|
||||
],
|
||||
});
|
||||
|
||||
export default logger;
|
||||
@ -19,8 +19,6 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { getHostedCluster } from "./cluster-store";
|
||||
|
||||
export type KubeResource =
|
||||
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" |
|
||||
"secrets" | "configmaps" | "ingresses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" |
|
||||
@ -73,18 +71,3 @@ export const apiResourceRecord: Record<KubeResource, KubeApiResourceData> = {
|
||||
// TODO: auto-populate all resources dynamically (see: kubectl api-resources -o=wide -v=7)
|
||||
export const apiResources: KubeApiResource[] = Object.entries(apiResourceRecord)
|
||||
.map(([apiName, data]) => ({ apiName: apiName as KubeResource, ...data }));
|
||||
|
||||
export function isAllowedResource(resources: KubeResource | KubeResource[]) {
|
||||
if (!Array.isArray(resources)) {
|
||||
resources = [resources];
|
||||
}
|
||||
const { allowedResources = [] } = getHostedCluster() || {};
|
||||
|
||||
for (const resource of resources) {
|
||||
if (!allowedResources.includes(resource)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ import { CaptureConsole, Dedupe, Offline } from "@sentry/integrations";
|
||||
import * as Sentry from "@sentry/electron";
|
||||
import { sentryDsn, isProduction } from "./vars";
|
||||
import { UserStore } from "./user-store";
|
||||
import logger from "../main/logger";
|
||||
import { inspect } from "util";
|
||||
|
||||
/**
|
||||
* "Translate" 'browser' to 'main' as Lens developer more familiar with the term 'main'
|
||||
@ -51,10 +51,13 @@ export function SentryInit() {
|
||||
return event;
|
||||
}
|
||||
|
||||
logger.info(`🔒 [SENTRY-BEFORE-SEND-HOOK]: allowErrorReporting: ${allowErrorReporting}. Sentry event is caught but not sent to server.`);
|
||||
logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ===");
|
||||
logger.info(event);
|
||||
logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ===");
|
||||
/**
|
||||
* Directly write to stdout so that no other integrations capture this and create an infinite loop
|
||||
*/
|
||||
process.stdout.write(`🔒 [SENTRY-BEFORE-SEND-HOOK]: allowErrorReporting: ${allowErrorReporting}. Sentry event is caught but not sent to server.`);
|
||||
process.stdout.write("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ===");
|
||||
process.stdout.write(inspect(event, false, null, true));
|
||||
process.stdout.write("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ===");
|
||||
|
||||
// if return null, the event won't be sent
|
||||
// ref https://github.com/getsentry/sentry-javascript/issues/2039
|
||||
@ -64,12 +67,11 @@ export function SentryInit() {
|
||||
integrations: [
|
||||
new CaptureConsole({ levels: ["error"] }),
|
||||
new Dedupe(),
|
||||
new Offline()
|
||||
new Offline(),
|
||||
],
|
||||
initialScope: {
|
||||
tags: {
|
||||
|
||||
"process": processName
|
||||
"process": processName,
|
||||
}
|
||||
},
|
||||
environment: isProduction ? "production" : "development",
|
||||
|
||||
46
src/common/utils/__tests__/cluster-id-url-parsing.test.ts
Normal file
46
src/common/utils/__tests__/cluster-id-url-parsing.test.ts
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { getClusterIdFromHost } from "../cluster-id-url-parsing";
|
||||
|
||||
describe("getClusterIdFromHost", () => {
|
||||
const clusterFakeId = "fe540901-0bd6-4f6c-b472-bce1559d7c4a";
|
||||
|
||||
it("should return undefined for non cluster frame hosts", () => {
|
||||
expect(getClusterIdFromHost("localhost:45345")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return ClusterId for cluster frame hosts", () => {
|
||||
expect(getClusterIdFromHost(`${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
});
|
||||
|
||||
it("should return ClusterId for cluster frame hosts with additional subdomains", () => {
|
||||
expect(getClusterIdFromHost(`abc.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.vwx.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.vwx.yz.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId);
|
||||
});
|
||||
});
|
||||
41
src/common/utils/allowed-resource.ts
Normal file
41
src/common/utils/allowed-resource.ts
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { ClusterStore } from "../cluster-store";
|
||||
import type { KubeResource } from "../rbac";
|
||||
import { getHostedClusterId } from "./cluster-id-url-parsing";
|
||||
|
||||
export function isAllowedResource(resource: KubeResource | KubeResource[]) {
|
||||
const resources = [resource].flat();
|
||||
const cluster = ClusterStore.getInstance().getById(getHostedClusterId());
|
||||
|
||||
if (!cluster?.allowedResources) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resources.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const allowedResources = new Set(cluster.allowedResources);
|
||||
|
||||
return resources.every(resource => allowedResources.has(resource));
|
||||
}
|
||||
59
src/common/utils/cluster-id-url-parsing.ts
Normal file
59
src/common/utils/cluster-id-url-parsing.ts
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import type { ClusterId } from "../cluster-types";
|
||||
|
||||
/**
|
||||
* Grab the `ClusterId` out of a host that was generated by `getClusterFrameUrl`, or nothing
|
||||
* @param host The host section of a URL
|
||||
* @returns The `ClusterId` part of the host, or `undefined`
|
||||
*/
|
||||
export function getClusterIdFromHost(host: string): ClusterId | undefined {
|
||||
// e.g host == "%clusterId.localhost:45345"
|
||||
const subDomains = host.split(":")[0].split(".");
|
||||
|
||||
return subDomains.slice(-2, -1)[0]; // ClusterId or undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OpenLens backend routing host for a given `ClusterId`
|
||||
* @param clusterId The ID to put in front of the current host
|
||||
* @returns a new URL host section
|
||||
*/
|
||||
export function getClusterFrameUrl(clusterId: ClusterId) {
|
||||
return `//${clusterId}.${location.host}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of `getClusterIdFromHost` from the current `location.host`
|
||||
*/
|
||||
export function getHostedClusterId(): ClusterId | undefined {
|
||||
return getClusterIdFromHost(location.host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true only if code is running within a cluster iframe context
|
||||
*/
|
||||
export function isClusterPageContext(): boolean {
|
||||
if (typeof window === "undefined") return false;
|
||||
|
||||
return !!getClusterIdFromHost(window.location.host);
|
||||
}
|
||||
@ -31,15 +31,18 @@ export * from "./autobind";
|
||||
export * from "./base64";
|
||||
export * from "./camelCase";
|
||||
export * from "./cloneJson";
|
||||
export * from "./cluster-id-url-parsing";
|
||||
export * from "./debouncePromise";
|
||||
export * from "./defineGlobal";
|
||||
export * from "./delay";
|
||||
export * from "./disposer";
|
||||
export * from "./downloadFile";
|
||||
export * from "./formatDuration";
|
||||
export * from "./escapeRegExp";
|
||||
export * from "./extended-map";
|
||||
export * from "./getRandId";
|
||||
export * from "./hash-set";
|
||||
export * from "./local-kubeconfig";
|
||||
export * from "./n-fircate";
|
||||
export * from "./openExternal";
|
||||
export * from "./paths";
|
||||
@ -51,6 +54,9 @@ export * from "./tar";
|
||||
export * from "./toggle-set";
|
||||
export * from "./toJS";
|
||||
export * from "./type-narrowing";
|
||||
export * from "./types";
|
||||
export * from "./convertMemory";
|
||||
export * from "./convertCpu";
|
||||
|
||||
import * as iter from "./iter";
|
||||
|
||||
|
||||
@ -19,37 +19,15 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
.ClusterStatus {
|
||||
--flex-gap: #{$padding * 2};
|
||||
import { app, remote } from "electron";
|
||||
import path from "path";
|
||||
import * as uuid from "uuid";
|
||||
import type { ClusterId } from "../cluster-types";
|
||||
|
||||
position: relative;
|
||||
min-width: 350px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
|
||||
pre {
|
||||
@include hidden-scrollbar;
|
||||
max-width: 70vw;
|
||||
max-height: 40vh;
|
||||
white-space: pre-line;
|
||||
|
||||
p {
|
||||
margin-bottom: $margin;
|
||||
}
|
||||
}
|
||||
|
||||
.Spinner {
|
||||
--spinner-size: 38px;
|
||||
--spinner-border: calc(var(--spinner-size) / 10);
|
||||
}
|
||||
|
||||
.Icon {
|
||||
--size: 70px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
a.interactive {
|
||||
cursor: pointer
|
||||
}
|
||||
export function storedKubeConfigFolder(): string {
|
||||
return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs");
|
||||
}
|
||||
|
||||
export function getCustomKubeConfigPath(clusterId: ClusterId = uuid.v4()): string {
|
||||
return path.resolve(storedKubeConfigFolder(), clusterId);
|
||||
}
|
||||
26
src/common/utils/types.ts
Normal file
26
src/common/utils/types.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An N length tuple of T
|
||||
*/
|
||||
export type Tuple<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
|
||||
type _TupleOf<T, N extends number, R extends unknown[]> = R["length"] extends N ? R : _TupleOf<T, N, [T, ...R]>;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user