diff --git a/.github/PULL_REQUEST_TEMPLATE/default.md b/.github/PULL_REQUEST_TEMPLATE/default.md deleted file mode 100644 index a54a6ef38c..0000000000 --- a/.github/PULL_REQUEST_TEMPLATE/default.md +++ /dev/null @@ -1,5 +0,0 @@ -Fixes # - -**Description of changes:** - -- diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 0000000000..0f90478a7c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,16 @@ + + +Fixes # + +**Description of changes:** + +- diff --git a/.github/PULL_REQUEST_TEMPLATE/release.md b/.github/PULL_REQUEST_TEMPLATE/release.md deleted file mode 100644 index 11e5822025..0000000000 --- a/.github/PULL_REQUEST_TEMPLATE/release.md +++ /dev/null @@ -1,13 +0,0 @@ -## Changes since v - -## 🚀 Features - -* - -## 🐛 Bug Fixes - -* - -## 🧰 Maintenance - -* diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 93536874e2..a5e8c4fe73 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -14,6 +14,7 @@ categories: - 'area/ci' - 'area/tests' - 'dependencies' + - 'area/documentation' template: | ## Changes since $PREVIOUS_TAG diff --git a/.github/workflows/license-header.yml b/.github/workflows/license-header.yml index daba6a9ca9..0da2f793df 100644 --- a/.github/workflows/license-header.yml +++ b/.github/workflows/license-header.yml @@ -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 diff --git a/.github/workflows/require-type-labels.yml b/.github/workflows/require-type-labels.yml new file mode 100644 index 0000000000..184ced5e9c --- /dev/null +++ b/.github/workflows/require-type-labels.yml @@ -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" diff --git a/__mocks__/windowMock.ts b/__mocks__/windowMock.ts index baf8fa1a65..6f599d5038 100644 --- a/__mocks__/windowMock.ts +++ b/__mocks__/windowMock.ts @@ -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(), + }); +} diff --git a/extensions/kube-object-event-status/package-lock.json b/extensions/kube-object-event-status/package-lock.json index f3b0fe6669..9dc7b55d28 100644 --- a/extensions/kube-object-event-status/package-lock.json +++ b/extensions/kube-object-event-status/package-lock.json @@ -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": { diff --git a/extensions/kube-object-event-status/package.json b/extensions/kube-object-event-status/package.json index 429bb98827..e8dfe38379 100644 --- a/extensions/kube-object-event-status/package.json +++ b/extensions/kube-object-event-status/package.json @@ -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" } } diff --git a/extensions/node-menu/package-lock.json b/extensions/node-menu/package-lock.json index 3ca2677ed4..cd0820ddd2 100644 --- a/extensions/node-menu/package-lock.json +++ b/extensions/node-menu/package-lock.json @@ -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", diff --git a/extensions/node-menu/package.json b/extensions/node-menu/package.json index dcec7757ec..fdaaee3ae1 100644 --- a/extensions/node-menu/package.json +++ b/extensions/node-menu/package.json @@ -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" } } diff --git a/extensions/pod-menu/package-lock.json b/extensions/pod-menu/package-lock.json index 70154d1055..beea3f16be 100644 --- a/extensions/pod-menu/package-lock.json +++ b/extensions/pod-menu/package-lock.json @@ -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", diff --git a/extensions/pod-menu/package.json b/extensions/pod-menu/package.json index 71ca4c2f3e..959059e5a2 100644 --- a/extensions/pod-menu/package.json +++ b/extensions/pod-menu/package.json @@ -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" } } diff --git a/integration/__tests__/app.tests.ts b/integration/__tests__/app.tests.ts index 7b8ff11435..450f6bd039 100644 --- a/integration/__tests__/app.tests.ts +++ b/integration/__tests__/app.tests.ts @@ -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"); diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index 27a0b508a8..c863903259 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -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); diff --git a/integration/__tests__/command-palette.tests.ts b/integration/__tests__/command-palette.tests.ts index 14e95d1264..4695f48b33 100644 --- a/integration/__tests__/command-palette.tests.ts +++ b/integration/__tests__/command-palette.tests.ts @@ -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..."); diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index d6f633e416..15fec4d20b 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -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 { + 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 diff --git a/package.json b/package.json index ce14895322..b6c81ba3b5 100644 --- a/package.json +++ b/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", diff --git a/src/common/__tests__/cluster-store.test.ts b/src/common/__tests__/cluster-store.test.ts index 6d4198d8d7..620debbb0b 100644 --- a/src/common/__tests__/cluster-store.test.ts +++ b/src/common/__tests__/cluster-store.test.ts @@ -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); - }); -}); diff --git a/src/common/__tests__/hotbar-store.test.ts b/src/common/__tests__/hotbar-store.test.ts index 267fbe3e8e..8207aaafac 100644 --- a/src/common/__tests__/hotbar-store.test.ts +++ b/src/common/__tests__/hotbar-store.test.ts @@ -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(); diff --git a/src/common/base-store.ts b/src/common/base-store.ts index 095e0c1877..c311bd8808 100644 --- a/src/common/base-store.ts +++ b/src/common/base-store.ts @@ -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 extends ConfOptions { syncOptions?: IReactionOptions; @@ -59,12 +61,14 @@ export abstract class BaseStore 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'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'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() { diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index b6e198a213..8e8940c644 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -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 { - 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; - - /** 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 { 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(); removedClusters = observable.map(); @@ -272,22 +179,3 @@ export class ClusterStore extends BaseStore { }); } } - -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()); -} diff --git a/src/common/cluster-types.ts b/src/common/cluster-types.ts new file mode 100644 index 0000000000..705110b895 --- /dev/null +++ b/src/common/cluster-types.ts @@ -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; + +/** + * 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; + +/** + * 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; +} + +/** + * 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; +} diff --git a/src/common/hotbar-store.ts b/src/common/hotbar-store.ts index 0faa165bf7..5bfb1ac73a 100644 --- a/src/common/hotbar-store.ts +++ b/src/common/hotbar-store.ts @@ -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; - -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 { @observable hotbars: Hotbar[] = []; @observable private _activeHotbarId: string; @@ -89,22 +69,22 @@ export class HotbarStore extends BaseStore { return this.hotbarIndex(this.activeHotbarId); } - static getInitialItems() { - return [...Array.from(Array(defaultHotbarCells).fill(null))]; - } - @action protected fromStore(data: Partial = {}) { 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 { } } - 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 { @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 { } @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 { */ @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 { 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; + } } } diff --git a/src/common/hotbar-types.ts b/src/common/hotbar-types.ts new file mode 100644 index 0000000000..f8fc5a225b --- /dev/null +++ b/src/common/hotbar-types.ts @@ -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; + +export interface HotbarCreateOptions { + id?: string; + name: string; + items?: Tuple; +} + +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, + name, + }; +} diff --git a/src/common/ipc/hotbar.ts b/src/common/ipc/hotbar.ts new file mode 100644 index 0000000000..01f91309ca --- /dev/null +++ b/src/common/ipc/hotbar.ts @@ -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"; diff --git a/src/common/ipc/index.ts b/src/common/ipc/index.ts index f412e656e8..13c6af2fcb 100644 --- a/src/common/ipc/index.ts +++ b/src/common/ipc/index.ts @@ -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"; diff --git a/src/renderer/item.store.ts b/src/common/item.store.ts similarity index 100% rename from src/renderer/item.store.ts rename to src/common/item.store.ts diff --git a/src/renderer/api/__tests__/api-manager.test.ts b/src/common/k8s-api/__tests__/api-manager.test.ts similarity index 96% rename from src/renderer/api/__tests__/api-manager.test.ts rename to src/common/k8s-api/__tests__/api-manager.test.ts index 83034d20b6..27c2575341 100644 --- a/src/renderer/api/__tests__/api-manager.test.ts +++ b/src/common/k8s-api/__tests__/api-manager.test.ts @@ -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"; diff --git a/src/renderer/api/__tests__/crd.test.ts b/src/common/k8s-api/__tests__/crd.test.ts similarity index 100% rename from src/renderer/api/__tests__/crd.test.ts rename to src/common/k8s-api/__tests__/crd.test.ts diff --git a/src/renderer/api/__tests__/endpoint.api.test.ts b/src/common/k8s-api/__tests__/endpoint.api.test.ts similarity index 100% rename from src/renderer/api/__tests__/endpoint.api.test.ts rename to src/common/k8s-api/__tests__/endpoint.api.test.ts diff --git a/src/renderer/api/__tests__/kube-api-parse.test.ts b/src/common/k8s-api/__tests__/kube-api-parse.test.ts similarity index 100% rename from src/renderer/api/__tests__/kube-api-parse.test.ts rename to src/common/k8s-api/__tests__/kube-api-parse.test.ts diff --git a/src/renderer/api/__tests__/kube-api.test.ts b/src/common/k8s-api/__tests__/kube-api.test.ts similarity index 84% rename from src/renderer/api/__tests__/kube-api.test.ts rename to src/common/k8s-api/__tests__/kube-api.test.ts index 1eb0199f89..1e1bac05fe 100644 --- a/src/renderer/api/__tests__/kube-api.test.ts +++ b/src/common/k8s-api/__tests__/kube-api.test.ts @@ -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], diff --git a/src/renderer/api/__tests__/kube-object.test.ts b/src/common/k8s-api/__tests__/kube-object.test.ts similarity index 100% rename from src/renderer/api/__tests__/kube-object.test.ts rename to src/common/k8s-api/__tests__/kube-object.test.ts diff --git a/src/renderer/api/__tests__/pods.api.test.ts b/src/common/k8s-api/__tests__/pods.api.test.ts similarity index 100% rename from src/renderer/api/__tests__/pods.api.test.ts rename to src/common/k8s-api/__tests__/pods.api.test.ts diff --git a/src/renderer/api/__tests__/pods.test.ts b/src/common/k8s-api/__tests__/pods.test.ts similarity index 100% rename from src/renderer/api/__tests__/pods.test.ts rename to src/common/k8s-api/__tests__/pods.test.ts diff --git a/src/renderer/api/api-manager.ts b/src/common/k8s-api/api-manager.ts similarity index 66% rename from src/renderer/api/api-manager.ts rename to src/common/k8s-api/api-manager.ts index 1e01bd4cfb..3070f932be 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/common/k8s-api/api-manager.ts @@ -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>(); @@ -48,6 +49,8 @@ export class ApiManager { } registerApi(apiBase: string, api: KubeApi) { + 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, apis: KubeApi[] = [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>(api: string | KubeApi): S | undefined { return this.stores.get(this.resolveApi(api)?.apiBase) as S; } + + lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string { + const { + kind, apiVersion, name, + namespace = parentObject.getNs() + } = ref; + + if (!kind) return ""; + + // search in registered apis by 'kind' & 'apiVersion' + const api = this.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion); + + if (api) { + return api.getUrl({ namespace, name }); + } + + // lookup api by generated resource link + const apiPrefixes = ["/apis", "/api"]; + const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`; + + for (const apiPrefix of apiPrefixes) { + const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource }); + + if (this.getApi(apiLink)) { + return apiLink; + } + } + + // resolve by kind only (hpa's might use refs to older versions of resources for example) + const apiByKind = this.getApi(api => api.kind === kind); + + if (apiByKind) { + return apiByKind.getUrl({ name, namespace }); + } + + // otherwise generate link with default prefix + // resource still might exists in k8s, but api is not registered in the app + return createKubeApiURL({ apiVersion, name, namespace, resource }); + } } export const apiManager = new ApiManager(); diff --git a/src/common/k8s-api/cluster-context.ts b/src/common/k8s-api/cluster-context.ts new file mode 100644 index 0000000000..596e658bde --- /dev/null +++ b/src/common/k8s-api/cluster-context.ts @@ -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) +} diff --git a/src/renderer/api/endpoints/cluster-role-binding.api.ts b/src/common/k8s-api/endpoints/cluster-role-binding.api.ts similarity index 84% rename from src/renderer/api/endpoints/cluster-role-binding.api.ts rename to src/common/k8s-api/endpoints/cluster-role-binding.api.ts index 868f00261a..1508e3716f 100644 --- a/src/renderer/api/endpoints/cluster-role-binding.api.ts +++ b/src/common/k8s-api/endpoints/cluster-role-binding.api.ts @@ -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; + +if (isClusterPageContext()) { + clusterRoleBindingApi = new KubeApi({ + objectConstructor: ClusterRoleBinding, + }); +} + +export { + clusterRoleBindingApi +}; diff --git a/src/renderer/api/endpoints/cluster-role.api.ts b/src/common/k8s-api/endpoints/cluster-role.api.ts similarity index 80% rename from src/renderer/api/endpoints/cluster-role.api.ts rename to src/common/k8s-api/endpoints/cluster-role.api.ts index 55a2f5283d..1478e7dcd1 100644 --- a/src/renderer/api/endpoints/cluster-role.api.ts +++ b/src/common/k8s-api/endpoints/cluster-role.api.ts @@ -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; + +if (isClusterPageContext()) { // initialize automatically only when within a cluster iframe/context + clusterRoleApi = new KubeApi({ + objectConstructor: ClusterRole, + }); +} + +export { + clusterRoleApi +}; diff --git a/src/renderer/api/endpoints/cluster.api.ts b/src/common/k8s-api/endpoints/cluster.api.ts similarity index 90% rename from src/renderer/api/endpoints/cluster.api.ts rename to src/common/k8s-api/endpoints/cluster.api.ts index f0879fa501..66fc1a8c5f 100644 --- a/src/renderer/api/endpoints/cluster.api.ts +++ b/src/common/k8s-api/endpoints/cluster.api.ts @@ -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 { 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 +}; diff --git a/src/renderer/api/endpoints/component-status.api.ts b/src/common/k8s-api/endpoints/component-status.api.ts similarity index 100% rename from src/renderer/api/endpoints/component-status.api.ts rename to src/common/k8s-api/endpoints/component-status.api.ts diff --git a/src/renderer/api/endpoints/configmap.api.ts b/src/common/k8s-api/endpoints/configmap.api.ts similarity index 82% rename from src/renderer/api/endpoints/configmap.api.ts rename to src/common/k8s-api/endpoints/configmap.api.ts index 5087f352ca..153e1a3169 100644 --- a/src/renderer/api/endpoints/configmap.api.ts +++ b/src/common/k8s-api/endpoints/configmap.api.ts @@ -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; + +if (isClusterPageContext()) { + configMapApi = new KubeApi({ + objectConstructor: ConfigMap, + }); +} + +export { + configMapApi +}; diff --git a/src/renderer/api/endpoints/crd.api.ts b/src/common/k8s-api/endpoints/crd.api.ts similarity index 91% rename from src/renderer/api/endpoints/crd.api.ts rename to src/common/k8s-api/endpoints/crd.api.ts index 35f85b8832..b1ab179cc4 100644 --- a/src/renderer/api/endpoints/crd.api.ts +++ b/src/common/k8s-api/endpoints/crd.api.ts @@ -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({ - objectConstructor: CustomResourceDefinition, - checkPreferredVersion: true, -}); +/** + * Only available within kubernetes cluster pages + */ +let crdApi: KubeApi; + +if (isClusterPageContext()) { + crdApi = new KubeApi({ + objectConstructor: CustomResourceDefinition, + checkPreferredVersion: true, + }); +} + +export { + crdApi +}; diff --git a/src/renderer/api/endpoints/cron-job.api.ts b/src/common/k8s-api/endpoints/cron-job.api.ts similarity index 93% rename from src/renderer/api/endpoints/cron-job.api.ts rename to src/common/k8s-api/endpoints/cron-job.api.ts index 43743b2bb4..85936e4d32 100644 --- a/src/renderer/api/endpoints/cron-job.api.ts +++ b/src/common/k8s-api/endpoints/cron-job.api.ts @@ -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 { 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 +}; diff --git a/src/renderer/api/endpoints/daemon-set.api.ts b/src/common/k8s-api/endpoints/daemon-set.api.ts similarity index 92% rename from src/renderer/api/endpoints/daemon-set.api.ts rename to src/common/k8s-api/endpoints/daemon-set.api.ts index cb584806d4..4cd3eff4f4 100644 --- a/src/renderer/api/endpoints/daemon-set.api.ts +++ b/src/common/k8s-api/endpoints/daemon-set.api.ts @@ -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 +}; diff --git a/src/renderer/api/endpoints/deployment.api.ts b/src/common/k8s-api/endpoints/deployment.api.ts similarity index 96% rename from src/renderer/api/endpoints/deployment.api.ts rename to src/common/k8s-api/endpoints/deployment.api.ts index 0d5bef48dd..dd364ab6c2 100644 --- a/src/renderer/api/endpoints/deployment.api.ts +++ b/src/common/k8s-api/endpoints/deployment.api.ts @@ -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 { 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 +}; diff --git a/src/renderer/api/endpoints/endpoint.api.ts b/src/common/k8s-api/endpoints/endpoint.api.ts similarity index 93% rename from src/renderer/api/endpoints/endpoint.api.ts rename to src/common/k8s-api/endpoints/endpoint.api.ts index 14bc399062..e6dceb2b8f 100644 --- a/src/renderer/api/endpoints/endpoint.api.ts +++ b/src/common/k8s-api/endpoints/endpoint.api.ts @@ -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; + +if (isClusterPageContext()) { + endpointApi = new KubeApi({ + objectConstructor: Endpoint, + }); +} + +export { + endpointApi +}; diff --git a/src/renderer/api/endpoints/events.api.ts b/src/common/k8s-api/endpoints/events.api.ts similarity index 90% rename from src/renderer/api/endpoints/events.api.ts rename to src/common/k8s-api/endpoints/events.api.ts index ad194a532a..f6b954be6b 100644 --- a/src/renderer/api/endpoints/events.api.ts +++ b/src/common/k8s-api/endpoints/events.api.ts @@ -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; + +if (isClusterPageContext()) { + eventApi = new KubeApi({ + objectConstructor: KubeEvent, + }); +} + +export { + eventApi +}; diff --git a/src/renderer/api/endpoints/helm-charts.api.ts b/src/common/k8s-api/endpoints/helm-charts.api.ts similarity index 98% rename from src/renderer/api/endpoints/helm-charts.api.ts rename to src/common/k8s-api/endpoints/helm-charts.api.ts index 2244bca1f2..c7bc662b75 100644 --- a/src/renderer/api/endpoints/helm-charts.api.ts +++ b/src/common/k8s-api/endpoints/helm-charts.api.ts @@ -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; export type HelmChartList = Record; diff --git a/src/renderer/api/endpoints/helm-releases.api.ts b/src/common/k8s-api/endpoints/helm-releases.api.ts similarity index 97% rename from src/renderer/api/endpoints/helm-releases.api.ts rename to src/common/k8s-api/endpoints/helm-releases.api.ts index 9a4a05875c..301e077e4e 100644 --- a/src/renderer/api/endpoints/helm-releases.api.ts +++ b/src/common/k8s-api/endpoints/helm-releases.api.ts @@ -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 { diff --git a/src/renderer/api/endpoints/hpa.api.ts b/src/common/k8s-api/endpoints/hpa.api.ts similarity index 94% rename from src/renderer/api/endpoints/hpa.api.ts rename to src/common/k8s-api/endpoints/hpa.api.ts index dba89d4111..4a217d23f1 100644 --- a/src/renderer/api/endpoints/hpa.api.ts +++ b/src/common/k8s-api/endpoints/hpa.api.ts @@ -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; + +if (isClusterPageContext()) { + hpaApi = new KubeApi({ + objectConstructor: HorizontalPodAutoscaler, + }); +} + +export { + hpaApi +}; diff --git a/src/renderer/api/endpoints/index.ts b/src/common/k8s-api/endpoints/index.ts similarity index 100% rename from src/renderer/api/endpoints/index.ts rename to src/common/k8s-api/endpoints/index.ts diff --git a/src/renderer/api/endpoints/ingress.api.ts b/src/common/k8s-api/endpoints/ingress.api.ts similarity index 93% rename from src/renderer/api/endpoints/ingress.api.ts rename to src/common/k8s-api/endpoints/ingress.api.ts index 31745f30c4..5a1a404f20 100644 --- a/src/renderer/api/endpoints/ingress.api.ts +++ b/src/common/k8s-api/endpoints/ingress.api.ts @@ -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 { } @@ -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 +}; diff --git a/src/renderer/api/endpoints/job.api.ts b/src/common/k8s-api/endpoints/job.api.ts similarity index 95% rename from src/renderer/api/endpoints/job.api.ts rename to src/common/k8s-api/endpoints/job.api.ts index 823a04bef9..539e3dc902 100644 --- a/src/renderer/api/endpoints/job.api.ts +++ b/src/common/k8s-api/endpoints/job.api.ts @@ -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 +}; diff --git a/src/renderer/api/endpoints/limit-range.api.ts b/src/common/k8s-api/endpoints/limit-range.api.ts similarity index 90% rename from src/renderer/api/endpoints/limit-range.api.ts rename to src/common/k8s-api/endpoints/limit-range.api.ts index 82b02cfa70..3c41aca1a1 100644 --- a/src/renderer/api/endpoints/limit-range.api.ts +++ b/src/common/k8s-api/endpoints/limit-range.api.ts @@ -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; + +if (isClusterPageContext()) { + limitRangeApi = new KubeApi({ + objectConstructor: LimitRange, + }); +} + +export { + limitRangeApi +}; diff --git a/src/renderer/api/endpoints/metrics.api.ts b/src/common/k8s-api/endpoints/metrics.api.ts similarity index 100% rename from src/renderer/api/endpoints/metrics.api.ts rename to src/common/k8s-api/endpoints/metrics.api.ts diff --git a/src/renderer/api/endpoints/namespaces.api.ts b/src/common/k8s-api/endpoints/namespaces.api.ts similarity index 88% rename from src/renderer/api/endpoints/namespaces.api.ts rename to src/common/k8s-api/endpoints/namespaces.api.ts index 208edb023f..f973ceb1b6 100644 --- a/src/renderer/api/endpoints/namespaces.api.ts +++ b/src/common/k8s-api/endpoints/namespaces.api.ts @@ -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 +}; diff --git a/src/renderer/api/endpoints/network-policy.api.ts b/src/common/k8s-api/endpoints/network-policy.api.ts similarity index 90% rename from src/renderer/api/endpoints/network-policy.api.ts rename to src/common/k8s-api/endpoints/network-policy.api.ts index 03a06b7c42..026aa0b047 100644 --- a/src/renderer/api/endpoints/network-policy.api.ts +++ b/src/common/k8s-api/endpoints/network-policy.api.ts @@ -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; + +if (isClusterPageContext()) { + networkPolicyApi = new KubeApi({ + objectConstructor: NetworkPolicy, + }); +} + +export { + networkPolicyApi +}; diff --git a/src/renderer/api/endpoints/nodes.api.ts b/src/common/k8s-api/endpoints/nodes.api.ts similarity index 96% rename from src/renderer/api/endpoints/nodes.api.ts rename to src/common/k8s-api/endpoints/nodes.api.ts index 21f7776c58..2705eeb1dd 100644 --- a/src/renderer/api/endpoints/nodes.api.ts +++ b/src/common/k8s-api/endpoints/nodes.api.ts @@ -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 { } @@ -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 +}; diff --git a/src/renderer/api/endpoints/persistent-volume-claims.api.ts b/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts similarity index 93% rename from src/renderer/api/endpoints/persistent-volume-claims.api.ts rename to src/common/k8s-api/endpoints/persistent-volume-claims.api.ts index 356122569a..1ac5d8df9a 100644 --- a/src/renderer/api/endpoints/persistent-volume-claims.api.ts +++ b/src/common/k8s-api/endpoints/persistent-volume-claims.api.ts @@ -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 { } @@ -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 +}; diff --git a/src/renderer/api/endpoints/persistent-volume.api.ts b/src/common/k8s-api/endpoints/persistent-volume.api.ts similarity index 89% rename from src/renderer/api/endpoints/persistent-volume.api.ts rename to src/common/k8s-api/endpoints/persistent-volume.api.ts index e71c355977..3a7a10ea6c 100644 --- a/src/renderer/api/endpoints/persistent-volume.api.ts +++ b/src/common/k8s-api/endpoints/persistent-volume.api.ts @@ -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; + +if (isClusterPageContext()) { + persistentVolumeApi = new KubeApi({ + objectConstructor: PersistentVolume, + }); +} + +export { + persistentVolumeApi +}; diff --git a/src/renderer/api/endpoints/pod-metrics.api.ts b/src/common/k8s-api/endpoints/pod-metrics.api.ts similarity index 85% rename from src/renderer/api/endpoints/pod-metrics.api.ts rename to src/common/k8s-api/endpoints/pod-metrics.api.ts index 191a128267..8d89f306b1 100644 --- a/src/renderer/api/endpoints/pod-metrics.api.ts +++ b/src/common/k8s-api/endpoints/pod-metrics.api.ts @@ -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; + +if (isClusterPageContext()) { + podMetricsApi = new KubeApi({ + objectConstructor: PodMetrics, + }); +} + +export { + podMetricsApi +}; diff --git a/src/renderer/api/endpoints/poddisruptionbudget.api.ts b/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts similarity index 90% rename from src/renderer/api/endpoints/poddisruptionbudget.api.ts rename to src/common/k8s-api/endpoints/poddisruptionbudget.api.ts index daa16933da..1e57c1a3ec 100644 --- a/src/renderer/api/endpoints/poddisruptionbudget.api.ts +++ b/src/common/k8s-api/endpoints/poddisruptionbudget.api.ts @@ -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; + +if (isClusterPageContext()) { + pdbApi = new KubeApi({ + objectConstructor: PodDisruptionBudget, + }); +} + +export { + pdbApi +}; diff --git a/src/renderer/api/endpoints/pods.api.ts b/src/common/k8s-api/endpoints/pods.api.ts similarity index 98% rename from src/renderer/api/endpoints/pods.api.ts rename to src/common/k8s-api/endpoints/pods.api.ts index e4d33c75bc..f002260de4 100644 --- a/src/renderer/api/endpoints/pods.api.ts +++ b/src/common/k8s-api/endpoints/pods.api.ts @@ -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 { async getLogs(params: { namespace: string; name: string }, query?: IPodLogsQuery): Promise { @@ -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 +}; diff --git a/src/renderer/api/endpoints/podsecuritypolicy.api.ts b/src/common/k8s-api/endpoints/podsecuritypolicy.api.ts similarity index 93% rename from src/renderer/api/endpoints/podsecuritypolicy.api.ts rename to src/common/k8s-api/endpoints/podsecuritypolicy.api.ts index eac827ffcc..c1b29f3c6e 100644 --- a/src/renderer/api/endpoints/podsecuritypolicy.api.ts +++ b/src/common/k8s-api/endpoints/podsecuritypolicy.api.ts @@ -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; + +if (isClusterPageContext()) { + pspApi = new KubeApi({ + objectConstructor: PodSecurityPolicy, + }); +} + +export { + pspApi +}; diff --git a/src/renderer/api/endpoints/replica-set.api.ts b/src/common/k8s-api/endpoints/replica-set.api.ts similarity index 92% rename from src/renderer/api/endpoints/replica-set.api.ts rename to src/common/k8s-api/endpoints/replica-set.api.ts index 4632e1bfad..eeaf361557 100644 --- a/src/renderer/api/endpoints/replica-set.api.ts +++ b/src/common/k8s-api/endpoints/replica-set.api.ts @@ -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 { 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 +}; diff --git a/src/renderer/api/endpoints/resource-applier.api.ts b/src/common/k8s-api/endpoints/resource-applier.api.ts similarity index 71% rename from src/renderer/api/endpoints/resource-applier.api.ts rename to src/common/k8s-api/endpoints/resource-applier.api.ts index b10c10f7db..b6a35d3a60 100644 --- a/src/renderer/api/endpoints/resource-applier.api.ts +++ b/src/common/k8s-api/endpoints/resource-applier.api.ts @@ -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(resource: object | string): Promise { + async update(resource: object | string): Promise { if (typeof resource === "string") { resource = jsYaml.safeLoad(resource); } - return apiBase - .post("/stack", { data: resource }) - .then(data => { - const items = data.map(obj => { - const api = apiManager.getApiByKind(obj.kind, obj.apiVersion); + const [data = null] = await apiBase.post("/stack", { data: resource }); - if (api) { - return new api.objectConstructor(obj); - } else { - return new KubeObject(obj); - } - }); - - return items[0] as K ?? null; - }); + return data; } }; diff --git a/src/renderer/api/endpoints/resource-quota.api.ts b/src/common/k8s-api/endpoints/resource-quota.api.ts similarity index 90% rename from src/renderer/api/endpoints/resource-quota.api.ts rename to src/common/k8s-api/endpoints/resource-quota.api.ts index 762c6682e1..3f6493aa01 100644 --- a/src/renderer/api/endpoints/resource-quota.api.ts +++ b/src/common/k8s-api/endpoints/resource-quota.api.ts @@ -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; + +if (isClusterPageContext()) { + resourceQuotaApi = new KubeApi({ + objectConstructor: ResourceQuota, + }); +} + +export { + resourceQuotaApi +}; diff --git a/src/renderer/api/endpoints/role-binding.api.ts b/src/common/k8s-api/endpoints/role-binding.api.ts similarity index 89% rename from src/renderer/api/endpoints/role-binding.api.ts rename to src/common/k8s-api/endpoints/role-binding.api.ts index c8c83d3151..df6b0c7bc5 100644 --- a/src/renderer/api/endpoints/role-binding.api.ts +++ b/src/common/k8s-api/endpoints/role-binding.api.ts @@ -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; + +if (isClusterPageContext()) { + roleBindingApi = new KubeApi({ + objectConstructor: RoleBinding, + }); +} + +export { + roleBindingApi +}; diff --git a/src/renderer/api/endpoints/role.api.ts b/src/common/k8s-api/endpoints/role.api.ts similarity index 87% rename from src/renderer/api/endpoints/role.api.ts rename to src/common/k8s-api/endpoints/role.api.ts index b504c7fc8b..f9c0be19fb 100644 --- a/src/renderer/api/endpoints/role.api.ts +++ b/src/common/k8s-api/endpoints/role.api.ts @@ -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; + +if (isClusterPageContext()) { + roleApi = new KubeApi({ + objectConstructor: Role, + }); +} + +export{ + roleApi +}; diff --git a/src/renderer/api/endpoints/secret.api.ts b/src/common/k8s-api/endpoints/secret.api.ts similarity index 90% rename from src/renderer/api/endpoints/secret.api.ts rename to src/common/k8s-api/endpoints/secret.api.ts index 5ddd0e1db3..99200933ff 100644 --- a/src/renderer/api/endpoints/secret.api.ts +++ b/src/common/k8s-api/endpoints/secret.api.ts @@ -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; + +if (isClusterPageContext()) { + secretsApi = new KubeApi({ + objectConstructor: Secret, + }); +} + +export { + secretsApi +}; diff --git a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts b/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts similarity index 89% rename from src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts rename to src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts index 84c27f21cb..799abec798 100644 --- a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts +++ b/src/common/k8s-api/endpoints/selfsubjectrulesreviews.api.ts @@ -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 { create({ namespace = "default" }): Promise { @@ -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 +}; + diff --git a/src/renderer/api/endpoints/service-accounts.api.ts b/src/common/k8s-api/endpoints/service-accounts.api.ts similarity index 86% rename from src/renderer/api/endpoints/service-accounts.api.ts rename to src/common/k8s-api/endpoints/service-accounts.api.ts index 6cc9d292ba..678541afe4 100644 --- a/src/renderer/api/endpoints/service-accounts.api.ts +++ b/src/common/k8s-api/endpoints/service-accounts.api.ts @@ -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({ - objectConstructor: ServiceAccount, -}); +let serviceAccountsApi: KubeApi; + +if (isClusterPageContext()) { + serviceAccountsApi = new KubeApi({ + objectConstructor: ServiceAccount, + }); +} + +export { + serviceAccountsApi +}; diff --git a/src/renderer/api/endpoints/service.api.ts b/src/common/k8s-api/endpoints/service.api.ts similarity index 92% rename from src/renderer/api/endpoints/service.api.ts rename to src/common/k8s-api/endpoints/service.api.ts index e9a6b9b40f..e5af9de828 100644 --- a/src/renderer/api/endpoints/service.api.ts +++ b/src/common/k8s-api/endpoints/service.api.ts @@ -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; + +if (isClusterPageContext()) { + serviceApi = new KubeApi({ + objectConstructor: Service, + }); +} + +export { + serviceApi +}; diff --git a/src/renderer/api/endpoints/stateful-set.api.ts b/src/common/k8s-api/endpoints/stateful-set.api.ts similarity index 94% rename from src/renderer/api/endpoints/stateful-set.api.ts rename to src/common/k8s-api/endpoints/stateful-set.api.ts index 21f4c6e02e..ee47fa6a24 100644 --- a/src/renderer/api/endpoints/stateful-set.api.ts +++ b/src/common/k8s-api/endpoints/stateful-set.api.ts @@ -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 { 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 +}; diff --git a/src/renderer/api/endpoints/storage-class.api.ts b/src/common/k8s-api/endpoints/storage-class.api.ts similarity index 89% rename from src/renderer/api/endpoints/storage-class.api.ts rename to src/common/k8s-api/endpoints/storage-class.api.ts index 226e3ab477..3b44a2e124 100644 --- a/src/renderer/api/endpoints/storage-class.api.ts +++ b/src/common/k8s-api/endpoints/storage-class.api.ts @@ -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; + +if (isClusterPageContext()) { + storageClassApi = new KubeApi({ + objectConstructor: StorageClass, + }); +} + +export { + storageClassApi +}; diff --git a/src/common/k8s-api/index.ts b/src/common/k8s-api/index.ts new file mode 100644 index 0000000000..791ee09285 --- /dev/null +++ b/src/common/k8s-api/index.ts @@ -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 +}; diff --git a/src/renderer/api/json-api.ts b/src/common/k8s-api/json-api.ts similarity index 85% rename from src/renderer/api/json-api.ts rename to src/common/k8s-api/json-api.ts index 0060259c76..5ebd30650d 100644 --- a/src/renderer/api/json-api.ts +++ b/src/common/k8s-api/json-api.ts @@ -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 { static reqInitDefault: RequestInit = { headers: { @@ -63,9 +65,9 @@ export class JsonApi { 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 { } getResponse(path: string, params?: P, init: RequestInit = {}): Promise { - 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 { this.writeLog({ method: reqInit.method.toUpperCase(), - reqUrl: reqPath, + reqUrl, reqInit, }); @@ -119,8 +119,8 @@ export class JsonApi { } protected async request(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 { } 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); } } diff --git a/src/renderer/api/kube-api-parse.ts b/src/common/k8s-api/kube-api-parse.ts similarity index 76% rename from src/renderer/api/kube-api-parse.ts rename to src/common/k8s-api/kube-api-parse.ts index 689a6b9858..57c835ed6b 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/common/k8s-api/kube-api-parse.ts @@ -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 }); -} diff --git a/src/renderer/api/kube-api.ts b/src/common/k8s-api/kube-api.ts similarity index 94% rename from src/renderer/api/kube-api.ts rename to src/common/k8s-api/kube-api.ts index 20c4672727..1131119a3b 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/common/k8s-api/kube-api.ts @@ -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 { /** @@ -56,11 +57,6 @@ export interface IKubeApiOptions { 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(cluster: IKubeApiCluster, kubeClass: KubeObjectConstructor): KubeApi { 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 { 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 { } } 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 { }); 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 { 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 { }); }); - byline(nodeStream).on("data", (line) => { + byline(response.body).on("data", (line) => { try { const event: IKubeWatchEvent = JSON.parse(line); @@ -479,7 +464,7 @@ export class KubeApi { }); }) .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 { } } } - -export * from "./kube-api-parse"; diff --git a/src/renderer/api/kube-json-api.ts b/src/common/k8s-api/kube-json-api.ts similarity index 98% rename from src/renderer/api/kube-json-api.ts rename to src/common/k8s-api/kube-json-api.ts index ebb01b696c..2e6e892b21 100644 --- a/src/renderer/api/kube-json-api.ts +++ b/src/common/k8s-api/kube-json-api.ts @@ -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 { return super.parseError(error, res); } } + diff --git a/src/renderer/kube-object.store.ts b/src/common/k8s-api/kube-object.store.ts similarity index 93% rename from src/renderer/kube-object.store.ts rename to src/common/k8s-api/kube-object.store.ts index 14dbbc6152..3215306d93 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/common/k8s-api/kube-object.store.ts @@ -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 { namespaces: string[]; @@ -192,9 +194,6 @@ export abstract class KubeObjectStore extends ItemStore 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 extends ItemStore } async update(item: T, data: Partial): Promise { - 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 extends ItemStore const { signal } = abortController; const callback = (data: IKubeWatchEvent, 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) { diff --git a/src/renderer/api/kube-object.ts b/src/common/k8s-api/kube-object.ts similarity index 97% rename from src/renderer/api/kube-object.ts rename to src/common/k8s-api/kube-object.ts index 2548cac3aa..c1e40eb2e5 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/common/k8s-api/kube-object.ts @@ -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 implements ItemObject { @@ -277,14 +287,14 @@ export class KubeObject(data: Partial): Promise { + async update(data: Partial): Promise { 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({ + return resourceApplierApi.update({ ...this.toPlainObject(), ...data, }); diff --git a/src/renderer/api/kube-watch-api.ts b/src/common/k8s-api/kube-watch-api.ts similarity index 96% rename from src/renderer/api/kube-watch-api.ts rename to src/common/k8s-api/kube-watch-api.ts index 4d316b5caa..5ce16dcfbd 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/common/k8s-api/kube-watch-api.ts @@ -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 { diff --git a/src/renderer/api/workload-kube-object.ts b/src/common/k8s-api/workload-kube-object.ts similarity index 100% rename from src/renderer/api/workload-kube-object.ts rename to src/common/k8s-api/workload-kube-object.ts diff --git a/src/common/logger.ts b/src/common/logger.ts new file mode 100644 index 0000000000..57f12ce4e9 --- /dev/null +++ b/src/common/logger.ts @@ -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; diff --git a/src/common/rbac.ts b/src/common/rbac.ts index 9d8242cd42..817d22b50a 100644 --- a/src/common/rbac.ts +++ b/src/common/rbac.ts @@ -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 = { // 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; -} diff --git a/src/common/sentry.ts b/src/common/sentry.ts index da0e749994..06bef321d1 100644 --- a/src/common/sentry.ts +++ b/src/common/sentry.ts @@ -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", diff --git a/src/common/utils/__tests__/cluster-id-url-parsing.test.ts b/src/common/utils/__tests__/cluster-id-url-parsing.test.ts new file mode 100644 index 0000000000..7b65fb27fa --- /dev/null +++ b/src/common/utils/__tests__/cluster-id-url-parsing.test.ts @@ -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); + }); +}); diff --git a/src/renderer/utils/__tests__/formatDuration.test.ts b/src/common/utils/__tests__/formatDuration.test.ts similarity index 100% rename from src/renderer/utils/__tests__/formatDuration.test.ts rename to src/common/utils/__tests__/formatDuration.test.ts diff --git a/src/common/utils/allowed-resource.ts b/src/common/utils/allowed-resource.ts new file mode 100644 index 0000000000..d8d3676f17 --- /dev/null +++ b/src/common/utils/allowed-resource.ts @@ -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)); +} diff --git a/src/common/utils/cluster-id-url-parsing.ts b/src/common/utils/cluster-id-url-parsing.ts new file mode 100644 index 0000000000..e692bc4595 --- /dev/null +++ b/src/common/utils/cluster-id-url-parsing.ts @@ -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); +} diff --git a/src/renderer/utils/convertCpu.ts b/src/common/utils/convertCpu.ts similarity index 100% rename from src/renderer/utils/convertCpu.ts rename to src/common/utils/convertCpu.ts diff --git a/src/renderer/utils/convertMemory.ts b/src/common/utils/convertMemory.ts similarity index 100% rename from src/renderer/utils/convertMemory.ts rename to src/common/utils/convertMemory.ts diff --git a/src/renderer/utils/formatDuration.ts b/src/common/utils/formatDuration.ts similarity index 100% rename from src/renderer/utils/formatDuration.ts rename to src/common/utils/formatDuration.ts diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 1644c07f36..3d7f4f9838 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -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"; diff --git a/src/renderer/components/cluster-manager/cluster-status.scss b/src/common/utils/local-kubeconfig.ts similarity index 69% rename from src/renderer/components/cluster-manager/cluster-status.scss rename to src/common/utils/local-kubeconfig.ts index 77d6e7693f..04ab27bfa4 100644 --- a/src/renderer/components/cluster-manager/cluster-status.scss +++ b/src/common/utils/local-kubeconfig.ts @@ -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); } diff --git a/src/renderer/utils/readableStream.ts b/src/common/utils/readableStream.ts similarity index 100% rename from src/renderer/utils/readableStream.ts rename to src/common/utils/readableStream.ts diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts new file mode 100644 index 0000000000..9fa3c580b9 --- /dev/null +++ b/src/common/utils/types.ts @@ -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 = N extends N ? number extends N ? T[] : _TupleOf : never; +type _TupleOf = R["length"] extends N ? R : _TupleOf; diff --git a/src/common/vars.ts b/src/common/vars.ts index 0dea82cab6..dec81f313e 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -42,6 +42,7 @@ export const publicPath = "/build/" as string; // Webpack build paths export const contextDir = process.cwd(); export const buildDir = path.join(contextDir, "static", publicPath); +export const preloadEntrypoint = path.join(contextDir, "src/preload.ts"); export const mainDir = path.join(contextDir, "src/main"); export const rendererDir = path.join(contextDir, "src/renderer"); export const htmlTemplate = path.resolve(rendererDir, "template.html"); diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index af69a6bef8..321ab80259 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -24,9 +24,9 @@ import { EventEmitter } from "events"; import { isEqual } from "lodash"; import { action, computed, makeObservable, observable, observe, reaction, when } from "mobx"; import path from "path"; -import { getHostedCluster } from "../common/cluster-store"; +import { ClusterStore } from "../common/cluster-store"; import { broadcastMessage, ipcMainOn, ipcRendererOn, requestMain, ipcMainHandle } from "../common/ipc"; -import { Disposer, Singleton, toJS } from "../common/utils"; +import { Disposer, getHostedClusterId, Singleton, toJS } from "../common/utils"; import logger from "../main/logger"; import type { InstalledExtension } from "./extension-discovery"; import { ExtensionsStore } from "./extensions-store"; @@ -296,7 +296,7 @@ export class ExtensionLoader extends Singleton { loadOnClusterRenderer() { logger.debug(`${logModule}: load on cluster renderer (dashboard)`); - const cluster = getHostedCluster(); + const cluster = ClusterStore.getInstance().getById(getHostedClusterId()); this.autoInitExtensions(async (extension: LensRendererExtension) => { if ((await extension.isEnabledForCluster(cluster)) === false) { diff --git a/src/extensions/main-api/index.ts b/src/extensions/main-api/index.ts index a596e8169e..012ff0ebde 100644 --- a/src/extensions/main-api/index.ts +++ b/src/extensions/main-api/index.ts @@ -21,12 +21,14 @@ import * as Catalog from "./catalog"; import * as Navigation from "./navigation"; +import * as K8sApi from "./k8s-api"; import { IpcMain as Ipc } from "../ipc/ipc-main"; import { LensMainExtension as LensExtension } from "../lens-main-extension"; export { Catalog, Navigation, + K8sApi, Ipc, LensExtension, }; diff --git a/src/extensions/main-api/k8s-api.ts b/src/extensions/main-api/k8s-api.ts new file mode 100644 index 0000000000..991415cc56 --- /dev/null +++ b/src/extensions/main-api/k8s-api.ts @@ -0,0 +1,60 @@ +/** + * 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 { isAllowedResource } from "../../common/utils/allowed-resource"; +export { ResourceStack } from "../../common/k8s/resource-stack"; +export { apiManager } from "../../common/k8s-api/api-manager"; +export { KubeApi, forCluster } from "../../common/k8s-api/kube-api"; +export { KubeObject } from "../../common/k8s-api/kube-object"; +export { Pod, podsApi, PodsApi } from "../../common/k8s-api/endpoints/pods.api"; +export { Node, nodesApi, NodesApi } from "../../common/k8s-api/endpoints/nodes.api"; +export { Deployment, deploymentApi, DeploymentApi } from "../../common/k8s-api/endpoints/deployment.api"; +export { DaemonSet, daemonSetApi } from "../../common/k8s-api/endpoints/daemon-set.api"; +export { StatefulSet, statefulSetApi } from "../../common/k8s-api/endpoints/stateful-set.api"; +export { Job, jobApi } from "../../common/k8s-api/endpoints/job.api"; +export { CronJob, cronJobApi } from "../../common/k8s-api/endpoints/cron-job.api"; +export { ConfigMap, configMapApi } from "../../common/k8s-api/endpoints/configmap.api"; +export { Secret, secretsApi } from "../../common/k8s-api/endpoints/secret.api"; +export { ReplicaSet, replicaSetApi } from "../../common/k8s-api/endpoints/replica-set.api"; +export { ResourceQuota, resourceQuotaApi } from "../../common/k8s-api/endpoints/resource-quota.api"; +export { LimitRange, limitRangeApi } from "../../common/k8s-api/endpoints/limit-range.api"; +export { HorizontalPodAutoscaler, hpaApi } from "../../common/k8s-api/endpoints/hpa.api"; +export { PodDisruptionBudget, pdbApi } from "../../common/k8s-api/endpoints/poddisruptionbudget.api"; +export { Service, serviceApi } from "../../common/k8s-api/endpoints/service.api"; +export { Endpoint, endpointApi } from "../../common/k8s-api/endpoints/endpoint.api"; +export { Ingress, ingressApi, IngressApi } from "../../common/k8s-api/endpoints/ingress.api"; +export { NetworkPolicy, networkPolicyApi } from "../../common/k8s-api/endpoints/network-policy.api"; +export { PersistentVolume, persistentVolumeApi } from "../../common/k8s-api/endpoints/persistent-volume.api"; +export { PersistentVolumeClaim, pvcApi, PersistentVolumeClaimsApi } from "../../common/k8s-api/endpoints/persistent-volume-claims.api"; +export { StorageClass, storageClassApi } from "../../common/k8s-api/endpoints/storage-class.api"; +export { Namespace, namespacesApi } from "../../common/k8s-api/endpoints/namespaces.api"; +export { KubeEvent, eventApi } from "../../common/k8s-api/endpoints/events.api"; +export { ServiceAccount, serviceAccountsApi } from "../../common/k8s-api/endpoints/service-accounts.api"; +export { Role, roleApi } from "../../common/k8s-api/endpoints/role.api"; +export { RoleBinding, roleBindingApi } from "../../common/k8s-api/endpoints/role-binding.api"; +export { ClusterRole, clusterRoleApi } from "../../common/k8s-api/endpoints/cluster-role.api"; +export { ClusterRoleBinding, clusterRoleBindingApi } from "../../common/k8s-api/endpoints/cluster-role-binding.api"; +export { CustomResourceDefinition, crdApi } from "../../common/k8s-api/endpoints/crd.api"; + +// types +export type { IKubeApiCluster } from "../../common/k8s-api/kube-api"; +export type { IPodContainer, IPodContainerStatus } from "../../common/k8s-api/endpoints/pods.api"; +export type { ISecretRef } from "../../common/k8s-api/endpoints/secret.api"; diff --git a/src/extensions/registries/kube-object-detail-registry.ts b/src/extensions/registries/kube-object-detail-registry.ts index 9df1d094f1..58c807f57a 100644 --- a/src/extensions/registries/kube-object-detail-registry.ts +++ b/src/extensions/registries/kube-object-detail-registry.ts @@ -24,7 +24,7 @@ import type { KubeObjectDetailsProps } from "../renderer-api/components"; import type { KubeObject } from "../renderer-api/k8s-api"; import { BaseRegistry } from "./base-registry"; -export interface KubeObjectDetailComponents { +export interface KubeObjectDetailComponents { Details: React.ComponentType>; } diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index cb4cfd0377..7173b592b3 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -62,7 +62,11 @@ export * from "../../renderer/components/chart/bar-chart"; export * from "../../renderer/components/chart/pie-chart"; // kube helpers -export * from "../../renderer/components/kube-object"; +export * from "../../renderer/components/kube-detail-params"; +export * from "../../renderer/components/kube-object-details"; +export * from "../../renderer/components/kube-object-list-layout"; +export * from "../../renderer/components/kube-object-menu"; +export * from "../../renderer/components/kube-object-meta"; export * from "../../renderer/components/+events/kube-event-details"; // specific exports diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index c579aafbb6..1622dd6f3d 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -19,47 +19,47 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export { isAllowedResource } from "../../common/rbac"; +export { isAllowedResource } from "../../common/utils/allowed-resource"; export { ResourceStack } from "../../common/k8s/resource-stack"; -export { apiManager } from "../../renderer/api/api-manager"; -export { KubeObjectStore } from "../../renderer/kube-object.store"; -export { KubeApi, forCluster } from "../../renderer/api/kube-api"; -export { KubeObject } from "../../renderer/api/kube-object"; -export { Pod, podsApi, PodsApi } from "../../renderer/api/endpoints"; -export { Node, nodesApi, NodesApi } from "../../renderer/api/endpoints"; -export { Deployment, deploymentApi, DeploymentApi } from "../../renderer/api/endpoints"; -export { DaemonSet, daemonSetApi } from "../../renderer/api/endpoints"; -export { StatefulSet, statefulSetApi } from "../../renderer/api/endpoints"; -export { Job, jobApi } from "../../renderer/api/endpoints"; -export { CronJob, cronJobApi } from "../../renderer/api/endpoints"; -export { ConfigMap, configMapApi } from "../../renderer/api/endpoints"; -export { Secret, secretsApi } from "../../renderer/api/endpoints"; -export { ReplicaSet, replicaSetApi } from "../../renderer/api/endpoints"; -export { ResourceQuota, resourceQuotaApi } from "../../renderer/api/endpoints"; -export { LimitRange, limitRangeApi } from "../../renderer/api/endpoints"; -export { HorizontalPodAutoscaler, hpaApi } from "../../renderer/api/endpoints"; -export { PodDisruptionBudget, pdbApi } from "../../renderer/api/endpoints"; -export { Service, serviceApi } from "../../renderer/api/endpoints"; -export { Endpoint, endpointApi } from "../../renderer/api/endpoints"; -export { Ingress, ingressApi, IngressApi } from "../../renderer/api/endpoints"; -export { NetworkPolicy, networkPolicyApi } from "../../renderer/api/endpoints"; -export { PersistentVolume, persistentVolumeApi } from "../../renderer/api/endpoints"; -export { PersistentVolumeClaim, pvcApi, PersistentVolumeClaimsApi } from "../../renderer/api/endpoints"; -export { StorageClass, storageClassApi } from "../../renderer/api/endpoints"; -export { Namespace, namespacesApi } from "../../renderer/api/endpoints"; -export { KubeEvent, eventApi } from "../../renderer/api/endpoints"; -export { ServiceAccount, serviceAccountsApi } from "../../renderer/api/endpoints"; -export { Role, roleApi } from "../../renderer/api/endpoints"; -export { RoleBinding, roleBindingApi } from "../../renderer/api/endpoints"; -export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints"; -export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints"; -export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints"; +export { apiManager } from "../../common/k8s-api/api-manager"; +export { KubeObjectStore } from "../../common/k8s-api/kube-object.store"; +export { KubeApi, forCluster } from "../../common/k8s-api/kube-api"; +export { KubeObject } from "../../common/k8s-api/kube-object"; +export { Pod, podsApi, PodsApi } from "../../common/k8s-api/endpoints"; +export { Node, nodesApi, NodesApi } from "../../common/k8s-api/endpoints"; +export { Deployment, deploymentApi, DeploymentApi } from "../../common/k8s-api/endpoints"; +export { DaemonSet, daemonSetApi } from "../../common/k8s-api/endpoints"; +export { StatefulSet, statefulSetApi } from "../../common/k8s-api/endpoints"; +export { Job, jobApi } from "../../common/k8s-api/endpoints"; +export { CronJob, cronJobApi } from "../../common/k8s-api/endpoints"; +export { ConfigMap, configMapApi } from "../../common/k8s-api/endpoints"; +export { Secret, secretsApi } from "../../common/k8s-api/endpoints"; +export { ReplicaSet, replicaSetApi } from "../../common/k8s-api/endpoints"; +export { ResourceQuota, resourceQuotaApi } from "../../common/k8s-api/endpoints"; +export { LimitRange, limitRangeApi } from "../../common/k8s-api/endpoints"; +export { HorizontalPodAutoscaler, hpaApi } from "../../common/k8s-api/endpoints"; +export { PodDisruptionBudget, pdbApi } from "../../common/k8s-api/endpoints"; +export { Service, serviceApi } from "../../common/k8s-api/endpoints"; +export { Endpoint, endpointApi } from "../../common/k8s-api/endpoints"; +export { Ingress, ingressApi, IngressApi } from "../../common/k8s-api/endpoints"; +export { NetworkPolicy, networkPolicyApi } from "../../common/k8s-api/endpoints"; +export { PersistentVolume, persistentVolumeApi } from "../../common/k8s-api/endpoints"; +export { PersistentVolumeClaim, pvcApi, PersistentVolumeClaimsApi } from "../../common/k8s-api/endpoints"; +export { StorageClass, storageClassApi } from "../../common/k8s-api/endpoints"; +export { Namespace, namespacesApi } from "../../common/k8s-api/endpoints"; +export { KubeEvent, eventApi } from "../../common/k8s-api/endpoints"; +export { ServiceAccount, serviceAccountsApi } from "../../common/k8s-api/endpoints"; +export { Role, roleApi } from "../../common/k8s-api/endpoints"; +export { RoleBinding, roleBindingApi } from "../../common/k8s-api/endpoints"; +export { ClusterRole, clusterRoleApi } from "../../common/k8s-api/endpoints"; +export { ClusterRoleBinding, clusterRoleBindingApi } from "../../common/k8s-api/endpoints"; +export { CustomResourceDefinition, crdApi } from "../../common/k8s-api/endpoints"; export { KubeObjectStatusLevel } from "./kube-object-status"; // types -export type { IKubeApiCluster } from "../../renderer/api/kube-api"; -export type { IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints"; -export type { ISecretRef } from "../../renderer/api/endpoints"; +export type { IKubeApiCluster } from "../../common/k8s-api/kube-api"; +export type { IPodContainer, IPodContainerStatus } from "../../common/k8s-api/endpoints"; +export type { ISecretRef } from "../../common/k8s-api/endpoints"; export type { KubeObjectStatus } from "./kube-object-status"; // stores diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index ab4186d2da..6c821b0e42 100644 --- a/src/extensions/renderer-api/navigation.ts +++ b/src/extensions/renderer-api/navigation.ts @@ -23,7 +23,7 @@ import { navigation, PageParam, PageParamInit } from "../../renderer/navigation" export type { PageParamInit, PageParam } from "../../renderer/navigation/page-param"; export { navigate, isActiveRoute } from "../../renderer/navigation/helpers"; -export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/components/kube-object/kube-object-details"; +export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/components/kube-detail-params"; export type { URLParams } from "../../common/utils/buildUrl"; export function createPageParam(init: PageParamInit) { diff --git a/src/main/catalog-sources/kubeconfig-sync.ts b/src/main/catalog-sources/kubeconfig-sync.ts index e60d9400de..668dad2884 100644 --- a/src/main/catalog-sources/kubeconfig-sync.ts +++ b/src/main/catalog-sources/kubeconfig-sync.ts @@ -22,23 +22,38 @@ import { action, observable, IComputedValue, computed, ObservableMap, runInAction, makeObservable, observe } from "mobx"; import type { CatalogEntity } from "../../common/catalog"; import { catalogEntityRegistry } from "../../main/catalog"; -import { watch } from "chokidar"; +import { FSWatcher, watch } from "chokidar"; import fs from "fs"; -import fse from "fs-extra"; +import path from "path"; import type stream from "stream"; -import { Disposer, ExtendedObservableMap, iter, Singleton } from "../../common/utils"; +import { Disposer, ExtendedObservableMap, iter, Singleton, storedKubeConfigFolder } from "../../common/utils"; import logger from "../logger"; import type { KubeConfig } from "@kubernetes/client-node"; import { loadConfigFromString, splitConfig } from "../../common/kube-helpers"; import { Cluster } from "../cluster"; import { catalogEntityFromCluster, ClusterManager } from "../cluster-manager"; import { UserStore } from "../../common/user-store"; -import { ClusterStore, UpdateClusterModel } from "../../common/cluster-store"; +import { ClusterStore } from "../../common/cluster-store"; import { createHash } from "crypto"; import { homedir } from "os"; +import globToRegExp from "glob-to-regexp"; +import { inspect } from "util"; +import type { UpdateClusterModel } from "../../common/cluster-types"; const logPrefix = "[KUBECONFIG-SYNC]:"; +/** + * This is the list of globs of which files are ignored when under a folder sync + */ +const ignoreGlobs = [ + "*.lock", // kubectl lock files + "*.swp", // vim swap files + ".DS_Store", // macOS specific +].map(rawGlob => ({ + rawGlob, + matcher: globToRegExp(rawGlob), +})); + export class KubeconfigSyncManager extends Singleton { protected sources = observable.map, Disposer]>(); protected syncing = false; @@ -70,7 +85,7 @@ export class KubeconfigSyncManager extends Singleton { ))); // This must be done so that c&p-ed clusters are visible - this.startNewSync(ClusterStore.storedKubeConfigFolder); + this.startNewSync(storedKubeConfigFolder()); for (const filePath of UserStore.getInstance().syncKubeconfigEntries.keys()) { this.startNewSync(filePath); @@ -101,20 +116,15 @@ export class KubeconfigSyncManager extends Singleton { } @action - protected async startNewSync(filePath: string): Promise { + protected startNewSync(filePath: string): void { if (this.sources.has(filePath)) { // don't start a new sync if we already have one return void logger.debug(`${logPrefix} already syncing file/folder`, { filePath }); } - try { - this.sources.set(filePath, await watchFileChanges(filePath)); - - logger.info(`${logPrefix} starting sync of file/folder`, { filePath }); - logger.debug(`${logPrefix} ${this.sources.size} files/folders watched`, { files: Array.from(this.sources.keys()) }); - } catch (error) { - logger.warn(`${logPrefix} failed to start watching changes: ${error}`); - } + this.sources.set(filePath, watchFileChanges(filePath)); + logger.info(`${logPrefix} starting sync of file/folder`, { filePath }); + logger.debug(`${logPrefix} ${this.sources.size} files/folders watched`, { files: Array.from(this.sources.keys()) }); } @action @@ -201,7 +211,7 @@ export function computeDiff(contents: string, source: RootSource, filePath: stri const entity = catalogEntityFromCluster(cluster); - if (!filePath.startsWith(ClusterStore.storedKubeConfigFolder)) { + if (!filePath.startsWith(storedKubeConfigFolder())) { entity.metadata.labels.file = filePath.replace(homedir(), "~"); } source.set(contextName, [cluster, entity]); @@ -258,37 +268,69 @@ function diffChangedConfig(filePath: string, source: RootSource): Disposer { return cleanup; } -async function watchFileChanges(filePath: string): Promise<[IComputedValue, Disposer]> { - const stat = await fse.stat(filePath); // traverses symlinks, is a race condition - const watcher = watch(filePath, { - followSymlinks: true, - depth: stat.isDirectory() ? 0 : 1, // DIRs works with 0 but files need 1 (bug: https://github.com/paulmillr/chokidar/issues/1095) - disableGlobbing: true, - ignorePermissionErrors: true, - usePolling: false, - awaitWriteFinish: { - pollInterval: 100, - stabilityThreshold: 1000, - }, - }); +function watchFileChanges(filePath: string): [IComputedValue, Disposer] { const rootSource = new ExtendedObservableMap>(); const derivedSource = computed(() => Array.from(iter.flatMap(rootSource.values(), from => iter.map(from.values(), child => child[1])))); - const stoppers = new Map(); - watcher - .on("change", (childFilePath) => { - stoppers.get(childFilePath)(); - stoppers.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map))); - }) - .on("add", (childFilePath) => { - stoppers.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map))); - }) - .on("unlink", (childFilePath) => { - stoppers.get(childFilePath)(); - stoppers.delete(childFilePath); - rootSource.delete(childFilePath); - }) - .on("error", error => logger.error(`${logPrefix} watching file/folder failed: ${error}`, { filePath })); + let watcher: FSWatcher; - return [derivedSource, () => watcher.close()]; + (async () => { + try { + const stat = await fs.promises.stat(filePath); + const isFolderSync = stat.isDirectory(); + const cleanupFns = new Map(); + + watcher = watch(filePath, { + followSymlinks: true, + depth: isFolderSync ? 0 : 1, // DIRs works with 0 but files need 1 (bug: https://github.com/paulmillr/chokidar/issues/1095) + disableGlobbing: true, + ignorePermissionErrors: true, + usePolling: false, + awaitWriteFinish: { + pollInterval: 100, + stabilityThreshold: 1000, + }, + atomic: 150, // for "atomic writes" + }); + + watcher + .on("change", (childFilePath) => { + const cleanup = cleanupFns.get(childFilePath); + + if (!cleanup) { + // file was previously ignored, do nothing + return void logger.debug(`${logPrefix} ${inspect(childFilePath)} that should have been previously ignored has changed. Doing nothing`); + } + + cleanup(); + cleanupFns.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map))); + }) + .on("add", (childFilePath) => { + if (isFolderSync) { + const fileName = path.basename(childFilePath); + + for (const ignoreGlob of ignoreGlobs) { + if (ignoreGlob.matcher.test(fileName)) { + return void logger.info(`${logPrefix} ignoring ${inspect(childFilePath)} due to ignore glob: ${ignoreGlob.rawGlob}`); + } + } + } + + cleanupFns.set(childFilePath, diffChangedConfig(childFilePath, rootSource.getOrInsert(childFilePath, observable.map))); + }) + .on("unlink", (childFilePath) => { + cleanupFns.get(childFilePath)?.(); + cleanupFns.delete(childFilePath); + rootSource.delete(childFilePath); + }) + .on("error", error => logger.error(`${logPrefix} watching file/folder failed: ${error}`, { filePath })); + } catch (error) { + console.log(error.stack); + logger.warn(`${logPrefix} failed to start watching changes: ${error}`); + } + })(); + + return [derivedSource, () => { + watcher?.close(); + }]; } diff --git a/src/main/cluster-detectors/cluster-id-detector.ts b/src/main/cluster-detectors/cluster-id-detector.ts index 9818b0d990..21d7a005b3 100644 --- a/src/main/cluster-detectors/cluster-id-detector.ts +++ b/src/main/cluster-detectors/cluster-id-detector.ts @@ -21,7 +21,7 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { createHash } from "crypto"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class ClusterIdDetector extends BaseClusterDetector { key = ClusterMetadataKey.CLUSTER_ID; diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index 82a09059e3..5d3461b0bb 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -20,20 +20,18 @@ */ import { observable } from "mobx"; -import type { ClusterMetadata } from "../../common/cluster-store"; +import type { ClusterMetadata } from "../../common/cluster-types"; +import { Singleton } from "../../common/utils"; import type { Cluster } from "../cluster"; import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector"; -import { ClusterIdDetector } from "./cluster-id-detector"; -import { DistributionDetector } from "./distribution-detector"; -import { LastSeenDetector } from "./last-seen-detector"; -import { NodesCountDetector } from "./nodes-count-detector"; -import { VersionDetector } from "./version-detector"; -export class DetectorRegistry { +export class DetectorRegistry extends Singleton { registry = observable.array([], { deep: false }); - add(detectorClass: typeof BaseClusterDetector) { + add(detectorClass: typeof BaseClusterDetector): this { this.registry.push(detectorClass); + + return this; } async detectForCluster(cluster: Cluster): Promise { @@ -63,10 +61,3 @@ export class DetectorRegistry { return metadata; } } - -export const detectorRegistry = new DetectorRegistry(); -detectorRegistry.add(ClusterIdDetector); -detectorRegistry.add(LastSeenDetector); -detectorRegistry.add(VersionDetector); -detectorRegistry.add(DistributionDetector); -detectorRegistry.add(NodesCountDetector); diff --git a/src/main/cluster-detectors/distribution-detector.ts b/src/main/cluster-detectors/distribution-detector.ts index c7f2791cee..0deb598b39 100644 --- a/src/main/cluster-detectors/distribution-detector.ts +++ b/src/main/cluster-detectors/distribution-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class DistributionDetector extends BaseClusterDetector { key = ClusterMetadataKey.DISTRIBUTION; @@ -60,7 +60,7 @@ export class DistributionDetector extends BaseClusterDetector { if (this.isK0s()) { return { value: "k0s", accuracy: 80}; } - + if (this.isVMWare()) { return { value: "vmware", accuracy: 90}; } @@ -179,7 +179,7 @@ export class DistributionDetector extends BaseClusterDetector { protected isK0s() { return this.version.includes("-k0s"); } - + protected isAlibaba() { return this.version.includes("-aliyun"); } diff --git a/src/main/cluster-detectors/last-seen-detector.ts b/src/main/cluster-detectors/last-seen-detector.ts index 537fef96cb..2aed3d0640 100644 --- a/src/main/cluster-detectors/last-seen-detector.ts +++ b/src/main/cluster-detectors/last-seen-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class LastSeenDetector extends BaseClusterDetector { key = ClusterMetadataKey.LAST_SEEN; diff --git a/src/main/cluster-detectors/nodes-count-detector.ts b/src/main/cluster-detectors/nodes-count-detector.ts index f30f5e6c70..2cb224b46a 100644 --- a/src/main/cluster-detectors/nodes-count-detector.ts +++ b/src/main/cluster-detectors/nodes-count-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class NodesCountDetector extends BaseClusterDetector { key = ClusterMetadataKey.NODES_COUNT; diff --git a/src/main/cluster-detectors/version-detector.ts b/src/main/cluster-detectors/version-detector.ts index f7240ab3ea..36d7e06dd1 100644 --- a/src/main/cluster-detectors/version-detector.ts +++ b/src/main/cluster-detectors/version-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class VersionDetector extends BaseClusterDetector { key = ClusterMetadataKey.VERSION; diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 56ce234e90..fdc3bf3e1a 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -22,15 +22,16 @@ import "../common/cluster-ipc"; import type http from "http"; import { action, autorun, makeObservable, observable, observe, reaction, toJS } from "mobx"; -import { ClusterId, ClusterStore, getClusterIdFromHost } from "../common/cluster-store"; import { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; -import { Singleton } from "../common/utils"; +import { getClusterIdFromHost, Singleton } from "../common/utils"; import { catalogEntityRegistry } from "./catalog"; import { KubernetesCluster, KubernetesClusterPrometheusMetrics, KubernetesClusterStatusPhase } from "../common/catalog-entities/kubernetes-cluster"; import { ipcMainOn } from "../common/ipc"; import { once } from "lodash"; +import { ClusterStore } from "../common/cluster-store"; +import type { ClusterId } from "../common/cluster-types"; const logPrefix = "[CLUSTER-MANAGER]:"; @@ -111,7 +112,15 @@ export class ClusterManager extends Singleton { }; entity.metadata.distro = cluster.distribution; entity.metadata.kubeVersion = cluster.version; - entity.metadata.name = cluster.name; + + if (cluster.preferences?.clusterName) { + /** + * Only set the name if the it is overriden in preferences. If it isn't + * set then the name of the entity has been explicitly set by its source + */ + entity.metadata.name = cluster.preferences.clusterName; + } + entity.spec.metrics ||= { source: "local" }; if (entity.spec.metrics.source === "local") { @@ -164,14 +173,15 @@ export class ClusterManager extends Singleton { if (!cluster) { try { + /** + * Add the bare minimum of data to ClusterStore. And especially no + * preferences, as those might be configured by the entity's source + */ this.store.addCluster({ id: entity.metadata.uid, - preferences: { - clusterName: entity.metadata.name - }, kubeConfigPath: entity.spec.kubeconfigPath, contextName: entity.spec.kubeconfigContext, - accessibleNamespaces: entity.spec.accessibleNamespaces + accessibleNamespaces: entity.spec.accessibleNamespaces ?? [], }); } catch (error) { if (error.code === "ENOENT" && error.path === entity.spec.kubeconfigPath) { diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 6d3331c447..b3eef9613f 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -20,7 +20,6 @@ */ import { ipcMain } from "electron"; -import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-store"; import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx"; import { broadcastMessage, ClusterListNamespaceForbiddenChannel } from "../common/ipc"; import { ContextHandler } from "./context-handler"; @@ -31,57 +30,10 @@ import { loadConfigFromFile, loadConfigFromFileSync, validateKubeConfig } from " import { apiResourceRecord, apiResources, KubeApiResource, KubeResource } from "../common/rbac"; import logger from "./logger"; import { VersionDetector } from "./cluster-detectors/version-detector"; -import { detectorRegistry } from "./cluster-detectors/detector-registry"; +import { DetectorRegistry } from "./cluster-detectors/detector-registry"; import plimit from "p-limit"; import { toJS } from "../common/utils"; -import { initialNodeShellImage } from "../common/cluster-store"; - -export enum ClusterStatus { - AccessGranted = 2, - AccessDenied = 1, - Offline = 0 -} - -export enum ClusterMetadataKey { - VERSION = "version", - CLUSTER_ID = "id", - DISTRIBUTION = "distribution", - NODES_COUNT = "nodes", - LAST_SEEN = "lastSeen", - PROMETHEUS = "prometheus" -} - -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" -} - -export type ClusterRefreshOptions = { - refreshMetadata?: boolean -}; - -export interface ClusterState { - apiUrl: string; - online: boolean; - disconnected: boolean; - accessible: boolean; - ready: boolean; - failureReason: string; - isAdmin: boolean; - allowedNamespaces: string[] - allowedResources: string[] - isGlobalWatchEnabled: boolean; -} +import { initialNodeShellImage, ClusterState, ClusterMetadataKey, ClusterRefreshOptions, ClusterStatus, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-types"; /** * Cluster @@ -452,7 +404,7 @@ export class Cluster implements ClusterModel, ClusterState { @action async refreshMetadata() { logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); - const metadata = await detectorRegistry.detectForCluster(this); + const metadata = await DetectorRegistry.getInstance().detectForCluster(this); const existingMetadata = this.metadata; this.metadata = Object.assign(existingMetadata, metadata); diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index 7e09d29f5c..82c365e821 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -21,7 +21,7 @@ import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"; import { PrometheusProviderRegistry } from "./prometheus/provider-registry"; -import type { ClusterPrometheusPreferences } from "../common/cluster-store"; +import type { ClusterPrometheusPreferences } from "../common/cluster-types"; import type { Cluster } from "./cluster"; import type httpProxy from "http-proxy"; import url, { UrlWithStringQuery } from "url"; diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index 7ab6c8f9db..5523e0f050 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -25,7 +25,7 @@ import { HelmRepo, HelmRepoManager } from "./helm-repo-manager"; import logger from "../logger"; import { promiseExec } from "../promise-exec"; import { helmCli } from "./helm-cli"; -import type { RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api"; +import type { RepoHelmChartList } from "../../common/k8s-api/endpoints/helm-charts.api"; type CachedYaml = { entries: RepoHelmChartList diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 3cf56ccb13..2fe531c215 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -24,7 +24,7 @@ import type { Cluster } from "../cluster"; import logger from "../logger"; import { HelmRepoManager } from "./helm-repo-manager"; import { HelmChartManager } from "./helm-chart-manager"; -import type { HelmChart, HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api"; +import type { HelmChart, HelmChartList, RepoHelmChartList } from "../../common/k8s-api/endpoints/helm-charts.api"; import { deleteRelease, getHistory, getRelease, getValues, installChart, listReleases, rollback, upgradeRelease } from "./helm-release-manager"; import { iter, sortCompareChartVersions } from "../../common/utils"; diff --git a/src/main/index.ts b/src/main/index.ts index a5116cfdb0..c8a9d105d2 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -28,7 +28,7 @@ import * as LensExtensionsMainApi from "../extensions/main-api"; import { app, autoUpdater, dialog, powerMonitor } from "electron"; import { appName, isMac, productName } from "../common/vars"; import path from "path"; -import { LensProxy } from "./proxy/lens-proxy"; +import { LensProxy } from "./lens-proxy"; import { WindowManager } from "./window-manager"; import { ClusterManager } from "./cluster-manager"; import { shellSync } from "./shell-sync"; @@ -41,7 +41,7 @@ import { InstalledExtension, ExtensionDiscovery } from "../extensions/extension- import type { LensExtensionId } from "../extensions/lens-extension"; import { installDeveloperTools } from "./developer-tools"; import { LensProtocolRouterMain } from "./protocol-handler"; -import { disposer, getAppVersion, getAppVersionFromProxyServer } from "../common/utils"; +import { disposer, getAppVersion, getAppVersionFromProxyServer, storedKubeConfigFolder } from "../common/utils"; import { bindBroadcastHandlers, ipcMainOn } from "../common/ipc"; import { startUpdateChecking } from "./app-updater"; import { IpcRendererNavigationEvents } from "../renderer/navigation/events"; @@ -49,7 +49,6 @@ import { pushCatalogToRenderer } from "./catalog-pusher"; import { catalogEntityRegistry } from "./catalog"; import { HelmRepoManager } from "./helm/helm-repo-manager"; import { syncGeneralEntities, syncWeblinks, KubeconfigSyncManager } from "./catalog-sources"; -import { handleWsUpgrade } from "./proxy/ws-upgrade"; import configurePackages from "../common/configure-packages"; import { PrometheusProviderRegistry } from "./prometheus"; import * as initializers from "./initializers"; @@ -60,9 +59,12 @@ import { WeblinkStore } from "../common/weblink-store"; import { ExtensionsStore } from "../extensions/extensions-store"; import { FilesystemProvisionerStore } from "./extension-filesystem"; import { SentryInit } from "../common/sentry"; +import { ensureDir } from "fs-extra"; +import { Router } from "./router"; +import { initMenu } from "./menu"; +import { initTray } from "./tray"; +import { kubeApiRequest, shellApiRequest } from "./proxy-functions"; -// This has to be called before start using winton-based logger -// For example, before any logger.log SentryInit(); const workingDir = path.join(app.getPath("appData"), appName); @@ -159,14 +161,17 @@ app.on("ready", async () => { HelmRepoManager.createInstance(); // create the instance - const lensProxy = LensProxy.createInstance( - handleWsUpgrade, - req => ClusterManager.getInstance().getClusterForRequest(req), - ); + const lensProxy = LensProxy.createInstance(new Router(), { + getClusterForRequest: req => ClusterManager.getInstance().getClusterForRequest(req), + kubeApiRequest, + shellApiRequest, + }); ClusterManager.createInstance().init(); KubeconfigSyncManager.createInstance(); + initializers.initClusterMetadataDetectors(); + try { logger.info("🔌 Starting LensProxy"); await lensProxy.listen(); @@ -204,14 +209,20 @@ app.on("ready", async () => { logger.info("🖥️ Starting WindowManager"); const windowManager = WindowManager.createInstance(); + cleanup.push( + initMenu(windowManager), + initTray(windowManager), + ); + installDeveloperTools(); if (!startHidden) { windowManager.ensureMainWindow(); } - ipcMainOn(IpcRendererNavigationEvents.LOADED, () => { + ipcMainOn(IpcRendererNavigationEvents.LOADED, async () => { cleanup.push(pushCatalogToRenderer(catalogEntityRegistry)); + await ensureDir(storedKubeConfigFolder()); KubeconfigSyncManager.getInstance().startSync(); startUpdateChecking(); LensProtocolRouterMain.getInstance().rendererLoaded = true; diff --git a/src/main/initializers/cluster-metadata-detectors.ts b/src/main/initializers/cluster-metadata-detectors.ts new file mode 100644 index 0000000000..47942cd28e --- /dev/null +++ b/src/main/initializers/cluster-metadata-detectors.ts @@ -0,0 +1,36 @@ +/** + * 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 { ClusterIdDetector } from "../cluster-detectors/cluster-id-detector"; +import { DetectorRegistry } from "../cluster-detectors/detector-registry"; +import { DistributionDetector } from "../cluster-detectors/distribution-detector"; +import { LastSeenDetector } from "../cluster-detectors/last-seen-detector"; +import { NodesCountDetector } from "../cluster-detectors/nodes-count-detector"; +import { VersionDetector } from "../cluster-detectors/version-detector"; + +export function initClusterMetadataDetectors() { + DetectorRegistry.createInstance() + .add(ClusterIdDetector) + .add(LastSeenDetector) + .add(VersionDetector) + .add(DistributionDetector) + .add(NodesCountDetector); +} diff --git a/src/main/initializers/index.ts b/src/main/initializers/index.ts index 526b61d4ed..34a5c32e34 100644 --- a/src/main/initializers/index.ts +++ b/src/main/initializers/index.ts @@ -22,3 +22,4 @@ export * from "./registries"; export * from "./metrics-providers"; export * from "./ipc"; +export * from "./cluster-metadata-detectors"; diff --git a/src/main/initializers/ipc.ts b/src/main/initializers/ipc.ts index 3614c602d7..efcd52a5a4 100644 --- a/src/main/initializers/ipc.ts +++ b/src/main/initializers/ipc.ts @@ -23,7 +23,8 @@ import type { IpcMainInvokeEvent } from "electron"; import { KubernetesCluster } from "../../common/catalog-entities"; import { clusterFrameMap } from "../../common/cluster-frames"; import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler, clusterDeleteHandler } from "../../common/cluster-ipc"; -import { ClusterId, ClusterStore } from "../../common/cluster-store"; +import { ClusterStore } from "../../common/cluster-store"; +import type { ClusterId } from "../../common/cluster-types"; import { appEventBus } from "../../common/event-bus"; import { ipcMainHandle } from "../../common/ipc"; import { catalogEntityRegistry } from "../catalog"; diff --git a/src/main/k8s-request.ts b/src/main/k8s-request.ts index b501bd5ce1..923ec81609 100644 --- a/src/main/k8s-request.ts +++ b/src/main/k8s-request.ts @@ -21,8 +21,8 @@ import request, { RequestPromiseOptions } from "request-promise-native"; import { apiKubePrefix } from "../common/vars"; -import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api"; -import { LensProxy } from "./proxy/lens-proxy"; +import type { IMetricsReqParams } from "../common/k8s-api/endpoints/metrics.api"; +import { LensProxy } from "./lens-proxy"; import type { Cluster } from "./cluster"; export async function k8sRequest(cluster: Cluster, path: string, options: RequestPromiseOptions = {}): Promise { diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index fc2e14a3cb..ab53118f60 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -27,7 +27,7 @@ import path from "path"; import fs from "fs-extra"; import { dumpConfigYaml } from "../common/kube-helpers"; import logger from "./logger"; -import { LensProxy } from "./proxy/lens-proxy"; +import { LensProxy } from "./lens-proxy"; export class KubeconfigManager { protected configDir = app.getPath("temp"); diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index 01b38c67fe..87166e597a 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -46,10 +46,10 @@ const kubectlMap: Map = new Map([ ["1.15", "1.15.11"], ["1.16", "1.16.15"], ["1.17", "1.17.17"], - ["1.18", bundledVersion], - ["1.19", "1.19.7"], - ["1.20", "1.20.2"], - ["1.21", "1.21.1"] + ["1.18", "1.18.20"], + ["1.19", "1.19.12"], + ["1.20", "1.20.8"], + ["1.21", bundledVersion] ]); const packageMirrors: Map = new Map([ ["default", "https://storage.googleapis.com/kubernetes-release/release"], diff --git a/src/main/proxy/lens-proxy.ts b/src/main/lens-proxy.ts similarity index 65% rename from src/main/proxy/lens-proxy.ts rename to src/main/lens-proxy.ts index 9ffff0fd6a..353ed935e7 100644 --- a/src/main/proxy/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -19,33 +19,42 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import net from "net"; +import type net from "net"; import type http from "http"; import spdy from "spdy"; import httpProxy from "http-proxy"; -import url from "url"; -import { apiPrefix, apiKubePrefix } from "../../common/vars"; -import { Router } from "../router"; -import type { ContextHandler } from "../context-handler"; -import logger from "../logger"; -import { Singleton } from "../../common/utils"; -import type { Cluster } from "../cluster"; +import { apiPrefix, apiKubePrefix } from "../common/vars"; +import type { Router } from "./router"; +import type { ContextHandler } from "./context-handler"; +import logger from "./logger"; +import { Singleton } from "../common/utils"; +import type { Cluster } from "./cluster"; +import type { ProxyApiRequestArgs } from "./proxy-functions"; -type WSUpgradeHandler = (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => void; +type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | null; + +export interface LensProxyFunctions { + getClusterForRequest: GetClusterForRequest, + shellApiRequest: (args: ProxyApiRequestArgs) => void | Promise; + kubeApiRequest: (args: ProxyApiRequestArgs) => void | Promise; +} export class LensProxy extends Singleton { protected origin: string; protected proxyServer: http.Server; - protected router = new Router(); protected closed = false; protected retryCounters = new Map(); + protected proxy = this.createProxy(); + protected getClusterForRequest: GetClusterForRequest; public port: number; - constructor(handleWsUpgrade: WSUpgradeHandler, protected getClusterForRequest: (req: http.IncomingMessage) => Cluster | undefined) { + constructor(protected router: Router, functions: LensProxyFunctions) { super(); - const proxy = this.createProxy(); + const { shellApiRequest, kubeApiRequest } = functions; + + this.getClusterForRequest = functions.getClusterForRequest; this.proxyServer = spdy.createServer({ spdy: { @@ -53,17 +62,16 @@ export class LensProxy extends Singleton { protocols: ["http/1.1", "spdy/3.1"] } }, (req: http.IncomingMessage, res: http.ServerResponse) => { - this.handleRequest(proxy, req, res); + this.handleRequest(req, res); }); this.proxyServer .on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => { - if (req.url.startsWith(`${apiPrefix}?`)) { - handleWsUpgrade(req, socket, head); - } else { - this.handleProxyUpgrade(proxy, req, socket, head) - .catch(error => logger.error(`[LENS-PROXY]: failed to handle proxy upgrade: ${error}`)); - } + const isInternal = req.url.startsWith(`${apiPrefix}?`); + const reqHandler = isInternal ? shellApiRequest : kubeApiRequest; + + (async () => reqHandler({ req, socket, head }))() + .catch(error => logger.error(logger.error(`[LENS-PROXY]: failed to handle proxy upgrade: ${error}`))); }); } @@ -89,6 +97,7 @@ export class LensProxy extends Singleton { }); this.port = port; + process.env.LENS_PROXY_PORT = port.toString(); resolve(); }) .once("error", (error) => { @@ -104,58 +113,6 @@ export class LensProxy extends Singleton { this.closed = true; } - protected async handleProxyUpgrade(proxy: httpProxy, req: http.IncomingMessage, socket: net.Socket, head: Buffer) { - const cluster = this.getClusterForRequest(req); - - if (cluster) { - const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, ""); - const apiUrl = url.parse(cluster.apiUrl); - const pUrl = url.parse(proxyUrl); - const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname }; - const proxySocket = new net.Socket(); - - proxySocket.connect(connectOpts, () => { - proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`); - proxySocket.write(`Host: ${apiUrl.host}\r\n`); - - for (let i = 0; i < req.rawHeaders.length; i += 2) { - const key = req.rawHeaders[i]; - - if (key !== "Host" && key !== "Authorization") { - proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`); - } - } - proxySocket.write("\r\n"); - proxySocket.write(head); - }); - - proxySocket.setKeepAlive(true); - socket.setKeepAlive(true); - proxySocket.setTimeout(0); - socket.setTimeout(0); - - proxySocket.on("data", function (chunk) { - socket.write(chunk); - }); - proxySocket.on("end", function () { - socket.end(); - }); - proxySocket.on("error", function () { - socket.write(`HTTP/${req.httpVersion} 500 Connection error\r\n\r\n`); - socket.end(); - }); - socket.on("data", function (chunk) { - proxySocket.write(chunk); - }); - socket.on("end", function () { - proxySocket.end(); - }); - socket.on("error", function () { - proxySocket.end(); - }); - } - } - protected createProxy(): httpProxy { const proxy = httpProxy.createProxyServer(); @@ -195,7 +152,7 @@ export class LensProxy extends Singleton { logger.debug(`Retrying proxy request to url: ${reqId}`); setTimeout(() => { this.retryCounters.set(reqId, retryCount + 1); - this.handleRequest(proxy, req, res) + this.handleRequest(req, res) .catch(error => logger.error(`[LENS-PROXY]: failed to handle request on proxy error: ${error}`)); }, timeoutMs); } @@ -226,7 +183,7 @@ export class LensProxy extends Singleton { return req.headers.host + req.url; } - protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) { + protected async handleRequest(req: http.IncomingMessage, res: http.ServerResponse) { const cluster = this.getClusterForRequest(req); if (cluster) { @@ -237,7 +194,7 @@ export class LensProxy extends Singleton { // this should be safe because we have already validated cluster uuid res.setHeader("Access-Control-Allow-Origin", "*"); - return proxy.web(req, res, proxyTarget); + return this.proxy.web(req, res, proxyTarget); } } this.router.route(cluster, req, res); diff --git a/src/main/logger.ts b/src/main/logger.ts index 89a0ede7f0..b6d7e7ebb9 100644 --- a/src/main/logger.ts +++ b/src/main/logger.ts @@ -19,33 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { app, remote } from "electron"; -import winston from "winston"; -import { isDebugging, isTestEnv } from "../common/vars"; - -const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info"; -const consoleOptions: winston.transports.ConsoleTransportOptions = { - handleExceptions: false, - level: logLevel, -}; -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.colorize(), - winston.format.simple(), - ), - transports: [ - new winston.transports.Console(consoleOptions), - ...(isTestEnv ? [] : [new winston.transports.File(fileOptions)]), - ], -}); +import logger from "../common/logger"; export default logger; diff --git a/src/main/proxy-functions/index.ts b/src/main/proxy-functions/index.ts new file mode 100644 index 0000000000..2154d81014 --- /dev/null +++ b/src/main/proxy-functions/index.ts @@ -0,0 +1,24 @@ +/** + * 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 * from "./shell-api-request"; +export * from "./kube-api-request"; +export * from "./types"; diff --git a/src/main/proxy-functions/kube-api-request.ts b/src/main/proxy-functions/kube-api-request.ts new file mode 100644 index 0000000000..cbd18f9beb --- /dev/null +++ b/src/main/proxy-functions/kube-api-request.ts @@ -0,0 +1,84 @@ +/** + * 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 { chunk } from "lodash"; +import net from "net"; +import url from "url"; +import { apiKubePrefix } from "../../common/vars"; +import { ClusterManager } from "../cluster-manager"; +import type { ProxyApiRequestArgs } from "./types"; + +const skipRawHeaders = new Set(["Host", "Authorization"]); + +export async function kubeApiRequest({ req, socket, head }: ProxyApiRequestArgs) { + const cluster = ClusterManager.getInstance().getClusterForRequest(req); + + if (!cluster) { + return; + } + + const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, ""); + const apiUrl = url.parse(cluster.apiUrl); + const pUrl = url.parse(proxyUrl); + const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname }; + const proxySocket = new net.Socket(); + + proxySocket.connect(connectOpts, () => { + proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`); + proxySocket.write(`Host: ${apiUrl.host}\r\n`); + + for (const [key, value] of chunk(req.rawHeaders, 2)) { + if (skipRawHeaders.has(key)) { + continue; + } + + proxySocket.write(`${key}: ${value}\r\n`); + } + + proxySocket.write("\r\n"); + proxySocket.write(head); + }); + + proxySocket.setKeepAlive(true); + socket.setKeepAlive(true); + proxySocket.setTimeout(0); + socket.setTimeout(0); + + proxySocket.on("data", function (chunk) { + socket.write(chunk); + }); + proxySocket.on("end", function () { + socket.end(); + }); + proxySocket.on("error", function () { + socket.write(`HTTP/${req.httpVersion} 500 Connection error\r\n\r\n`); + socket.end(); + }); + socket.on("data", function (chunk) { + proxySocket.write(chunk); + }); + socket.on("end", function () { + proxySocket.end(); + }); + socket.on("error", function () { + proxySocket.end(); + }); +} diff --git a/src/main/proxy/ws-upgrade.ts b/src/main/proxy-functions/shell-api-request.ts similarity index 75% rename from src/main/proxy/ws-upgrade.ts rename to src/main/proxy-functions/shell-api-request.ts index 595b05430d..3edaecff81 100644 --- a/src/main/proxy/ws-upgrade.ts +++ b/src/main/proxy-functions/shell-api-request.ts @@ -19,24 +19,18 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/** - * This file is here so that the "../shell-session" import can be injected into - * LensProxy at creation time. So that the `pty.node` extension isn't loaded - * into Lens Extension webpack bundle. - */ - -import * as WebSocket from "ws"; import type http from "http"; -import type net from "net"; import url from "url"; -import { NodeShellSession, LocalShellSession } from "../shell-session"; -import { ClusterManager } from "../cluster-manager"; import logger from "../logger"; +import * as WebSocket from "ws"; +import { NodeShellSession, LocalShellSession } from "../shell-session"; +import type { ProxyApiRequestArgs } from "./types"; +import { ClusterManager } from "../cluster-manager"; -function createWsListener(): WebSocket.Server { +export function shellApiRequest({ req, socket, head }: ProxyApiRequestArgs) { const ws = new WebSocket.Server({ noServer: true }); - return ws.on("connection", ((socket: WebSocket, req: http.IncomingMessage) => { + ws.on("connection", ((socket: WebSocket, req: http.IncomingMessage) => { const cluster = ClusterManager.getInstance().getClusterForRequest(req); const nodeParam = url.parse(req.url, true).query["node"]?.toString(); const shell = nodeParam @@ -46,12 +40,8 @@ function createWsListener(): WebSocket.Server { shell.open() .catch(error => logger.error(`[SHELL-SESSION]: failed to open: ${error}`, { error })); })); -} -export async function handleWsUpgrade(req: http.IncomingMessage, socket: net.Socket, head: Buffer) { - const wsServer = createWsListener(); - - wsServer.handleUpgrade(req, socket, head, (con) => { - wsServer.emit("connection", con, req); + ws.handleUpgrade(req, socket, head, (con) => { + ws.emit("connection", con, req); }); } diff --git a/src/main/proxy-functions/types.ts b/src/main/proxy-functions/types.ts new file mode 100644 index 0000000000..57d3db1b7c --- /dev/null +++ b/src/main/proxy-functions/types.ts @@ -0,0 +1,29 @@ +/** + * 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 http from "http"; +import type net from "net"; + +export interface ProxyApiRequestArgs { + req: http.IncomingMessage, + socket: net.Socket, + head: Buffer, +} diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index c309b42ccf..2b8aa0f921 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -22,8 +22,8 @@ import _ from "lodash"; import type { LensApiRequest } from "../router"; import { respondJson } from "../utils/http-responses"; -import { Cluster, ClusterMetadataKey } from "../cluster"; -import type { ClusterPrometheusMetadata } from "../../common/cluster-store"; +import type { Cluster } from "../cluster"; +import { ClusterMetadataKey, ClusterPrometheusMetadata } from "../../common/cluster-types"; import logger from "../logger"; import { getMetrics } from "../k8s-request"; import { PrometheusProviderRegistry } from "../prometheus"; diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 9a56aaafb8..88d7dff0af 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -19,20 +19,19 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { ClusterId } from "../common/cluster-store"; +import type { ClusterId } from "../common/cluster-types"; import { makeObservable, observable } from "mobx"; import { app, BrowserWindow, dialog, ipcMain, shell, webContents } from "electron"; import windowStateKeeper from "electron-window-state"; import { appEventBus } from "../common/event-bus"; import { ipcMainOn } from "../common/ipc"; -import { initMenu } from "./menu"; -import { initTray } from "./tray"; import { delay, iter, Singleton } from "../common/utils"; import { ClusterFrameInfo, clusterFrameMap } from "../common/cluster-frames"; import { IpcRendererNavigationEvents } from "../renderer/navigation/events"; import logger from "./logger"; import { productName } from "../common/vars"; -import { LensProxy } from "./proxy/lens-proxy"; +import { LensProxy } from "./lens-proxy"; +import * as path from "path"; function isHideable(window: BrowserWindow | null): boolean { return Boolean(window && !window.isDestroyed()); @@ -56,8 +55,6 @@ export class WindowManager extends Singleton { super(); makeObservable(this); this.bindEvents(); - this.initMenu(); - this.initTray(); } get mainUrl() { @@ -88,6 +85,7 @@ export class WindowManager extends Singleton { titleBarStyle: "hidden", backgroundColor: "#1e2124", webPreferences: { + preload: path.join(__static, "build", "preload.js"), nodeIntegration: true, nodeIntegrationInSubFrames: true, enableRemoteModule: true, @@ -136,14 +134,6 @@ export class WindowManager extends Singleton { } } - protected async initMenu() { - this.disposers.menuAutoUpdater = initMenu(this); - } - - protected initTray() { - this.disposers.trayAutoUpdater = initTray(this); - } - protected bindEvents() { // track visible cluster from ui ipcMainOn(IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID, (event, clusterId: ClusterId) => { diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index 2599005332..7ef4b042ec 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -25,9 +25,10 @@ import path from "path"; import { app } from "electron"; import fse from "fs-extra"; -import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { loadConfigFromFileSync } from "../../common/kube-helpers"; import { MigrationDeclaration, migrationLog } from "../helpers"; +import type { ClusterModel } from "../../common/cluster-types"; +import { getCustomKubeConfigPath, storedKubeConfigFolder } from "../../common/utils"; interface Pre360ClusterModel extends ClusterModel { kubeConfig: string; @@ -40,7 +41,7 @@ export default { const storedClusters: Pre360ClusterModel[] = store.get("clusters") ?? []; const migratedClusters: ClusterModel[] = []; - fse.ensureDirSync(ClusterStore.storedKubeConfigFolder); + fse.ensureDirSync(storedKubeConfigFolder()); migrationLog("Number of clusters to migrate: ", storedClusters.length); @@ -49,7 +50,7 @@ export default { * migrate kubeconfig */ try { - const absPath = ClusterStore.getCustomKubeConfigPath(clusterModel.id); + const absPath = getCustomKubeConfigPath(clusterModel.id); // take the embedded kubeconfig and dump it into a file fse.writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 }); diff --git a/src/migrations/cluster-store/5.0.0-beta.10.ts b/src/migrations/cluster-store/5.0.0-beta.10.ts index 4b7fa9f3bd..a26f0ed662 100644 --- a/src/migrations/cluster-store/5.0.0-beta.10.ts +++ b/src/migrations/cluster-store/5.0.0-beta.10.ts @@ -22,7 +22,7 @@ import path from "path"; import { app } from "electron"; import fse from "fs-extra"; -import type { ClusterModel } from "../../common/cluster-store"; +import type { ClusterModel } from "../../common/cluster-types"; import type { MigrationDeclaration } from "../helpers"; interface Pre500WorkspaceStoreModel { diff --git a/src/migrations/cluster-store/5.0.0-beta.13.ts b/src/migrations/cluster-store/5.0.0-beta.13.ts index e6f260db1b..6c8f37e366 100644 --- a/src/migrations/cluster-store/5.0.0-beta.13.ts +++ b/src/migrations/cluster-store/5.0.0-beta.13.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { ClusterModel, ClusterPreferences, ClusterPrometheusPreferences } from "../../common/cluster-store"; +import type { ClusterModel, ClusterPreferences, ClusterPrometheusPreferences } from "../../common/cluster-types"; import { MigrationDeclaration, migrationLog } from "../helpers"; import { generateNewIdFor } from "../utils"; import path from "path"; diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index c1c5eb2dc5..965d03ee5a 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -21,7 +21,7 @@ // Fix embedded kubeconfig paths under snap config -import type { ClusterModel } from "../../common/cluster-store"; +import type { ClusterModel } from "../../common/cluster-types"; import { getAppVersion } from "../../common/utils/app-version"; import fs from "fs"; import { MigrationDeclaration, migrationLog } from "../helpers"; diff --git a/src/migrations/hotbar-store/5.0.0-alpha.0.ts b/src/migrations/hotbar-store/5.0.0-alpha.0.ts index 1a61ce8ef3..4ba145b662 100644 --- a/src/migrations/hotbar-store/5.0.0-alpha.0.ts +++ b/src/migrations/hotbar-store/5.0.0-alpha.0.ts @@ -20,20 +20,14 @@ */ // Cleans up a store that had the state related data stored -import { Hotbar, HotbarStore } from "../../common/hotbar-store"; -import * as uuid from "uuid"; import type { MigrationDeclaration } from "../helpers"; import { catalogEntity } from "../../main/catalog-sources/general"; +import { getEmptyHotbar } from "../../common/hotbar-types"; export default { version: "5.0.0-alpha.0", run(store) { - const hotbar: Hotbar = { - id: uuid.v4(), - name: "default", - items: HotbarStore.getInitialItems(), - }; - + const hotbar = getEmptyHotbar("default"); const { metadata: { uid, name, source } } = catalogEntity; hotbar.items[0] = { entity: { uid, name, source } }; diff --git a/src/migrations/hotbar-store/5.0.0-alpha.2.ts b/src/migrations/hotbar-store/5.0.0-alpha.2.ts index e049a6d731..0a662b466a 100644 --- a/src/migrations/hotbar-store/5.0.0-alpha.2.ts +++ b/src/migrations/hotbar-store/5.0.0-alpha.2.ts @@ -20,7 +20,7 @@ */ // Cleans up a store that had the state related data stored -import type { Hotbar } from "../../common/hotbar-store"; +import type { Hotbar } from "../../common/hotbar-types"; import * as uuid from "uuid"; import type { MigrationDeclaration } from "../helpers"; diff --git a/src/migrations/hotbar-store/5.0.0-beta.10.ts b/src/migrations/hotbar-store/5.0.0-beta.10.ts index 3dd635effc..7d7abc01b7 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.10.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.10.ts @@ -25,7 +25,7 @@ import { isNull } from "lodash"; import path from "path"; import * as uuid from "uuid"; import type { ClusterStoreModel } from "../../common/cluster-store"; -import { defaultHotbarCells, Hotbar, HotbarStore } from "../../common/hotbar-store"; +import { defaultHotbarCells, getEmptyHotbar, Hotbar, HotbarItem } from "../../common/hotbar-types"; import { catalogEntity } from "../../main/catalog-sources/general"; import { MigrationDeclaration, migrationLog } from "../helpers"; import { generateNewIdFor } from "../utils"; @@ -37,6 +37,12 @@ interface Pre500WorkspaceStoreModel { }[]; } +interface PartialHotbar { + id: string; + name: string; + items: (null | HotbarItem)[]; +} + export default { version: "5.0.0-beta.10", run(store) { @@ -46,7 +52,7 @@ export default { try { const workspaceStoreData: Pre500WorkspaceStoreModel = fse.readJsonSync(path.join(userDataPath, "lens-workspace-store.json")); const { clusters }: ClusterStoreModel = fse.readJSONSync(path.join(userDataPath, "lens-cluster-store.json")); - const workspaceHotbars = new Map(); // mapping from WorkspaceId to HotBar + const workspaceHotbars = new Map(); // mapping from WorkspaceId to HotBar for (const { id, name } of workspaceStoreData.workspaces) { migrationLog(`Creating new hotbar for ${name}`); @@ -103,7 +109,7 @@ export default { hotbar.items.push(null); } - hotbars.push(hotbar); + hotbars.push(hotbar as Hotbar); } /** @@ -123,11 +129,7 @@ export default { if (freeIndex === -1) { // making a new hotbar is less destructive if the first hotbar // called "default" is full than overriding a hotbar item - const hotbar = { - id: uuid.v4(), - name: "initial", - items: HotbarStore.getInitialItems(), - }; + const hotbar = getEmptyHotbar("initial"); hotbar.items[0] = { entity: { uid, name, source } }; hotbars.unshift(hotbar); @@ -135,11 +137,7 @@ export default { defaultHotbar.items[freeIndex] = { entity: { uid, name, source } }; } } else { - const hotbar = { - id: uuid.v4(), - name: "default", - items: HotbarStore.getInitialItems(), - }; + const hotbar = getEmptyHotbar("default"); hotbar.items[0] = { entity: { uid, name, source } }; hotbars.unshift(hotbar); diff --git a/src/migrations/hotbar-store/5.0.0-beta.5.ts b/src/migrations/hotbar-store/5.0.0-beta.5.ts index 8d589e9543..f9cfd77262 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.5.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.5.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { Hotbar } from "../../common/hotbar-store"; +import type { Hotbar } from "../../common/hotbar-types"; import { catalogEntityRegistry } from "../../main/catalog"; import type { MigrationDeclaration } from "../helpers"; diff --git a/src/migrations/user-store/5.0.3-beta.1.ts b/src/migrations/user-store/5.0.3-beta.1.ts index ef3448116d..728cf6a395 100644 --- a/src/migrations/user-store/5.0.3-beta.1.ts +++ b/src/migrations/user-store/5.0.3-beta.1.ts @@ -23,10 +23,10 @@ import { app } from "electron"; import { existsSync, readFileSync } from "fs"; import path from "path"; import os from "os"; -import { ClusterStore, ClusterStoreModel } from "../../common/cluster-store"; +import type { ClusterStoreModel } from "../../common/cluster-store"; import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../common/user-store"; import { MigrationDeclaration, migrationLog } from "../helpers"; -import { isLogicalChildPath } from "../../common/utils"; +import { isLogicalChildPath, storedKubeConfigFolder } from "../../common/utils"; export default { version: "5.0.3-beta.1", @@ -42,8 +42,8 @@ export default { for (const cluster of clusters) { const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath); - if (dirOfKubeconfig === ClusterStore.storedKubeConfigFolder) { - migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under ClusterStore.storedKubeConfigFolder`); + if (dirOfKubeconfig === storedKubeConfigFolder()) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under the stored KubeConfig folder`); continue; } diff --git a/src/main/proxy/index.ts b/src/preload.ts similarity index 92% rename from src/main/proxy/index.ts rename to src/preload.ts index def9c80b5a..71c601c2fa 100644 --- a/src/main/proxy/index.ts +++ b/src/preload.ts @@ -19,7 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -// Don't export the contents here -// It will break the extension webpack +import fetch from "node-fetch"; -export default {}; +export { + fetch +}; diff --git a/src/renderer/api/index.ts b/src/renderer/api/index.ts index e46898d3b7..054dac794f 100644 --- a/src/renderer/api/index.ts +++ b/src/renderer/api/index.ts @@ -19,19 +19,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { JsonApi, JsonApiErrorParsed } from "./json-api"; -import { KubeJsonApi } from "./kube-json-api"; +import type { JsonApiErrorParsed } from "../../common/k8s-api/json-api"; +import type { Response } from "node-fetch"; import { Notifications } from "../components/notifications"; -import { apiKubePrefix, apiPrefix, isDebugging, isDevelopment } from "../../common/vars"; +import { apiBase, apiKube } from "../../common/k8s-api"; +export { apiBase, apiKube } from "../../common/k8s-api"; -export const apiBase = new JsonApi({ - apiBase: apiPrefix, - debug: isDevelopment || isDebugging, -}); -export const apiKube = new KubeJsonApi({ - apiBase: apiKubePrefix, - debug: isDevelopment, -}); // Common handler for HTTP api errors export function onApiError(error: JsonApiErrorParsed, res: Response) { @@ -43,5 +36,5 @@ export function onApiError(error: JsonApiErrorParsed, res: Response) { } } -apiBase.onError.addListener(onApiError); -apiKube.onError.addListener(onApiError); +if (apiBase) apiBase.onError.addListener(onApiError); +if (apiKube) apiKube.onError.addListener(onApiError); diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 7ee8529492..5e59767081 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -30,12 +30,11 @@ import path from "path"; import React from "react"; import { catalogURL } from "../../../common/routes"; -import { ClusterStore } from "../../../common/cluster-store"; import { appEventBus } from "../../../common/event-bus"; import { loadConfigFromString, splitConfig } from "../../../common/kube-helpers"; import { docsUrl } from "../../../common/vars"; import { navigate } from "../../navigation"; -import { iter } from "../../utils"; +import { getCustomKubeConfigPath, iter } from "../../utils"; import { AceEditor } from "../ace-editor"; import { Button } from "../button"; import { Notifications } from "../notifications"; @@ -93,7 +92,7 @@ export class AddCluster extends React.Component { appEventBus.emit({ name: "cluster-add", action: "click" }); try { - const absPath = ClusterStore.getCustomKubeConfigPath(); + const absPath = getCustomKubeConfigPath(); await fse.ensureDir(path.dirname(absPath)); await fse.writeFile(absPath, this.customConfig.trim(), { encoding: "utf-8", mode: 0o600 }); diff --git a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx index 963df018af..d1a152808a 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx @@ -22,7 +22,7 @@ import "./helm-chart-details.scss"; import React, { Component } from "react"; -import { getChartDetails, HelmChart } from "../../api/endpoints/helm-charts.api"; +import { getChartDetails, HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api"; import { observable, autorun, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { Drawer, DrawerItem } from "../drawer"; diff --git a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts index 71a5072068..e97e9fc276 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts +++ b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts @@ -22,8 +22,8 @@ import semver from "semver"; import { observable, makeObservable } from "mobx"; import { autoBind, sortCompareChartVersions } from "../../utils"; -import { getChartDetails, HelmChart, listCharts } from "../../api/endpoints/helm-charts.api"; -import { ItemStore } from "../../item.store"; +import { getChartDetails, HelmChart, listCharts } from "../../../common/k8s-api/endpoints/helm-charts.api"; +import { ItemStore } from "../../../common/item.store"; import flatten from "lodash/flatten"; export interface IChartVersion { diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index 1fc1dbf7b0..169b2c258d 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -25,7 +25,7 @@ import React, { Component } from "react"; import type { RouteComponentProps } from "react-router"; import { observer } from "mobx-react"; import { helmChartStore } from "./helm-chart.store"; -import type { HelmChart } from "../../api/endpoints/helm-charts.api"; +import type { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api"; import { HelmChartDetails } from "./helm-chart-details"; import { navigation } from "../../navigation"; import { ItemListLayout } from "../item-object-list/item-list-layout"; diff --git a/src/renderer/components/+apps-releases/release-details.tsx b/src/renderer/components/+apps-releases/release-details.tsx index fae2e3ba71..e3e68ffb53 100644 --- a/src/renderer/components/+apps-releases/release-details.tsx +++ b/src/renderer/components/+apps-releases/release-details.tsx @@ -27,7 +27,7 @@ import isEqual from "lodash/isEqual"; import { observable, reaction, makeObservable } from "mobx"; import { Link } from "react-router-dom"; import kebabCase from "lodash/kebabCase"; -import { getRelease, getReleaseValues, HelmRelease, IReleaseDetails } from "../../api/endpoints/helm-releases.api"; +import { getRelease, getReleaseValues, HelmRelease, IReleaseDetails } from "../../../common/k8s-api/endpoints/helm-releases.api"; import { HelmReleaseMenu } from "./release-menu"; import { Drawer, DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; @@ -41,11 +41,11 @@ import { releaseStore } from "./release.store"; import { Notifications } from "../notifications"; import { createUpgradeChartTab } from "../dock/upgrade-chart.store"; import { ThemeStore } from "../../theme.store"; -import { apiManager } from "../../api/api-manager"; +import { apiManager } from "../../../common/k8s-api/api-manager"; import { SubTitle } from "../layout/sub-title"; import { secretsStore } from "../+config-secrets/secrets.store"; -import { Secret } from "../../api/endpoints"; -import { getDetailsUrl } from "../kube-object"; +import { Secret } from "../../../common/k8s-api/endpoints"; +import { getDetailsUrl } from "../kube-detail-params"; import { Checkbox } from "../checkbox"; interface Props { diff --git a/src/renderer/components/+apps-releases/release-menu.tsx b/src/renderer/components/+apps-releases/release-menu.tsx index 30f048c8cb..0b8d4b8c91 100644 --- a/src/renderer/components/+apps-releases/release-menu.tsx +++ b/src/renderer/components/+apps-releases/release-menu.tsx @@ -20,7 +20,7 @@ */ import React from "react"; -import type { HelmRelease } from "../../api/endpoints/helm-releases.api"; +import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api"; import { boundMethod, cssNames } from "../../utils"; import { releaseStore } from "./release.store"; import { MenuActions, MenuActionsProps } from "../menu/menu-actions"; @@ -45,7 +45,7 @@ export class HelmReleaseMenu extends React.Component { const { release, hideDetails } = this.props; createUpgradeChartTab(release); - hideDetails && hideDetails(); + hideDetails?.(); } @boundMethod diff --git a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx index e42813f1f9..07de38232f 100644 --- a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx +++ b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx @@ -26,7 +26,7 @@ import { observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; -import { getReleaseHistory, HelmRelease, IReleaseRevision } from "../../api/endpoints/helm-releases.api"; +import { getReleaseHistory, HelmRelease, IReleaseRevision } from "../../../common/k8s-api/endpoints/helm-releases.api"; import { releaseStore } from "./release.store"; import { Select, SelectOption } from "../select"; import { Notifications } from "../notifications"; diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 9d704566e7..93b5cf5eef 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -22,9 +22,9 @@ import isEqual from "lodash/isEqual"; import { action, observable, reaction, when, makeObservable } from "mobx"; import { autoBind } from "../../utils"; -import { createRelease, deleteRelease, HelmRelease, IReleaseCreatePayload, IReleaseUpdatePayload, listReleases, rollbackRelease, updateRelease } from "../../api/endpoints/helm-releases.api"; -import { ItemStore } from "../../item.store"; -import type { Secret } from "../../api/endpoints"; +import { createRelease, deleteRelease, HelmRelease, IReleaseCreatePayload, IReleaseUpdatePayload, listReleases, rollbackRelease, updateRelease } from "../../../common/k8s-api/endpoints/helm-releases.api"; +import { ItemStore } from "../../../common/item.store"; +import type { Secret } from "../../../common/k8s-api/endpoints"; import { secretsStore } from "../+config-secrets/secrets.store"; import { namespaceStore } from "../+namespaces/namespace.store"; import { Notifications } from "../notifications"; diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index cf464710c5..d43174cc10 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -26,7 +26,7 @@ import kebabCase from "lodash/kebabCase"; import { disposeOnUnmount, observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { releaseStore } from "./release.store"; -import type { HelmRelease } from "../../api/endpoints/helm-releases.api"; +import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api"; import { ReleaseDetails } from "./release-details"; import { ReleaseRollbackDialog } from "./release-rollback-dialog"; import { navigation } from "../../navigation"; diff --git a/src/renderer/components/+catalog/catalog-entity.store.tsx b/src/renderer/components/+catalog/catalog-entity.store.tsx index b606d54c1a..c5bb96e5f2 100644 --- a/src/renderer/components/+catalog/catalog-entity.store.tsx +++ b/src/renderer/components/+catalog/catalog-entity.store.tsx @@ -25,14 +25,14 @@ import React from "react"; import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from "mobx"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import type { CatalogEntity, CatalogEntityActionContext } from "../../api/catalog-entity"; -import { ItemObject, ItemStore } from "../../item.store"; +import { ItemObject, ItemStore } from "../../../common/item.store"; import { CatalogCategory, catalogCategoryRegistry } from "../../../common/catalog"; import { autoBind } from "../../../common/utils"; import { Badge } from "../badge"; import { navigation } from "../../navigation"; import { searchUrlParam } from "../input"; import { makeCss } from "../../../common/utils/makeCss"; -import { KubeObject } from "../../api/kube-object"; +import { KubeObject } from "../../../common/k8s-api/kube-object"; const css = makeCss(styles); diff --git a/src/renderer/components/+cluster/cluster-issues.tsx b/src/renderer/components/+cluster/cluster-issues.tsx index f35f8bea61..9b5f73b9a6 100644 --- a/src/renderer/components/+cluster/cluster-issues.tsx +++ b/src/renderer/components/+cluster/cluster-issues.tsx @@ -30,12 +30,12 @@ import { Table, TableCell, TableHead, TableRow } from "../table"; import { nodesStore } from "../+nodes/nodes.store"; import { eventStore } from "../+events/event.store"; import { boundMethod, cssNames, prevDefault } from "../../utils"; -import type { ItemObject } from "../../item.store"; +import type { ItemObject } from "../../../common/item.store"; import { Spinner } from "../spinner"; import { ThemeStore } from "../../theme.store"; -import { lookupApiLink } from "../../api/kube-api"; -import { kubeSelectedUrlParam, showDetails } from "../kube-object"; -import { kubeWatchApi } from "../../api/kube-watch-api"; +import { kubeSelectedUrlParam, showDetails } from "../kube-detail-params"; +import { kubeWatchApi } from "../../../common/k8s-api/kube-watch-api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; interface Props { className?: string; @@ -106,7 +106,7 @@ export class ClusterIssues extends React.Component { age: getAge(), message, kind, - selfLink: lookupApiLink(involvedObject, error), + selfLink: apiManager.lookupApiLink(involvedObject, error), }); }); diff --git a/src/renderer/components/+cluster/cluster-metrics.tsx b/src/renderer/components/+cluster/cluster-metrics.tsx index 0c4910e7e5..43e540dca2 100644 --- a/src/renderer/components/+cluster/cluster-metrics.tsx +++ b/src/renderer/components/+cluster/cluster-metrics.tsx @@ -31,7 +31,7 @@ import { Spinner } from "../spinner"; import { ZebraStripes } from "../chart/zebra-stripes.plugin"; import { ClusterNoMetrics } from "./cluster-no-metrics"; import { ClusterMetricSwitchers } from "./cluster-metric-switchers"; -import { getMetricLastPoints } from "../../api/endpoints/metrics.api"; +import { getMetricLastPoints } from "../../../common/k8s-api/endpoints/metrics.api"; export const ClusterMetrics = observer(() => { const { metricType, metricNodeRole, getMetricsValues, metricsLoaded, metrics } = clusterOverviewStore; diff --git a/src/renderer/components/+cluster/cluster-overview.store.ts b/src/renderer/components/+cluster/cluster-overview.store.ts index 547eb6832f..17cc100109 100644 --- a/src/renderer/components/+cluster/cluster-overview.store.ts +++ b/src/renderer/components/+cluster/cluster-overview.store.ts @@ -20,12 +20,12 @@ */ import { action, observable, reaction, when, makeObservable } from "mobx"; -import { KubeObjectStore } from "../../kube-object.store"; -import { Cluster, clusterApi, getMetricsByNodeNames, IClusterMetrics } from "../../api/endpoints"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { Cluster, clusterApi, getMetricsByNodeNames, IClusterMetrics } from "../../../common/k8s-api/endpoints"; import { autoBind, createStorage } from "../../utils"; -import { IMetricsReqParams, normalizeMetrics } from "../../api/endpoints/metrics.api"; +import { IMetricsReqParams, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api"; import { nodesStore } from "../+nodes/nodes.store"; -import { apiManager } from "../../api/api-manager"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export enum MetricType { MEMORY = "memory", diff --git a/src/renderer/components/+cluster/cluster-overview.tsx b/src/renderer/components/+cluster/cluster-overview.tsx index 8149f614ff..e68c2f752f 100644 --- a/src/renderer/components/+cluster/cluster-overview.tsx +++ b/src/renderer/components/+cluster/cluster-overview.tsx @@ -26,8 +26,7 @@ import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { nodesStore } from "../+nodes/nodes.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import { getHostedCluster } from "../../../common/cluster-store"; -import { interval } from "../../utils"; +import { getHostedClusterId, interval } from "../../utils"; import { TabLayout } from "../layout/tab-layout"; import { Spinner } from "../spinner"; import { ClusterIssues } from "./cluster-issues"; @@ -35,14 +34,19 @@ import { ClusterMetrics } from "./cluster-metrics"; import { clusterOverviewStore } from "./cluster-overview.store"; import { ClusterPieCharts } from "./cluster-pie-charts"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; +import { ClusterStore } from "../../../common/cluster-store"; @observer export class ClusterOverview extends React.Component { private metricPoller = interval(60, () => this.loadMetrics()); loadMetrics() { - getHostedCluster().available && clusterOverviewStore.loadMetrics(); + const cluster = ClusterStore.getInstance().getById(getHostedClusterId()); + + if (cluster.available) { + clusterOverviewStore.loadMetrics(); + } } componentDidMount() { diff --git a/src/renderer/components/+cluster/cluster-pie-charts.tsx b/src/renderer/components/+cluster/cluster-pie-charts.tsx index 979a91f0bb..76bb6967f6 100644 --- a/src/renderer/components/+cluster/cluster-pie-charts.tsx +++ b/src/renderer/components/+cluster/cluster-pie-charts.tsx @@ -31,7 +31,7 @@ import { ChartData, PieChart } from "../chart"; import { ClusterNoMetrics } from "./cluster-no-metrics"; import { bytesToUnits } from "../../utils"; import { ThemeStore } from "../../theme.store"; -import { getMetricLastPoints } from "../../api/endpoints/metrics.api"; +import { getMetricLastPoints } from "../../../common/k8s-api/endpoints/metrics.api"; function createLabels(rawLabelData: [string, number | undefined][]): string[] { return rawLabelData.map(([key, value]) => `${key}: ${value?.toFixed(2) || "N/A"}`); diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index cf56b2c35c..4dd544e5b1 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -26,18 +26,19 @@ import { observer } from "mobx-react"; import { Link } from "react-router-dom"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; -import { KubeObjectDetailsProps, getDetailsUrl } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; import { cssNames } from "../../utils"; -import { HorizontalPodAutoscaler, HpaMetricType, IHpaMetric } from "../../api/endpoints/hpa.api"; +import { HorizontalPodAutoscaler, HpaMetricType, IHpaMetric } from "../../../common/k8s-api/endpoints/hpa.api"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { lookupApiLink } from "../../api/kube-api"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { KubeObjectMeta } from "../kube-object-meta"; +import { getDetailsUrl } from "../kube-detail-params"; -interface Props extends KubeObjectDetailsProps { +export interface HpaDetailsProps extends KubeObjectDetailsProps { } @observer -export class HpaDetails extends React.Component { +export class HpaDetails extends React.Component { renderMetrics() { const { object: hpa } = this.props; @@ -54,7 +55,7 @@ export class HpaDetails extends React.Component { case HpaMetricType.Object: const { target } = metric.object; const { kind, name } = target; - const objectUrl = getDetailsUrl(lookupApiLink(target, hpa)); + const objectUrl = getDetailsUrl(apiManager.lookupApiLink(target, hpa)); return ( <> @@ -107,7 +108,7 @@ export class HpaDetails extends React.Component { {scaleTargetRef && ( - + {scaleTargetRef.kind}/{scaleTargetRef.name} )} diff --git a/src/renderer/components/+config-autoscalers/hpa.store.ts b/src/renderer/components/+config-autoscalers/hpa.store.ts index d92ffd3a6f..c129b32acd 100644 --- a/src/renderer/components/+config-autoscalers/hpa.store.ts +++ b/src/renderer/components/+config-autoscalers/hpa.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { HorizontalPodAutoscaler, hpaApi } from "../../api/endpoints/hpa.api"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { HorizontalPodAutoscaler, hpaApi } from "../../../common/k8s-api/endpoints/hpa.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class HPAStore extends KubeObjectStore { api = hpaApi; diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index 35bf3d6375..c620e6c629 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -24,8 +24,8 @@ import "./hpa.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../kube-object"; -import type { HorizontalPodAutoscaler } from "../../api/endpoints/hpa.api"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; +import type { HorizontalPodAutoscaler } from "../../../common/k8s-api/endpoints/hpa.api"; import { hpaStore } from "./hpa.store"; import { Badge } from "../badge"; import { cssNames } from "../../utils"; diff --git a/src/renderer/components/+config-limit-ranges/limit-range-details.tsx b/src/renderer/components/+config-limit-ranges/limit-range-details.tsx index 8531029313..e9acbd0a22 100644 --- a/src/renderer/components/+config-limit-ranges/limit-range-details.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-range-details.tsx @@ -23,9 +23,9 @@ import "./limit-range-details.scss"; import React from "react"; import { observer } from "mobx-react"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import { LimitPart, LimitRange, LimitRangeItem, Resource } from "../../api/endpoints/limit-range.api"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { LimitPart, LimitRange, LimitRangeItem, Resource } from "../../../common/k8s-api/endpoints/limit-range.api"; +import { KubeObjectMeta } from "../kube-object-meta"; import { DrawerItem } from "../drawer/drawer-item"; import { Badge } from "../badge"; diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.store.ts b/src/renderer/components/+config-limit-ranges/limit-ranges.store.ts index af7ebe6b41..4f4bd52ced 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.store.ts +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { apiManager } from "../../api/api-manager"; -import { LimitRange, limitRangeApi } from "../../api/endpoints/limit-range.api"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { LimitRange, limitRangeApi } from "../../../common/k8s-api/endpoints/limit-range.api"; export class LimitRangesStore extends KubeObjectStore { api = limitRangeApi; diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx index e0bec106aa..dfc132b20f 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx @@ -23,7 +23,7 @@ import "./limit-ranges.scss"; import type { RouteComponentProps } from "react-router"; import { observer } from "mobx-react"; -import { KubeObjectListLayout } from "../kube-object/kube-object-list-layout"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { limitRangeStore } from "./limit-ranges.store"; import React from "react"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+config-maps/config-map-details.tsx b/src/renderer/components/+config-maps/config-map-details.tsx index 4858868186..abbd31c97a 100644 --- a/src/renderer/components/+config-maps/config-map-details.tsx +++ b/src/renderer/components/+config-maps/config-map-details.tsx @@ -29,9 +29,9 @@ import { Notifications } from "../notifications"; import { Input } from "../input"; import { Button } from "../button"; import { configMapsStore } from "./config-maps.store"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import type { ConfigMap } from "../../api/endpoints"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { ConfigMap } from "../../../common/k8s-api/endpoints"; +import { KubeObjectMeta } from "../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+config-maps/config-maps.store.ts b/src/renderer/components/+config-maps/config-maps.store.ts index e45c9b3b27..164b9fa604 100644 --- a/src/renderer/components/+config-maps/config-maps.store.ts +++ b/src/renderer/components/+config-maps/config-maps.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { ConfigMap, configMapApi } from "../../api/endpoints/configmap.api"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { ConfigMap, configMapApi } from "../../../common/k8s-api/endpoints/configmap.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class ConfigMapsStore extends KubeObjectStore { api = configMapApi; diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index b9fecc9fc9..9733846994 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -25,7 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { configMapsStore } from "./config-maps.store"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { ConfigMapsRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx index ad4bc41dc1..15c17ae639 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx @@ -25,9 +25,9 @@ import React from "react"; import { observer } from "mobx-react"; import { DrawerItem } from "../drawer"; import { Badge } from "../badge"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import type { PodDisruptionBudget } from "../../api/endpoints"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { PodDisruptionBudget } from "../../../common/k8s-api/endpoints"; +import { KubeObjectMeta } from "../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts index b4a48fbef7..3011e20065 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { pdbApi, PodDisruptionBudget } from "../../api/endpoints/poddisruptionbudget.api"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { pdbApi, PodDisruptionBudget } from "../../../common/k8s-api/endpoints/poddisruptionbudget.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class PodDisruptionBudgetsStore extends KubeObjectStore { api = pdbApi; diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx index f662c96ab3..1278f96f59 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx @@ -24,9 +24,10 @@ import "./pod-disruption-budgets.scss"; import * as React from "react"; import { observer } from "mobx-react"; import { podDisruptionBudgetsStore } from "./pod-disruption-budgets.store"; -import type { PodDisruptionBudget } from "../../api/endpoints/poddisruptionbudget.api"; -import { KubeObjectDetailsProps, KubeObjectListLayout } from "../kube-object"; +import type { PodDisruptionBudget } from "../../../common/k8s-api/endpoints/poddisruptionbudget.api"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; enum columnId { name = "name", diff --git a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx index b341d2c86a..0fc2149e45 100644 --- a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx +++ b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx @@ -28,7 +28,7 @@ import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; import { Input } from "../input"; import { systemName } from "../input/input_validators"; -import { IResourceQuotaValues, resourceQuotaApi } from "../../api/endpoints/resource-quota.api"; +import { IResourceQuotaValues, resourceQuotaApi } from "../../../common/k8s-api/endpoints/resource-quota.api"; import { Select } from "../select"; import { Icon } from "../icon"; import { Button } from "../button"; diff --git a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx index cf7c505dcf..3b07bc9a7a 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -25,11 +25,11 @@ import kebabCase from "lodash/kebabCase"; import { observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; import { cpuUnitsToNumber, cssNames, unitsToBytes, metricUnitsToNumber } from "../../utils"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import type { ResourceQuota } from "../../api/endpoints/resource-quota.api"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { ResourceQuota } from "../../../common/k8s-api/endpoints/resource-quota.api"; import { LineProgress } from "../line-progress"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts b/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts index 5e7494b33a..9ec218f346 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { ResourceQuota, resourceQuotaApi } from "../../api/endpoints/resource-quota.api"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { ResourceQuota, resourceQuotaApi } from "../../../common/k8s-api/endpoints/resource-quota.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class ResourceQuotasStore extends KubeObjectStore { api = resourceQuotaApi; diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx index e1f54f2499..060b1e29fa 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -24,7 +24,7 @@ import "./resource-quotas.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { AddQuotaDialog } from "./add-quota-dialog"; import { resourceQuotaStore } from "./resource-quotas.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+config-secrets/add-secret-dialog.tsx b/src/renderer/components/+config-secrets/add-secret-dialog.tsx index 5c417023e2..d74a523dc5 100644 --- a/src/renderer/components/+config-secrets/add-secret-dialog.tsx +++ b/src/renderer/components/+config-secrets/add-secret-dialog.tsx @@ -28,16 +28,16 @@ import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; import { Input } from "../input"; import { systemName } from "../input/input_validators"; -import { Secret, secretsApi, SecretType } from "../../api/endpoints"; +import { Secret, secretsApi, SecretType } from "../../../common/k8s-api/endpoints"; import { SubTitle } from "../layout/sub-title"; import { NamespaceSelect } from "../+namespaces/namespace-select"; import { Select, SelectOption } from "../select"; import { Icon } from "../icon"; -import type { KubeObjectMetadata } from "../../api/kube-object"; +import type { KubeObjectMetadata } from "../../../common/k8s-api/kube-object"; import { base64 } from "../../utils"; import { Notifications } from "../notifications"; import upperFirst from "lodash/upperFirst"; -import { showDetails } from "../kube-object"; +import { showDetails } from "../kube-detail-params"; interface Props extends Partial { } diff --git a/src/renderer/components/+config-secrets/secret-details.tsx b/src/renderer/components/+config-secrets/secret-details.tsx index 672ba86203..bfd6e9d257 100644 --- a/src/renderer/components/+config-secrets/secret-details.tsx +++ b/src/renderer/components/+config-secrets/secret-details.tsx @@ -32,9 +32,9 @@ import { Notifications } from "../notifications"; import { base64 } from "../../utils"; import { Icon } from "../icon"; import { secretsStore } from "./secrets.store"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import type { Secret } from "../../api/endpoints"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { Secret } from "../../../common/k8s-api/endpoints"; +import { KubeObjectMeta } from "../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+config-secrets/secrets.store.ts b/src/renderer/components/+config-secrets/secrets.store.ts index f338232371..4bf99bceda 100644 --- a/src/renderer/components/+config-secrets/secrets.store.ts +++ b/src/renderer/components/+config-secrets/secrets.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { Secret, secretsApi } from "../../api/endpoints"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { Secret, secretsApi } from "../../../common/k8s-api/endpoints"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class SecretsStore extends KubeObjectStore { api = secretsApi; diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index f00c20d67e..7e75b04d0e 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -25,7 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { AddSecretDialog } from "./add-secret-dialog"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { Badge } from "../badge"; import { secretsStore } from "./secrets.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+config/config.tsx b/src/renderer/components/+config/config.tsx index c04f5eeb37..24d84cff34 100644 --- a/src/renderer/components/+config/config.tsx +++ b/src/renderer/components/+config/config.tsx @@ -27,7 +27,7 @@ import { Secrets } from "../+config-secrets"; import { ResourceQuotas } from "../+config-resource-quotas"; import { PodDisruptionBudgets } from "../+config-pod-disruption-budgets"; import { HorizontalPodAutoscalers } from "../+config-autoscalers"; -import { isAllowedResource } from "../../../common/rbac"; +import { isAllowedResource } from "../../../common/utils/allowed-resource"; import { LimitRanges } from "../+config-limit-ranges"; import * as routes from "../../../common/routes"; diff --git a/src/renderer/components/+custom-resources/crd-details.tsx b/src/renderer/components/+custom-resources/crd-details.tsx index bef1dc6f67..d8de38d671 100644 --- a/src/renderer/components/+custom-resources/crd-details.tsx +++ b/src/renderer/components/+custom-resources/crd-details.tsx @@ -24,14 +24,14 @@ import "./crd-details.scss"; import React from "react"; import { Link } from "react-router-dom"; import { observer } from "mobx-react"; -import type { CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import type { CustomResourceDefinition } from "../../../common/k8s-api/endpoints/crd.api"; import { AceEditor } from "../ace-editor"; import { Badge } from "../badge"; import { DrawerItem, DrawerTitle } from "../drawer"; -import type { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { Input } from "../input"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+custom-resources/crd-list.tsx b/src/renderer/components/+custom-resources/crd-list.tsx index 70ae2c96fb..e257289008 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -26,9 +26,9 @@ import { computed, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { Link } from "react-router-dom"; import { stopPropagation } from "../../utils"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { crdStore } from "./crd.store"; -import type { CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import type { CustomResourceDefinition } from "../../../common/k8s-api/endpoints/crd.api"; import { Select, SelectOption } from "../select"; import { createPageParam } from "../../navigation"; import { Icon } from "../icon"; @@ -116,7 +116,7 @@ export class CrdList extends React.Component { controlShouldRenderValue={false} formatOptionLabel={({ value: group }: SelectOption) => { const isSelected = selectedGroups.includes(group); - + return (
diff --git a/src/renderer/components/+custom-resources/crd-resource-details.tsx b/src/renderer/components/+custom-resources/crd-resource-details.tsx index dc6181c63c..b20ad7d885 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.tsx +++ b/src/renderer/components/+custom-resources/crd-resource-details.tsx @@ -24,18 +24,18 @@ import "./crd-resource-details.scss"; import React from "react"; import jsonPath from "jsonpath"; import { observer } from "mobx-react"; -import { computed, makeObservable } from "mobx"; import { cssNames } from "../../utils"; import { Badge } from "../badge"; import { DrawerItem } from "../drawer"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import { crdStore } from "./crd.store"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { KubeObjectMeta } from "../kube-object-meta"; import { Input } from "../input"; -import type { AdditionalPrinterColumnsV1, CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import type { AdditionalPrinterColumnsV1, CustomResourceDefinition } from "../../../common/k8s-api/endpoints/crd.api"; import { parseJsonPath } from "../../utils/jsonPath"; +import type { KubeObject, KubeObjectMetadata, KubeObjectStatus } from "../../../common/k8s-api/kube-object"; -interface Props extends KubeObjectDetailsProps { +interface Props extends KubeObjectDetailsProps { + crd: CustomResourceDefinition; } function convertSpecValue(value: any): any { @@ -60,31 +60,22 @@ function convertSpecValue(value: any): any { @observer export class CrdResourceDetails extends React.Component { - constructor(props: Props) { - super(props); - makeObservable(this); - } - - @computed get crd() { - return crdStore.getByObject(this.props.object); - } - - renderAdditionalColumns(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) { + renderAdditionalColumns(resource: KubeObject, columns: AdditionalPrinterColumnsV1[]) { return columns.map(({ name, jsonPath: jp }) => ( - {convertSpecValue(jsonPath.value(crd, parseJsonPath(jp.slice(1))))} + {convertSpecValue(jsonPath.value(resource, parseJsonPath(jp.slice(1))))} )); } - renderStatus(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) { - const showStatus = !columns.find(column => column.name == "Status") && crd.status?.conditions; + renderStatus(customResource: KubeObject, columns: AdditionalPrinterColumnsV1[]) { + const showStatus = !columns.find(column => column.name == "Status") && Array.isArray(customResource.status?.conditions); if (!showStatus) { return null; } - const conditions = crd.status.conditions + const conditions = customResource.status.conditions .filter(({ type, reason }) => type || reason) .map(({ type, reason, message, status }) => ({ kind: type || reason, message, status })) .map(({ kind, message, status }, index) => ( @@ -104,17 +95,16 @@ export class CrdResourceDetails extends React.Component { } render() { - const { props: { object }, crd } = this; + const { props: { object, crd } } = this; if (!object || !crd) { return null; } - const className = cssNames("CrdResourceDetails", crd.getResourceKind()); const extraColumns = crd.getPrinterColumns(); return ( -
+
{this.renderAdditionalColumns(object, extraColumns)} {this.renderStatus(object, extraColumns)} diff --git a/src/renderer/components/+custom-resources/crd-resource.store.ts b/src/renderer/components/+custom-resources/crd-resource.store.ts index 335a015aa7..f71f8e6400 100644 --- a/src/renderer/components/+custom-resources/crd-resource.store.ts +++ b/src/renderer/components/+custom-resources/crd-resource.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { KubeApi } from "../../api/kube-api"; -import { KubeObjectStore } from "../../kube-object.store"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeApi } from "../../../common/k8s-api/kube-api"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; export class CRDResourceStore extends KubeObjectStore { api: KubeApi; diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index be12f910c1..7c0e36639a 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -25,12 +25,12 @@ import React from "react"; import jsonPath from "jsonpath"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../kube-object"; -import type { KubeObject } from "../../api/kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { computed, makeObservable } from "mobx"; import { crdStore } from "./crd.store"; import type { TableSortCallbacks } from "../table"; -import { apiManager } from "../../api/api-manager"; +import { apiManager } from "../../../common/k8s-api/api-manager"; import { parseJsonPath } from "../../utils/jsonPath"; import type { CRDRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+custom-resources/crd.store.ts b/src/renderer/components/+custom-resources/crd.store.ts index 25415e5ab3..83c8b5cdb6 100644 --- a/src/renderer/components/+custom-resources/crd.store.ts +++ b/src/renderer/components/+custom-resources/crd.store.ts @@ -20,13 +20,13 @@ */ import { computed, reaction, makeObservable } from "mobx"; -import { KubeObjectStore } from "../../kube-object.store"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; -import { crdApi, CustomResourceDefinition } from "../../api/endpoints/crd.api"; -import { apiManager } from "../../api/api-manager"; -import { KubeApi } from "../../api/kube-api"; +import { crdApi, CustomResourceDefinition } from "../../../common/k8s-api/endpoints/crd.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { KubeApi } from "../../../common/k8s-api/kube-api"; import { CRDResourceStore } from "./crd-resource.store"; -import { KubeObject } from "../../api/kube-object"; +import { KubeObject } from "../../../common/k8s-api/kube-object"; function initStore(crd: CustomResourceDefinition) { const apiBase = crd.getResourceApiBase(); diff --git a/src/renderer/components/+events/event-details.tsx b/src/renderer/components/+events/event-details.tsx index 639c4b9dcf..010928a6d5 100644 --- a/src/renderer/components/+events/event-details.tsx +++ b/src/renderer/components/+events/event-details.tsx @@ -26,12 +26,13 @@ import kebabCase from "lodash/kebabCase"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Link } from "react-router-dom"; import { observer } from "mobx-react"; -import { KubeObjectDetailsProps, getDetailsUrl } from "../kube-object"; -import type { KubeEvent } from "../../api/endpoints/events.api"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { KubeEvent } from "../../../common/k8s-api/endpoints/events.api"; +import { KubeObjectMeta } from "../kube-object-meta"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { lookupApiLink } from "../../api/kube-api"; import { LocaleDate } from "../locale-date"; +import { getDetailsUrl } from "../kube-detail-params"; +import { apiManager } from "../../../common/k8s-api/api-manager"; interface Props extends KubeObjectDetailsProps { } @@ -81,7 +82,7 @@ export class EventDetails extends React.Component { - + {name} diff --git a/src/renderer/components/+events/event.store.ts b/src/renderer/components/+events/event.store.ts index c2f90475d0..b655e7f611 100644 --- a/src/renderer/components/+events/event.store.ts +++ b/src/renderer/components/+events/event.store.ts @@ -21,13 +21,13 @@ import groupBy from "lodash/groupBy"; import compact from "lodash/compact"; -import { KubeObjectStore } from "../../kube-object.store"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; -import { eventApi, KubeEvent } from "../../api/endpoints/events.api"; -import type { KubeObject } from "../../api/kube-object"; -import { Pod } from "../../api/endpoints/pods.api"; +import { eventApi, KubeEvent } from "../../../common/k8s-api/endpoints/events.api"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; +import { Pod } from "../../../common/k8s-api/endpoints/pods.api"; import { podsStore } from "../+workloads-pods/pods.store"; -import { apiManager } from "../../api/api-manager"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class EventStore extends KubeObjectStore { api = eventApi; diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index 23aa985ab8..456de9e2aa 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -27,16 +27,17 @@ import { observer } from "mobx-react"; import { orderBy } from "lodash"; import { TabLayout } from "../layout/tab-layout"; import { EventStore, eventStore } from "./event.store"; -import { getDetailsUrl, KubeObjectListLayout, KubeObjectListLayoutProps } from "../kube-object"; -import type { KubeEvent } from "../../api/endpoints/events.api"; +import { KubeObjectListLayout, KubeObjectListLayoutProps } from "../kube-object-list-layout"; +import type { KubeEvent } from "../../../common/k8s-api/endpoints/events.api"; import type { TableSortCallbacks, TableSortParams } from "../table"; import type { HeaderCustomizer } from "../item-object-list"; import { Tooltip } from "../tooltip"; import { Link } from "react-router-dom"; import { cssNames, IClassName, stopPropagation } from "../../utils"; import { Icon } from "../icon"; -import { lookupApiLink } from "../../api/kube-api"; import { eventsURL } from "../../../common/routes"; +import { getDetailsUrl } from "../kube-detail-params"; +import { apiManager } from "../../../common/k8s-api/api-manager"; enum columnId { message = "message", @@ -133,7 +134,7 @@ export class Events extends React.Component { tooltip={`Limited to ${store.limit}`} /> , - title, + title, ...headerPlaceholders }; }; @@ -195,7 +196,7 @@ export class Events extends React.Component { ) }, event.getNs(), - + {involvedObject.kind}: {involvedObject.name} , event.getSource(), diff --git a/src/renderer/components/+events/kube-event-details.tsx b/src/renderer/components/+events/kube-event-details.tsx index 4ac3e63a84..7f00fd6a15 100644 --- a/src/renderer/components/+events/kube-event-details.tsx +++ b/src/renderer/components/+events/kube-event-details.tsx @@ -23,7 +23,7 @@ import "./kube-event-details.scss"; import React from "react"; import { observer } from "mobx-react"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { DrawerItem, DrawerTitle } from "../drawer"; import { cssNames } from "../../utils"; import { eventStore } from "./event.store"; diff --git a/src/renderer/components/+events/kube-event-icon.tsx b/src/renderer/components/+events/kube-event-icon.tsx index 03bfa92a07..8fe83d2940 100644 --- a/src/renderer/components/+events/kube-event-icon.tsx +++ b/src/renderer/components/+events/kube-event-icon.tsx @@ -23,10 +23,10 @@ import "./kube-event-icon.scss"; import React from "react"; import { Icon } from "../icon"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { eventStore } from "./event.store"; import { cssNames } from "../../utils"; -import type { KubeEvent } from "../../api/endpoints/events.api"; +import type { KubeEvent } from "../../../common/k8s-api/endpoints/events.api"; interface Props { object: KubeObject; diff --git a/src/renderer/components/+extensions/__tests__/extensions.test.tsx b/src/renderer/components/+extensions/__tests__/extensions.test.tsx index f51ba24575..85e88b9792 100644 --- a/src/renderer/components/+extensions/__tests__/extensions.test.tsx +++ b/src/renderer/components/+extensions/__tests__/extensions.test.tsx @@ -30,6 +30,9 @@ import { ConfirmDialog } from "../../confirm-dialog"; import { ExtensionInstallationStateStore } from "../extension-install.store"; import { Extensions } from "../extensions"; import mockFs from "mock-fs"; +import { mockWindow } from "../../../../../__mocks__/windowMock"; + +mockWindow(); jest.setTimeout(30000); jest.mock("fs-extra"); diff --git a/src/renderer/components/+namespaces/add-namespace-dialog.tsx b/src/renderer/components/+namespaces/add-namespace-dialog.tsx index 2427c9fd9b..e01381efe9 100644 --- a/src/renderer/components/+namespaces/add-namespace-dialog.tsx +++ b/src/renderer/components/+namespaces/add-namespace-dialog.tsx @@ -27,7 +27,7 @@ import { observer } from "mobx-react"; import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; import { namespaceStore } from "./namespace.store"; -import type { Namespace } from "../../api/endpoints"; +import type { Namespace } from "../../../common/k8s-api/endpoints"; import { Input } from "../input"; import { systemName } from "../input/input_validators"; import { Notifications } from "../notifications"; diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index ee051977e5..08493e7a6b 100644 --- a/src/renderer/components/+namespaces/namespace-details.tsx +++ b/src/renderer/components/+namespaces/namespace-details.tsx @@ -26,17 +26,18 @@ import { computed, makeObservable, observable, reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem } from "../drawer"; import { boundMethod, cssNames } from "../../utils"; -import { getMetricsForNamespace, IPodMetrics, Namespace } from "../../api/endpoints"; -import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; +import { getMetricsForNamespace, IPodMetrics, Namespace } from "../../../common/k8s-api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; import { Link } from "react-router-dom"; import { Spinner } from "../spinner"; import { resourceQuotaStore } from "../+config-resource-quotas/resource-quotas.store"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; import { limitRangeStore } from "../+config-limit-ranges/limit-ranges.store"; import { ResourceMetrics } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; +import { getDetailsUrl } from "../kube-detail-params"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+namespaces/namespace-select.tsx b/src/renderer/components/+namespaces/namespace-select.tsx index 3a662ef66c..0cefdb2905 100644 --- a/src/renderer/components/+namespaces/namespace-select.tsx +++ b/src/renderer/components/+namespaces/namespace-select.tsx @@ -28,7 +28,7 @@ import { Select, SelectOption, SelectProps } from "../select"; import { cssNames } from "../../utils"; import { Icon } from "../icon"; import { namespaceStore } from "./namespace.store"; -import { kubeWatchApi } from "../../api/kube-watch-api"; +import { kubeWatchApi } from "../../../common/k8s-api/kube-watch-api"; interface Props extends SelectProps { showIcons?: boolean; diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index cc4a8b98ce..54f98702fc 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -21,9 +21,9 @@ import { action, comparer, computed, IReactionDisposer, IReactionOptions, makeObservable, reaction, } from "mobx"; import { autoBind, createStorage, noop } from "../../utils"; -import { KubeObjectStore, KubeObjectStoreLoadingParams } from "../../kube-object.store"; -import { Namespace, namespacesApi } from "../../api/endpoints/namespaces.api"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore, KubeObjectStoreLoadingParams } from "../../../common/k8s-api/kube-object.store"; +import { Namespace, namespacesApi } from "../../../common/k8s-api/endpoints/namespaces.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class NamespaceStore extends KubeObjectStore { api = namespacesApi; diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index cc29fa05ea..f0d3164e23 100644 --- a/src/renderer/components/+namespaces/namespaces.tsx +++ b/src/renderer/components/+namespaces/namespaces.tsx @@ -22,12 +22,12 @@ import "./namespaces.scss"; import React from "react"; -import { NamespaceStatus } from "../../api/endpoints"; +import { NamespaceStatus } from "../../../common/k8s-api/endpoints"; import { AddNamespaceDialog } from "./add-namespace-dialog"; import { TabLayout } from "../layout/tab-layout"; import { Badge } from "../badge"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { namespaceStore } from "./namespace.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { NamespacesRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+network-endpoints/endpoint-details.tsx b/src/renderer/components/+network-endpoints/endpoint-details.tsx index 8554a4b2f7..7805cd8d70 100644 --- a/src/renderer/components/+network-endpoints/endpoint-details.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-details.tsx @@ -24,9 +24,9 @@ import "./endpoint-details.scss"; import React from "react"; import { observer } from "mobx-react"; import { DrawerTitle } from "../drawer"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import type { Endpoint } from "../../api/endpoints"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { Endpoint } from "../../../common/k8s-api/endpoints"; +import { KubeObjectMeta } from "../kube-object-meta"; import { EndpointSubsetList } from "./endpoint-subset-list"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx index 1556394a9c..7dcb1fc99b 100644 --- a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx @@ -23,12 +23,12 @@ import "./endpoint-subset-list.scss"; import React from "react"; import { observer } from "mobx-react"; -import { EndpointSubset, Endpoint, EndpointAddress} from "../../api/endpoints"; +import { EndpointSubset, Endpoint, EndpointAddress} from "../../../common/k8s-api/endpoints"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { boundMethod } from "../../utils"; -import { lookupApiLink } from "../../api/kube-api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; import { Link } from "react-router-dom"; -import { getDetailsUrl } from "../kube-object"; +import { getDetailsUrl } from "../kube-detail-params"; interface Props { subset: EndpointSubset; @@ -92,7 +92,7 @@ export class EndpointSubsetList extends React.Component { {address.hostname} { address.targetRef && ( - + {address.targetRef.name} )} diff --git a/src/renderer/components/+network-endpoints/endpoints.store.ts b/src/renderer/components/+network-endpoints/endpoints.store.ts index f51e8a072a..e19f868dea 100644 --- a/src/renderer/components/+network-endpoints/endpoints.store.ts +++ b/src/renderer/components/+network-endpoints/endpoints.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { Endpoint, endpointApi } from "../../api/endpoints/endpoint.api"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { Endpoint, endpointApi } from "../../../common/k8s-api/endpoints/endpoint.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class EndpointStore extends KubeObjectStore { api = endpointApi; diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index 940ab89783..38c99fc19c 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -25,7 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; import { endpointStore } from "./endpoints.store"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { EndpointRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+network-ingresses/ingress-charts.tsx b/src/renderer/components/+network-ingresses/ingress-charts.tsx index 178d61652c..0811209450 100644 --- a/src/renderer/components/+network-ingresses/ingress-charts.tsx +++ b/src/renderer/components/+network-ingresses/ingress-charts.tsx @@ -22,9 +22,9 @@ import React, { useContext } from "react"; import { observer } from "mobx-react"; import type { ChartOptions, ChartPoint } from "chart.js"; -import type { IIngressMetrics, Ingress } from "../../api/endpoints"; +import type { IIngressMetrics, Ingress } from "../../../common/k8s-api/endpoints"; import { BarChart, memoryOptions } from "../chart"; -import { normalizeMetrics, isMetricsEmpty } from "../../api/endpoints/metrics.api"; +import { normalizeMetrics, isMetricsEmpty } from "../../../common/k8s-api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; import { ResourceMetricsContext, IResourceMetricsValue } from "../resource-metrics"; diff --git a/src/renderer/components/+network-ingresses/ingress-details.tsx b/src/renderer/components/+network-ingresses/ingress-details.tsx index 995e4d3b0f..7fe7665041 100644 --- a/src/renderer/components/+network-ingresses/ingress-details.tsx +++ b/src/renderer/components/+network-ingresses/ingress-details.tsx @@ -25,15 +25,15 @@ import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { observable, reaction } from "mobx"; import { DrawerItem, DrawerTitle } from "../drawer"; -import type { ILoadBalancerIngress, Ingress } from "../../api/endpoints"; +import type { ILoadBalancerIngress, Ingress } from "../../../common/k8s-api/endpoints"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { ResourceMetrics } from "../resource-metrics"; -import type { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; import { IngressCharts } from "./ingress-charts"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { getBackendServiceNamePort, getMetricsForIngress, IIngressMetrics } from "../../api/endpoints/ingress.api"; +import { KubeObjectMeta } from "../kube-object-meta"; +import { getBackendServiceNamePort, getMetricsForIngress, IIngressMetrics } from "../../../common/k8s-api/endpoints/ingress.api"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+network-ingresses/ingress.store.ts b/src/renderer/components/+network-ingresses/ingress.store.ts index 72190a5103..ecf25ffa6a 100644 --- a/src/renderer/components/+network-ingresses/ingress.store.ts +++ b/src/renderer/components/+network-ingresses/ingress.store.ts @@ -18,9 +18,9 @@ * 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 { apiManager } from "../../api/api-manager"; -import { Ingress, ingressApi } from "../../api/endpoints"; -import { KubeObjectStore } from "../../kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { Ingress, ingressApi } from "../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; export class IngressStore extends KubeObjectStore { api = ingressApi; diff --git a/src/renderer/components/+network-ingresses/ingresses.tsx b/src/renderer/components/+network-ingresses/ingresses.tsx index 153a4eb62f..cfe71e7c8c 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -25,7 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; import { ingressStore } from "./ingress.store"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { IngressRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+network-policies/network-policies.tsx b/src/renderer/components/+network-policies/network-policies.tsx index 65579eaa56..f6ba704de4 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -24,7 +24,7 @@ import "./network-policies.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { networkPolicyStore } from "./network-policy.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { NetworkPoliciesRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+network-policies/network-policy-details.tsx b/src/renderer/components/+network-policies/network-policy-details.tsx index 7ac8f2f7bf..e08b891c41 100644 --- a/src/renderer/components/+network-policies/network-policy-details.tsx +++ b/src/renderer/components/+network-policies/network-policy-details.tsx @@ -24,12 +24,12 @@ import "./network-policy-details.scss"; import get from "lodash/get"; import React, { Fragment } from "react"; import { DrawerItem, DrawerTitle } from "../drawer"; -import type { IPolicyEgress, IPolicyIngress, IPolicyIpBlock, IPolicySelector, NetworkPolicy } from "../../api/endpoints/network-policy.api"; +import type { IPolicyEgress, IPolicyIngress, IPolicyIpBlock, IPolicySelector, NetworkPolicy } from "../../../common/k8s-api/endpoints/network-policy.api"; import { Badge } from "../badge"; import { SubTitle } from "../layout/sub-title"; import { observer } from "mobx-react"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { KubeObjectMeta } from "../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+network-policies/network-policy.store.ts b/src/renderer/components/+network-policies/network-policy.store.ts index f5186e4cfd..4dc547a82e 100644 --- a/src/renderer/components/+network-policies/network-policy.store.ts +++ b/src/renderer/components/+network-policies/network-policy.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { NetworkPolicy, networkPolicyApi } from "../../api/endpoints/network-policy.api"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { NetworkPolicy, networkPolicyApi } from "../../../common/k8s-api/endpoints/network-policy.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class NetworkPolicyStore extends KubeObjectStore { api = networkPolicyApi; diff --git a/src/renderer/components/+network-services/service-details-endpoint.tsx b/src/renderer/components/+network-services/service-details-endpoint.tsx index 2e04c78f1a..a36425afb6 100644 --- a/src/renderer/components/+network-services/service-details-endpoint.tsx +++ b/src/renderer/components/+network-services/service-details-endpoint.tsx @@ -19,14 +19,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { observer } from "mobx-react"; import React from "react"; import { Table, TableHead, TableCell, TableRow } from "../table"; import { prevDefault } from "../../utils"; import { endpointStore } from "../+network-endpoints/endpoints.store"; import { Spinner } from "../spinner"; -import { showDetails } from "../kube-object"; +import { showDetails } from "../kube-detail-params"; interface Props { endpoint: KubeObject; diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx index ec10cd5f94..66a09672a1 100644 --- a/src/renderer/components/+network-services/service-details.tsx +++ b/src/renderer/components/+network-services/service-details.tsx @@ -25,13 +25,13 @@ import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import type { Service } from "../../api/endpoints"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { Service } from "../../../common/k8s-api/endpoints"; +import { KubeObjectMeta } from "../kube-object-meta"; import { ServicePortComponent } from "./service-port-component"; import { endpointStore } from "../+network-endpoints/endpoints.store"; import { ServiceDetailsEndpoint } from "./service-details-endpoint"; -import { kubeWatchApi } from "../../api/kube-watch-api"; +import { kubeWatchApi } from "../../../common/k8s-api/kube-watch-api"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+network-services/service-port-component.tsx b/src/renderer/components/+network-services/service-port-component.tsx index a0c4c32f49..96bb7385cb 100644 --- a/src/renderer/components/+network-services/service-port-component.tsx +++ b/src/renderer/components/+network-services/service-port-component.tsx @@ -23,7 +23,7 @@ import "./service-port-component.scss"; import React from "react"; import { observer } from "mobx-react"; -import type { Service, ServicePort } from "../../api/endpoints"; +import type { Service, ServicePort } from "../../../common/k8s-api/endpoints"; import { apiBase } from "../../api"; import { observable, makeObservable } from "mobx"; import { cssNames } from "../../utils"; diff --git a/src/renderer/components/+network-services/services.store.ts b/src/renderer/components/+network-services/services.store.ts index 608d311617..3da75d70a3 100644 --- a/src/renderer/components/+network-services/services.store.ts +++ b/src/renderer/components/+network-services/services.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; -import { Service, serviceApi } from "../../api/endpoints/service.api"; -import { apiManager } from "../../api/api-manager"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { Service, serviceApi } from "../../../common/k8s-api/endpoints/service.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class ServiceStore extends KubeObjectStore { api = serviceApi; diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index 745236be61..fe3b2b40ab 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -24,7 +24,7 @@ import "./services.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { Badge } from "../badge"; import { serviceStore } from "./services.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+network/network.tsx b/src/renderer/components/+network/network.tsx index ae4a7596fa..7c177ee2a3 100644 --- a/src/renderer/components/+network/network.tsx +++ b/src/renderer/components/+network/network.tsx @@ -28,7 +28,7 @@ import { Services } from "../+network-services"; import { Endpoints } from "../+network-endpoints"; import { Ingresses } from "../+network-ingresses"; import { NetworkPolicies } from "../+network-policies"; -import { isAllowedResource } from "../../../common/rbac"; +import { isAllowedResource } from "../../../common/utils/allowed-resource"; import * as routes from "../../../common/routes"; @observer diff --git a/src/renderer/components/+nodes/node-charts.tsx b/src/renderer/components/+nodes/node-charts.tsx index 60d6e08842..6f9495fce5 100644 --- a/src/renderer/components/+nodes/node-charts.tsx +++ b/src/renderer/components/+nodes/node-charts.tsx @@ -20,9 +20,9 @@ */ import React, { useContext } from "react"; -import type { IClusterMetrics, Node } from "../../api/endpoints"; +import type { IClusterMetrics, Node } from "../../../common/k8s-api/endpoints"; import { BarChart, cpuOptions, memoryOptions } from "../chart"; -import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; +import { isMetricsEmpty, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; import { observer } from "mobx-react"; @@ -172,7 +172,7 @@ export const NodeCharts = observer(() => { yAxes: [{ ticks: { callback: value => value - } + } }] }, tooltips: { diff --git a/src/renderer/components/+nodes/node-details-resources.tsx b/src/renderer/components/+nodes/node-details-resources.tsx index 636a3f55f0..c53018d62f 100644 --- a/src/renderer/components/+nodes/node-details-resources.tsx +++ b/src/renderer/components/+nodes/node-details-resources.tsx @@ -25,7 +25,7 @@ import { Table } from "../table/table"; import { TableHead } from "../table/table-head"; import { TableRow } from "../table/table-row"; import React from "react"; -import type { Node } from "../../api/endpoints"; +import type { Node } from "../../../common/k8s-api/endpoints"; import { TableCell } from "../table/table-cell"; interface Props { diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index 56ce3e53e2..9e86939260 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -29,14 +29,14 @@ import { DrawerItem, DrawerItemLabels } from "../drawer"; import { Badge } from "../badge"; import { ResourceMetrics } from "../resource-metrics"; import { podsStore } from "../+workloads-pods/pods.store"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import { getMetricsByNodeNames, IClusterMetrics, Node } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { getMetricsByNodeNames, IClusterMetrics, Node } from "../../../common/k8s-api/endpoints"; import { NodeCharts } from "./node-charts"; import { makeObservable, observable, reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { NodeDetailsResources } from "./node-details-resources"; import { DrawerTitle } from "../drawer/drawer-title"; import { boundMethod } from "../../utils"; diff --git a/src/renderer/components/+nodes/nodes.store.ts b/src/renderer/components/+nodes/nodes.store.ts index 43b5e32cca..e398c2896d 100644 --- a/src/renderer/components/+nodes/nodes.store.ts +++ b/src/renderer/components/+nodes/nodes.store.ts @@ -21,9 +21,9 @@ import { sum } from "lodash"; import { computed, makeObservable } from "mobx"; -import { apiManager } from "../../api/api-manager"; -import { Node, nodesApi } from "../../api/endpoints"; -import { KubeObjectStore } from "../../kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { Node, nodesApi } from "../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; export class NodesStore extends KubeObjectStore { diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 1225ea8c15..4df10dcadf 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -27,16 +27,16 @@ import { cssNames, interval } from "../../utils"; import { TabLayout } from "../layout/tab-layout"; import { nodesStore } from "./nodes.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import { KubeObjectListLayout } from "../kube-object"; -import { getMetricsForAllNodes, INodeMetrics, Node } from "../../api/endpoints/nodes.api"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; +import { getMetricsForAllNodes, INodeMetrics, Node } from "../../../common/k8s-api/endpoints/nodes.api"; import { LineProgress } from "../line-progress"; -import { bytesToUnits } from "../../utils/convertMemory"; +import { bytesToUnits } from "../../../common/utils/convertMemory"; import { Tooltip, TooltipPosition } from "../tooltip"; import kebabCase from "lodash/kebabCase"; import upperFirst from "lodash/upperFirst"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { Badge } from "../badge/badge"; -import { kubeWatchApi } from "../../api/kube-watch-api"; +import { kubeWatchApi } from "../../../common/k8s-api/kube-watch-api"; import { eventStore } from "../+events/event.store"; import type { NodesRouteParams } from "../../../common/routes"; import { observable } from "mobx"; diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts b/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts index ea51c2acb6..afb655b426 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { PodSecurityPolicy, pspApi } from "../../api/endpoints"; -import { KubeObjectStore } from "../../kube-object.store"; -import { apiManager } from "../../api/api-manager"; +import { PodSecurityPolicy, pspApi } from "../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class PodSecurityPoliciesStore extends KubeObjectStore { api = pspApi; diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx index c578bf8e34..232f7a5fba 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx @@ -23,7 +23,7 @@ import "./pod-security-policies.scss"; import React from "react"; import { observer } from "mobx-react"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { podSecurityPoliciesStore } from "./pod-security-policies.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx index abdefe9228..0c1c73567a 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx @@ -24,11 +24,11 @@ import "./pod-security-policy-details.scss"; import React from "react"; import { observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import type { PodSecurityPolicy } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { PodSecurityPolicy } from "../../../common/k8s-api/endpoints"; import { Badge } from "../badge"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+storage-classes/storage-class-details.tsx b/src/renderer/components/+storage-classes/storage-class-details.tsx index 0d2b9e0600..2e8eae63bb 100644 --- a/src/renderer/components/+storage-classes/storage-class-details.tsx +++ b/src/renderer/components/+storage-classes/storage-class-details.tsx @@ -26,9 +26,9 @@ import startCase from "lodash/startCase"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; import { observer } from "mobx-react"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import type { StorageClass } from "../../api/endpoints"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import type { StorageClass } from "../../../common/k8s-api/endpoints"; +import { KubeObjectMeta } from "../kube-object-meta"; import { storageClassStore } from "./storage-class.store"; import { VolumeDetailsList } from "../+storage-volumes/volume-details-list"; import { volumesStore } from "../+storage-volumes/volumes.store"; diff --git a/src/renderer/components/+storage-classes/storage-class.store.ts b/src/renderer/components/+storage-classes/storage-class.store.ts index f2f7056377..67c7d33f6b 100644 --- a/src/renderer/components/+storage-classes/storage-class.store.ts +++ b/src/renderer/components/+storage-classes/storage-class.store.ts @@ -19,10 +19,10 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; -import { StorageClass, storageClassApi } from "../../api/endpoints/storage-class.api"; -import { apiManager } from "../../api/api-manager"; +import { StorageClass, storageClassApi } from "../../../common/k8s-api/endpoints/storage-class.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; import { volumesStore } from "../+storage-volumes/volumes.store"; export class StorageClassStore extends KubeObjectStore { diff --git a/src/renderer/components/+storage-classes/storage-classes.tsx b/src/renderer/components/+storage-classes/storage-classes.tsx index d81d32041e..64edc494e1 100644 --- a/src/renderer/components/+storage-classes/storage-classes.tsx +++ b/src/renderer/components/+storage-classes/storage-classes.tsx @@ -24,7 +24,7 @@ import "./storage-classes.scss"; import React from "react"; import type { RouteComponentProps } from "react-router-dom"; import { observer } from "mobx-react"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { storageClassStore } from "./storage-class.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { StorageClassesRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx index 372d6bfb6e..2836d33f91 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx @@ -30,10 +30,12 @@ import { podsStore } from "../+workloads-pods/pods.store"; import { Link } from "react-router-dom"; import { ResourceMetrics } from "../resource-metrics"; import { VolumeClaimDiskChart } from "./volume-claim-disk-chart"; -import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-object"; -import { getMetricsForPvc, IPvcMetrics, PersistentVolumeClaim } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { getMetricsForPvc, IPvcMetrics, PersistentVolumeClaim } from "../../../common/k8s-api/endpoints"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; +import { KubeObjectMeta } from "../kube-object-meta"; +import { getDetailsUrl } from "../kube-detail-params"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx index cd1c6f7024..04e888e4f1 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx @@ -21,9 +21,9 @@ import React, { useContext } from "react"; import { observer } from "mobx-react"; -import type { IPvcMetrics, PersistentVolumeClaim } from "../../api/endpoints"; +import type { IPvcMetrics, PersistentVolumeClaim } from "../../../common/k8s-api/endpoints"; import { BarChart, ChartDataSets, memoryOptions } from "../chart"; -import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; +import { isMetricsEmpty, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; import { ThemeStore } from "../../theme.store"; diff --git a/src/renderer/components/+storage-volume-claims/volume-claim.store.ts b/src/renderer/components/+storage-volume-claims/volume-claim.store.ts index 4beca645a5..808592083a 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim.store.ts +++ b/src/renderer/components/+storage-volume-claims/volume-claim.store.ts @@ -18,9 +18,9 @@ * 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 { apiManager } from "../../api/api-manager"; -import { PersistentVolumeClaim, pvcApi } from "../../api/endpoints"; -import { KubeObjectStore } from "../../kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { PersistentVolumeClaim, pvcApi } from "../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; export class VolumeClaimStore extends KubeObjectStore { api = pvcApi; diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.tsx b/src/renderer/components/+storage-volume-claims/volume-claims.tsx index 60230033f9..798cce0e53 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -26,12 +26,13 @@ import { observer } from "mobx-react"; import { Link, RouteComponentProps } from "react-router-dom"; import { volumeClaimStore } from "./volume-claim.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; -import { unitsToBytes } from "../../utils/convertMemory"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; +import { unitsToBytes } from "../../../common/utils/convertMemory"; import { stopPropagation } from "../../utils"; -import { storageClassApi } from "../../api/endpoints"; +import { storageClassApi } from "../../../common/k8s-api/endpoints"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { VolumeClaimsRouteParams } from "../../../common/routes"; +import { getDetailsUrl } from "../kube-detail-params"; enum columnId { name = "name", diff --git a/src/renderer/components/+storage-volumes/volume-details-list.tsx b/src/renderer/components/+storage-volumes/volume-details-list.tsx index e38af1d3f8..b9e2f9af0d 100644 --- a/src/renderer/components/+storage-volumes/volume-details-list.tsx +++ b/src/renderer/components/+storage-volumes/volume-details-list.tsx @@ -23,11 +23,11 @@ import "./volume-details-list.scss"; import React from "react"; import { observer } from "mobx-react"; -import type { PersistentVolume } from "../../api/endpoints/persistent-volume.api"; +import type { PersistentVolume } from "../../../common/k8s-api/endpoints/persistent-volume.api"; import { boundMethod } from "../../../common/utils/autobind"; import { TableRow } from "../table/table-row"; import { cssNames, prevDefault } from "../../utils"; -import { showDetails } from "../kube-object/kube-object-details"; +import { showDetails } from "../kube-detail-params"; import { TableCell } from "../table/table-cell"; import { Spinner } from "../spinner/spinner"; import { DrawerTitle } from "../drawer/drawer-title"; diff --git a/src/renderer/components/+storage-volumes/volume-details.tsx b/src/renderer/components/+storage-volumes/volume-details.tsx index 66354db988..781df4b5b4 100644 --- a/src/renderer/components/+storage-volumes/volume-details.tsx +++ b/src/renderer/components/+storage-volumes/volume-details.tsx @@ -27,9 +27,10 @@ import { Link } from "react-router-dom"; import { observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; -import { PersistentVolume, pvcApi } from "../../api/endpoints"; -import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { PersistentVolume, pvcApi } from "../../../common/k8s-api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { KubeObjectMeta } from "../kube-object-meta"; +import { getDetailsUrl } from "../kube-detail-params"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+storage-volumes/volumes.store.ts b/src/renderer/components/+storage-volumes/volumes.store.ts index 726792884b..f0567db82c 100644 --- a/src/renderer/components/+storage-volumes/volumes.store.ts +++ b/src/renderer/components/+storage-volumes/volumes.store.ts @@ -19,11 +19,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; -import { PersistentVolume, persistentVolumeApi } from "../../api/endpoints/persistent-volume.api"; -import { apiManager } from "../../api/api-manager"; -import type { StorageClass } from "../../api/endpoints/storage-class.api"; +import { PersistentVolume, persistentVolumeApi } from "../../../common/k8s-api/endpoints/persistent-volume.api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import type { StorageClass } from "../../../common/k8s-api/endpoints/storage-class.api"; export class PersistentVolumesStore extends KubeObjectStore { api = persistentVolumeApi; diff --git a/src/renderer/components/+storage-volumes/volumes.tsx b/src/renderer/components/+storage-volumes/volumes.tsx index ce1e313e9b..c98ff6f8fb 100644 --- a/src/renderer/components/+storage-volumes/volumes.tsx +++ b/src/renderer/components/+storage-volumes/volumes.tsx @@ -24,10 +24,11 @@ import "./volumes.scss"; import React from "react"; import { observer } from "mobx-react"; import { Link, RouteComponentProps } from "react-router-dom"; -import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; +import { getDetailsUrl } from "../kube-detail-params"; import { stopPropagation } from "../../utils"; import { volumesStore } from "./volumes.store"; -import { pvcApi, storageClassApi } from "../../api/endpoints"; +import { pvcApi, storageClassApi } from "../../../common/k8s-api/endpoints"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { VolumesRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+storage/storage.tsx b/src/renderer/components/+storage/storage.tsx index 3d4dd55ce3..cdc06a1e3c 100644 --- a/src/renderer/components/+storage/storage.tsx +++ b/src/renderer/components/+storage/storage.tsx @@ -27,7 +27,7 @@ import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; import { PersistentVolumes } from "../+storage-volumes"; import { StorageClasses } from "../+storage-classes"; import { PersistentVolumeClaims } from "../+storage-volume-claims"; -import { isAllowedResource } from "../../../common/rbac"; +import { isAllowedResource } from "../../../common/utils/allowed-resource"; import * as routes from "../../../common/routes"; @observer diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx index 7dea8c083e..2be9588fa7 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx +++ b/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx @@ -25,13 +25,13 @@ import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import React from "react"; -import type { ClusterRoleBinding, ClusterRoleBindingSubject } from "../../../api/endpoints"; +import type { ClusterRoleBinding, ClusterRoleBindingSubject } from "../../../../common/k8s-api/endpoints"; import { autoBind, ObservableHashSet, prevDefault } from "../../../utils"; import { AddRemoveButtons } from "../../add-remove-buttons"; import { ConfirmDialog } from "../../confirm-dialog"; import { DrawerTitle } from "../../drawer"; -import type { KubeObjectDetailsProps } from "../../kube-object"; -import { KubeObjectMeta } from "../../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../../kube-object-details"; +import { KubeObjectMeta } from "../../kube-object-meta"; import { Table, TableCell, TableHead, TableRow } from "../../table"; import { ClusterRoleBindingDialog } from "./dialog"; import { clusterRoleBindingsStore } from "./store"; diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx index 0d810f6c48..b575068804 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx +++ b/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx @@ -26,11 +26,11 @@ import { disposeOnUnmount, observer } from "mobx-react"; import React from "react"; import { serviceAccountsStore } from "../+service-accounts/store"; -import { ClusterRole, ClusterRoleBinding, ClusterRoleBindingSubject, ServiceAccount } from "../../../api/endpoints"; +import { ClusterRole, ClusterRoleBinding, ClusterRoleBindingSubject, ServiceAccount } from "../../../../common/k8s-api/endpoints"; import { Dialog, DialogProps } from "../../dialog"; import { EditableList } from "../../editable-list"; import { Icon } from "../../icon"; -import { showDetails } from "../../kube-object"; +import { showDetails } from "../../kube-detail-params"; import { SubTitle } from "../../layout/sub-title"; import { Notifications } from "../../notifications"; import { Select, SelectOption } from "../../select"; @@ -202,13 +202,13 @@ export class ClusterRoleBindingDialog extends React.Component { if (!this.selectedRoleRef || this.bindingName === this.selectedRoleRef.getName()) { this.bindingName = value.getName(); } - + this.selectedRoleRef = value; }} /> - { } diff --git a/src/renderer/components/+user-management/+cluster-roles/store.ts b/src/renderer/components/+user-management/+cluster-roles/store.ts index 6fe25a2c42..d3d5da561b 100644 --- a/src/renderer/components/+user-management/+cluster-roles/store.ts +++ b/src/renderer/components/+user-management/+cluster-roles/store.ts @@ -18,9 +18,9 @@ * 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 { apiManager } from "../../../api/api-manager"; -import { ClusterRole, clusterRoleApi } from "../../../api/endpoints"; -import { KubeObjectStore } from "../../../kube-object.store"; +import { apiManager } from "../../../../common/k8s-api/api-manager"; +import { ClusterRole, clusterRoleApi } from "../../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../../utils"; export class ClusterRolesStore extends KubeObjectStore { diff --git a/src/renderer/components/+user-management/+cluster-roles/view.tsx b/src/renderer/components/+user-management/+cluster-roles/view.tsx index 271802c10b..aa36fbd82a 100644 --- a/src/renderer/components/+user-management/+cluster-roles/view.tsx +++ b/src/renderer/components/+user-management/+cluster-roles/view.tsx @@ -24,7 +24,7 @@ import "./view.scss"; import { observer } from "mobx-react"; import React from "react"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../../kube-object"; +import { KubeObjectListLayout } from "../../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { AddClusterRoleDialog } from "./add-dialog"; import { clusterRolesStore } from "./store"; diff --git a/src/renderer/components/+user-management/+role-bindings/details.tsx b/src/renderer/components/+user-management/+role-bindings/details.tsx index aee0f6c2af..b04690dcf7 100644 --- a/src/renderer/components/+user-management/+role-bindings/details.tsx +++ b/src/renderer/components/+user-management/+role-bindings/details.tsx @@ -24,13 +24,13 @@ import "./details.scss"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import React from "react"; -import type { RoleBinding, RoleBindingSubject } from "../../../api/endpoints"; +import type { RoleBinding, RoleBindingSubject } from "../../../../common/k8s-api/endpoints"; import { prevDefault, boundMethod } from "../../../utils"; import { AddRemoveButtons } from "../../add-remove-buttons"; import { ConfirmDialog } from "../../confirm-dialog"; import { DrawerTitle } from "../../drawer"; -import type { KubeObjectDetailsProps } from "../../kube-object"; -import { KubeObjectMeta } from "../../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../../kube-object-details"; +import { KubeObjectMeta } from "../../kube-object-meta"; import { Table, TableCell, TableHead, TableRow } from "../../table"; import { RoleBindingDialog } from "./dialog"; import { roleBindingsStore } from "./store"; diff --git a/src/renderer/components/+user-management/+role-bindings/dialog.tsx b/src/renderer/components/+user-management/+role-bindings/dialog.tsx index c163a01b83..0f331ee698 100644 --- a/src/renderer/components/+user-management/+role-bindings/dialog.tsx +++ b/src/renderer/components/+user-management/+role-bindings/dialog.tsx @@ -28,11 +28,11 @@ import React from "react"; import { rolesStore } from "../+roles/store"; import { serviceAccountsStore } from "../+service-accounts/store"; import { NamespaceSelect } from "../../+namespaces/namespace-select"; -import { ClusterRole, Role, roleApi, RoleBinding, RoleBindingSubject, ServiceAccount } from "../../../api/endpoints"; +import { ClusterRole, Role, roleApi, RoleBinding, RoleBindingSubject, ServiceAccount } from "../../../../common/k8s-api/endpoints"; import { Dialog, DialogProps } from "../../dialog"; import { EditableList } from "../../editable-list"; import { Icon } from "../../icon"; -import { showDetails } from "../../kube-object"; +import { showDetails } from "../../kube-detail-params"; import { SubTitle } from "../../layout/sub-title"; import { Notifications } from "../../notifications"; import { Select, SelectOption } from "../../select"; diff --git a/src/renderer/components/+user-management/+role-bindings/hashers.ts b/src/renderer/components/+user-management/+role-bindings/hashers.ts index 2d8771bb18..2ab149738b 100644 --- a/src/renderer/components/+user-management/+role-bindings/hashers.ts +++ b/src/renderer/components/+user-management/+role-bindings/hashers.ts @@ -20,7 +20,7 @@ */ import { MD5 } from "crypto-js"; -import type { RoleBindingSubject } from "../../../api/endpoints"; +import type { RoleBindingSubject } from "../../../../common/k8s-api/endpoints"; export function hashRoleBindingSubject(subject: RoleBindingSubject): string { return MD5(JSON.stringify([ diff --git a/src/renderer/components/+user-management/+role-bindings/store.ts b/src/renderer/components/+user-management/+role-bindings/store.ts index d59db292e6..c55126b1a4 100644 --- a/src/renderer/components/+user-management/+role-bindings/store.ts +++ b/src/renderer/components/+user-management/+role-bindings/store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { apiManager } from "../../../api/api-manager"; -import { RoleBinding, roleBindingApi, RoleBindingSubject } from "../../../api/endpoints"; -import { KubeObjectStore } from "../../../kube-object.store"; +import { apiManager } from "../../../../common/k8s-api/api-manager"; +import { RoleBinding, roleBindingApi, RoleBindingSubject } from "../../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store"; import { HashSet } from "../../../utils"; import { hashRoleBindingSubject } from "./hashers"; diff --git a/src/renderer/components/+user-management/+role-bindings/view.tsx b/src/renderer/components/+user-management/+role-bindings/view.tsx index 247e72482c..3eb60ad9ba 100644 --- a/src/renderer/components/+user-management/+role-bindings/view.tsx +++ b/src/renderer/components/+user-management/+role-bindings/view.tsx @@ -23,7 +23,7 @@ import "./view.scss"; import { observer } from "mobx-react"; import React from "react"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../../kube-object"; +import { KubeObjectListLayout } from "../../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { RoleBindingDialog } from "./dialog"; import { roleBindingsStore } from "./store"; diff --git a/src/renderer/components/+user-management/+roles/add-dialog.tsx b/src/renderer/components/+user-management/+roles/add-dialog.tsx index 361c14dc61..65d4505976 100644 --- a/src/renderer/components/+user-management/+roles/add-dialog.tsx +++ b/src/renderer/components/+user-management/+roles/add-dialog.tsx @@ -28,7 +28,7 @@ import { observer } from "mobx-react"; import { NamespaceSelect } from "../../+namespaces/namespace-select"; import { Dialog, DialogProps } from "../../dialog"; import { Input } from "../../input"; -import { showDetails } from "../../kube-object"; +import { showDetails } from "../../kube-detail-params"; import { SubTitle } from "../../layout/sub-title"; import { Notifications } from "../../notifications"; import { Wizard, WizardStep } from "../../wizard"; @@ -40,7 +40,7 @@ interface Props extends Partial { @observer export class AddRoleDialog extends React.Component { static isOpen = observable.box(false); - + @observable roleName = ""; @observable namespace = ""; diff --git a/src/renderer/components/+user-management/+roles/details.tsx b/src/renderer/components/+user-management/+roles/details.tsx index 2b6f822ed0..02aa46f560 100644 --- a/src/renderer/components/+user-management/+roles/details.tsx +++ b/src/renderer/components/+user-management/+roles/details.tsx @@ -24,10 +24,10 @@ import "./details.scss"; import { observer } from "mobx-react"; import React from "react"; -import type { Role } from "../../../api/endpoints"; +import type { Role } from "../../../../common/k8s-api/endpoints"; import { DrawerTitle } from "../../drawer"; -import type { KubeObjectDetailsProps } from "../../kube-object"; -import { KubeObjectMeta } from "../../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../../kube-object-details"; +import { KubeObjectMeta } from "../../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+user-management/+roles/store.ts b/src/renderer/components/+user-management/+roles/store.ts index 43774e8b09..e0033af6e7 100644 --- a/src/renderer/components/+user-management/+roles/store.ts +++ b/src/renderer/components/+user-management/+roles/store.ts @@ -18,9 +18,9 @@ * 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 { apiManager } from "../../../api/api-manager"; -import { Role, roleApi } from "../../../api/endpoints"; -import { KubeObjectStore } from "../../../kube-object.store"; +import { apiManager } from "../../../../common/k8s-api/api-manager"; +import { Role, roleApi } from "../../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../../utils"; export class RolesStore extends KubeObjectStore { diff --git a/src/renderer/components/+user-management/+roles/view.tsx b/src/renderer/components/+user-management/+roles/view.tsx index dd71c83b93..30e58e787d 100644 --- a/src/renderer/components/+user-management/+roles/view.tsx +++ b/src/renderer/components/+user-management/+roles/view.tsx @@ -24,7 +24,7 @@ import "./view.scss"; import { observer } from "mobx-react"; import React from "react"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../../kube-object"; +import { KubeObjectListLayout } from "../../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { AddRoleDialog } from "./add-dialog"; import { rolesStore } from "./store"; diff --git a/src/renderer/components/+user-management/+service-accounts/create-dialog.tsx b/src/renderer/components/+user-management/+service-accounts/create-dialog.tsx index 1f50e717c6..5665835ff4 100644 --- a/src/renderer/components/+user-management/+service-accounts/create-dialog.tsx +++ b/src/renderer/components/+user-management/+service-accounts/create-dialog.tsx @@ -29,7 +29,7 @@ import { NamespaceSelect } from "../../+namespaces/namespace-select"; import { Dialog, DialogProps } from "../../dialog"; import { Input } from "../../input"; import { systemName } from "../../input/input_validators"; -import { showDetails } from "../../kube-object"; +import { showDetails } from "../../kube-detail-params"; import { SubTitle } from "../../layout/sub-title"; import { Notifications } from "../../notifications"; import { Wizard, WizardStep } from "../../wizard"; diff --git a/src/renderer/components/+user-management/+service-accounts/details.tsx b/src/renderer/components/+user-management/+service-accounts/details.tsx index 578cde2ab4..3cc12dd24d 100644 --- a/src/renderer/components/+user-management/+service-accounts/details.tsx +++ b/src/renderer/components/+user-management/+service-accounts/details.tsx @@ -27,13 +27,14 @@ import React from "react"; import { Link } from "react-router-dom"; import { secretsStore } from "../../+config-secrets/secrets.store"; -import { Secret, ServiceAccount } from "../../../api/endpoints"; +import { Secret, ServiceAccount } from "../../../../common/k8s-api/endpoints"; import { DrawerItem, DrawerTitle } from "../../drawer"; import { Icon } from "../../icon"; -import { getDetailsUrl, KubeObjectDetailsProps } from "../../kube-object"; -import { KubeObjectMeta } from "../../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../../kube-object-details"; +import { KubeObjectMeta } from "../../kube-object-meta"; import { Spinner } from "../../spinner"; import { ServiceAccountsSecret } from "./secret"; +import { getDetailsUrl } from "../../kube-detail-params"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+user-management/+service-accounts/secret.tsx b/src/renderer/components/+user-management/+service-accounts/secret.tsx index 4eff2b30dd..3acd53f0dc 100644 --- a/src/renderer/components/+user-management/+service-accounts/secret.tsx +++ b/src/renderer/components/+user-management/+service-accounts/secret.tsx @@ -24,7 +24,7 @@ import "./secret.scss"; import moment from "moment"; import React from "react"; -import type { Secret } from "../../../api/endpoints/secret.api"; +import type { Secret } from "../../../../common/k8s-api/endpoints/secret.api"; import { prevDefault } from "../../../utils"; import { Icon } from "../../icon"; diff --git a/src/renderer/components/+user-management/+service-accounts/store.ts b/src/renderer/components/+user-management/+service-accounts/store.ts index 51bbabca34..3e3abd4d4a 100644 --- a/src/renderer/components/+user-management/+service-accounts/store.ts +++ b/src/renderer/components/+user-management/+service-accounts/store.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { apiManager } from "../../../api/api-manager"; -import { ServiceAccount, serviceAccountsApi } from "../../../api/endpoints"; -import { KubeObjectStore } from "../../../kube-object.store"; +import { apiManager } from "../../../../common/k8s-api/api-manager"; +import { ServiceAccount, serviceAccountsApi } from "../../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../../utils"; export class ServiceAccountsStore extends KubeObjectStore { diff --git a/src/renderer/components/+user-management/+service-accounts/view.tsx b/src/renderer/components/+user-management/+service-accounts/view.tsx index c8bdaaa656..a538384b95 100644 --- a/src/renderer/components/+user-management/+service-accounts/view.tsx +++ b/src/renderer/components/+user-management/+service-accounts/view.tsx @@ -24,11 +24,11 @@ import "./view.scss"; import { observer } from "mobx-react"; import React from "react"; import type { RouteComponentProps } from "react-router"; -import type { ServiceAccount } from "../../../api/endpoints/service-accounts.api"; +import type { ServiceAccount } from "../../../../common/k8s-api/endpoints/service-accounts.api"; import { Icon } from "../../icon"; -import { KubeObjectListLayout } from "../../kube-object"; +import { KubeObjectListLayout } from "../../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; -import type { KubeObjectMenuProps } from "../../kube-object/kube-object-menu"; +import type { KubeObjectMenuProps } from "../../kube-object-menu"; import { openServiceAccountKubeConfig } from "../../kubeconfig-dialog"; import { MenuItem } from "../../menu"; import { CreateServiceAccountDialog } from "./create-dialog"; diff --git a/src/renderer/components/+user-management/select-options.tsx b/src/renderer/components/+user-management/select-options.tsx index 65bfeeec9e..a51824f388 100644 --- a/src/renderer/components/+user-management/select-options.tsx +++ b/src/renderer/components/+user-management/select-options.tsx @@ -20,8 +20,8 @@ */ import React from "react"; -import type { ServiceAccount } from "../../api/endpoints"; -import type { KubeObject } from "../../api/kube-object"; +import type { ServiceAccount } from "../../../common/k8s-api/endpoints"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { Icon } from "../icon"; import type { SelectOption } from "../select"; import { TooltipPosition } from "../tooltip"; diff --git a/src/renderer/components/+user-management/user-management.tsx b/src/renderer/components/+user-management/user-management.tsx index 3c7e042cd5..2b6191a13e 100644 --- a/src/renderer/components/+user-management/user-management.tsx +++ b/src/renderer/components/+user-management/user-management.tsx @@ -25,7 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; import { PodSecurityPolicies } from "../+pod-security-policies"; -import { isAllowedResource } from "../../../common/rbac"; +import { isAllowedResource } from "../../../common/utils/allowed-resource"; import * as routes from "../../../common/routes"; import { ClusterRoleBindings } from "./+cluster-role-bindings"; import { ServiceAccounts } from "./+service-accounts"; diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx index 12f919b4e6..108ec47012 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx @@ -29,9 +29,10 @@ import { Badge } from "../badge/badge"; import { jobStore } from "../+workloads-jobs/job.store"; import { Link } from "react-router-dom"; import { cronJobStore } from "./cronjob.store"; -import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; -import type { CronJob, Job } from "../../api/endpoints"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { getDetailsUrl } from "../kube-detail-params"; +import type { CronJob, Job } from "../../../common/k8s-api/endpoints"; +import { KubeObjectMeta } from "../kube-object-meta"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx index 6938185479..aa0d401cae 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx @@ -26,12 +26,12 @@ import { observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; -import { CronJob, cronJobApi, jobApi } from "../../api/endpoints"; +import { CronJob, cronJobApi, jobApi } from "../../../common/k8s-api/endpoints"; import { Notifications } from "../notifications"; import { cssNames } from "../../utils"; import { Input } from "../input"; import { systemName, maxLength } from "../input/input_validators"; -import type { KubeObjectMetadata } from "../../api/kube-object"; +import type { KubeObjectMetadata } from "../../../common/k8s-api/kube-object"; interface Props extends Partial { } diff --git a/src/renderer/components/+workloads-cronjobs/cronjob.store.ts b/src/renderer/components/+workloads-cronjobs/cronjob.store.ts index 90ea0e0c2c..4f46eaf60a 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob.store.ts +++ b/src/renderer/components/+workloads-cronjobs/cronjob.store.ts @@ -19,11 +19,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; -import { CronJob, cronJobApi } from "../../api/endpoints/cron-job.api"; +import { CronJob, cronJobApi } from "../../../common/k8s-api/endpoints/cron-job.api"; import { jobStore } from "../+workloads-jobs/job.store"; -import { apiManager } from "../../api/api-manager"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class CronJobStore extends KubeObjectStore { api = cronJobApi; diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index 8dca609361..40dcb481ba 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -24,14 +24,14 @@ import "./cronjobs.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import { CronJob, cronJobApi } from "../../api/endpoints/cron-job.api"; +import { CronJob, cronJobApi } from "../../../common/k8s-api/endpoints/cron-job.api"; import { MenuItem } from "../menu"; import { Icon } from "../icon"; import { cronJobStore } from "./cronjob.store"; import { jobStore } from "../+workloads-jobs/job.store"; import { eventStore } from "../+events/event.store"; -import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; -import { KubeObjectListLayout } from "../kube-object"; +import type { KubeObjectMenuProps } from "../kube-object-menu"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { CronJobTriggerDialog } from "./cronjob-trigger-dialog"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { ConfirmDialog } from "../confirm-dialog/confirm-dialog"; diff --git a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx index 4479995506..92615e54ef 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx @@ -30,15 +30,15 @@ import { PodDetailsTolerations } from "../+workloads-pods/pod-details-toleration import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"; import { daemonSetStore } from "./daemonsets.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import { DaemonSet, getMetricsForDaemonSets, IPodMetrics } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { DaemonSet, getMetricsForDaemonSets, IPodMetrics } from "../../../common/k8s-api/endpoints"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { makeObservable, observable, reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { boundMethod } from "../../utils"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.store.ts b/src/renderer/components/+workloads-daemonsets/daemonsets.store.ts index e8f729fde1..605aa65c93 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.store.ts +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.store.ts @@ -21,9 +21,9 @@ import { makeObservable } from "mobx"; import { podsStore } from "../+workloads-pods/pods.store"; -import { apiManager } from "../../api/api-manager"; -import { DaemonSet, daemonSetApi, Pod, PodStatus } from "../../api/endpoints"; -import { KubeObjectStore } from "../../kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { DaemonSet, daemonSetApi, Pod, PodStatus } from "../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; export class DaemonSetStore extends KubeObjectStore { diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx index 63f04a8049..e9c4442b15 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx @@ -24,12 +24,12 @@ import "./daemonsets.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import type { DaemonSet } from "../../api/endpoints"; +import type { DaemonSet } from "../../../common/k8s-api/endpoints"; import { eventStore } from "../+events/event.store"; import { daemonSetStore } from "./daemonsets.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { nodesStore } from "../+nodes/nodes.store"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { Badge } from "../badge"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { DaemonSetsRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index 110c9a5679..8f4a45a580 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -26,21 +26,21 @@ import kebabCase from "lodash/kebabCase"; import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem } from "../drawer"; import { Badge } from "../badge"; -import { Deployment, getMetricsForDeployments, IPodMetrics } from "../../api/endpoints"; +import { Deployment, getMetricsForDeployments, IPodMetrics } from "../../../common/k8s-api/endpoints"; import { PodDetailsTolerations } from "../+workloads-pods/pod-details-tolerations"; import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"; import { podsStore } from "../+workloads-pods/pods.store"; -import type { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { deploymentStore } from "./deployments.store"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { makeObservable, observable, reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; import { DeploymentReplicaSets } from "./deployment-replicasets"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { boundMethod } from "../../utils"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx b/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx index 0a556ddcfc..e332b19fe8 100644 --- a/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx @@ -23,15 +23,15 @@ import "./deployment-replicasets.scss"; import React from "react"; import { observer } from "mobx-react"; -import type { ReplicaSet } from "../../api/endpoints"; -import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import type { ReplicaSet } from "../../../common/k8s-api/endpoints"; +import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object-menu"; import { Spinner } from "../spinner"; import { prevDefault, stopPropagation } from "../../utils"; import { DrawerTitle } from "../drawer"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; -import { showDetails } from "../kube-object"; +import { showDetails } from "../kube-detail-params"; enum sortBy { diff --git a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx index 2df89e90df..22c90dda2c 100644 --- a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx @@ -24,8 +24,7 @@ import { render, waitFor, fireEvent } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; import { DeploymentScaleDialog } from "./deployment-scale-dialog"; -jest.mock("../../api/endpoints"); -import { Deployment, deploymentApi } from "../../api/endpoints"; +import { Deployment, DeploymentApi } from "../../../common/k8s-api/endpoints/deployment.api"; const dummyDeployment: Deployment = { apiVersion: "v1", @@ -116,6 +115,13 @@ const dummyDeployment: Deployment = { }; describe("", () => { + let deploymentApi: DeploymentApi; + + beforeEach(() => { + deploymentApi = new DeploymentApi({ + objectConstructor: Deployment, + }); + }); it("renders w/o errors", () => { const { container } = render(); @@ -124,12 +130,12 @@ describe("", () => { }); it("inits with a dummy deployment with mocked current/desired scale", async () => { - // mock deploymentApi.getReplicas() which will be called + // mock deploymentApi.getReplicas() which will be called // when rendered. const initReplicas = 3; deploymentApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); - const { getByTestId } = render(); + const { getByTestId } = render(); DeploymentScaleDialog.open(dummyDeployment); // we need to wait for the DeploymentScaleDialog to show up @@ -143,14 +149,14 @@ describe("", () => { expect(currentScale).toHaveTextContent(`${initReplicas}`); expect(desiredScale).toHaveTextContent(`${initReplicas}`); }); - + }); it("changes the desired scale when clicking the icon buttons +/-", async () => { const initReplicas = 1; deploymentApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); - const component = render(); + const component = render(); DeploymentScaleDialog.open(dummyDeployment); await waitFor(async () => { diff --git a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.tsx b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.tsx index 0e7ae52f3d..f4dec0a9b9 100644 --- a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.tsx @@ -26,13 +26,14 @@ import { computed, observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; -import { Deployment, deploymentApi } from "../../api/endpoints"; +import { Deployment, DeploymentApi, deploymentApi } from "../../../common/k8s-api/endpoints"; import { Icon } from "../icon"; import { Slider } from "../slider"; import { Notifications } from "../notifications"; import { cssNames } from "../../utils"; interface Props extends Partial { + deploymentApi: DeploymentApi } const dialogState = observable.object({ @@ -42,6 +43,10 @@ const dialogState = observable.object({ @observer export class DeploymentScaleDialog extends Component { + static defaultProps = { + deploymentApi + }; + @observable ready = false; @observable currentReplicas = 0; @observable desiredReplicas = 0; @@ -80,7 +85,7 @@ export class DeploymentScaleDialog extends Component { onOpen = async () => { const { deployment } = this; - this.currentReplicas = await deploymentApi.getReplicas({ + this.currentReplicas = await this.props.deploymentApi.getReplicas({ namespace: deployment.getNs(), name: deployment.getName(), }); @@ -102,7 +107,7 @@ export class DeploymentScaleDialog extends Component { try { if (currentReplicas !== desiredReplicas) { - await deploymentApi.scale({ + await this.props.deploymentApi.scale({ name: deployment.getName(), namespace: deployment.getNs(), }, desiredReplicas); diff --git a/src/renderer/components/+workloads-deployments/deployments.store.ts b/src/renderer/components/+workloads-deployments/deployments.store.ts index 34b6e295ad..64f349491e 100644 --- a/src/renderer/components/+workloads-deployments/deployments.store.ts +++ b/src/renderer/components/+workloads-deployments/deployments.store.ts @@ -21,9 +21,9 @@ import { makeObservable } from "mobx"; import { podsStore } from "../+workloads-pods/pods.store"; -import { apiManager } from "../../api/api-manager"; -import { Deployment, deploymentApi, PodStatus } from "../../api/endpoints"; -import { KubeObjectStore } from "../../kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { Deployment, deploymentApi, PodStatus } from "../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; export class DeploymentStore extends KubeObjectStore { diff --git a/src/renderer/components/+workloads-deployments/deployments.tsx b/src/renderer/components/+workloads-deployments/deployments.tsx index d43670f6e7..28705fd53d 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -24,8 +24,8 @@ import "./deployments.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import { Deployment, deploymentApi } from "../../api/endpoints"; -import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import { Deployment, deploymentApi } from "../../../common/k8s-api/endpoints"; +import type { KubeObjectMenuProps } from "../kube-object-menu"; import { MenuItem } from "../menu"; import { Icon } from "../icon"; import { DeploymentScaleDialog } from "./deployment-scale-dialog"; @@ -35,7 +35,7 @@ import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { nodesStore } from "../+nodes/nodes.store"; import { eventStore } from "../+events/event.store"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { cssNames } from "../../utils"; import kebabCase from "lodash/kebabCase"; import orderBy from "lodash/orderBy"; diff --git a/src/renderer/components/+workloads-jobs/job-details.tsx b/src/renderer/components/+workloads-jobs/job-details.tsx index b0ba055122..6c4d9d3525 100644 --- a/src/renderer/components/+workloads-jobs/job-details.tsx +++ b/src/renderer/components/+workloads-jobs/job-details.tsx @@ -32,17 +32,18 @@ import { PodDetailsTolerations } from "../+workloads-pods/pod-details-toleration import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"; import { podsStore } from "../+workloads-pods/pods.store"; import { jobStore } from "./job.store"; -import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; -import { getMetricsForJobs, IPodMetrics, Job } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { getMetricsForJobs, IPodMetrics, Job } from "../../../common/k8s-api/endpoints"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; -import { lookupApiLink } from "../../api/kube-api"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; import { makeObservable, observable } from "mobx"; import { podMetricTabs, PodCharts } from "../+workloads-pods/pod-charts"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { ResourceMetrics } from "../resource-metrics"; import { boundMethod } from "autobind-decorator"; +import { getDetailsUrl } from "../kube-detail-params"; +import { apiManager } from "../../../common/k8s-api/api-manager"; interface Props extends KubeObjectDetailsProps { } @@ -116,7 +117,7 @@ export class JobDetails extends React.Component { { ownerRefs.map(ref => { const { name, kind } = ref; - const detailsUrl = getDetailsUrl(lookupApiLink(ref, job)); + const detailsUrl = getDetailsUrl(apiManager.lookupApiLink(ref, job)); return (

diff --git a/src/renderer/components/+workloads-jobs/job.store.ts b/src/renderer/components/+workloads-jobs/job.store.ts index 643f29385a..71f854c6c3 100644 --- a/src/renderer/components/+workloads-jobs/job.store.ts +++ b/src/renderer/components/+workloads-jobs/job.store.ts @@ -19,12 +19,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; -import { Job, jobApi } from "../../api/endpoints/job.api"; -import { CronJob, Pod, PodStatus } from "../../api/endpoints"; +import { Job, jobApi } from "../../../common/k8s-api/endpoints/job.api"; +import { CronJob, Pod, PodStatus } from "../../../common/k8s-api/endpoints"; import { podsStore } from "../+workloads-pods/pods.store"; -import { apiManager } from "../../api/api-manager"; +import { apiManager } from "../../../common/k8s-api/api-manager"; export class JobStore extends KubeObjectStore { api = jobApi; diff --git a/src/renderer/components/+workloads-jobs/jobs.tsx b/src/renderer/components/+workloads-jobs/jobs.tsx index e2640db6f6..6dc2362604 100644 --- a/src/renderer/components/+workloads-jobs/jobs.tsx +++ b/src/renderer/components/+workloads-jobs/jobs.tsx @@ -27,7 +27,7 @@ import type { RouteComponentProps } from "react-router"; import { podsStore } from "../+workloads-pods/pods.store"; import { jobStore } from "./job.store"; import { eventStore } from "../+events/event.store"; -import { KubeObjectListLayout } from "../kube-object"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import kebabCase from "lodash/kebabCase"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { JobsRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+workloads-overview/overview-statuses.tsx b/src/renderer/components/+workloads-overview/overview-statuses.tsx index ebf62c1d98..f20b9d25ff 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -28,10 +28,11 @@ import { Link } from "react-router-dom"; import { workloadStores } from "../+workloads"; import { namespaceStore } from "../+namespaces/namespace.store"; import { NamespaceSelectFilter } from "../+namespaces/namespace-select-filter"; -import { isAllowedResource, KubeResource } from "../../../common/rbac"; +import type { KubeResource } from "../../../common/rbac"; import { ResourceNames } from "../../utils/rbac"; import { boundMethod } from "../../utils"; import { workloadURL } from "../../../common/routes"; +import { isAllowedResource } from "../../../common/utils/allowed-resource"; const resources: KubeResource[] = [ "pods", diff --git a/src/renderer/components/+workloads-overview/overview.tsx b/src/renderer/components/+workloads-overview/overview.tsx index ec025f0d80..695e3edf95 100644 --- a/src/renderer/components/+workloads-overview/overview.tsx +++ b/src/renderer/components/+workloads-overview/overview.tsx @@ -32,7 +32,7 @@ import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; import { jobStore } from "../+workloads-jobs/job.store"; import { cronJobStore } from "../+workloads-cronjobs/cronjob.store"; -import { kubeWatchApi } from "../../api/kube-watch-api"; +import { kubeWatchApi } from "../../../common/k8s-api/kube-watch-api"; import { clusterContext } from "../context"; import { WorkloadsOverviewDetailRegistry } from "../../../extensions/registries"; import type { WorkloadsOverviewRouteParams } from "../../../common/routes"; diff --git a/src/renderer/components/+workloads-pods/__tests__/pod-tolerations.test.tsx b/src/renderer/components/+workloads-pods/__tests__/pod-tolerations.test.tsx index 30ef2e98e9..72d12af5a9 100644 --- a/src/renderer/components/+workloads-pods/__tests__/pod-tolerations.test.tsx +++ b/src/renderer/components/+workloads-pods/__tests__/pod-tolerations.test.tsx @@ -22,7 +22,7 @@ import React from "react"; import "@testing-library/jest-dom/extend-expect"; import { fireEvent, render } from "@testing-library/react"; -import type { IToleration } from "../../../api/workload-kube-object"; +import type { IToleration } from "../../../../common/k8s-api/workload-kube-object"; import { PodTolerations } from "../pod-tolerations"; jest.mock("electron", () => ({ diff --git a/src/renderer/components/+workloads-pods/container-charts.tsx b/src/renderer/components/+workloads-pods/container-charts.tsx index 0c810b47de..9586d7bf7c 100644 --- a/src/renderer/components/+workloads-pods/container-charts.tsx +++ b/src/renderer/components/+workloads-pods/container-charts.tsx @@ -21,9 +21,9 @@ import React, { useContext } from "react"; import { observer } from "mobx-react"; -import type { IPodMetrics } from "../../api/endpoints"; +import type { IPodMetrics } from "../../../common/k8s-api/endpoints"; import { BarChart, cpuOptions, memoryOptions } from "../chart"; -import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; +import { isMetricsEmpty, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; import { ThemeStore } from "../../theme.store"; diff --git a/src/renderer/components/+workloads-pods/pod-charts.tsx b/src/renderer/components/+workloads-pods/pod-charts.tsx index cc05aeec55..4caf12fbbd 100644 --- a/src/renderer/components/+workloads-pods/pod-charts.tsx +++ b/src/renderer/components/+workloads-pods/pod-charts.tsx @@ -22,13 +22,13 @@ import { mapValues } from "lodash"; import { observer } from "mobx-react"; import React, { useContext } from "react"; -import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; +import { isMetricsEmpty, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api"; import { BarChart, cpuOptions, memoryOptions } from "../chart"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; import { NoMetrics } from "../resource-metrics/no-metrics"; -import type { WorkloadKubeObject } from "../../api/workload-kube-object"; -import type { IPodMetrics } from "../../api/endpoints"; +import type { WorkloadKubeObject } from "../../../common/k8s-api/workload-kube-object"; +import type { IPodMetrics } from "../../../common/k8s-api/endpoints"; export const podMetricTabs = [ "CPU", diff --git a/src/renderer/components/+workloads-pods/pod-container-env.tsx b/src/renderer/components/+workloads-pods/pod-container-env.tsx index 3d3eb33474..4c847e68bb 100644 --- a/src/renderer/components/+workloads-pods/pod-container-env.tsx +++ b/src/renderer/components/+workloads-pods/pod-container-env.tsx @@ -23,7 +23,7 @@ import "./pod-container-env.scss"; import React, { useEffect, useState } from "react"; import { observer } from "mobx-react"; -import type { IPodContainer, Secret } from "../../api/endpoints"; +import type { IPodContainer, Secret } from "../../../common/k8s-api/endpoints"; import { DrawerItem } from "../drawer"; import { autorun } from "mobx"; import { secretsStore } from "../+config-secrets/secrets.store"; diff --git a/src/renderer/components/+workloads-pods/pod-container-port.tsx b/src/renderer/components/+workloads-pods/pod-container-port.tsx index 9e035c1fd9..c8bb435b55 100644 --- a/src/renderer/components/+workloads-pods/pod-container-port.tsx +++ b/src/renderer/components/+workloads-pods/pod-container-port.tsx @@ -23,7 +23,7 @@ import "./pod-container-port.scss"; import React from "react"; import { observer } from "mobx-react"; -import type { Pod } from "../../api/endpoints"; +import type { Pod } from "../../../common/k8s-api/endpoints"; import { apiBase } from "../../api"; import { observable, makeObservable } from "mobx"; import { cssNames } from "../../utils"; diff --git a/src/renderer/components/+workloads-pods/pod-details-affinities.tsx b/src/renderer/components/+workloads-pods/pod-details-affinities.tsx index 7be1722286..f20a3b7a65 100644 --- a/src/renderer/components/+workloads-pods/pod-details-affinities.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-affinities.tsx @@ -24,7 +24,7 @@ import React from "react"; import jsYaml from "js-yaml"; import { AceEditor } from "../ace-editor"; import { DrawerParamToggler, DrawerItem } from "../drawer"; -import type { Pod, Deployment, DaemonSet, StatefulSet, ReplicaSet, Job } from "../../api/endpoints"; +import type { Pod, Deployment, DaemonSet, StatefulSet, ReplicaSet, Job } from "../../../common/k8s-api/endpoints"; interface Props { workload: Pod | Deployment | DaemonSet | StatefulSet | ReplicaSet | Job; diff --git a/src/renderer/components/+workloads-pods/pod-details-container.tsx b/src/renderer/components/+workloads-pods/pod-details-container.tsx index a6aeae0593..c39ed80751 100644 --- a/src/renderer/components/+workloads-pods/pod-details-container.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-container.tsx @@ -22,7 +22,7 @@ import "./pod-details-container.scss"; import React from "react"; -import type { IPodContainer, IPodContainerStatus, Pod } from "../../api/endpoints"; +import type { IPodContainer, IPodContainerStatus, Pod } from "../../../common/k8s-api/endpoints"; import { DrawerItem } from "../drawer"; import { cssNames } from "../../utils"; import { StatusBrick } from "../status-brick"; @@ -30,11 +30,11 @@ import { Badge } from "../badge"; import { ContainerEnvironment } from "./pod-container-env"; import { PodContainerPort } from "./pod-container-port"; import { ResourceMetrics } from "../resource-metrics"; -import type { IMetrics } from "../../api/endpoints/metrics.api"; +import type { IMetrics } from "../../../common/k8s-api/endpoints/metrics.api"; import { ContainerCharts } from "./container-charts"; import { LocaleDate } from "../locale-date"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; interface Props { pod: Pod; diff --git a/src/renderer/components/+workloads-pods/pod-details-list.tsx b/src/renderer/components/+workloads-pods/pod-details-list.tsx index 8ea49c366d..b3dbe80fe7 100644 --- a/src/renderer/components/+workloads-pods/pod-details-list.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-list.tsx @@ -26,15 +26,15 @@ import kebabCase from "lodash/kebabCase"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { podsStore } from "./pods.store"; -import type { Pod } from "../../api/endpoints"; +import type { Pod } from "../../../common/k8s-api/endpoints"; import { boundMethod, bytesToUnits, cssNames, interval, prevDefault } from "../../utils"; import { LineProgress } from "../line-progress"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { Spinner } from "../spinner"; import { DrawerTitle } from "../drawer"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; -import { showDetails } from "../kube-object"; +import { showDetails } from "../kube-detail-params"; enum sortBy { name = "name", diff --git a/src/renderer/components/+workloads-pods/pod-details-secrets.tsx b/src/renderer/components/+workloads-pods/pod-details-secrets.tsx index 9ca49c3668..706da34668 100644 --- a/src/renderer/components/+workloads-pods/pod-details-secrets.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-secrets.tsx @@ -25,8 +25,8 @@ import React, { Component } from "react"; import { Link } from "react-router-dom"; import { autorun, observable, makeObservable } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; -import { Pod, Secret, secretsApi } from "../../api/endpoints"; -import { getDetailsUrl } from "../kube-object"; +import { Pod, Secret, secretsApi } from "../../../common/k8s-api/endpoints"; +import { getDetailsUrl } from "../kube-detail-params"; interface Props { pod: Pod; diff --git a/src/renderer/components/+workloads-pods/pod-details-statuses.tsx b/src/renderer/components/+workloads-pods/pod-details-statuses.tsx index 90c59ef778..36e6a26fb4 100644 --- a/src/renderer/components/+workloads-pods/pod-details-statuses.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-statuses.tsx @@ -23,7 +23,7 @@ import "./pod-details-statuses.scss"; import React from "react"; import countBy from "lodash/countBy"; import kebabCase from "lodash/kebabCase"; -import type { Pod } from "../../api/endpoints"; +import type { Pod } from "../../../common/k8s-api/endpoints"; interface Props { pods: Pod[]; diff --git a/src/renderer/components/+workloads-pods/pod-details-tolerations.tsx b/src/renderer/components/+workloads-pods/pod-details-tolerations.tsx index 124192d549..70b1d36e7e 100644 --- a/src/renderer/components/+workloads-pods/pod-details-tolerations.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-tolerations.tsx @@ -22,7 +22,7 @@ import "./pod-details-tolerations.scss"; import React from "react"; import { DrawerParamToggler, DrawerItem } from "../drawer"; -import type { WorkloadKubeObject } from "../../api/workload-kube-object"; +import type { WorkloadKubeObject } from "../../../common/k8s-api/workload-kube-object"; import { PodTolerations } from "./pod-tolerations"; interface Props { diff --git a/src/renderer/components/+workloads-pods/pod-details.tsx b/src/renderer/components/+workloads-pods/pod-details.tsx index 6249288b77..9f95c5289f 100644 --- a/src/renderer/components/+workloads-pods/pod-details.tsx +++ b/src/renderer/components/+workloads-pods/pod-details.tsx @@ -26,7 +26,7 @@ import kebabCase from "lodash/kebabCase"; import { disposeOnUnmount, observer } from "mobx-react"; import { Link } from "react-router-dom"; import { observable, reaction, makeObservable } from "mobx"; -import { IPodMetrics, nodesApi, Pod, pvcApi, configMapApi, getMetricsForPods } from "../../api/endpoints"; +import { IPodMetrics, nodesApi, Pod, pvcApi, configMapApi, getMetricsForPods } from "../../../common/k8s-api/endpoints"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; import { boundMethod, cssNames, toJS } from "../../utils"; @@ -36,12 +36,13 @@ import { PodDetailsTolerations } from "./pod-details-tolerations"; import { Icon } from "../icon"; import { PodDetailsSecrets } from "./pod-details-secrets"; import { ResourceMetrics } from "../resource-metrics"; -import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; -import { getItemMetrics } from "../../api/endpoints/metrics.api"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { getItemMetrics } from "../../../common/k8s-api/endpoints/metrics.api"; import { PodCharts, podMetricTabs } from "./pod-charts"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; +import { getDetailsUrl } from "../kube-detail-params"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+workloads-pods/pod-tolerations.tsx b/src/renderer/components/+workloads-pods/pod-tolerations.tsx index 28793e0ea5..e2be706b7b 100644 --- a/src/renderer/components/+workloads-pods/pod-tolerations.tsx +++ b/src/renderer/components/+workloads-pods/pod-tolerations.tsx @@ -23,7 +23,7 @@ import "./pod-tolerations.scss"; import React from "react"; import uniqueId from "lodash/uniqueId"; -import type { IToleration } from "../../api/workload-kube-object"; +import type { IToleration } from "../../../common/k8s-api/workload-kube-object"; import { Table, TableCell, TableHead, TableRow } from "../table"; interface Props { diff --git a/src/renderer/components/+workloads-pods/pods.store.ts b/src/renderer/components/+workloads-pods/pods.store.ts index 9c2b925400..8941fc6c05 100644 --- a/src/renderer/components/+workloads-pods/pods.store.ts +++ b/src/renderer/components/+workloads-pods/pods.store.ts @@ -21,11 +21,11 @@ import countBy from "lodash/countBy"; import { observable, makeObservable } from "mobx"; -import { KubeObjectStore } from "../../kube-object.store"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind, cpuUnitsToNumber, unitsToBytes } from "../../utils"; -import { Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints"; -import { apiManager } from "../../api/api-manager"; -import type { WorkloadKubeObject } from "../../api/workload-kube-object"; +import { Pod, PodMetrics, podMetricsApi, podsApi } from "../../../common/k8s-api/endpoints"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import type { WorkloadKubeObject } from "../../../common/k8s-api/workload-kube-object"; export class PodsStore extends KubeObjectStore { api = podsApi; diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index b91a8a98e8..448bfa75c8 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -28,17 +28,18 @@ import { podsStore } from "./pods.store"; import type { RouteComponentProps } from "react-router"; import { volumeClaimStore } from "../+storage-volume-claims/volume-claim.store"; import { eventStore } from "../+events/event.store"; -import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; -import { nodesApi, Pod } from "../../api/endpoints"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; +import { nodesApi, Pod } from "../../../common/k8s-api/endpoints"; import { StatusBrick } from "../status-brick"; import { cssNames, stopPropagation } from "../../utils"; import toPairs from "lodash/toPairs"; import startCase from "lodash/startCase"; import kebabCase from "lodash/kebabCase"; -import { lookupApiLink } from "../../api/kube-api"; +import { apiManager } from "../../../common/k8s-api/api-manager"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { Badge } from "../badge"; import type { PodsRouteParams } from "../../../common/routes"; +import { getDetailsUrl } from "../kube-detail-params"; enum columnId { name = "name", @@ -134,7 +135,7 @@ export class Pods extends React.Component { pod.getRestartsCount(), pod.getOwnerRefs().map(ref => { const { kind, name } = ref; - const detailsLink = getDetailsUrl(lookupApiLink(ref, pod)); + const detailsLink = getDetailsUrl(apiManager.lookupApiLink(ref, pod)); return ( diff --git a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx index 7c06b56840..7da1e22361 100644 --- a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx +++ b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx @@ -30,14 +30,14 @@ import { PodDetailsTolerations } from "../+workloads-pods/pod-details-toleration import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"; import { disposeOnUnmount, observer } from "mobx-react"; import { podsStore } from "../+workloads-pods/pods.store"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import { getMetricsForReplicaSets, IPodMetrics, ReplicaSet } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { getMetricsForReplicaSets, IPodMetrics, ReplicaSet } from "../../../common/k8s-api/endpoints"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { boundMethod } from "../../utils"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+workloads-replicasets/replicaset-scale-dialog.test.tsx b/src/renderer/components/+workloads-replicasets/replicaset-scale-dialog.test.tsx index 6107d43643..7f8c31e99c 100755 --- a/src/renderer/components/+workloads-replicasets/replicaset-scale-dialog.test.tsx +++ b/src/renderer/components/+workloads-replicasets/replicaset-scale-dialog.test.tsx @@ -21,11 +21,10 @@ import "@testing-library/jest-dom/extend-expect"; -jest.mock("../../api/endpoints"); import { ReplicaSetScaleDialog } from "./replicaset-scale-dialog"; import { render, waitFor, fireEvent } from "@testing-library/react"; import React from "react"; -import { ReplicaSet, replicaSetApi } from "../../api/endpoints/replica-set.api"; +import { ReplicaSet, ReplicaSetApi } from "../../../common/k8s-api/endpoints/replica-set.api"; const dummyReplicaSet: ReplicaSet = { apiVersion: "v1", @@ -111,8 +110,16 @@ const dummyReplicaSet: ReplicaSet = { }; describe("", () => { + let replicaSetApi: ReplicaSetApi; + + beforeEach(() => { + replicaSetApi = new ReplicaSetApi({ + objectConstructor: ReplicaSet + }); + }); + it("renders w/o errors", () => { - const { container } = render(); + const { container } = render(); expect(container).toBeInstanceOf(HTMLElement); }); @@ -123,7 +130,7 @@ describe("", () => { const initReplicas = 1; replicaSetApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); - const { getByTestId } = render(); + const { getByTestId } = render(); ReplicaSetScaleDialog.open(dummyReplicaSet); // we need to wait for the replicaSetScaleDialog to show up @@ -143,7 +150,7 @@ describe("", () => { const initReplicas = 1; replicaSetApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); - const component = render(); + const component = render(); ReplicaSetScaleDialog.open(dummyReplicaSet); await waitFor(async () => { diff --git a/src/renderer/components/+workloads-replicasets/replicaset-scale-dialog.tsx b/src/renderer/components/+workloads-replicasets/replicaset-scale-dialog.tsx index 0e98dde43a..3fda576d0e 100644 --- a/src/renderer/components/+workloads-replicasets/replicaset-scale-dialog.tsx +++ b/src/renderer/components/+workloads-replicasets/replicaset-scale-dialog.tsx @@ -30,9 +30,10 @@ import { Icon } from "../icon"; import { Slider } from "../slider"; import { Notifications } from "../notifications"; import { cssNames } from "../../utils"; -import { ReplicaSet, replicaSetApi } from "../../api/endpoints/replica-set.api"; +import { ReplicaSet, ReplicaSetApi, replicaSetApi } from "../../../common/k8s-api/endpoints/replica-set.api"; interface Props extends Partial { + replicaSetApi: ReplicaSetApi } const dialogState = observable.object({ @@ -42,6 +43,10 @@ const dialogState = observable.object({ @observer export class ReplicaSetScaleDialog extends Component { + static defaultProps = { + replicaSetApi + }; + @observable ready = false; @observable currentReplicas = 0; @observable desiredReplicas = 0; @@ -71,7 +76,7 @@ export class ReplicaSetScaleDialog extends Component { onOpen = async () => { const { replicaSet } = this; - this.currentReplicas = await replicaSetApi.getReplicas({ + this.currentReplicas = await this.props.replicaSetApi.getReplicas({ namespace: replicaSet.getNs(), name: replicaSet.getName(), }); @@ -102,7 +107,7 @@ export class ReplicaSetScaleDialog extends Component { try { if (currentReplicas !== desiredReplicas) { - await replicaSetApi.scale({ + await this.props.replicaSetApi.scale({ name: replicaSet.getName(), namespace: replicaSet.getNs(), }, desiredReplicas); diff --git a/src/renderer/components/+workloads-replicasets/replicasets.store.ts b/src/renderer/components/+workloads-replicasets/replicasets.store.ts index 5daa57e45d..15c25c1e4e 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.store.ts +++ b/src/renderer/components/+workloads-replicasets/replicasets.store.ts @@ -21,10 +21,10 @@ import { makeObservable } from "mobx"; import { podsStore } from "../+workloads-pods/pods.store"; -import { apiManager } from "../../api/api-manager"; -import { Deployment, ReplicaSet, replicaSetApi } from "../../api/endpoints"; -import { PodStatus } from "../../api/endpoints/pods.api"; -import { KubeObjectStore } from "../../kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { Deployment, ReplicaSet, replicaSetApi } from "../../../common/k8s-api/endpoints"; +import { PodStatus } from "../../../common/k8s-api/endpoints/pods.api"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; export class ReplicaSetStore extends KubeObjectStore { diff --git a/src/renderer/components/+workloads-replicasets/replicasets.tsx b/src/renderer/components/+workloads-replicasets/replicasets.tsx index 447280899f..8eaaa8f7cb 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.tsx +++ b/src/renderer/components/+workloads-replicasets/replicasets.tsx @@ -23,12 +23,12 @@ import "./replicasets.scss"; import React from "react"; import { observer } from "mobx-react"; -import type { ReplicaSet } from "../../api/endpoints"; -import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import type { ReplicaSet } from "../../../common/k8s-api/endpoints"; +import type { KubeObjectMenuProps } from "../kube-object-menu"; import { replicaSetStore } from "./replicasets.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { RouteComponentProps } from "react-router"; -import { KubeObjectListLayout } from "../kube-object/kube-object-list-layout"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { MenuItem } from "../menu/menu"; import { Icon } from "../icon/icon"; import { ReplicaSetScaleDialog } from "./replicaset-scale-dialog"; diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx index f16578c703..ff116105c9 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx @@ -31,14 +31,14 @@ import { PodDetailsTolerations } from "../+workloads-pods/pod-details-toleration import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"; import { podsStore } from "../+workloads-pods/pods.store"; import { statefulSetStore } from "./statefulset.store"; -import type { KubeObjectDetailsProps } from "../kube-object"; -import { getMetricsForStatefulSets, IPodMetrics, StatefulSet } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { getMetricsForStatefulSets, IPodMetrics, StatefulSet } from "../../../common/k8s-api/endpoints"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; -import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { KubeObjectMeta } from "../kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { boundMethod } from "../../utils"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.test.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.test.tsx index 5c12040022..b27d8b0892 100755 --- a/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.test.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.test.tsx @@ -21,8 +21,7 @@ import "@testing-library/jest-dom/extend-expect"; -jest.mock("../../api/endpoints"); -import { StatefulSet, statefulSetApi } from "../../api/endpoints"; +import { StatefulSet, StatefulSetApi } from "../../../common/k8s-api/endpoints"; import { StatefulSetScaleDialog } from "./statefulset-scale-dialog"; import { render, waitFor, fireEvent } from "@testing-library/react"; import React from "react"; @@ -121,8 +120,16 @@ const dummyStatefulSet: StatefulSet = { }; describe("", () => { + let statefulSetApi: StatefulSetApi; + + beforeEach(() => { + statefulSetApi = new StatefulSetApi({ + objectConstructor: StatefulSet + }); + }); + it("renders w/o errors", () => { - const { container } = render(); + const { container } = render(); expect(container).toBeInstanceOf(HTMLElement); }); @@ -133,7 +140,7 @@ describe("", () => { const initReplicas = 1; statefulSetApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); - const { getByTestId } = render(); + const { getByTestId } = render(); StatefulSetScaleDialog.open(dummyStatefulSet); // we need to wait for the StatefulSetScaleDialog to show up @@ -153,7 +160,7 @@ describe("", () => { const initReplicas = 1; statefulSetApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); - const component = render(); + const component = render(); StatefulSetScaleDialog.open(dummyStatefulSet); await waitFor(async () => { diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.tsx index cce00287a9..7fb49fabbe 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-scale-dialog.tsx @@ -21,7 +21,7 @@ import "./statefulset-scale-dialog.scss"; -import { StatefulSet, statefulSetApi } from "../../api/endpoints"; +import { StatefulSet, StatefulSetApi, statefulSetApi } from "../../../common/k8s-api/endpoints"; import React, { Component } from "react"; import { computed, makeObservable, observable } from "mobx"; import { observer } from "mobx-react"; @@ -33,6 +33,7 @@ import { Notifications } from "../notifications"; import { cssNames } from "../../utils"; interface Props extends Partial { + statefulSetApi: StatefulSetApi } const dialogState = observable.object({ @@ -42,6 +43,9 @@ const dialogState = observable.object({ @observer export class StatefulSetScaleDialog extends Component { + static defaultProps = { + statefulSetApi + }; @observable ready = false; @observable currentReplicas = 0; @observable desiredReplicas = 0; @@ -71,7 +75,7 @@ export class StatefulSetScaleDialog extends Component { onOpen = async () => { const { statefulSet } = this; - this.currentReplicas = await statefulSetApi.getReplicas({ + this.currentReplicas = await this.props.statefulSetApi.getReplicas({ namespace: statefulSet.getNs(), name: statefulSet.getName(), }); @@ -102,7 +106,7 @@ export class StatefulSetScaleDialog extends Component { try { if (currentReplicas !== desiredReplicas) { - await statefulSetApi.scale({ + await this.props.statefulSetApi.scale({ name: statefulSet.getName(), namespace: statefulSet.getNs(), }, desiredReplicas); diff --git a/src/renderer/components/+workloads-statefulsets/statefulset.store.ts b/src/renderer/components/+workloads-statefulsets/statefulset.store.ts index 73c03a1b60..cf5b8ea36d 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset.store.ts +++ b/src/renderer/components/+workloads-statefulsets/statefulset.store.ts @@ -21,9 +21,9 @@ import { makeObservable } from "mobx"; import { podsStore } from "../+workloads-pods/pods.store"; -import { apiManager } from "../../api/api-manager"; -import { PodStatus, StatefulSet, statefulSetApi } from "../../api/endpoints"; -import { KubeObjectStore } from "../../kube-object.store"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import { PodStatus, StatefulSet, statefulSetApi } from "../../../common/k8s-api/endpoints"; +import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { autoBind } from "../../utils"; export class StatefulSetStore extends KubeObjectStore { diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx index ff6441f33a..c3b5b0e023 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx @@ -24,13 +24,13 @@ import "./statefulsets.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import type { StatefulSet } from "../../api/endpoints"; +import type { StatefulSet } from "../../../common/k8s-api/endpoints"; import { podsStore } from "../+workloads-pods/pods.store"; import { statefulSetStore } from "./statefulset.store"; import { nodesStore } from "../+nodes/nodes.store"; import { eventStore } from "../+events/event.store"; -import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; -import { KubeObjectListLayout } from "../kube-object"; +import type { KubeObjectMenuProps } from "../kube-object-menu"; +import { KubeObjectListLayout } from "../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { StatefulSetScaleDialog } from "./statefulset-scale-dialog"; import { MenuItem } from "../menu/menu"; diff --git a/src/renderer/components/+workloads/workloads.stores.ts b/src/renderer/components/+workloads/workloads.stores.ts index e53ea7cb03..d3d69c2a17 100644 --- a/src/renderer/components/+workloads/workloads.stores.ts +++ b/src/renderer/components/+workloads/workloads.stores.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { KubeObjectStore } from "../../kube-object.store"; +import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { deploymentStore } from "../+workloads-deployments/deployments.store"; import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store"; @@ -28,7 +28,7 @@ import { jobStore } from "../+workloads-jobs/job.store"; import { cronJobStore } from "../+workloads-cronjobs/cronjob.store"; import type { KubeResource } from "../../../common/rbac"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; export const workloadStores = new Map>([ ["pods", podsStore], diff --git a/src/renderer/components/+workloads/workloads.tsx b/src/renderer/components/+workloads/workloads.tsx index 5f8724b928..71007b1195 100644 --- a/src/renderer/components/+workloads/workloads.tsx +++ b/src/renderer/components/+workloads/workloads.tsx @@ -31,7 +31,7 @@ import { DaemonSets } from "../+workloads-daemonsets"; import { StatefulSets } from "../+workloads-statefulsets"; import { Jobs } from "../+workloads-jobs"; import { CronJobs } from "../+workloads-cronjobs"; -import { isAllowedResource } from "../../../common/rbac"; +import { isAllowedResource } from "../../../common/utils/allowed-resource"; import { ReplicaSets } from "../+workloads-replicasets"; import * as routes from "../../../common/routes"; diff --git a/src/renderer/components/__tests__/cronjob.store.test.ts b/src/renderer/components/__tests__/cronjob.store.test.ts index fcd8f93023..35531b2ec2 100644 --- a/src/renderer/components/__tests__/cronjob.store.test.ts +++ b/src/renderer/components/__tests__/cronjob.store.test.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import { cronJobStore } from "../+workloads-cronjobs/cronjob.store"; -import { CronJob } from "../../api/endpoints"; +import { CronJob } from "../../../common/k8s-api/endpoints"; const spec = { schedule: "test", diff --git a/src/renderer/components/__tests__/daemonset.store.test.ts b/src/renderer/components/__tests__/daemonset.store.test.ts index 00dcce5468..65ea991d9b 100644 --- a/src/renderer/components/__tests__/daemonset.store.test.ts +++ b/src/renderer/components/__tests__/daemonset.store.test.ts @@ -22,7 +22,7 @@ import { observable } from "mobx"; import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import { DaemonSet, Pod } from "../../api/endpoints"; +import { DaemonSet, Pod } from "../../../common/k8s-api/endpoints"; const runningDaemonSet = new DaemonSet({ apiVersion: "foo", diff --git a/src/renderer/components/__tests__/deployments.store.test.ts b/src/renderer/components/__tests__/deployments.store.test.ts index 6d7552dd6b..7742b55313 100644 --- a/src/renderer/components/__tests__/deployments.store.test.ts +++ b/src/renderer/components/__tests__/deployments.store.test.ts @@ -22,7 +22,7 @@ import { observable } from "mobx"; import { deploymentStore } from "../+workloads-deployments/deployments.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import { Deployment, Pod } from "../../api/endpoints"; +import { Deployment, Pod } from "../../../common/k8s-api/endpoints"; const spec = { containers: [{ diff --git a/src/renderer/components/__tests__/job.store.test.ts b/src/renderer/components/__tests__/job.store.test.ts index 9f3a81ba91..f3d850e3dc 100644 --- a/src/renderer/components/__tests__/job.store.test.ts +++ b/src/renderer/components/__tests__/job.store.test.ts @@ -22,7 +22,7 @@ import { observable } from "mobx"; import { jobStore } from "../+workloads-jobs/job.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import { Job, Pod } from "../../api/endpoints"; +import { Job, Pod } from "../../../common/k8s-api/endpoints"; const runningJob = new Job({ apiVersion: "foo", diff --git a/src/renderer/components/__tests__/pods.store.test.ts b/src/renderer/components/__tests__/pods.store.test.ts index 69d4f49840..74fe9de9f6 100644 --- a/src/renderer/components/__tests__/pods.store.test.ts +++ b/src/renderer/components/__tests__/pods.store.test.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { Pod } from "../../api/endpoints"; +import { Pod } from "../../../common/k8s-api/endpoints"; import { podsStore } from "../+workloads-pods/pods.store"; const runningPod = new Pod({ diff --git a/src/renderer/components/__tests__/replicaset.store.test.ts b/src/renderer/components/__tests__/replicaset.store.test.ts index 74404e9004..3114290bc7 100644 --- a/src/renderer/components/__tests__/replicaset.store.test.ts +++ b/src/renderer/components/__tests__/replicaset.store.test.ts @@ -22,7 +22,7 @@ import { observable } from "mobx"; import { podsStore } from "../+workloads-pods/pods.store"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; -import { ReplicaSet, Pod } from "../../api/endpoints"; +import { ReplicaSet, Pod } from "../../../common/k8s-api/endpoints"; const runningReplicaSet = new ReplicaSet({ apiVersion: "foo", diff --git a/src/renderer/components/__tests__/statefulset.store.test.ts b/src/renderer/components/__tests__/statefulset.store.test.ts index 162684f092..4121be6c58 100644 --- a/src/renderer/components/__tests__/statefulset.store.test.ts +++ b/src/renderer/components/__tests__/statefulset.store.test.ts @@ -22,7 +22,7 @@ import { observable } from "mobx"; import { podsStore } from "../+workloads-pods/pods.store"; import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store"; -import { StatefulSet, Pod } from "../../api/endpoints"; +import { StatefulSet, Pod } from "../../../common/k8s-api/endpoints"; const runningStatefulSet = new StatefulSet({ apiVersion: "foo", diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 52c9d5d0c3..46e285969a 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -31,8 +31,7 @@ import { Events } from "./+events/events"; import { DeploymentScaleDialog } from "./+workloads-deployments/deployment-scale-dialog"; import { CronJobTriggerDialog } from "./+workloads-cronjobs/cronjob-trigger-dialog"; import { CustomResources } from "./+custom-resources/custom-resources"; -import { isAllowedResource } from "../../common/rbac"; -import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store"; +import { isAllowedResource } from "../../common/utils/allowed-resource"; import logger from "../../main/logger"; import { webFrame } from "electron"; import { ClusterPageRegistry, getExtensionPageUrl } from "../../extensions/registries/page-registry"; @@ -46,17 +45,17 @@ import { StatefulSetScaleDialog } from "./+workloads-statefulsets/statefulset-sc import { eventStore } from "./+events/event.store"; import { nodesStore } from "./+nodes/nodes.store"; import { podsStore } from "./+workloads-pods/pods.store"; -import { kubeWatchApi } from "../api/kube-watch-api"; +import { kubeWatchApi } from "../../common/k8s-api/kube-watch-api"; import { ReplicaSetScaleDialog } from "./+workloads-replicasets/replicaset-scale-dialog"; import { CommandContainer } from "./command-palette/command-container"; -import { KubeObjectStore } from "../kube-object.store"; +import { KubeObjectStore } from "../../common/k8s-api/kube-object.store"; import { clusterContext } from "./context"; import * as routes from "../../common/routes"; import { TabLayout, TabLayoutRoute } from "./layout/tab-layout"; import { ErrorBoundary } from "./error-boundary"; import { MainLayout } from "./layout/main-layout"; import { Notifications } from "./notifications"; -import { KubeObjectDetails } from "./kube-object"; +import { KubeObjectDetails } from "./kube-object-details"; import { KubeConfigDialog } from "./kubeconfig-dialog"; import { Terminal } from "./dock/terminal"; import { namespaceStore } from "./+namespaces/namespace.store"; @@ -70,9 +69,14 @@ import { Workloads } from "./+workloads"; import { Config } from "./+config"; import { Storage } from "./+storage"; import { catalogEntityRegistry } from "../api/catalog-entity-registry"; +import { getHostedClusterId } from "../utils"; +import { ClusterStore } from "../../common/cluster-store"; +import type { ClusterId } from "../../common/cluster-types"; @observer export class App extends React.Component { + static clusterId: ClusterId; + constructor(props: {}) { super(props); makeObservable(this); @@ -81,15 +85,18 @@ export class App extends React.Component { static async init() { catalogEntityRegistry.init(); const frameId = webFrame.routingId; - const clusterId = getHostedClusterId(); - logger.info(`[APP]: Init dashboard, clusterId=${clusterId}, frameId=${frameId}`); + App.clusterId = getHostedClusterId(); + + logger.info(`[APP]: Init dashboard, clusterId=${App.clusterId}, frameId=${frameId}`); await Terminal.preloadFonts(); + await requestMain(clusterSetFrameIdHandler, App.clusterId); - await requestMain(clusterSetFrameIdHandler, clusterId); - await getHostedCluster().whenReady; // cluster.activate() is done at this point + const cluster = ClusterStore.getInstance().getById(App.clusterId); - const activeEntityDisposer = reaction(() => catalogEntityRegistry.getById(clusterId), (entity) => { + await cluster.whenReady; // cluster.activate() is done at this point + + const activeEntityDisposer = reaction(() => catalogEntityRegistry.getById(App.clusterId), (entity) => { if (!entity) { return; } @@ -103,7 +110,7 @@ export class App extends React.Component { name: "cluster", action: "open", params: { - clusterId + clusterId: App.clusterId } }); }); @@ -212,7 +219,7 @@ export class App extends React.Component { - + ); diff --git a/src/renderer/components/cluster-manager/cluster-status.module.css b/src/renderer/components/cluster-manager/cluster-status.module.css new file mode 100644 index 0000000000..194ef467db --- /dev/null +++ b/src/renderer/components/cluster-manager/cluster-status.module.css @@ -0,0 +1,39 @@ +.status { + --flex-gap: 16px; + + position: relative; + min-width: 350px; + margin: auto; + text-align: center; + z-index: 1; + background: var(--mainBackground); + width: 100%; + height: 100%; + + pre { + max-width: 70vw; + max-height: 40vh; + white-space: pre-line; + overflow: auto; + line-height: 1.7; + + p { + margin-bottom: var(--margin); + } + } + + a { + cursor: pointer; + } +} + +.spinner { + --spinner-size: 38px; + --spinner-border: calc(var(--spinner-size) / 10); +} + +.icon { + --size: 70px; + margin: auto; + color: var(--colorError); +} \ No newline at end of file diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 366a809b59..a3c3f96b5f 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -19,14 +19,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import "./cluster-status.scss"; +import styles from "./cluster-status.module.css"; import { ipcRenderer } from "electron"; import { computed, observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import React from "react"; import { clusterActivateHandler } from "../../../common/cluster-ipc"; -import { ClusterId, ClusterStore } from "../../../common/cluster-store"; +import { ClusterStore } from "../../../common/cluster-store"; import { ipcRendererOn, requestMain } from "../../../common/ipc"; import type { Cluster } from "../../../main/cluster"; import { cssNames, IClassName } from "../../utils"; @@ -36,6 +36,7 @@ import { Spinner } from "../spinner"; import type { KubeAuthProxyLog } from "../../../main/kube-auth-proxy"; import { navigate } from "../../navigation"; import { entitySettingsURL } from "../../../common/routes"; +import type { ClusterId } from "../../../common/cluster-types"; interface Props { className?: IClassName; @@ -99,31 +100,31 @@ export class ClusterStatus extends React.Component { if (!hasErrors || this.isReconnecting) { return ( - <> - +

+
             

{this.isReconnecting ? "Reconnecting" : "Connecting"}…

{authOutput.map(({ data, error }, index) => { return

{data}

; })}
- +
); } return ( - <> - +
+

{cluster.preferences.clusterName}

-
+        
           {authOutput.map(({ data, error }, index) => {
             return 

{data}

; })}
{failureReason && ( -
{failureReason}
+
{failureReason}
)}
); } render() { return ( -
+
{this.renderContent()}
); diff --git a/src/renderer/components/cluster-manager/lens-views.ts b/src/renderer/components/cluster-manager/lens-views.ts index ace85eed6e..3fcce1ed6f 100644 --- a/src/renderer/components/cluster-manager/lens-views.ts +++ b/src/renderer/components/cluster-manager/lens-views.ts @@ -20,10 +20,12 @@ */ import { observable, when } from "mobx"; -import { ClusterId, ClusterStore, getClusterFrameUrl } from "../../../common/cluster-store"; import logger from "../../../main/logger"; import { requestMain } from "../../../common/ipc"; import { clusterVisibilityHandler } from "../../../common/cluster-ipc"; +import { ClusterStore } from "../../../common/cluster-store"; +import type { ClusterId } from "../../../common/cluster-types"; +import { getClusterFrameUrl } from "../../utils"; export interface LensView { isLoaded?: boolean diff --git a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx index 8cce59bbe8..571886364a 100644 --- a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx @@ -25,8 +25,9 @@ import { Select, SelectOption } from "../../select/select"; import { Icon } from "../../icon/icon"; import { Button } from "../../button/button"; import { SubTitle } from "../../layout/sub-title"; -import { Cluster, ClusterMetricsResourceType } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { observable, reaction, makeObservable } from "mobx"; +import { ClusterMetricsResourceType } from "../../../../common/cluster-types"; interface Props { cluster: Cluster; diff --git a/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx index a5b4300fe3..1fb101a15c 100644 --- a/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx @@ -26,7 +26,7 @@ import React from "react"; import { Input } from "../../input/input"; import { disposeOnUnmount, observer } from "mobx-react"; import { Icon } from "../../icon/icon"; -import { initialNodeShellImage } from "../../../../common/cluster-store"; +import { initialNodeShellImage } from "../../../../common/cluster-types"; interface Props { cluster: Cluster; diff --git a/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx index a74606b1ec..26469a87ad 100644 --- a/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx @@ -27,7 +27,7 @@ import { Select, SelectOption } from "../../select"; import { Input } from "../../input"; import { observable, computed, autorun, makeObservable } from "mobx"; import { productName } from "../../../../common/vars"; -import { MetricProviderInfo, metricsApi } from "../../../api/endpoints/metrics.api"; +import { MetricProviderInfo, metricsApi } from "../../../../common/k8s-api/endpoints/metrics.api"; import { Spinner } from "../../spinner"; interface Props { diff --git a/src/renderer/components/command-palette/command-container.tsx b/src/renderer/components/command-palette/command-container.tsx index b95d177891..cc67d27964 100644 --- a/src/renderer/components/command-palette/command-container.tsx +++ b/src/renderer/components/command-palette/command-container.tsx @@ -21,32 +21,15 @@ import "./command-container.scss"; -import { action, observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import React from "react"; import { Dialog } from "../dialog"; -import { EventEmitter } from "../../../common/event-emitter"; import { ipcRendererOn } from "../../../common/ipc"; import { CommandDialog } from "./command-dialog"; -import type { ClusterId } from "../../../common/cluster-store"; +import type { ClusterId } from "../../../common/cluster-types"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { CommandRegistration, CommandRegistry } from "../../../extensions/registries/command-registry"; - -export type CommandDialogEvent = { - component: React.ReactElement -}; - -const commandDialogBus = new EventEmitter<[CommandDialogEvent]>(); - -export class CommandOverlay { - static open(component: React.ReactElement) { - commandDialogBus.emit({ component }); - } - - static close() { - commandDialogBus.emit({ component: null }); - } -} +import { CommandOverlay } from "./command-overlay"; export interface CommandContainerProps { clusterId?: ClusterId; @@ -54,25 +37,13 @@ export interface CommandContainerProps { @observer export class CommandContainer extends React.Component { - @observable.ref commandComponent: React.ReactNode; - - constructor(props: CommandContainerProps) { - super(props); - makeObservable(this); - } - private escHandler(event: KeyboardEvent) { if (event.key === "Escape") { event.stopPropagation(); - this.closeDialog(); + CommandOverlay.close(); } } - @action - private closeDialog() { - this.commandComponent = null; - } - private findCommandById(commandId: string) { return CommandRegistry.getInstance().getItems().find((command) => command.id === commandId); } @@ -98,16 +69,18 @@ export class CommandContainer extends React.Component { }); } window.addEventListener("keyup", (e) => this.escHandler(e), true); - commandDialogBus.addListener((event) => { - this.commandComponent = event.component; - }); } render() { return ( - this.commandComponent = null} modal={false}> +
- {this.commandComponent} + {CommandOverlay.component}
); diff --git a/src/renderer/components/command-palette/command-dialog.tsx b/src/renderer/components/command-palette/command-dialog.tsx index 493d9bea70..b99a73ee9f 100644 --- a/src/renderer/components/command-palette/command-dialog.tsx +++ b/src/renderer/components/command-palette/command-dialog.tsx @@ -25,7 +25,7 @@ import { computed, makeObservable, observable } from "mobx"; import { observer } from "mobx-react"; import React from "react"; import { CommandRegistry } from "../../../extensions/registries/command-registry"; -import { CommandOverlay } from "./command-container"; +import { CommandOverlay } from "./command-overlay"; import { broadcastMessage } from "../../../common/ipc"; import { navigate } from "../../navigation"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; diff --git a/src/renderer/components/command-palette/command-overlay.ts b/src/renderer/components/command-palette/command-overlay.ts new file mode 100644 index 0000000000..1058b2f9d3 --- /dev/null +++ b/src/renderer/components/command-palette/command-overlay.ts @@ -0,0 +1,47 @@ +/** + * 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 { observable } from "mobx"; +import React from "react"; + +export class CommandOverlay { + static #component = observable.box(null, { deep: false }); + + static get isOpen(): boolean { + return Boolean(CommandOverlay.#component.get()); + } + + static open(component: React.ReactElement) { + if (!React.isValidElement(component)) { + throw new TypeError("CommandOverlay.open must be passed a valid ReactElement"); + } + + CommandOverlay.#component.set(component); + } + + static close() { + CommandOverlay.#component.set(null); + } + + static get component(): React.ReactElement | null { + return CommandOverlay.#component.get(); + } +} diff --git a/src/renderer/components/command-palette/index.ts b/src/renderer/components/command-palette/index.ts index ea2e83ed31..27169ddae2 100644 --- a/src/renderer/components/command-palette/index.ts +++ b/src/renderer/components/command-palette/index.ts @@ -21,3 +21,4 @@ export * from "./command-container"; export * from "./command-dialog"; +export * from "./command-overlay"; diff --git a/src/renderer/components/confirm-dialog/confirm-dialog.tsx b/src/renderer/components/confirm-dialog/confirm-dialog.tsx index 47e7eab665..a4a8bdcddf 100644 --- a/src/renderer/components/confirm-dialog/confirm-dialog.tsx +++ b/src/renderer/components/confirm-dialog/confirm-dialog.tsx @@ -28,6 +28,7 @@ import { cssNames, noop, prevDefault } from "../../utils"; import { Button, ButtonProps } from "../button"; import { Dialog, DialogProps } from "../dialog"; import { Icon } from "../icon"; +import { Notifications } from "../notifications"; export interface ConfirmDialogProps extends Partial { } @@ -90,7 +91,14 @@ export class ConfirmDialog extends React.Component { ok = async () => { try { this.isSaving = true; - await Promise.resolve(this.params.ok()).catch(noop); + await (async () => this.params.ok())(); + } catch (error) { + Notifications.error( + <> +

Confirmation action failed:

+

{error?.message ?? error?.toString?.() ?? "Unknown error"}

+ + ); } finally { this.isSaving = false; dialogState.isOpen = false; @@ -103,7 +111,14 @@ export class ConfirmDialog extends React.Component { close = async () => { try { - await Promise.resolve(this.params.cancel()).catch(noop); + await Promise.resolve(this.params.cancel()); + } catch (error) { + Notifications.error( + <> +

Cancelling action failed:

+

{error?.message ?? error?.toString?.() ?? "Unknown error"}

+ + ); } finally { this.isSaving = false; dialogState.isOpen = false; diff --git a/src/renderer/components/context.ts b/src/renderer/components/context.ts index f62b904f6e..6e37aabdce 100755 --- a/src/renderer/components/context.ts +++ b/src/renderer/components/context.ts @@ -19,19 +19,15 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import { ClusterStore } from "../../common/cluster-store"; import type { Cluster } from "../../main/cluster"; -import { getHostedCluster } from "../../common/cluster-store"; +import { getHostedClusterId } from "../utils"; import { namespaceStore } from "./+namespaces/namespace.store"; - -export interface ClusterContext { - cluster?: Cluster; - allNamespaces: string[]; // available / allowed namespaces from cluster.ts - contextNamespaces: string[]; // selected by user (see: namespace-select.tsx) -} +import type { ClusterContext } from "../../common/k8s-api/cluster-context"; export const clusterContext: ClusterContext = { get cluster(): Cluster | null { - return getHostedCluster(); + return ClusterStore.getInstance().getById(getHostedClusterId()); }, get allNamespaces(): string[] { diff --git a/src/renderer/components/dock/__test__/log-resource-selector.test.tsx b/src/renderer/components/dock/__test__/log-resource-selector.test.tsx index 17ebb92d09..45e8a858f1 100644 --- a/src/renderer/components/dock/__test__/log-resource-selector.test.tsx +++ b/src/renderer/components/dock/__test__/log-resource-selector.test.tsx @@ -24,7 +24,7 @@ import "@testing-library/jest-dom/extend-expect"; import { render } from "@testing-library/react"; import selectEvent from "react-select-event"; -import { Pod } from "../../../api/endpoints"; +import { Pod } from "../../../../common/k8s-api/endpoints"; import { LogResourceSelector } from "../log-resource-selector"; import type { LogTabData } from "../log-tab.store"; import { dockerPod, deploymentPod1 } from "./pod.mock"; diff --git a/src/renderer/components/dock/__test__/log-tab.store.test.ts b/src/renderer/components/dock/__test__/log-tab.store.test.ts index da7d0b1052..7048be780a 100644 --- a/src/renderer/components/dock/__test__/log-tab.store.test.ts +++ b/src/renderer/components/dock/__test__/log-tab.store.test.ts @@ -21,7 +21,7 @@ import { podsStore } from "../../+workloads-pods/pods.store"; import { UserStore } from "../../../../common/user-store"; -import { Pod } from "../../../api/endpoints"; +import { Pod } from "../../../../common/k8s-api/endpoints"; import { ThemeStore } from "../../../theme.store"; import { dockStore } from "../dock.store"; import { logTabStore } from "../log-tab.store"; diff --git a/src/renderer/components/dock/create-resource.tsx b/src/renderer/components/dock/create-resource.tsx index f3423a7771..f826b772aa 100644 --- a/src/renderer/components/dock/create-resource.tsx +++ b/src/renderer/components/dock/create-resource.tsx @@ -33,8 +33,8 @@ import { createResourceStore } from "./create-resource.store"; import type { DockTab } from "./dock.store"; import { EditorPanel } from "./editor-panel"; import { InfoPanel } from "./info-panel"; -import { resourceApplierApi } from "../../api/endpoints/resource-applier.api"; -import type { JsonApiErrorParsed } from "../../api/json-api"; +import { resourceApplierApi } from "../../../common/k8s-api/endpoints/resource-applier.api"; +import type { JsonApiErrorParsed } from "../../../common/k8s-api/json-api"; import { Notifications } from "../notifications"; interface Props { @@ -105,7 +105,7 @@ export class CreateResource extends React.Component { await Promise.all( resources.map(data => { return resourceApplierApi.update(data) - .then(item => createdResources.push(item.getName())) + .then(item => createdResources.push(item.metadata.name)) .catch((err: JsonApiErrorParsed) => errors.push(err.toString())); }) ); diff --git a/src/renderer/components/dock/edit-resource.store.ts b/src/renderer/components/dock/edit-resource.store.ts index c0467b330b..2c8d26bbb9 100644 --- a/src/renderer/components/dock/edit-resource.store.ts +++ b/src/renderer/components/dock/edit-resource.store.ts @@ -23,9 +23,9 @@ import { autoBind, noop } from "../../utils"; import { DockTabStore } from "./dock-tab.store"; import { autorun, IReactionDisposer } from "mobx"; import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; -import type { KubeObject } from "../../api/kube-object"; -import { apiManager } from "../../api/api-manager"; -import type { KubeObjectStore } from "../../kube-object.store"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; +import { apiManager } from "../../../common/k8s-api/api-manager"; +import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; export interface EditingResource { resource: string; // resource path, e.g. /api/v1/namespaces/default diff --git a/src/renderer/components/dock/edit-resource.tsx b/src/renderer/components/dock/edit-resource.tsx index 0496ef3104..19a238ab30 100644 --- a/src/renderer/components/dock/edit-resource.tsx +++ b/src/renderer/components/dock/edit-resource.tsx @@ -32,7 +32,7 @@ import { InfoPanel } from "./info-panel"; import { Badge } from "../badge"; import { EditorPanel } from "./editor-panel"; import { Spinner } from "../spinner"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; interface Props { className?: string; diff --git a/src/renderer/components/dock/install-chart.store.ts b/src/renderer/components/dock/install-chart.store.ts index f7ae6930e6..fb185ffb52 100644 --- a/src/renderer/components/dock/install-chart.store.ts +++ b/src/renderer/components/dock/install-chart.store.ts @@ -22,8 +22,8 @@ import { action, autorun, makeObservable } from "mobx"; import { dockStore, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; -import { getChartDetails, getChartValues, HelmChart } from "../../api/endpoints/helm-charts.api"; -import type { IReleaseUpdateDetails } from "../../api/endpoints/helm-releases.api"; +import { getChartDetails, getChartValues, HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api"; +import type { IReleaseUpdateDetails } from "../../../common/k8s-api/endpoints/helm-releases.api"; import { Notifications } from "../notifications"; export interface IChartInstallData { diff --git a/src/renderer/components/dock/log-controls.tsx b/src/renderer/components/dock/log-controls.tsx index b12350d8f8..b7ac1c5fb4 100644 --- a/src/renderer/components/dock/log-controls.tsx +++ b/src/renderer/components/dock/log-controls.tsx @@ -24,7 +24,7 @@ import "./log-controls.scss"; import React from "react"; import { observer } from "mobx-react"; -import { Pod } from "../../api/endpoints"; +import { Pod } from "../../../common/k8s-api/endpoints"; import { cssNames, saveFileDialog } from "../../utils"; import { logStore } from "./log.store"; import { Checkbox } from "../checkbox"; diff --git a/src/renderer/components/dock/log-resource-selector.tsx b/src/renderer/components/dock/log-resource-selector.tsx index 068ad44d89..ab7a7560ed 100644 --- a/src/renderer/components/dock/log-resource-selector.tsx +++ b/src/renderer/components/dock/log-resource-selector.tsx @@ -24,7 +24,7 @@ import "./log-resource-selector.scss"; import React, { useEffect } from "react"; import { observer } from "mobx-react"; -import { Pod } from "../../api/endpoints"; +import { Pod } from "../../../common/k8s-api/endpoints"; import { Badge } from "../badge"; import { Select, SelectOption } from "../select"; import { LogTabData, logTabStore } from "./log-tab.store"; diff --git a/src/renderer/components/dock/log-tab.store.ts b/src/renderer/components/dock/log-tab.store.ts index bd7d61539b..5b6b73904f 100644 --- a/src/renderer/components/dock/log-tab.store.ts +++ b/src/renderer/components/dock/log-tab.store.ts @@ -23,8 +23,8 @@ import uniqueId from "lodash/uniqueId"; import { reaction } from "mobx"; import { podsStore } from "../+workloads-pods/pods.store"; -import { IPodContainer, Pod } from "../../api/endpoints"; -import type { WorkloadKubeObject } from "../../api/workload-kube-object"; +import { IPodContainer, Pod } from "../../../common/k8s-api/endpoints"; +import type { WorkloadKubeObject } from "../../../common/k8s-api/workload-kube-object"; import { DockTabStore } from "./dock-tab.store"; import { dockStore, DockTabCreateSpecific, TabKind } from "./dock.store"; diff --git a/src/renderer/components/dock/log.store.ts b/src/renderer/components/dock/log.store.ts index 710ed3a690..b03e00becb 100644 --- a/src/renderer/components/dock/log.store.ts +++ b/src/renderer/components/dock/log.store.ts @@ -21,7 +21,7 @@ import { autorun, computed, observable, makeObservable } from "mobx"; -import { IPodLogsQuery, Pod, podsApi } from "../../api/endpoints"; +import { IPodLogsQuery, Pod, podsApi } from "../../../common/k8s-api/endpoints"; import { autoBind, interval } from "../../utils"; import { dockStore, TabId, TabKind } from "./dock.store"; import { logTabStore } from "./log-tab.store"; diff --git a/src/renderer/components/dock/upgrade-chart.store.ts b/src/renderer/components/dock/upgrade-chart.store.ts index 4a43ae4ab1..7667f7c00e 100644 --- a/src/renderer/components/dock/upgrade-chart.store.ts +++ b/src/renderer/components/dock/upgrade-chart.store.ts @@ -22,7 +22,7 @@ import { action, autorun, computed, IReactionDisposer, reaction, makeObservable } from "mobx"; import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; -import { getReleaseValues, HelmRelease } from "../../api/endpoints/helm-releases.api"; +import { getReleaseValues, HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api"; import { releaseStore } from "../+apps-releases/release.store"; import { iter } from "../../utils"; diff --git a/src/renderer/components/dock/upgrade-chart.tsx b/src/renderer/components/dock/upgrade-chart.tsx index 0628aeb19e..582bd6b8e0 100644 --- a/src/renderer/components/dock/upgrade-chart.tsx +++ b/src/renderer/components/dock/upgrade-chart.tsx @@ -33,7 +33,7 @@ import { releaseStore } from "../+apps-releases/release.store"; import { Badge } from "../badge"; import { EditorPanel } from "./editor-panel"; import { helmChartStore, IChartVersion } from "../+apps-helm-charts/helm-chart.store"; -import type { HelmRelease } from "../../api/endpoints/helm-releases.api"; +import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api"; import { Select, SelectOption } from "../select"; interface Props { diff --git a/src/renderer/components/hotbar/hotbar-menu.tsx b/src/renderer/components/hotbar/hotbar-menu.tsx index 56fa7a25fc..5df1f48049 100644 --- a/src/renderer/components/hotbar/hotbar-menu.tsx +++ b/src/renderer/components/hotbar/hotbar-menu.tsx @@ -26,13 +26,14 @@ import { observer } from "mobx-react"; import { HotbarEntityIcon } from "./hotbar-entity-icon"; import { cssNames, IClassName } from "../../utils"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; -import { defaultHotbarCells, HotbarItem, HotbarStore } from "../../../common/hotbar-store"; +import { HotbarStore } from "../../../common/hotbar-store"; import { CatalogEntity, catalogEntityRunContext } from "../../api/catalog-entity"; import { DragDropContext, Draggable, Droppable, DropResult } from "react-beautiful-dnd"; import { HotbarSelector } from "./hotbar-selector"; import { HotbarCell } from "./hotbar-cell"; import { HotbarIcon } from "./hotbar-icon"; import { computed } from "mobx"; +import { defaultHotbarCells, HotbarItem } from "../../../common/hotbar-types"; interface Props { className?: IClassName; diff --git a/src/renderer/components/hotbar/hotbar-selector.tsx b/src/renderer/components/hotbar/hotbar-selector.tsx index cc9617aa47..0144f2befd 100644 --- a/src/renderer/components/hotbar/hotbar-selector.tsx +++ b/src/renderer/components/hotbar/hotbar-selector.tsx @@ -23,12 +23,13 @@ import "./hotbar-selector.scss"; import React from "react"; import { Icon } from "../icon"; import { Badge } from "../badge"; -import { Hotbar, HotbarStore } from "../../../common/hotbar-store"; +import { HotbarStore } from "../../../common/hotbar-store"; import { CommandOverlay } from "../command-palette"; import { HotbarSwitchCommand } from "./hotbar-switch-command"; import { hotbarDisplayIndex } from "./hotbar-display-label"; import { TooltipPosition } from "../tooltip"; import { observer } from "mobx-react"; +import type { Hotbar } from "../../../common/hotbar-types"; interface Props { hotbar: Hotbar; diff --git a/src/renderer/components/item-object-list/item-list-layout.tsx b/src/renderer/components/item-object-list/item-list-layout.tsx index 5b27858740..d19e9d20c8 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -31,7 +31,7 @@ import { boundMethod, createStorage, cssNames, IClassName, isReactNode, noop, Ob import { AddRemoveButtons, AddRemoveButtonsProps } from "../add-remove-buttons"; import { NoItems } from "../no-items"; import { Spinner } from "../spinner"; -import type { ItemObject, ItemStore } from "../../item.store"; +import type { ItemObject, ItemStore } from "../../../common/item.store"; import { SearchInputUrlProps, SearchInputUrl } from "../input"; import { Filter, FilterType, pageFilters } from "./page-filters.store"; import { PageFiltersList } from "./page-filters-list"; diff --git a/src/renderer/components/kube-detail-params/index.ts b/src/renderer/components/kube-detail-params/index.ts new file mode 100644 index 0000000000..146e52e6dd --- /dev/null +++ b/src/renderer/components/kube-detail-params/index.ts @@ -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 * from "./params"; diff --git a/src/renderer/components/kube-detail-params/params.ts b/src/renderer/components/kube-detail-params/params.ts new file mode 100644 index 0000000000..09256077d0 --- /dev/null +++ b/src/renderer/components/kube-detail-params/params.ts @@ -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 { createPageParam, navigation } from "../../navigation"; + +/** + * Used to store `object.selfLink` to show more info about resource in the details panel. + */ +export const kubeDetailsUrlParam = createPageParam({ + name: "kube-details", +}); + +/** + * Used to highlight last active/selected table row with the resource. + * + * @example + * If we go to "Nodes (page) -> Node (details) -> Pod (details)", + * last clicked Node should be "active" while Pod details are shown). + */ +export const kubeSelectedUrlParam = createPageParam({ + name: "kube-selected", + get defaultValue() { + return kubeDetailsUrlParam.get(); + } +}); + +export function showDetails(selfLink = "", resetSelected = true) { + const detailsUrl = getDetailsUrl(selfLink, resetSelected); + + navigation.merge({ search: detailsUrl }); +} + +export function hideDetails() { + showDetails(); +} + +export function getDetailsUrl(selfLink: string, resetSelected = false, mergeGlobals = true) { + console.debug("getDetailsUrl", { selfLink, resetSelected, mergeGlobals }); + const params = new URLSearchParams(mergeGlobals ? navigation.searchParams : ""); + + params.set(kubeDetailsUrlParam.name, selfLink); + + if (resetSelected) { + params.delete(kubeSelectedUrlParam.name); + } else { + params.set(kubeSelectedUrlParam.name, kubeSelectedUrlParam.get()); + } + + return `?${params}`; +} diff --git a/src/renderer/components/kube-object-details/index.ts b/src/renderer/components/kube-object-details/index.ts new file mode 100644 index 0000000000..9675c16f58 --- /dev/null +++ b/src/renderer/components/kube-object-details/index.ts @@ -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 * from "./kube-object-details"; diff --git a/src/renderer/components/kube-object/kube-object-details.scss b/src/renderer/components/kube-object-details/kube-object-details.scss similarity index 100% rename from src/renderer/components/kube-object/kube-object-details.scss rename to src/renderer/components/kube-object-details/kube-object-details.scss diff --git a/src/renderer/components/kube-object/kube-object-details.tsx b/src/renderer/components/kube-object-details/kube-object-details.tsx similarity index 71% rename from src/renderer/components/kube-object/kube-object-details.tsx rename to src/renderer/components/kube-object-details/kube-object-details.tsx index 7ef8686130..be888c6505 100644 --- a/src/renderer/components/kube-object/kube-object-details.tsx +++ b/src/renderer/components/kube-object-details/kube-object-details.tsx @@ -24,63 +24,20 @@ import "./kube-object-details.scss"; import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { computed, observable, reaction, makeObservable } from "mobx"; -import { createPageParam, navigation } from "../../navigation"; import { Drawer } from "../drawer"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { Spinner } from "../spinner"; -import { apiManager } from "../../api/api-manager"; +import { apiManager } from "../../../common/k8s-api/api-manager"; import { crdStore } from "../+custom-resources/crd.store"; -import { KubeObjectMenu } from "./kube-object-menu"; +import { KubeObjectMenu } from "../kube-object-menu"; import { KubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import logger from "../../../main/logger"; +import { CrdResourceDetails } from "../+custom-resources"; +import { KubeObjectMeta } from "../kube-object-meta"; +import { hideDetails, kubeDetailsUrlParam } from "../kube-detail-params"; -/** - * Used to store `object.selfLink` to show more info about resource in the details panel. - */ -export const kubeDetailsUrlParam = createPageParam({ - name: "kube-details", -}); -/** - * Used to highlight last active/selected table row with the resource. - * - * @example - * If we go to "Nodes (page) -> Node (details) -> Pod (details)", - * last clicked Node should be "active" while Pod details are shown). - */ -export const kubeSelectedUrlParam = createPageParam({ - name: "kube-selected", - get defaultValue() { - return kubeDetailsUrlParam.get(); - } -}); - -export function showDetails(selfLink = "", resetSelected = true) { - const detailsUrl = getDetailsUrl(selfLink, resetSelected); - - navigation.merge({ search: detailsUrl }); -} - -export function hideDetails() { - showDetails(); -} - -export function getDetailsUrl(selfLink: string, resetSelected = false, mergeGlobals = true) { - logger.debug("getDetailsUrl", { selfLink, resetSelected, mergeGlobals }); - const params = new URLSearchParams(mergeGlobals ? navigation.searchParams : ""); - - params.set(kubeDetailsUrlParam.name, selfLink); - - if (resetSelected) { - params.delete(kubeSelectedUrlParam.name); - } else { - params.set(kubeSelectedUrlParam.name, kubeSelectedUrlParam.get()); - } - - return `?${params}`; -} - -export interface KubeObjectDetailsProps { +export interface KubeObjectDetailsProps { className?: string; object: T; } @@ -111,10 +68,6 @@ export class KubeObjectDetails extends React.Component { } } - @computed get isCrdInstance() { - return !!crdStore.getByObject(this.object); - } - @disposeOnUnmount loader = reaction(() => [ this.path, @@ -169,6 +122,23 @@ export class KubeObjectDetails extends React.Component { )); + if (details.length === 0) { + const crd = crdStore.getByObject(object); + + /** + * This is a fallback so that if a custom resource object doesn't have + * any defined details we should try and display at least some details + */ + if (crd) { + details.push(); + } + } + + if (details.length === 0) { + // if we still don't have any details to show, just show the standard object metadata + details.push(); + } + return ( extends ItemListLayoutProps { store: KubeObjectStore; diff --git a/src/renderer/components/kube-object-menu/index.ts b/src/renderer/components/kube-object-menu/index.ts new file mode 100644 index 0000000000..43cd5ea4a0 --- /dev/null +++ b/src/renderer/components/kube-object-menu/index.ts @@ -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 * from "./kube-object-menu"; diff --git a/src/renderer/components/kube-object/kube-object-menu.tsx b/src/renderer/components/kube-object-menu/kube-object-menu.tsx similarity index 94% rename from src/renderer/components/kube-object/kube-object-menu.tsx rename to src/renderer/components/kube-object-menu/kube-object-menu.tsx index f614ffc980..1848fa2906 100644 --- a/src/renderer/components/kube-object/kube-object-menu.tsx +++ b/src/renderer/components/kube-object-menu/kube-object-menu.tsx @@ -21,11 +21,11 @@ import React from "react"; import { boundMethod, cssNames } from "../../utils"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { editResourceTab } from "../dock/edit-resource.store"; import { MenuActions, MenuActionsProps } from "../menu/menu-actions"; -import { hideDetails } from "./kube-object-details"; -import { apiManager } from "../../api/api-manager"; +import { hideDetails } from "../kube-detail-params"; +import { apiManager } from "../../../common/k8s-api/api-manager"; import { KubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; export interface KubeObjectMenuProps extends MenuActionsProps { @@ -85,7 +85,7 @@ export class KubeObjectMenu extends React.Component { { ownerRefs.map(ref => { const { name, kind } = ref; - const ownerDetailsUrl = getDetailsUrl(lookupApiLink(ref, object)); + const ownerDetailsUrl = getDetailsUrl(apiManager.lookupApiLink(ref, object)); return (

diff --git a/src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx b/src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx index 82903f7b5c..a9a9aacfdc 100644 --- a/src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx +++ b/src/renderer/components/kubeconfig-dialog/kubeconfig-dialog.tsx @@ -26,7 +26,7 @@ import { observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import jsYaml from "js-yaml"; import { AceEditor } from "../ace-editor"; -import type { ServiceAccount } from "../../api/endpoints"; +import type { ServiceAccount } from "../../../common/k8s-api/endpoints"; import { copyToClipboard, cssNames, saveFileDialog } from "../../utils"; import { Button } from "../button"; import { Dialog, DialogProps } from "../dialog"; diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 96e3a26dac..44e57e9202 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -33,7 +33,7 @@ import { Network } from "../+network"; import { crdStore } from "../+custom-resources/crd.store"; import { CustomResources } from "../+custom-resources/custom-resources"; import { isActiveRoute } from "../../navigation"; -import { isAllowedResource } from "../../../common/rbac"; +import { isAllowedResource } from "../../../common/utils/allowed-resource"; import { Spinner } from "../spinner"; import { ClusterPageMenuRegistration, ClusterPageMenuRegistry, ClusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries"; import { SidebarItem } from "./sidebar-item"; diff --git a/src/renderer/components/notifications/notifications.store.tsx b/src/renderer/components/notifications/notifications.store.tsx index 63ab5d5e05..9a47f588ac 100644 --- a/src/renderer/components/notifications/notifications.store.tsx +++ b/src/renderer/components/notifications/notifications.store.tsx @@ -23,7 +23,7 @@ import type React from "react"; import { action, observable, makeObservable } from "mobx"; import { autoBind } from "../../utils"; import uniqueId from "lodash/uniqueId"; -import type { JsonApiErrorParsed } from "../../api/json-api"; +import type { JsonApiErrorParsed } from "../../../common/k8s-api/json-api"; export type NotificationId = string | number; export type NotificationMessage = React.ReactNode | React.ReactNode[] | JsonApiErrorParsed; diff --git a/src/renderer/components/notifications/notifications.tsx b/src/renderer/components/notifications/notifications.tsx index b4e9344aa0..3aa138ef4e 100644 --- a/src/renderer/components/notifications/notifications.tsx +++ b/src/renderer/components/notifications/notifications.tsx @@ -24,7 +24,7 @@ import "./notifications.scss"; import React from "react"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; -import { JsonApiErrorParsed } from "../../api/json-api"; +import { JsonApiErrorParsed } from "../../../common/k8s-api/json-api"; import { cssNames, prevDefault } from "../../utils"; import { Notification, NotificationMessage, notificationsStore, NotificationStatus } from "./notifications.store"; import { Animate } from "../animate"; diff --git a/src/renderer/components/render-delay/__tests__/render-delay.test.tsx b/src/renderer/components/render-delay/__tests__/render-delay.test.tsx index f81003e588..6540ec4dd9 100644 --- a/src/renderer/components/render-delay/__tests__/render-delay.test.tsx +++ b/src/renderer/components/render-delay/__tests__/render-delay.test.tsx @@ -22,6 +22,9 @@ import React from "react"; import "@testing-library/jest-dom/extend-expect"; import { render } from "@testing-library/react"; import { RenderDelay } from "../render-delay"; +import { mockWindow } from "../../../../../__mocks__/windowMock"; + +mockWindow(); describe("", () => { it("renders w/o errors", () => { diff --git a/src/renderer/components/resource-metrics/resource-metrics-text.tsx b/src/renderer/components/resource-metrics/resource-metrics-text.tsx index a83ef8118c..7708711569 100644 --- a/src/renderer/components/resource-metrics/resource-metrics-text.tsx +++ b/src/renderer/components/resource-metrics/resource-metrics-text.tsx @@ -20,8 +20,8 @@ */ import React from "react"; -import type { IPodMetrics } from "../../api/endpoints"; -import { getMetricLastPoints, IMetrics } from "../../api/endpoints/metrics.api"; +import type { IPodMetrics } from "../../../common/k8s-api/endpoints"; +import { getMetricLastPoints, IMetrics } from "../../../common/k8s-api/endpoints/metrics.api"; import { bytesToUnits } from "../../utils"; import { Badge } from "../badge"; import { DrawerItem } from "../drawer"; diff --git a/src/renderer/components/resource-metrics/resource-metrics.tsx b/src/renderer/components/resource-metrics/resource-metrics.tsx index aaf111a8cb..3b7a214fbb 100644 --- a/src/renderer/components/resource-metrics/resource-metrics.tsx +++ b/src/renderer/components/resource-metrics/resource-metrics.tsx @@ -24,7 +24,7 @@ import "./resource-metrics.scss"; import React, { createContext, useEffect, useState } from "react"; import { Radio, RadioGroup } from "../radio"; import { useInterval } from "../../hooks"; -import type { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../../common/k8s-api/kube-object"; import { cssNames } from "../../utils"; import { Spinner } from "../spinner"; diff --git a/src/renderer/components/table/table-row.tsx b/src/renderer/components/table/table-row.tsx index 9b3ce613e1..d4c148b4e3 100644 --- a/src/renderer/components/table/table-row.tsx +++ b/src/renderer/components/table/table-row.tsx @@ -23,7 +23,7 @@ import "./table-row.scss"; import React, { CSSProperties } from "react"; import { cssNames } from "../../utils"; -import type { ItemObject } from "../../item.store"; +import type { ItemObject } from "../../../common/item.store"; export type TableRowElem = React.ReactElement; diff --git a/src/renderer/components/tabs/tabs.tsx b/src/renderer/components/tabs/tabs.tsx index 8a910211fa..719b11cf76 100644 --- a/src/renderer/components/tabs/tabs.tsx +++ b/src/renderer/components/tabs/tabs.tsx @@ -127,7 +127,7 @@ export class Tab extends React.PureComponent { this.ref.current?.click(); } - this.props?.onKeyDown(evt); + this.props.onKeyDown?.(evt); } componentDidMount() { diff --git a/src/renderer/components/virtual-list/virtual-list.tsx b/src/renderer/components/virtual-list/virtual-list.tsx index ad6d93af3a..36f62dff93 100644 --- a/src/renderer/components/virtual-list/virtual-list.tsx +++ b/src/renderer/components/virtual-list/virtual-list.tsx @@ -28,7 +28,7 @@ import { observer } from "mobx-react"; import { Align, ListChildComponentProps, ListOnScrollProps, VariableSizeList } from "react-window"; import { cssNames, noop } from "../../utils"; import type { TableRowProps } from "../table/table-row"; -import type { ItemObject } from "../../item.store"; +import type { ItemObject } from "../../../common/item.store"; import debounce from "lodash/debounce"; import isEqual from "lodash/isEqual"; import AutoSizer from "react-virtualized-auto-sizer"; diff --git a/src/renderer/initializers/kube-object-detail-registry.tsx b/src/renderer/initializers/kube-object-detail-registry.tsx index ddc7617f45..592c1f5252 100644 --- a/src/renderer/initializers/kube-object-detail-registry.tsx +++ b/src/renderer/initializers/kube-object-detail-registry.tsx @@ -20,16 +20,14 @@ */ import React from "react"; -import type * as endpoints from "../api/endpoints"; -import type { KubeObject } from "../api/kube-object"; import { KubeObjectDetailRegistry } from "../api/kube-object-detail-registry"; -import { HpaDetails } from "../components/+config-autoscalers"; +import { HpaDetails, HpaDetailsProps } from "../components/+config-autoscalers"; import { LimitRangeDetails } from "../components/+config-limit-ranges"; import { ConfigMapDetails } from "../components/+config-maps"; import { PodDisruptionBudgetDetails } from "../components/+config-pod-disruption-budgets"; import { ResourceQuotaDetails } from "../components/+config-resource-quotas"; import { SecretDetails } from "../components/+config-secrets"; -import { CRDDetails, CrdResourceDetails } from "../components/+custom-resources"; +import { CRDDetails } from "../components/+custom-resources"; import { EventDetails } from "../components/+events"; import { KubeEventDetails } from "../components/+events/kube-event-details"; import { NamespaceDetails } from "../components/+namespaces"; @@ -54,8 +52,7 @@ import { JobDetails } from "../components/+workloads-jobs"; import { PodDetails } from "../components/+workloads-pods"; import { ReplicaSetDetails } from "../components/+workloads-replicasets"; import { StatefulSetDetails } from "../components/+workloads-statefulsets"; -import type { KubeObjectDetailsProps } from "../components/kube-object"; -import type { CustomResourceDefinition } from "../api/endpoints"; +import type { KubeObjectDetailsProps } from "../components/kube-object-details"; export function intiKubeObjectDetailRegistry() { KubeObjectDetailRegistry.getInstance() @@ -64,7 +61,8 @@ export function intiKubeObjectDetailRegistry() { kind: "HorizontalPodAutoscaler", apiVersions: ["autoscaling/v2beta1"], components: { - Details: (props: KubeObjectDetailsProps) => , + // Note: this line is left in the long form as a validation that this usecase is valid + Details: (props: HpaDetailsProps) => , } }, { @@ -72,21 +70,22 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["autoscaling/v2beta1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , - } + // Note: this line is left in the long form as a validation that this usecase is valid + Details: (props: KubeObjectDetailsProps) => , + }, }, { kind: "LimitRange", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: LimitRangeDetails, } }, { kind: "ConfigMap", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: ConfigMapDetails, } }, { @@ -94,56 +93,56 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "PodDisruptionBudget", apiVersions: ["policy/v1beta1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: PodDisruptionBudgetDetails, } }, { kind: "ResourceQuota", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: ResourceQuotaDetails, } }, { kind: "Secret", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: SecretDetails, } }, { kind: "CustomResourceDefinition", apiVersions: ["apiextensions.k8s.io/v1", "apiextensions.k8s.io/v1beta1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: CRDDetails, } }, { kind: "Event", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: EventDetails, } }, { kind: "Namespace", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: NamespaceDetails, } }, { kind: "Endpoints", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: EndpointDetails, } }, { @@ -151,14 +150,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "Ingress", apiVersions: ["networking.k8s.io/v1", "extensions/v1beta1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: IngressDetails, } }, { @@ -166,14 +165,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["networking.k8s.io/v1", "extensions/v1beta1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "NetworkPolicy", apiVersions: ["networking.k8s.io/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: NetworkPolicyDetails, } }, { @@ -181,14 +180,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["networking.k8s.io/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "Service", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: ServiceDetails, } }, { @@ -196,14 +195,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "Node", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: NodeDetails, } }, { @@ -211,21 +210,21 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "PodSecurityPolicy", apiVersions: ["policy/v1beta1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: PodSecurityPolicyDetails, } }, { kind: "StorageClass", apiVersions: ["storage.k8s.io/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: StorageClassDetails, } }, { @@ -233,14 +232,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["storage.k8s.io/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "PersistentVolumeClaim", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: PersistentVolumeClaimDetails, } }, { @@ -248,14 +247,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "PersistentVolume", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: PersistentVolumeDetails, } }, { @@ -263,14 +262,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "Role", apiVersions: ["rbac.authorization.k8s.io/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: RoleDetails, } }, { @@ -278,14 +277,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["rbac.authorization.k8s.io/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "ClusterRole", apiVersions: ["rbac.authorization.k8s.io/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: ClusterRoleDetails, } }, { @@ -293,14 +292,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["rbac.authorization.k8s.io/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "RoleBinding", apiVersions: ["rbac.authorization.k8s.io/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: RoleBindingDetails, } }, { @@ -308,14 +307,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["rbac.authorization.k8s.io/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "ClusterRoleBinding", apiVersions: ["rbac.authorization.k8s.io/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: ClusterRoleBindingDetails, } }, { @@ -323,14 +322,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["rbac.authorization.k8s.io/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "ServiceAccount", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: ServiceAccountsDetails, } }, { @@ -338,14 +337,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "CronJob", apiVersions: ["batch/v1beta1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: CronJobDetails, } }, { @@ -353,14 +352,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["batch/v1beta1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "DaemonSet", apiVersions: ["apps/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: DaemonSetDetails, } }, { @@ -368,14 +367,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["apps/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "Deployment", apiVersions: ["apps/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: DeploymentDetails, } }, { @@ -383,14 +382,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["apps/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "Job", apiVersions: ["batch/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: JobDetails, } }, { @@ -398,14 +397,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["batch/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "Pod", apiVersions: ["v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: PodDetails, } }, { @@ -413,14 +412,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "ReplicaSet", apiVersions: ["apps/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: ReplicaSetDetails, } }, { @@ -428,14 +427,14 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["apps/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, { kind: "StatefulSet", apiVersions: ["apps/v1"], components: { - Details: (props: KubeObjectDetailsProps) => , + Details: StatefulSetDetails, } }, { @@ -443,15 +442,8 @@ export function intiKubeObjectDetailRegistry() { apiVersions: ["apps/v1"], priority: 5, components: { - Details: (props: KubeObjectDetailsProps) => , + Details: KubeEventDetails, } }, - { - kind: "CustomResourceDefinition", - apiVersions: ["apiextensions.k8s.io/v1"], - components: { - Details: (props: KubeObjectDetailsProps) => , - } - } ]); } diff --git a/src/renderer/initializers/workloads-overview-detail-registry.tsx b/src/renderer/initializers/workloads-overview-detail-registry.tsx index b374bb11af..b8aec840bf 100644 --- a/src/renderer/initializers/workloads-overview-detail-registry.tsx +++ b/src/renderer/initializers/workloads-overview-detail-registry.tsx @@ -20,7 +20,7 @@ */ import React from "react"; -import { isAllowedResource } from "../../common/rbac"; +import { isAllowedResource } from "../../common/utils/allowed-resource"; import { WorkloadsOverviewDetailRegistry } from "../../extensions/registries"; import { Events } from "../components/+events"; import { OverviewStatuses } from "../components/+workloads-overview/overview-statuses"; diff --git a/src/renderer/ipc/index.tsx b/src/renderer/ipc/index.tsx index 338f71c38d..139f4bd362 100644 --- a/src/renderer/ipc/index.tsx +++ b/src/renderer/ipc/index.tsx @@ -21,13 +21,14 @@ import React from "react"; import { ipcRenderer, IpcRendererEvent } from "electron"; -import { areArgsUpdateAvailableFromMain, UpdateAvailableChannel, onCorrect, UpdateAvailableFromMain, BackchannelArg, ClusterListNamespaceForbiddenChannel, isListNamespaceForbiddenArgs, ListNamespaceForbiddenArgs } from "../../common/ipc"; +import { areArgsUpdateAvailableFromMain, UpdateAvailableChannel, onCorrect, UpdateAvailableFromMain, BackchannelArg, ClusterListNamespaceForbiddenChannel, isListNamespaceForbiddenArgs, ListNamespaceForbiddenArgs, HotbarTooManyItems } from "../../common/ipc"; import { Notifications, notificationsStore } from "../components/notifications"; import { Button } from "../components/button"; import { isMac } from "../../common/vars"; import { ClusterStore } from "../../common/cluster-store"; import { navigate } from "../navigation"; import { entitySettingsURL } from "../../common/routes"; +import { defaultHotbarCells } from "../../common/hotbar-types"; function sendToBackchannel(backchannel: string, notificationId: string, data: BackchannelArg): void { notificationsStore.remove(notificationId); @@ -112,6 +113,10 @@ function ListNamespacesForbiddenHandler(event: IpcRendererEvent, ...[clusterId]: ); } +function HotbarTooManyItemsHandler(): void { + Notifications.error(`Cannot have more than ${defaultHotbarCells} items pinned to a hotbar`); +} + export function registerIpcHandlers() { onCorrect({ source: ipcRenderer, @@ -125,4 +130,10 @@ export function registerIpcHandlers() { listener: ListNamespacesForbiddenHandler, verifier: isListNamespaceForbiddenArgs, }); + onCorrect({ + source: ipcRenderer, + channel: HotbarTooManyItems, + listener: HotbarTooManyItemsHandler, + verifier: (args: unknown[]): args is [] => args.length === 0, + }); } diff --git a/src/renderer/utils/createStorage.ts b/src/renderer/utils/createStorage.ts index 0e1452ac80..3636180c35 100755 --- a/src/renderer/utils/createStorage.ts +++ b/src/renderer/utils/createStorage.ts @@ -26,8 +26,9 @@ import { app, remote } from "electron"; import { comparer, observable, reaction, toJS, when } from "mobx"; import fse from "fs-extra"; import { StorageHelper } from "./storageHelper"; -import { ClusterStore, getHostedClusterId } from "../../common/cluster-store"; +import { ClusterStore } from "../../common/cluster-store"; import logger from "../../main/logger"; +import { getHostedClusterId } from "../../common/utils"; const storage = observable({ initialized: false, diff --git a/src/renderer/utils/index.ts b/src/renderer/utils/index.ts index a0b20d1e2d..537aab13ba 100755 --- a/src/renderer/utils/index.ts +++ b/src/renderer/utils/index.ts @@ -32,10 +32,9 @@ export * from "./storageHelper"; export * from "./createStorage"; export * from "./interval"; export * from "./copyToClipboard"; -export * from "./formatDuration"; export * from "./isReactNode"; -export * from "./convertMemory"; -export * from "./convertCpu"; +export * from "../../common/utils/convertMemory"; +export * from "../../common/utils/convertCpu"; export * from "./metricUnitsToNumber"; export * from "./display-booleans"; export * from "./isMiddleClick"; diff --git a/webpack.main.ts b/webpack.main.ts index ae78d06d09..33d9daf6af 100755 --- a/webpack.main.ts +++ b/webpack.main.ts @@ -22,13 +22,15 @@ import path from "path"; import type webpack from "webpack"; import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin"; -import { isProduction, mainDir, buildDir, isDevelopment } from "./src/common/vars"; +import { isProduction, mainDir, buildDir, isDevelopment, preloadEntrypoint } from "./src/common/vars"; import nodeExternals from "webpack-node-externals"; import ProgressBarPlugin from "progress-bar-webpack-plugin"; import * as vars from "./src/common/vars"; import getTSLoader from "./src/common/getTSLoader"; -export default function (): webpack.Configuration { +const configs: {(): webpack.Configuration}[] = []; + +configs.push((): webpack.Configuration => { console.info("WEBPACK:main", vars); return { @@ -64,4 +66,43 @@ export default function (): webpack.Configuration { new ForkTsCheckerPlugin(), ].filter(Boolean) }; -} +}); + +configs.push((): webpack.Configuration => { + console.info("WEBPACK:preload", vars); + + return { + context: __dirname, + target: "electron-main", + mode: isProduction ? "production" : "development", + devtool: isProduction ? "source-map" : "cheap-eval-source-map", + cache: isDevelopment, + entry: { + main: path.resolve(preloadEntrypoint), + }, + output: { + libraryTarget: "global", + path: buildDir, + filename: "preload.js" + }, + resolve: { + extensions: [".json", ".js", ".ts"], + mainFields: ["main"] + }, + module: { + rules: [ + { + test: /\.node$/, + use: "node-loader" + }, + getTSLoader(/\.ts$/) + ] + }, + plugins: [ + new ProgressBarPlugin(), + new ForkTsCheckerPlugin(), + ].filter(Boolean) + }; +}); + +export default configs; diff --git a/yarn.lock b/yarn.lock index 5bbd393f6b..054c84ffa6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -332,6 +332,15 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@dabh/diagnostics@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31" + integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@develar/schema-utils@~2.6.5": version "2.6.5" resolved "https://registry.yarnpkg.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz#3ece22c5838402419a6e0425f85742b961d9b6c6" @@ -823,14 +832,14 @@ dependencies: cross-spawn "^7.0.1" -"@material-ui/core@^4.11.4": - version "4.11.4" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.11.4.tgz#4fb9fe5dec5dcf780b687e3a40cff78b2b9640a4" - integrity sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg== +"@material-ui/core@^4.12.3": + version "4.12.3" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.3.tgz#80d665caf0f1f034e52355c5450c0e38b099d3ca" + integrity sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw== dependencies: "@babel/runtime" "^7.4.4" "@material-ui/styles" "^4.11.4" - "@material-ui/system" "^4.11.3" + "@material-ui/system" "^4.12.1" "@material-ui/types" "5.1.0" "@material-ui/utils" "^4.11.2" "@types/react-transition-group" "^4.2.0" @@ -881,10 +890,10 @@ jss-plugin-vendor-prefixer "^10.5.1" prop-types "^15.7.2" -"@material-ui/system@^4.11.3": - version "4.11.3" - resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.11.3.tgz#466bc14c9986798fd325665927c963eb47cc4143" - integrity sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw== +"@material-ui/system@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.1.tgz#2dd96c243f8c0a331b2bb6d46efd7771a399707c" + integrity sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw== dependencies: "@babel/runtime" "^7.4.4" "@material-ui/utils" "^4.11.2" @@ -1016,13 +1025,13 @@ "@sentry/utils" "6.8.0" tslib "^1.9.3" -"@sentry/integrations@^6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.8.0.tgz#990d042d683ed4b45fcbe0cbf3e8077587a45f85" - integrity sha512-K8xmWGQFKxkKj5rMwGENm0SbbUs/SVhHE+V8+KkhXFmHAwfNAYTFaNg0Ryu9DADAJ4QYzZvYeRxl8voFecOqzA== +"@sentry/integrations@^6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.10.0.tgz#f8f9e7efd55ec44d0408bd4493df1c9ceabaaa63" + integrity sha512-NMtB0jjFYFZRxyjYu2dWLThk9YPIwqhi4hYywmWkbv4/ILzi5Rwnh+aqNW6yrj8qG4b9itNMh3YvEzmf0aqauw== dependencies: - "@sentry/types" "6.8.0" - "@sentry/utils" "6.8.0" + "@sentry/types" "6.10.0" + "@sentry/utils" "6.10.0" localforage "^1.8.1" tslib "^1.9.3" @@ -1082,16 +1091,29 @@ "@sentry/utils" "6.7.1" tslib "^1.9.3" +"@sentry/types@6.10.0", "@sentry/types@^6.8.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.10.0.tgz#6b1f44e5ed4dbc2710bead24d1b32fb08daf04e1" + integrity sha512-M7s0JFgG7/6/yNVYoPUbxzaXDhnzyIQYRRJJKRaTD77YO4MHvi4Ke8alBWqD5fer0cPIfcSkBqa9BLdqRqcMWw== + "@sentry/types@6.7.1": version "6.7.1" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.7.1.tgz#c8263e1886df5e815570c4668eb40a1cfaa1c88b" integrity sha512-9AO7HKoip2MBMNQJEd6+AKtjj2+q9Ze4ooWUdEvdOVSt5drg7BGpK221/p9JEOyJAZwEPEXdcMd3VAIMiOb4MA== -"@sentry/types@6.8.0", "@sentry/types@^6.8.0": +"@sentry/types@6.8.0": version "6.8.0" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.8.0.tgz#97fd531a0ed1e75e65b4a24b26509fb7c15eb7b8" integrity sha512-PbSxqlh6Fd5thNU5f8EVYBVvX+G7XdPA+ThNb2QvSK8yv3rIf0McHTyF6sIebgJ38OYN7ZFK7vvhC/RgSAfYTA== +"@sentry/utils@6.10.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.10.0.tgz#839a099fa0a1f0ca0893c7ce8c55ba0608c1d80f" + integrity sha512-F9OczOcZMFtazYVZ6LfRIe65/eOfQbiAedIKS0li4npuMz0jKYRbxrjd/U7oLiNQkPAp4/BujU4m1ZIwq6a+tg== + dependencies: + "@sentry/types" "6.10.0" + tslib "^1.9.3" + "@sentry/utils@6.7.1": version "6.7.1" resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.7.1.tgz#909184ad580f0f6375e1e4d4a6ffd33dfe64a4d1" @@ -1328,10 +1350,10 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== -"@types/color@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.1.tgz#2900490ed04da8116c5058cd5dba3572d5a25071" - integrity sha512-oeUWVaAwI+xINDUx+3F2vJkl/vVB03VChFF/Gl3iQCdbcakjuoJyMOba+3BXRtnBhxZ7uBYqQBi9EpLnvSoztA== +"@types/color@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.2.tgz#3779043e782f562aa9157b5fc6bd07e14fd8e7f3" + integrity sha512-INiJl6sfNn8iyC5paxVzqiVUEj2boIlFki02uRTAkKwAj++7aAF+ZfEv/XrIeBa0XI/fTZuDHW8rEEcEVnON+Q== dependencies: "@types/color-convert" "*" @@ -1412,6 +1434,11 @@ dependencies: "@types/node" "*" +"@types/glob-to-regexp@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#f684bc7b9a24691f1f80d045dbb7260bf9cc415b" + integrity sha512-S0mIukll6fbF0tvrKic/jj+jI8SHoSvGU+Cs95b/jzZEnBYCbj+7aJtQ9yeABuK3xP1okwA3jEH9qIRayijnvQ== + "@types/glob@^7.1.1": version "7.1.3" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" @@ -1505,10 +1532,10 @@ "@types/http-proxy" "*" "@types/node" "*" -"@types/http-proxy@*", "@types/http-proxy@^1.17.5": - version "1.17.5" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.5.tgz#c203c5e6e9dc6820d27a40eb1e511c70a220423d" - integrity sha512-GNkDE7bTv6Sf8JbV2GksknKOsk7OznNYHSdrtvPJXO0qJ9odZig6IZKUi5RFGi6d1bf6dgIAe4uXi3DBc7069Q== +"@types/http-proxy@*", "@types/http-proxy@^1.17.7": + version "1.17.7" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.7.tgz#30ea85cc2c868368352a37f0d0d3581e24834c6f" + integrity sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w== dependencies: "@types/node" "*" @@ -1568,16 +1595,16 @@ "@types/parse5" "*" "@types/tough-cookie" "*" -"@types/json-schema@^7.0.3": - version "7.0.5" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" - integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== - "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6": version "7.0.7" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== +"@types/json-schema@^7.0.7": + version "7.0.8" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818" + integrity sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -1658,6 +1685,14 @@ resolved "https://registry.yarnpkg.com/@types/module-alias/-/module-alias-2.0.0.tgz#882668f8b8cdbda44812c3b592c590909e18849e" integrity sha512-e3sW4oEH0qS1QxSfX7PT6xIi5qk/YSMsrB9Lq8EtkhQBZB+bKyfkP+jpLJRySanvBhAQPSv2PEBe81M8Iy/7yg== +"@types/node-fetch@^2.5.12": + version "2.5.12" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" + integrity sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node@*": version "14.14.41" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.41.tgz#d0b939d94c1d7bd53d04824af45f1139b8c45615" @@ -1983,6 +2018,11 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d" integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A== +"@types/triple-beam@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.2.tgz#38ecb64f01aa0d02b7c8f4222d7c38af6316fef8" + integrity sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g== + "@types/trusted-types@*": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.4.tgz#922d092c84a776a59acb0bd6785fd82b59b9bad5" @@ -2092,31 +2132,30 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^4.14.2", "@typescript-eslint/eslint-plugin@^4.5.0": - version "4.14.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.2.tgz#47a15803cfab89580b96933d348c2721f3d2f6fe" - integrity sha512-uMGfG7GFYK/nYutK/iqYJv6K/Xuog/vrRRZX9aEP4Zv1jsYXuvFUMDFLhUnc8WFv3D2R5QhNQL3VYKmvLS5zsQ== +"@typescript-eslint/eslint-plugin@^4.29.0", "@typescript-eslint/eslint-plugin@^4.5.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz#b866c9cd193bfaba5e89bade0015629ebeb27996" + integrity sha512-eiREtqWRZ8aVJcNru7cT/AMVnYd9a2UHsfZT8MR1dW3UUEg6jDv9EQ9Cq4CUPZesyQ58YUpoAADGv71jY8RwgA== dependencies: - "@typescript-eslint/experimental-utils" "4.14.2" - "@typescript-eslint/scope-manager" "4.14.2" - debug "^4.1.1" + "@typescript-eslint/experimental-utils" "4.29.0" + "@typescript-eslint/scope-manager" "4.29.0" + debug "^4.3.1" functional-red-black-tree "^1.0.1" - lodash "^4.17.15" - regexpp "^3.0.0" - semver "^7.3.2" - tsutils "^3.17.1" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.14.2": - version "4.14.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.2.tgz#9df35049d1d36b6cbaba534d703648b9e1f05cbb" - integrity sha512-mV9pmET4C2y2WlyHmD+Iun8SAEqkLahHGBkGqDVslHkmoj3VnxnGP4ANlwuxxfq1BsKdl/MPieDbohCEQgKrwA== +"@typescript-eslint/experimental-utils@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.0.tgz#19b1417602d0e1ef325b3312ee95f61220542df5" + integrity sha512-FpNVKykfeaIxlArLUP/yQfv/5/3rhl1ov6RWgud4OgbqWLkEq7lqgQU9iiavZRzpzCRQV4XddyFz3wFXdkiX9w== dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.14.2" - "@typescript-eslint/types" "4.14.2" - "@typescript-eslint/typescript-estree" "4.14.2" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.29.0" + "@typescript-eslint/types" "4.29.0" + "@typescript-eslint/typescript-estree" "4.29.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" "@typescript-eslint/parser@^4.0.0": version "4.8.2" @@ -2128,13 +2167,13 @@ "@typescript-eslint/typescript-estree" "4.8.2" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.14.2": - version "4.14.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.14.2.tgz#64cbc9ca64b60069aae0c060b2bf81163243b266" - integrity sha512-cuV9wMrzKm6yIuV48aTPfIeqErt5xceTheAgk70N1V4/2Ecj+fhl34iro/vIssJlb7XtzcaD07hWk7Jk0nKghg== +"@typescript-eslint/scope-manager@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.0.tgz#cf5474f87321bedf416ef65839b693bddd838599" + integrity sha512-HPq7XAaDMM3DpmuijxLV9Io8/6pQnliiXMQUcAdjpJJSR+fdmbD/zHCd7hMkjJn04UQtCQBtshgxClzg6NIS2w== dependencies: - "@typescript-eslint/types" "4.14.2" - "@typescript-eslint/visitor-keys" "4.14.2" + "@typescript-eslint/types" "4.29.0" + "@typescript-eslint/visitor-keys" "4.29.0" "@typescript-eslint/scope-manager@4.8.2": version "4.8.2" @@ -2144,29 +2183,28 @@ "@typescript-eslint/types" "4.8.2" "@typescript-eslint/visitor-keys" "4.8.2" -"@typescript-eslint/types@4.14.2": - version "4.14.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.14.2.tgz#d96da62be22dc9dc6a06647f3633815350fb3174" - integrity sha512-LltxawRW6wXy4Gck6ZKlBD05tCHQUj4KLn4iR69IyRiDHX3d3NCAhO+ix5OR2Q+q9bjCrHE/HKt+riZkd1At8Q== +"@typescript-eslint/types@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" + integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== "@typescript-eslint/types@4.8.2": version "4.8.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.8.2.tgz#c862dd0e569d9478eb82d6aee662ea53f5661a36" integrity sha512-z1/AVcVF8ju5ObaHe2fOpZYEQrwHyZ7PTOlmjd3EoFeX9sv7UekQhfrCmgUO7PruLNfSHrJGQvrW3Q7xQ8EoAw== -"@typescript-eslint/typescript-estree@4.14.2": - version "4.14.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.2.tgz#9c5ebd8cae4d7b014f890acd81e8e17f309c9df9" - integrity sha512-ESiFl8afXxt1dNj8ENEZT12p+jl9PqRur+Y19m0Z/SPikGL6rqq4e7Me60SU9a2M28uz48/8yct97VQYaGl0Vg== +"@typescript-eslint/typescript-estree@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.0.tgz#af7ab547757b86c91bfdbc54ff86845410856256" + integrity sha512-8ZpNHDIOyqzzgZrQW9+xQ4k5hM62Xy2R4RPO3DQxMc5Rq5QkCdSpk/drka+DL9w6sXNzV5nrdlBmf8+x495QXQ== dependencies: - "@typescript-eslint/types" "4.14.2" - "@typescript-eslint/visitor-keys" "4.14.2" - debug "^4.1.1" - globby "^11.0.1" + "@typescript-eslint/types" "4.29.0" + "@typescript-eslint/visitor-keys" "4.29.0" + debug "^4.3.1" + globby "^11.0.3" is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" + semver "^7.3.5" + tsutils "^3.21.0" "@typescript-eslint/typescript-estree@4.8.2": version "4.8.2" @@ -2182,12 +2220,12 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@4.14.2": - version "4.14.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.2.tgz#997cbe2cb0690e1f384a833f64794e98727c70c6" - integrity sha512-KBB+xLBxnBdTENs/rUgeUKO0UkPBRs2vD09oMRRIkj5BEN8PX1ToXV532desXfpQnZsYTyLLviS7JrPhdL154w== +"@typescript-eslint/visitor-keys@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.0.tgz#1ff60f240def4d85ea68d4fd2e4e9759b7850c04" + integrity sha512-LoaofO1C/jAJYs0uEpYMXfHboGXzOJeV118X4OsZu9f7rG7Pr9B3+4HTU8+err81rADa4xfQmAxnRnPAI2jp+Q== dependencies: - "@typescript-eslint/types" "4.14.2" + "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" "@typescript-eslint/visitor-keys@4.8.2": @@ -2894,13 +2932,18 @@ async@0.9.x: resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= -async@^2.0.0, async@^2.6.1, async@^2.6.2: +async@^2.0.0, async@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== dependencies: lodash "^4.17.14" +async@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" + integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -3672,15 +3715,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.1.1: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== @@ -3698,10 +3733,10 @@ chardet@^0.4.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= -chart.js@^2.9.3: - version "2.9.3" - resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.3.tgz#ae3884114dafd381bc600f5b35a189138aac1ef7" - integrity sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw== +chart.js@^2.9.4: + version "2.9.4" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684" + integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A== dependencies: chartjs-color "^2.1.0" moment "^2.10.2" @@ -4049,17 +4084,12 @@ colorette@^1.2.2: resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== -colornames@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" - integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= - colors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= -colors@^1.1.2, colors@^1.2.1: +colors@^1.1.2, colors@^1.2.1, colors@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== @@ -4080,7 +4110,7 @@ columnify@~1.5.4: strip-ansi "^3.0.0" wcwidth "^1.0.0" -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -4931,15 +4961,6 @@ dezalgo@^1.0.0, dezalgo@~1.0.3: asap "^2.0.0" wrappy "1" -diagnostics@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a" - integrity sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ== - dependencies: - colorspace "1.1.x" - enabled "1.0.x" - kuler "1.0.x" - didyoumean@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.1.tgz#e92edfdada6537d484d73c0172fd1eba0c4976ff" @@ -5364,12 +5385,10 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== -enabled@1.0.x: - version "1.0.2" - resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" - integrity sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M= - dependencies: - env-variable "0.0.x" +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== encodeurl@^1.0.2, encodeurl@~1.0.2: version "1.0.2" @@ -5430,11 +5449,6 @@ env-paths@^2.2.0: resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA== -env-variable@0.0.x: - version "0.0.6" - resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.6.tgz#74ab20b3786c545b62b4a4813ab8cf22726c9808" - integrity sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg== - err-code@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" @@ -5673,7 +5687,7 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^5.0.0, eslint-scope@^5.1.0, eslint-scope@^5.1.1: +eslint-scope@^5.1.0, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -5681,13 +5695,20 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.0, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.0.0, eslint-utils@^2.1.0: +eslint-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" @@ -6160,10 +6181,10 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -fecha@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" - integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== +fecha@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce" + integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q== figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.2" @@ -6354,6 +6375,11 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + follow-redirects@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb" @@ -6397,6 +6423,15 @@ form-data@^2.5.0: combined-stream "^1.0.6" mime-types "^2.1.12" +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -6729,6 +6764,11 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -6852,6 +6892,18 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -8098,7 +8150,7 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.1, is-wsl@^2.2.0: +is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -8987,12 +9039,10 @@ klona@^2.0.4: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== -kuler@1.0.x: - version "1.0.1" - resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6" - integrity sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ== - dependencies: - colornames "^1.1.1" +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== latest-version@^3.0.0: version "3.1.0" @@ -9417,14 +9467,14 @@ lodash@4.x, lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lo resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -logform@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360" - integrity sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ== +logform@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2" + integrity sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg== dependencies: colors "^1.2.1" fast-safe-stringify "^2.0.4" - fecha "^2.3.3" + fecha "^4.2.0" ms "^2.1.1" triple-beam "^1.3.0" @@ -10141,7 +10191,7 @@ node-fetch-npm@^2.0.2: json-parse-better-errors "^1.0.0" safe-buffer "^5.1.1" -node-fetch@2.6.1: +node-fetch@2.6.1, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -10250,10 +10300,10 @@ node-notifier@^8.0.0: uuid "^8.3.0" which "^2.0.2" -node-pty@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0.tgz#8f9bcc0d1c5b970a3184ffd533d862c7eb6590a6" - integrity sha512-MBnCQl83FTYOu7B4xWw10AW77AAh7ThCE1VXEv+JeWj8mSpGo+0bwgsV+b23ljBFwEM9OmsOv3kM27iUPPm84g== +node-pty@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.1.tgz#cd05d03a2710315ec40221232ec04186f6ac2c6d" + integrity sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg== dependencies: nan "^2.14.0" @@ -10802,10 +10852,12 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0, once@~1.4.0: dependencies: wrappy "1" -one-time@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e" - integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4= +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" onetime@^2.0.0: version "2.0.1" @@ -10828,14 +10880,6 @@ onigasm@^2.2.5: dependencies: lru-cache "^5.1.1" -open@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/open/-/open-7.3.1.tgz#111119cb919ca1acd988f49685c4fdd0f4755356" - integrity sha512-f2wt9DCBKKjlFbjzGb8MOAW8LH8F0mrs1zc7KTjAJ9PZNQbfenzWbNP1VZJvw6ICMG9r14Ah6yfwPn7T7i646A== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - opener@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" @@ -11573,10 +11617,10 @@ postcss@^6.0.14, postcss@^6.0.2: source-map "^0.6.1" supports-color "^5.4.0" -postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.14, postcss@^8.2.15, postcss@^8.3.0: - version "8.3.5" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709" - integrity sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA== +postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.15, postcss@^8.3.0, postcss@^8.3.6: + version "8.3.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" + integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A== dependencies: colorette "^1.2.2" nanoid "^3.1.23" @@ -12245,7 +12289,7 @@ read@1, read@~1.0.1, read@~1.0.7: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@^2.3.7, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -12376,7 +12420,7 @@ regexp.prototype.flags@^1.3.1: call-bind "^1.0.2" define-properties "^1.1.3" -regexpp@^3.0.0, regexpp@^3.1.0: +regexpp@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== @@ -13973,10 +14017,10 @@ tar@^4.4.10, tar@^4.4.12, tar@^4.4.13: safe-buffer "^5.1.2" yallist "^3.0.3" -tar@^6.0.2, tar@^6.0.5: - version "6.1.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" - integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA== +tar@^6.0.2, tar@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.4.tgz#9f0722b772a5e00dba7d52e1923b37a7ec3799b3" + integrity sha512-kcPWrO8S5ABjuZ/v1xQHP8xCEvj1dQ1d9iAb6Qs4jLYzaAIYWwST2IQpz7Ud8VNYRI+fGhFjrnzRKmRggKWg3g== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -14335,20 +14379,15 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" - integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== - -tslib@^2.2.0: +tslib@^2.1.0, tslib@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== -tsutils@^3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== +tsutils@^3.17.1, tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== dependencies: tslib "^1.8.1" @@ -15249,6 +15288,15 @@ win-ca@^3.2.0: node-forge "^0.8.2" split "^1.0.1" +winston-console-format@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/winston-console-format/-/winston-console-format-1.0.8.tgz#591adc8e9567c3397a3fa2e29e596d56e48db840" + integrity sha512-dq7t/E0D0QRi4XIOwu6HM1+5e//WPqylH88GVjKEhQVrzGFg34MCz+G7pMJcXFBen9C0kBsu5GYgbYsE2LDwKw== + dependencies: + colors "^1.4.0" + logform "^2.2.0" + triple-beam "^1.3.0" + winston-transport-browserconsole@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/winston-transport-browserconsole/-/winston-transport-browserconsole-1.0.5.tgz#8ef1bc32da5fb0a66604f2b8b6f127ed725108c9" @@ -15257,28 +15305,28 @@ winston-transport-browserconsole@^1.0.5: winston "^3.2.1" winston-transport "^4.3.0" -winston-transport@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.3.0.tgz#df68c0c202482c448d9b47313c07304c2d7c2c66" - integrity sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A== +winston-transport@^4.3.0, winston-transport@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59" + integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw== dependencies: - readable-stream "^2.3.6" + readable-stream "^2.3.7" triple-beam "^1.2.0" -winston@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/winston/-/winston-3.2.1.tgz#63061377976c73584028be2490a1846055f77f07" - integrity sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw== +winston@^3.2.1, winston@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170" + integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw== dependencies: - async "^2.6.1" - diagnostics "^1.1.1" - is-stream "^1.1.0" - logform "^2.1.1" - one-time "0.0.4" - readable-stream "^3.1.1" + "@dabh/diagnostics" "^2.0.2" + async "^3.1.0" + is-stream "^2.0.0" + logform "^2.2.0" + one-time "^1.0.0" + readable-stream "^3.4.0" stack-trace "0.0.x" triple-beam "^1.3.0" - winston-transport "^4.3.0" + winston-transport "^4.4.0" word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3"