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

Merge branch 'master' into refresh-extensions-page

This commit is contained in:
Alex Andreev 2021-05-18 13:47:17 +03:00
commit daf7a89e3c
80 changed files with 1707 additions and 214 deletions

View File

@ -1,3 +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.
*/
const packageJson = require("./package.json"); const packageJson = require("./package.json");
module.exports = { module.exports = {
@ -27,9 +48,11 @@ module.exports = {
sourceType: "module", sourceType: "module",
}, },
plugins: [ plugins: [
"unused-imports" "header",
"unused-imports",
], ],
rules: { rules: {
"header/header": [2, "./license-header"],
"indent": ["error", 2, { "indent": ["error", 2, {
"SwitchCase": 1, "SwitchCase": 1,
}], }],
@ -72,6 +95,7 @@ module.exports = {
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
], ],
plugins: [ plugins: [
"header",
"unused-imports" "unused-imports"
], ],
parserOptions: { parserOptions: {
@ -79,6 +103,7 @@ module.exports = {
sourceType: "module", sourceType: "module",
}, },
rules: { rules: {
"header/header": [2, "./license-header"],
"no-invalid-this": "off", "no-invalid-this": "off",
"@typescript-eslint/no-invalid-this": ["error"], "@typescript-eslint/no-invalid-this": ["error"],
"@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-function-return-type": "off",
@ -127,6 +152,7 @@ module.exports = {
], ],
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
plugins: [ plugins: [
"header",
"unused-imports" "unused-imports"
], ],
extends: [ extends: [
@ -139,6 +165,7 @@ module.exports = {
jsx: true, jsx: true,
}, },
rules: { rules: {
"header/header": [2, "./license-header"],
"no-invalid-this": "off", "no-invalid-this": "off",
"@typescript-eslint/no-invalid-this": ["error"], "@typescript-eslint/no-invalid-this": ["error"],
"@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-function-return-type": "off",

View File

@ -7,7 +7,7 @@ on:
branches: branches:
- master - master
jobs: jobs:
test: css:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -23,16 +23,4 @@ jobs:
set -e set -e
export PATH=${PATH}:`go env GOPATH`/bin export PATH=${PATH}:`go env GOPATH`/bin
addlicense -check -l mit -c "OpenLens Authors" *.ts* addlicense -check -l mit -c "OpenLens Authors" src/**/*.?css
addlicense -check -l mit -c "OpenLens Authors" src/common/**/*.ts*
addlicense -check -l mit -c "OpenLens Authors" src/common/**/*.?css
addlicense -check -l mit -c "OpenLens Authors" src/main/**/*.ts*
addlicense -check -l mit -c "OpenLens Authors" src/renderer/**/*.ts*
addlicense -check -l mit -c "OpenLens Authors" src/renderer/**/*.?css
addlicense -check -l mit -c "OpenLens Authors" src/extensions/**/*.ts*
addlicense -check -l mit -c "OpenLens Authors" extensions/**/*.ts*

View File

@ -1,3 +1,23 @@
/**
* 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.
*/
module.exports = { module.exports = {
Trans: ({ children }: { children: React.ReactNode }) => children, Trans: ({ children }: { children: React.ReactNode }) => children,
t: (message: string) => message t: (message: string) => message

View File

@ -1,3 +1,23 @@
/**
* 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.
*/
module.exports = { module.exports = {
require: jest.fn(), require: jest.fn(),
match: jest.fn(), match: jest.fn(),

View File

@ -1 +1,21 @@
/**
* 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.
*/
module.exports = {}; module.exports = {};

View File

@ -1 +1,21 @@
/**
* 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.
*/
module.exports = {}; module.exports = {};

View File

@ -1,5 +1,23 @@
// Generate tray icons from SVG to PNG + different sizes and colors (B&W) /**
// Command: `yarn build:tray-icons` * 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 path from "path"; import path from "path";
import sharp from "sharp"; import sharp from "sharp";
import jsdom from "jsdom"; import jsdom from "jsdom";

View File

@ -1,3 +1,23 @@
/**
* 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 { helmCli } from "../src/main/helm/helm-cli"; import { helmCli } from "../src/main/helm/helm-cli";
helmCli.ensureBinary(); helmCli.ensureBinary();

View File

@ -1,3 +1,23 @@
/**
* 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 packageInfo from "../package.json"; import packageInfo from "../package.json";
import fs from "fs"; import fs from "fs";
import request from "request"; import request from "request";

View File

@ -1,3 +1,23 @@
/**
* 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.
*/
const { notarize } = require("electron-notarize"); const { notarize } = require("electron-notarize");
exports.default = async function notarizing(context) { exports.default = async function notarizing(context) {

View File

@ -1,3 +1,23 @@
/**
* 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 fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import appInfo from "../package.json"; import appInfo from "../package.json";

View File

@ -1,3 +1,23 @@
/**
* 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 fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import packageInfo from "../src/extensions/npm/extensions/package.json"; import packageInfo from "../src/extensions/npm/extensions/package.json";

View File

@ -1,12 +1 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block analytics %}
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-90E1JB4HW4"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-90E1JB4HW4');
</script>
{% endblock %}

View File

@ -24,6 +24,7 @@ Each guide or code sample includes the following:
| [KubeObjectListLayout](kube-object-list-layout.md) | | | [KubeObjectListLayout](kube-object-list-layout.md) | |
| [Working with mobx](working-with-mobx.md) | | | [Working with mobx](working-with-mobx.md) | |
| [Protocol Handlers](protocol-handlers.md) | | | [Protocol Handlers](protocol-handlers.md) | |
| [Sending Data between main and renderer](ipc.md) | |
## Samples ## Samples

View File

@ -0,0 +1,131 @@
# Inter Process Communication
A Lens Extension can utilize IPC to send information between its `LensRendererExtension` and its `LensMainExtension`.
This is useful when wanting to communicate directly within your extension.
For example, if a user logs into a service that your extension is a facade for and `main` needs to know some information so that you can start syncing items to the `Catalog`, this would be a good way to send that information along.
IPC channels are blocked off per extension.
Meaning that each extension can only communicate with itself.
## Types of IPC
There are two flavours of IPC that are provided:
- Event based
- Request based
### Event Based IPC
This is the same as an [Event Emitter](https://nodejs.org/api/events.html#events_class_eventemitter) but is not limited to just one Javascript process.
This is a good option when you need to report that something has happened but you don't need a response.
This is a fully two-way form of communication.
Both `LensMainExtension` and `LensRendererExtension` can do this sort of IPC.
### Request Based IPC
This is more like a Remote Procedure Call (RPC).
With this sort of IPC the caller waits for the result from the other side.
This is accomplished by returning a `Promise<T>` which needs to be `await`-ed.
This is a unidirectional form of communication.
Only `LensRendererExtension` can initiate this kind of request, and only `LensMainExtension` can and respond this this kind of request.
## Registering IPC Handlers and Listeners
The general terminology is as follows:
- A "handler" is the function that responds to a "Request Based IPC" event.
- A "listener" is the function that is called when a "Event Based IPC" event is emitted.
To register either a handler or a listener, you should do something like the following:
`main.ts`:
```typescript
import { LensMainExtension, Interface, Types, Store } from "@k8slens/extensions";
import { registerListeners, IpcMain } from "./helpers/main";
export class ExampleExtensionMain extends LensMainExtension {
onActivate() {
IpcMain.createInstance(this);
}
}
```
This file shows that you need to create an instance of the store to be able to use IPC.
Lens will automatically clean up that store and all the handlers on deactivation and uninstall.
---
`helpers/main.ts`:
```typescript
import { Store } from "@k8slens/extensions";
export class IpcMain extends Store.MainIpcStore {
constructor(extension: LensMainExtension) {
super(extension);
this.listenIpc("initialize", onInitialize);
}
}
function onInitialize(event: Types.IpcMainEvent, id: string) {
console.log(`starting to initialize: ${id}`);
}
```
In other files, it is not necessary to pass around any instances.
It should be able to just call `getInstance()` everywhere in your extension as needed.
---
`renderer.ts`:
```typescript
import { LensRendererExtension, Interface, Types } from "@k8slens/extensions";
import { IpcRenderer } from "./helpers/renderer";
export class ExampleExtensionRenderer extends LensRendererExtension {
onActivate() {
const ipc = IpcRenderer.createInstance(this);
setTimeout(() => ipc.broadcastIpc("initialize", "an-id"), 5000);
}
}
```
It is also needed to create an instance to broadcast messages too.
---
`helpers/renderer.ts`:
```typescript
import { Store } from "@k8slens/extensions";
export class IpcMain extends Store.RendererIpcStore {}
```
It is necessary to create child classes of these `abstract class`'s in your extension before you can use them.
---
As this example shows: the channel names *must* be the same.
It should also be noted that "listeners" and "handlers" are specific to either `LensRendererExtension` and `LensMainExtension`.
There is no behind the scenes transfer of these functions.
If you want to register a "handler" you would call `Store.MainIpcStore.handleIpc(...)` instead.
The cleanup of these handlers is handled by Lens itself.
`Store.RendererIpcStore.broadcastIpc(...)` and `Store.MainIpcStore.broadcastIpc(...)` sends an event to all renderer frames and to main.
Because of this, no matter where you broadcast from, all listeners in `main` and `renderer` will be notified.
### Allowed Values
This IPC mechanism utilizes the [Structured Clone Algorithm](developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) for serialization.
This means that more types than what are JSON serializable can be used, but not all the information will be passed through.
## Using IPC
Calling IPC is very simple.
If you are meaning to do an event based call, merely call `broadcastIpc(<channel>, ...<args>)` from within your extension.
If you are meaning to do a request based call from `renderer`, you should do `const res = await Store.RendererIpcStore.invokeIpc(<channel>, ...<args>));` instead.

View File

@ -1,3 +1,23 @@
/**
* 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.
*/
const path = require("path"); const path = require("path");
module.exports = [ module.exports = [

View File

@ -1,3 +1,23 @@
/**
* 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.
*/
const path = require("path"); const path = require("path");
module.exports = [ module.exports = [

View File

@ -1,3 +1,23 @@
/**
* 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.
*/
const path = require("path"); const path = require("path");
module.exports = [ module.exports = [

View File

@ -1,3 +1,23 @@
/**
* 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.
*/
const path = require("path"); const path = require("path");
module.exports = [ module.exports = [

View File

@ -1,5 +1,22 @@
/** /**
* @jest-environment node * 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.
*/ */
/* /*

View File

@ -1,8 +1,22 @@
/* /**
Cluster tests are run if there is a pre-existing minikube cluster. Before running cluster tests the TEST_NAMESPACE * Copyright (c) 2021 OpenLens Authors
namespace is removed, if it exists, from the minikube cluster. Resources are created as part of the cluster tests in the *
TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube * Permission is hereby granted, free of charge, to any person obtaining a copy of
cluster and vice versa. * 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 { Application } from "spectron"; import { Application } from "spectron";
import * as utils from "../helpers/utils"; import * as utils from "../helpers/utils";

View File

@ -1,3 +1,23 @@
/**
* 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 { Application } from "spectron"; import { Application } from "spectron";
import * as utils from "../helpers/utils"; import * as utils from "../helpers/utils";

View File

@ -1,3 +1,23 @@
/**
* 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 { spawnSync } from "child_process"; import { spawnSync } from "child_process";
import { Application } from "spectron"; import { Application } from "spectron";

View File

@ -1,3 +1,23 @@
/**
* 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 { Application } from "spectron"; import { Application } from "spectron";
import * as util from "util"; import * as util from "util";
import { exec } from "child_process"; import { exec } from "child_process";

22
license-header Normal file
View File

@ -0,0 +1,22 @@
/**
* Copyright (c) 2021 OpenLens Authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

View File

@ -7,6 +7,9 @@ repo_name: GitHub
repo_url: https://github.com/lensapp/lens repo_url: https://github.com/lensapp/lens
copyright: Copyright &copy; 2021 <a href="https://mirantis.com/">Mirantis Inc.</a> - All rights reserved. copyright: Copyright &copy; 2021 <a href="https://mirantis.com/">Mirantis Inc.</a> - All rights reserved.
edit_uri: "" edit_uri: ""
google_analytics:
- UA-159377374-2
- auto
nav: nav:
- Overview: README.md - Overview: README.md
- Getting Started: getting-started/README.md - Getting Started: getting-started/README.md
@ -35,6 +38,7 @@ nav:
- Stores: extensions/guides/stores.md - Stores: extensions/guides/stores.md
- Working with MobX: extensions/guides/working-with-mobx.md - Working with MobX: extensions/guides/working-with-mobx.md
- Protocol Handlers: extensions/guides/protocol-handlers.md - Protocol Handlers: extensions/guides/protocol-handlers.md
- IPC: extensions/guides/ipc.md
- Testing and Publishing: - Testing and Publishing:
- Testing Extensions: extensions/testing-and-publishing/testing.md - Testing Extensions: extensions/testing-and-publishing/testing.md
- Publishing Extensions: extensions/testing-and-publishing/publishing.md - Publishing Extensions: extensions/testing-and-publishing/publishing.md

View File

@ -292,7 +292,6 @@
"@types/tar": "^4.0.4", "@types/tar": "^4.0.4",
"@types/tcp-port-used": "^1.0.0", "@types/tcp-port-used": "^1.0.0",
"@types/tempy": "^0.3.0", "@types/tempy": "^0.3.0",
"@types/universal-analytics": "^0.4.4",
"@types/url-parse": "^1.4.3", "@types/url-parse": "^1.4.3",
"@types/uuid": "^8.3.0", "@types/uuid": "^8.3.0",
"@types/webdriverio": "^4.13.0", "@types/webdriverio": "^4.13.0",
@ -316,6 +315,7 @@
"electron-builder": "^22.10.5", "electron-builder": "^22.10.5",
"electron-notarize": "^0.3.0", "electron-notarize": "^0.3.0",
"eslint": "^7.7.0", "eslint": "^7.7.0",
"eslint-plugin-header": "^3.1.1",
"eslint-plugin-react": "^7.21.5", "eslint-plugin-react": "^7.21.5",
"eslint-plugin-unused-imports": "^1.0.1", "eslint-plugin-unused-imports": "^1.0.1",
"file-loader": "^6.0.0", "file-loader": "^6.0.0",

View File

@ -20,7 +20,6 @@
*/ */
import mockFs from "mock-fs"; import mockFs from "mock-fs";
import { CatalogEntityItem } from "../../renderer/components/+catalog/catalog-entity.store";
import { ClusterStore } from "../cluster-store"; import { ClusterStore } from "../cluster-store";
import { HotbarStore } from "../hotbar-store"; import { HotbarStore } from "../hotbar-store";
@ -159,10 +158,9 @@ describe("HotbarStore", () => {
it("adds items", () => { it("adds items", () => {
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const entity = new CatalogEntityItem(testCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(entity); hotbarStore.addToHotbar(testCluster);
const items = hotbarStore.getActive().items.filter(Boolean); const items = hotbarStore.getActive().items.filter(Boolean);
expect(items.length).toEqual(1); expect(items.length).toEqual(1);
@ -170,10 +168,9 @@ describe("HotbarStore", () => {
it("removes items", () => { it("removes items", () => {
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const entity = new CatalogEntityItem(testCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(entity); hotbarStore.addToHotbar(testCluster);
hotbarStore.removeFromHotbar("test"); hotbarStore.removeFromHotbar("test");
const items = hotbarStore.getActive().items.filter(Boolean); const items = hotbarStore.getActive().items.filter(Boolean);
@ -182,10 +179,9 @@ describe("HotbarStore", () => {
it("does nothing if removing with invalid uid", () => { it("does nothing if removing with invalid uid", () => {
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const entity = new CatalogEntityItem(testCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(entity); hotbarStore.addToHotbar(testCluster);
hotbarStore.removeFromHotbar("invalid uid"); hotbarStore.removeFromHotbar("invalid uid");
const items = hotbarStore.getActive().items.filter(Boolean); const items = hotbarStore.getActive().items.filter(Boolean);
@ -194,14 +190,11 @@ describe("HotbarStore", () => {
it("moves item to empty cell", () => { it("moves item to empty cell", () => {
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const test = new CatalogEntityItem(testCluster);
const minikube = new CatalogEntityItem(minikubeCluster);
const aws = new CatalogEntityItem(awsCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(test); hotbarStore.addToHotbar(testCluster);
hotbarStore.addToHotbar(minikube); hotbarStore.addToHotbar(minikubeCluster);
hotbarStore.addToHotbar(aws); hotbarStore.addToHotbar(awsCluster);
expect(hotbarStore.getActive().items[5]).toBeNull(); expect(hotbarStore.getActive().items[5]).toBeNull();
@ -213,14 +206,11 @@ describe("HotbarStore", () => {
it("moves items down", () => { it("moves items down", () => {
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const test = new CatalogEntityItem(testCluster);
const minikube = new CatalogEntityItem(minikubeCluster);
const aws = new CatalogEntityItem(awsCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(test); hotbarStore.addToHotbar(testCluster);
hotbarStore.addToHotbar(minikube); hotbarStore.addToHotbar(minikubeCluster);
hotbarStore.addToHotbar(aws); hotbarStore.addToHotbar(awsCluster);
// aws -> test // aws -> test
hotbarStore.restackItems(2, 0); hotbarStore.restackItems(2, 0);
@ -232,14 +222,11 @@ describe("HotbarStore", () => {
it("moves items up", () => { it("moves items up", () => {
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const test = new CatalogEntityItem(testCluster);
const minikube = new CatalogEntityItem(minikubeCluster);
const aws = new CatalogEntityItem(awsCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(test); hotbarStore.addToHotbar(testCluster);
hotbarStore.addToHotbar(minikube); hotbarStore.addToHotbar(minikubeCluster);
hotbarStore.addToHotbar(aws); hotbarStore.addToHotbar(awsCluster);
// test -> aws // test -> aws
hotbarStore.restackItems(0, 2); hotbarStore.restackItems(0, 2);
@ -251,10 +238,9 @@ describe("HotbarStore", () => {
it("does nothing when item moved to same cell", () => { it("does nothing when item moved to same cell", () => {
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const test = new CatalogEntityItem(testCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(test); hotbarStore.addToHotbar(testCluster);
hotbarStore.restackItems(0, 0); hotbarStore.restackItems(0, 0);
expect(hotbarStore.getActive().items[0].entity.uid).toEqual("test"); expect(hotbarStore.getActive().items[0].entity.uid).toEqual("test");
@ -262,15 +248,12 @@ describe("HotbarStore", () => {
it("new items takes first empty cell", () => { it("new items takes first empty cell", () => {
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const test = new CatalogEntityItem(testCluster);
const minikube = new CatalogEntityItem(minikubeCluster);
const aws = new CatalogEntityItem(awsCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(test); hotbarStore.addToHotbar(testCluster);
hotbarStore.addToHotbar(aws); hotbarStore.addToHotbar(awsCluster);
hotbarStore.restackItems(0, 3); hotbarStore.restackItems(0, 3);
hotbarStore.addToHotbar(minikube); hotbarStore.addToHotbar(minikubeCluster);
expect(hotbarStore.getActive().items[0].entity.uid).toEqual("minikube"); expect(hotbarStore.getActive().items[0].entity.uid).toEqual("minikube");
}); });
@ -282,10 +265,9 @@ describe("HotbarStore", () => {
console.error = jest.fn(); console.error = jest.fn();
const hotbarStore = HotbarStore.createInstance(); const hotbarStore = HotbarStore.createInstance();
const test = new CatalogEntityItem(testCluster);
hotbarStore.load(); hotbarStore.load();
hotbarStore.addToHotbar(test); hotbarStore.addToHotbar(testCluster);
expect(() => hotbarStore.restackItems(-5, 0)).toThrow(); expect(() => hotbarStore.restackItems(-5, 0)).toThrow();
expect(() => hotbarStore.restackItems(2, -1)).toThrow(); expect(() => hotbarStore.restackItems(2, -1)).toThrow();

View File

@ -21,11 +21,12 @@
import { catalogCategoryRegistry } from "../catalog/catalog-category-registry"; import { catalogCategoryRegistry } from "../catalog/catalog-category-registry";
import { CatalogEntity, CatalogEntityActionContext, CatalogEntityAddMenuContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog"; import { CatalogEntity, CatalogEntityActionContext, CatalogEntityAddMenuContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
import { clusterDisconnectHandler } from "../cluster-ipc"; import { clusterActivateHandler, clusterDisconnectHandler } from "../cluster-ipc";
import { ClusterStore } from "../cluster-store"; import { ClusterStore } from "../cluster-store";
import { requestMain } from "../ipc"; import { requestMain } from "../ipc";
import { productName } from "../vars"; import { productName } from "../vars";
import { CatalogCategory, CatalogCategorySpec } from "../catalog"; import { CatalogCategory, CatalogCategorySpec } from "../catalog";
import { app } from "electron";
export type KubernetesClusterSpec = { export type KubernetesClusterSpec = {
kubeconfigPath: string; kubeconfigPath: string;
@ -40,6 +41,38 @@ export class KubernetesCluster extends CatalogEntity<CatalogEntityMetadata, Kube
public readonly apiVersion = "entity.k8slens.dev/v1alpha1"; public readonly apiVersion = "entity.k8slens.dev/v1alpha1";
public readonly kind = "KubernetesCluster"; public readonly kind = "KubernetesCluster";
async connect(): Promise<void> {
if (app) {
const cluster = ClusterStore.getInstance().getById(this.metadata.uid);
if (!cluster) return;
await cluster.activate();
return;
}
await requestMain(clusterActivateHandler, this.metadata.uid, false);
return;
}
async disconnect(): Promise<void> {
if (app) {
const cluster = ClusterStore.getInstance().getById(this.metadata.uid);
if (!cluster) return;
cluster.disconnect();
return;
}
await requestMain(clusterDisconnectHandler, this.metadata.uid, false);
return;
}
async onRun(context: CatalogEntityActionContext) { async onRun(context: CatalogEntityActionContext) {
context.navigate(`/cluster/${this.metadata.uid}`); context.navigate(`/cluster/${this.metadata.uid}`);
} }

View File

@ -23,8 +23,8 @@ import { action, comparer, observable, toJS } from "mobx";
import { BaseStore } from "./base-store"; import { BaseStore } from "./base-store";
import migrations from "../migrations/hotbar-store"; import migrations from "../migrations/hotbar-store";
import * as uuid from "uuid"; import * as uuid from "uuid";
import { CatalogEntityItem } from "../renderer/components/+catalog/catalog-entity.store";
import isNull from "lodash/isNull"; import isNull from "lodash/isNull";
import { CatalogEntity } from "./catalog";
export interface HotbarItem { export interface HotbarItem {
entity: { entity: {
@ -81,8 +81,12 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
} }
} }
hotbarIndex(id: string) {
return this.hotbars.findIndex((hotbar) => hotbar.id === id);
}
get activeHotbarIndex() { get activeHotbarIndex() {
return this.hotbars.findIndex((hotbar) => hotbar.id === this.activeHotbarId); return this.hotbarIndex(this.activeHotbarId);
} }
get initialItems() { get initialItems() {
@ -147,15 +151,15 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
} }
@action @action
addToHotbar(item: CatalogEntityItem, cellIndex = -1) { addToHotbar(item: CatalogEntity, cellIndex = -1) {
const hotbar = this.getActive(); const hotbar = this.getActive();
const newItem = { entity: { const newItem = { entity: {
uid: item.id, uid: item.metadata.uid,
name: item.name, name: item.metadata.name,
source: item.source source: item.metadata.source
}}; }};
if (hotbar.items.find(i => i?.entity.uid === item.id)) { if (hotbar.items.find(i => i?.entity.uid === item.metadata.uid)) {
return; return;
} }

View File

@ -42,27 +42,24 @@ function getSubFrames(): ClusterFrameInfo[] {
return toJS(Array.from(clusterFrameMap.values()), { recurseEverything: true }); return toJS(Array.from(clusterFrameMap.values()), { recurseEverything: true });
} }
export async function broadcastMessage(channel: string, ...args: any[]) { export function broadcastMessage(channel: string, ...args: any[]) {
const views = (webContents || remote?.webContents)?.getAllWebContents(); const views = (webContents || remote?.webContents)?.getAllWebContents();
if (!views) return; if (!views) return;
if (ipcRenderer) { ipcRenderer?.send(channel, ...args);
ipcRenderer.send(channel, ...args); ipcMain?.emit(channel, ...args);
} else if (ipcMain) {
ipcMain.emit(channel, ...args);
}
const subFramesP = ipcRenderer
? requestMain(subFramesChannel)
: Promise.resolve(getSubFrames());
subFramesP
.then(subFrames => {
for (const view of views) { for (const view of views) {
const type = view.getType();
logger.silly(`[IPC]: broadcasting "${channel}" to ${type}=${view.id}`, { args });
view.send(channel, ...args);
try { try {
const subFrames: ClusterFrameInfo[] = ipcRenderer logger.silly(`[IPC]: broadcasting "${channel}" to ${view.getType()}=${view.id}`, { args });
? await requestMain(subFramesChannel) view.send(channel, ...args);
: getSubFrames();
for (const frameInfo of subFrames) { for (const frameInfo of subFrames) {
view.sendToFrame([frameInfo.processId, frameInfo.frameId], channel, ...args); view.sendToFrame([frameInfo.processId, frameInfo.frameId], channel, ...args);
@ -71,6 +68,7 @@ export async function broadcastMessage(channel: string, ...args: any[]) {
logger.error("[IPC]: failed to send IPC message", { error: String(error) }); logger.error("[IPC]: failed to send IPC message", { error: String(error) });
} }
} }
});
} }
export function subscribeToBroadcast(channel: string, listener: (...args: any[]) => any) { export function subscribeToBroadcast(channel: string, listener: (...args: any[]) => any) {

View File

@ -19,10 +19,12 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
import { ipcMain } from "electron";
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import logger from "../../main/logger"; import logger from "../../main/logger";
import { Disposer } from "../utils";
export type HandlerEvent<EM extends EventEmitter> = Parameters<Parameters<EM["on"]>[1]>[0]; export type ListenerEvent<EM extends EventEmitter> = Parameters<Parameters<EM["on"]>[1]>[0];
export type ListVerifier<T extends any[]> = (args: unknown[]) => args is T; export type ListVerifier<T extends any[]> = (args: unknown[]) => args is T;
export type Rest<T> = T extends [any, ...infer R] ? R : []; export type Rest<T> = T extends [any, ...infer R] ? R : [];
@ -34,22 +36,22 @@ export type Rest<T> = T extends [any, ...infer R] ? R : [];
* @param verifier The function to be called to verify that the args are the correct type * @param verifier The function to be called to verify that the args are the correct type
*/ */
export function onceCorrect< export function onceCorrect<
EM extends EventEmitter, IPC extends EventEmitter,
L extends (event: HandlerEvent<EM>, ...args: any[]) => any Listener extends (event: ListenerEvent<IPC>, ...args: any[]) => any
>({ >({
source, source,
channel, channel,
listener, listener,
verifier, verifier,
}: { }: {
source: EM, source: IPC,
channel: string | symbol, channel: string,
listener: L, listener: Listener,
verifier: ListVerifier<Rest<Parameters<L>>>, verifier: ListVerifier<Rest<Parameters<Listener>>>,
}): void { }): void {
function handler(event: HandlerEvent<EM>, ...args: unknown[]): void { function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]): void {
if (verifier(args)) { if (verifier(args)) {
source.removeListener(channel, handler); // remove immediately source.removeListener(channel, wrappedListener); // remove immediately
(async () => (listener(event, ...args)))() // might return a promise, or throw, or reject (async () => (listener(event, ...args)))() // might return a promise, or throw, or reject
.catch((error: any) => logger.error("[IPC]: channel once handler threw error", { channel, error })); .catch((error: any) => logger.error("[IPC]: channel once handler threw error", { channel, error }));
@ -58,7 +60,7 @@ export function onceCorrect<
} }
} }
source.on(channel, handler); source.on(channel, wrappedListener);
} }
/** /**
@ -68,25 +70,53 @@ export function onceCorrect<
* @param verifier The function to be called to verify that the args are the correct type * @param verifier The function to be called to verify that the args are the correct type
*/ */
export function onCorrect< export function onCorrect<
EM extends EventEmitter, IPC extends EventEmitter,
L extends (event: HandlerEvent<EM>, ...args: any[]) => any Listener extends (event: ListenerEvent<IPC>, ...args: any[]) => any
>({ >({
source, source,
channel, channel,
listener, listener,
verifier, verifier,
}: { }: {
source: EM, source: IPC,
channel: string | symbol, channel: string,
listener: L, listener: Listener,
verifier: ListVerifier<Rest<Parameters<L>>>, verifier: ListVerifier<Rest<Parameters<Listener>>>,
}): void { }): Disposer {
source.on(channel, (event, ...args: unknown[]) => { function wrappedListener(event: ListenerEvent<IPC>, ...args: unknown[]) {
if (verifier(args)) { if (verifier(args)) {
(async () => (listener(event, ...args)))() // might return a promise, or throw, or reject (async () => (listener(event, ...args)))() // might return a promise, or throw, or reject
.catch(error => logger.error("[IPC]: channel on handler threw error", { channel, error })); .catch(error => logger.error("[IPC]: channel on handler threw error", { channel, error }));
} else { } else {
logger.error("[IPC]: channel was emitted with invalid data", { channel, args }); logger.error("[IPC]: channel was emitted with invalid data", { channel, args });
} }
}); }
source.on(channel, wrappedListener);
return () => source.off(channel, wrappedListener);
}
export function handleCorrect<
Handler extends (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any,
>({
channel,
handler,
verifier,
}: {
channel: string,
handler: Handler,
verifier: ListVerifier<Rest<Parameters<Handler>>>,
}): Disposer {
function wrappedHandler(event: Electron.IpcMainInvokeEvent, ...args: unknown[]): ReturnType<Handler> {
if (verifier(args)) {
return handler(event, ...args);
}
throw new TypeError(`Invalid args for invoke on channel: ${channel}`);
}
ipcMain.handle(channel, wrappedHandler);
return () => ipcMain.removeHandler(channel);
} }

View File

@ -31,6 +31,7 @@ import * as Util from "./utils";
import * as ClusterFeature from "./cluster-feature"; import * as ClusterFeature from "./cluster-feature";
import * as Interface from "../interfaces"; import * as Interface from "../interfaces";
import * as Catalog from "./catalog"; import * as Catalog from "./catalog";
import * as Types from "./types";
export { export {
App, App,
@ -39,5 +40,6 @@ export {
ClusterFeature, ClusterFeature,
Interface, Interface,
Store, Store,
Types,
Util, Util,
}; };

View File

@ -20,3 +20,5 @@
*/ */
export { ExtensionStore } from "../extension-store"; export { ExtensionStore } from "../extension-store";
export { MainIpcStore } from "../main-ipc-store";
export { RendererIpcStore } from "../renderer-ipc-store";

View File

@ -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 type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent;
export type IpcRendererEvent = Electron.IpcRendererEvent;
export type IpcMainEvent = Electron.IpcMainEvent;

View File

@ -0,0 +1,39 @@
/**
* 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 { Singleton } from "../common/utils";
import { LensExtension } from "./lens-extension";
import { createHash } from "crypto";
import { broadcastMessage } from "../common/ipc";
export const IpcPrefix = Symbol();
export abstract class IpcStore extends Singleton {
readonly [IpcPrefix]: string;
constructor(protected extension: LensExtension) {
super();
this[IpcPrefix] = createHash("sha256").update(extension.id).digest("hex");
}
broadcastIpc(channel: string, ...args: any[]): void {
broadcastMessage(`extensions@${this[IpcPrefix]}:${channel}`, ...args);
}
}

View File

@ -23,7 +23,8 @@ import type { InstalledExtension } from "./extension-discovery";
import { action, observable, reaction } from "mobx"; import { action, observable, reaction } from "mobx";
import { FilesystemProvisionerStore } from "../main/extension-filesystem"; import { FilesystemProvisionerStore } from "../main/extension-filesystem";
import logger from "../main/logger"; import logger from "../main/logger";
import { ProtocolHandlerRegistration } from "./registries/protocol-handler-registry"; import { ProtocolHandlerRegistration } from "./registries";
import { disposer } from "../common/utils";
export type LensExtensionId = string; // path to manifest (package.json) export type LensExtensionId = string; // path to manifest (package.json)
export type LensExtensionConstructor = new (...args: ConstructorParameters<typeof LensExtension>) => LensExtension; export type LensExtensionConstructor = new (...args: ConstructorParameters<typeof LensExtension>) => LensExtension;
@ -37,6 +38,8 @@ export interface LensExtensionManifest {
lens?: object; // fixme: add more required fields for validation lens?: object; // fixme: add more required fields for validation
} }
export const Disposers = Symbol();
export class LensExtension { export class LensExtension {
readonly id: LensExtensionId; readonly id: LensExtensionId;
readonly manifest: LensExtensionManifest; readonly manifest: LensExtensionManifest;
@ -46,6 +49,7 @@ export class LensExtension {
protocolHandlers: ProtocolHandlerRegistration[] = []; protocolHandlers: ProtocolHandlerRegistration[] = [];
@observable private isEnabled = false; @observable private isEnabled = false;
[Disposers] = disposer();
constructor({ id, manifest, manifestPath, isBundled }: InstalledExtension) { constructor({ id, manifest, manifestPath, isBundled }: InstalledExtension) {
this.id = id; this.id = id;
@ -62,6 +66,10 @@ export class LensExtension {
return this.manifest.version; return this.manifest.version;
} }
get description() {
return this.manifest.description;
}
/** /**
* getExtensionFileFolder returns the path to an already created folder. This * getExtensionFileFolder returns the path to an already created folder. This
* folder is for the sole use of this extension. * folder is for the sole use of this extension.
@ -73,15 +81,11 @@ export class LensExtension {
return FilesystemProvisionerStore.getInstance().requestDirectory(this.id); return FilesystemProvisionerStore.getInstance().requestDirectory(this.id);
} }
get description() {
return this.manifest.description;
}
@action @action
async enable() { async enable() {
if (this.isEnabled) return; if (this.isEnabled) return;
this.isEnabled = true; this.isEnabled = true;
this.onActivate(); this.onActivate?.();
logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`); logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`);
} }
@ -89,7 +93,8 @@ export class LensExtension {
async disable() { async disable() {
if (!this.isEnabled) return; if (!this.isEnabled) return;
this.isEnabled = false; this.isEnabled = false;
this.onDeactivate(); this.onDeactivate?.();
this[Disposers]();
logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`); logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`);
} }
@ -125,12 +130,12 @@ export class LensExtension {
}; };
} }
protected onActivate() { protected onActivate(): void {
// mock return;
} }
protected onDeactivate() { protected onDeactivate(): void {
// mock return;
} }
} }

View File

@ -19,12 +19,12 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
import type { MenuRegistration } from "./registries/menu-registry";
import { LensExtension } from "./lens-extension"; import { LensExtension } from "./lens-extension";
import { WindowManager } from "../main/window-manager"; import { WindowManager } from "../main/window-manager";
import { getExtensionPageUrl } from "./registries/page-registry"; import { getExtensionPageUrl } from "./registries/page-registry";
import { CatalogEntity, catalogEntityRegistry } from "../common/catalog"; import { CatalogEntity, catalogEntityRegistry } from "../common/catalog";
import { IObservableArray } from "mobx"; import { IObservableArray } from "mobx";
import { MenuRegistration } from "./registries";
export class LensMainExtension extends LensExtension { export class LensMainExtension extends LensExtension {
appMenus: MenuRegistration[] = []; appMenus: MenuRegistration[] = [];

View File

@ -0,0 +1,45 @@
/**
* 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 { ipcMain } from "electron";
import { IpcPrefix, IpcStore } from "./ipc-store";
import { Disposers } from "./lens-extension";
import { LensMainExtension } from "./lens-main-extension";
export abstract class MainIpcStore extends IpcStore {
constructor(extension: LensMainExtension) {
super(extension);
extension[Disposers].push(() => MainIpcStore.resetInstance());
}
handleIpc(channel: string, handler: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any): void {
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
ipcMain.handle(prefixedChannel, handler);
this.extension[Disposers].push(() => ipcMain.removeHandler(prefixedChannel));
}
listenIpc(channel: string, listener: (event: Electron.IpcMainEvent, ...args: any[]) => any): void {
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
ipcMain.addListener(prefixedChannel, listener);
this.extension[Disposers].push(() => ipcMain.removeListener(prefixedChannel, listener));
}
}

View File

@ -32,3 +32,4 @@ export * from "./kube-object-status-registry";
export * from "./command-registry"; export * from "./command-registry";
export * from "./entity-setting-registry"; export * from "./entity-setting-registry";
export * from "./welcome-menu-registry"; export * from "./welcome-menu-registry";
export * from "./protocol-handler-registry";

View File

@ -0,0 +1,44 @@
/**
* 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 { ipcRenderer } from "electron";
import { IpcPrefix, IpcStore } from "./ipc-store";
import { Disposers } from "./lens-extension";
import { LensRendererExtension } from "./lens-renderer-extension";
export abstract class RendererIpcStore extends IpcStore {
constructor(extension: LensRendererExtension) {
super(extension);
extension[Disposers].push(() => RendererIpcStore.resetInstance());
}
listenIpc(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): void {
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
ipcRenderer.addListener(prefixedChannel, listener);
this.extension[Disposers].push(() => ipcRenderer.removeListener(prefixedChannel, listener));
}
invokeIpc(channel: string, ...args: any[]): Promise<any> {
const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`;
return ipcRenderer.invoke(prefixedChannel, ...args);
}
}

View File

@ -1,3 +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.
*/
import fetchMock from "jest-fetch-mock"; import fetchMock from "jest-fetch-mock";
// rewire global.fetch to call 'fetchMock' // rewire global.fetch to call 'fetchMock'
fetchMock.enableMocks(); fetchMock.enableMocks();

View File

@ -77,7 +77,7 @@ export class NodeShellSession extends ShellSession {
}], }],
containers: [{ containers: [{
name: "shell", name: "shell",
image: "docker.io/alpine:3.12", image: "docker.io/alpine:3.13",
securityContext: { securityContext: {
privileged: true, privileged: true,
}, },
@ -120,6 +120,11 @@ export class NodeShellSession extends ShellSession {
}); });
} }
protected exit() {
super.exit();
this.deleteNodeShellPod();
}
protected deleteNodeShellPod() { protected deleteNodeShellPod() {
this this
.kc .kc

View File

@ -1,3 +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.
*/
/* Early store format had the kubeconfig directly under context name, this moves /* Early store format had the kubeconfig directly under context name, this moves
it under the kubeConfig key */ it under the kubeConfig key */

View File

@ -1,3 +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.
*/
// Cleans up a store that had the state related data stored // Cleans up a store that had the state related data stored
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";

View File

@ -1,3 +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.
*/
// Move cluster icon from root to preferences // Move cluster icon from root to preferences
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";

View File

@ -1,3 +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.
*/
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";
import yaml from "js-yaml"; import yaml from "js-yaml";
@ -42,4 +63,3 @@ export default migration({
} }
} }
}); });

View File

@ -1,3 +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.
*/
// Add existing clusters to "default" workspace // Add existing clusters to "default" workspace
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";

View File

@ -1,3 +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.
*/
// Add id for clusters and store them to array // Add id for clusters and store them to array
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";

View File

@ -1,3 +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.
*/
// Move embedded kubeconfig into separate file and add reference to it to cluster settings // Move embedded kubeconfig into separate file and add reference to it to cluster settings
// convert file path cluster icons to their base64 encoded versions // convert file path cluster icons to their base64 encoded versions

View File

@ -1,3 +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.
*/
// Cluster store migrations // Cluster store migrations
import version200Beta2 from "./2.0.0-beta.2"; import version200Beta2 from "./2.0.0-beta.2";

View File

@ -1,3 +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.
*/
// Fix embedded kubeconfig paths under snap config // Fix embedded kubeconfig paths under snap config
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";

View File

@ -1,3 +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.
*/
// Cleans up a store that had the state related data stored // Cleans up a store that had the state related data stored
import { Hotbar } from "../../common/hotbar-store"; import { Hotbar } from "../../common/hotbar-store";
import { ClusterStore } from "../../common/cluster-store"; import { ClusterStore } from "../../common/cluster-store";

View File

@ -1,3 +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.
*/
// Cleans up a store that had the state related data stored // Cleans up a store that had the state related data stored
import { Hotbar } from "../../common/hotbar-store"; import { Hotbar } from "../../common/hotbar-store";
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";

View File

@ -1,3 +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.
*/
import type { Hotbar } from "../../common/hotbar-store"; import type { Hotbar } from "../../common/hotbar-store";
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";
import { catalogEntityRegistry } from "../../renderer/api/catalog-entity-registry"; import { catalogEntityRegistry } from "../../renderer/api/catalog-entity-registry";

View File

@ -1,3 +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.
*/
// Hotbar store migrations // Hotbar store migrations
import version500alpha0 from "./5.0.0-alpha.0"; import version500alpha0 from "./5.0.0-alpha.0";

View File

@ -1,3 +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.
*/
import Config from "conf"; import Config from "conf";
import { isTestEnv } from "../common/vars"; import { isTestEnv } from "../common/vars";

View File

@ -1,3 +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.
*/
// Add / reset "lastSeenAppVersion" // Add / reset "lastSeenAppVersion"
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";

View File

@ -1,3 +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.
*/
// Switch representation of hiddenTableColumns in store // Switch representation of hiddenTableColumns in store
import { migration } from "../migration-wrapper"; import { migration } from "../migration-wrapper";

View File

@ -1,3 +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.
*/
import fse from "fs-extra"; import fse from "fs-extra";
import { app, remote } from "electron"; import { app, remote } from "electron";
import path from "path"; import path from "path";

View File

@ -1,3 +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.
*/
// User store migrations // User store migrations
import version210Beta4 from "./2.1.0-beta.4"; import version210Beta4 from "./2.1.0-beta.4";

View File

@ -68,7 +68,7 @@ export class Catalog extends React.Component {
} }
addToHotbar(item: CatalogEntityItem): void { addToHotbar(item: CatalogEntityItem): void {
HotbarStore.getInstance().addToHotbar(item); HotbarStore.getInstance().addToHotbar(item.entity);
} }
onDetails(item: CatalogEntityItem) { onDetails(item: CatalogEntityItem) {
@ -137,7 +137,7 @@ export class Catalog extends React.Component {
return ( return (
<MenuActions onOpen={() => item.onContextMenuOpen(this.contextMenu)}> <MenuActions onOpen={() => item.onContextMenuOpen(this.contextMenu)}>
<MenuItem key="add-to-hotbar" onClick={() => this.addToHotbar(item) }> <MenuItem key="add-to-hotbar" onClick={() => this.addToHotbar(item) }>
<Icon material="add" small interactive={true} title="Add to hotbar"/> Add to Hotbar <Icon material="push_pin" small interactive={true} title="Pin to Hotbar"/> Pin to Hotbar
</MenuItem> </MenuItem>
{ {
menuItems.map((menuItem, index) => ( menuItems.map((menuItem, index) => (

View File

@ -1,3 +1,23 @@
/**
* 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 React from "react"; import React from "react";
import { makeStyles, Tooltip, TooltipProps } from "@material-ui/core"; import { makeStyles, Tooltip, TooltipProps } from "@material-ui/core";

View File

@ -42,6 +42,8 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting"; import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting";
import { ClusterStore } from "../../../common/cluster-store"; import { ClusterStore } from "../../../common/cluster-store";
import { replicaSetStore } from "../+workloads-replicasets/replicasets.store";
import { DeploymentReplicaSets } from "./deployment-replicasets";
interface Props extends KubeObjectDetailsProps<Deployment> { interface Props extends KubeObjectDetailsProps<Deployment> {
} }
@ -55,6 +57,7 @@ export class DeploymentDetails extends React.Component<Props> {
componentDidMount() { componentDidMount() {
podsStore.reloadAll(); podsStore.reloadAll();
replicaSetStore.reloadAll();
} }
componentWillUnmount() { componentWillUnmount() {
@ -69,6 +72,7 @@ export class DeploymentDetails extends React.Component<Props> {
const nodeSelector = deployment.getNodeSelectors(); const nodeSelector = deployment.getNodeSelectors();
const selectors = deployment.getSelectors(); const selectors = deployment.getSelectors();
const childPods = deploymentStore.getChildPods(deployment); const childPods = deploymentStore.getChildPods(deployment);
const replicaSets = replicaSetStore.getReplicaSetsByOwner(deployment);
const metrics = deploymentStore.metrics; const metrics = deploymentStore.metrics;
const isMetricHidden = ClusterStore.getInstance().isMetricHidden(ResourceType.Deployment); const isMetricHidden = ClusterStore.getInstance().isMetricHidden(ResourceType.Deployment);
@ -131,6 +135,7 @@ export class DeploymentDetails extends React.Component<Props> {
<PodDetailsTolerations workload={deployment}/> <PodDetailsTolerations workload={deployment}/>
<PodDetailsAffinities workload={deployment}/> <PodDetailsAffinities workload={deployment}/>
<ResourceMetricsText metrics={metrics}/> <ResourceMetricsText metrics={metrics}/>
<DeploymentReplicaSets replicaSets={replicaSets}/>
<PodDetailsList pods={childPods} owner={deployment}/> <PodDetailsList pods={childPods} owner={deployment}/>
</div> </div>
); );

View File

@ -0,0 +1,36 @@
.DeploymentDetails {
.ReplicaSets {
position: relative;
min-height: 80px;
.Table {
margin: 0 (-$margin * 3);
}
.TableCell {
&:first-child {
margin-left: $margin;
}
&:last-child {
margin-right: $margin;
}
&.name {
flex-grow: 2;
}
&.warning {
@include table-cell-warning;
}
&.namespace {
flex-grow: 1.2;
}
&.actions {
@include table-cell-action;
}
}
}
}

View File

@ -0,0 +1,119 @@
/**
* 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 "./deployment-replicasets.scss";
import React from "react";
import { observer } from "mobx-react";
import { ReplicaSet } from "../../api/endpoints";
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/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";
enum sortBy {
name = "name",
namespace = "namespace",
pods = "pods",
age = "age",
}
interface Props {
replicaSets: ReplicaSet[];
}
@observer
export class DeploymentReplicaSets extends React.Component<Props> {
private sortingCallbacks = {
[sortBy.name]: (replicaSet: ReplicaSet) => replicaSet.getName(),
[sortBy.namespace]: (replicaSet: ReplicaSet) => replicaSet.getNs(),
[sortBy.age]: (replicaSet: ReplicaSet) => replicaSet.metadata.creationTimestamp,
[sortBy.pods]: (replicaSet: ReplicaSet) => this.getPodsLength(replicaSet),
};
getPodsLength(replicaSet: ReplicaSet) {
return replicaSetStore.getChildPods(replicaSet).length;
}
render() {
const { replicaSets } = this.props;
if (!replicaSets.length && !replicaSetStore.isLoaded) return (
<div className="ReplicaSets"><Spinner center/></div>
);
if (!replicaSets.length) return null;
return (
<div className="ReplicaSets flex column">
<DrawerTitle title="Deploy Revisions"/>
<Table
selectable
scrollable={false}
sortable={this.sortingCallbacks}
sortByDefault={{ sortBy: sortBy.pods, orderBy: "desc" }}
sortSyncWithUrl={false}
className="box grow"
>
<TableHead>
<TableCell className="name" sortBy={sortBy.name}>Name</TableCell>
<TableCell className="warning"/>
<TableCell className="namespace" sortBy={sortBy.namespace}>Namespace</TableCell>
<TableCell className="pods" sortBy={sortBy.pods}>Pods</TableCell>
<TableCell className="age" sortBy={sortBy.age}>Age</TableCell>
<TableCell className="actions"/>
</TableHead>
{
replicaSets.map(replica => {
return (
<TableRow
key={replica.getId()}
sortItem={replica}
nowrap
onClick={prevDefault(() => showDetails(replica.selfLink, false))}
>
<TableCell className="name">{replica.getName()}</TableCell>
<TableCell className="warning"><KubeObjectStatusIcon key="icon" object={replica}/></TableCell>
<TableCell className="namespace">{replica.getNs()}</TableCell>
<TableCell className="pods">{this.getPodsLength(replica)}</TableCell>
<TableCell className="age">{replica.getAge()}</TableCell>
<TableCell className="actions" onClick={stopPropagation}>
<ReplicaSetMenu object={replica}/>
</TableCell>
</TableRow>
);
})
}
</Table>
</div>
);
}
}
export function ReplicaSetMenu(props: KubeObjectMenuProps<ReplicaSet>) {
return (
<KubeObjectMenu {...props}/>
);
}

View File

@ -1,3 +1,23 @@
/**
* 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 "./hotbar-menu.scss"; import "./hotbar-menu.scss";
import "./hotbar.commands"; import "./hotbar.commands";

View File

@ -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 { HotbarStore } from "../../../common/hotbar-store";
function hotbarIndex(id: string) {
return HotbarStore.getInstance().hotbarIndex(id) + 1;
}
export function hotbarDisplayLabel(id: string) : string {
const hotbar = HotbarStore.getInstance().getById(id);
return `${hotbarIndex(id)}: ${hotbar.name}`;
}
export function hotbarDisplayIndex(id: string) : string {
return hotbarIndex(id).toString();
}

View File

@ -1,23 +1,43 @@
import "./hotbar-icon.scss"; /**
* 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 React, { DOMAttributes } from "react"; import React, { DOMAttributes } from "react";
import { observable } from "mobx"; import { observable } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import randomColor from "randomcolor";
import { CatalogEntity, CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../../common/catalog"; import { CatalogEntity, CatalogEntityContextMenuContext } from "../../../common/catalog";
import { catalogCategoryRegistry } from "../../api/catalog-category-registry"; import { catalogCategoryRegistry } from "../../api/catalog-category-registry";
import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
import { navigate } from "../../navigation"; import { navigate } from "../../navigation";
import { cssNames, IClassName } from "../../utils"; import { cssNames, IClassName } from "../../utils";
import { ConfirmDialog } from "../confirm-dialog";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { HotbarIcon } from "./hotbar-icon"; import { HotbarIcon } from "./hotbar-icon";
import { HotbarStore } from "../../../common/hotbar-store";
interface Props extends DOMAttributes<HTMLElement> { interface Props extends DOMAttributes<HTMLElement> {
entity: CatalogEntity; entity: CatalogEntity;
index: number;
className?: IClassName; className?: IClassName;
errorClass?: IClassName; errorClass?: IClassName;
add: (item: CatalogEntity, index: number) => void;
remove: (uid: string) => void; remove: (uid: string) => void;
} }
@ -57,33 +77,18 @@ export class HotbarEntityIcon extends React.Component<Props> {
return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId(); return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId();
} }
onMenuItemClick(menuItem: CatalogEntityContextMenu) { isPersisted(entity: CatalogEntity) {
if (menuItem.confirm) { return HotbarStore.getInstance().getActive().items.find((item) => item?.entity?.uid === entity.metadata.uid) !== undefined;
ConfirmDialog.open({
okButtonProps: {
primary: false,
accent: true,
},
ok: () => {
menuItem.onClick();
},
message: menuItem.confirm.message
});
} else {
menuItem.onClick();
}
}
generateAvatarStyle(entity: CatalogEntity): React.CSSProperties {
return {
"backgroundColor": randomColor({ seed: `${entity.metadata.name}-${entity.metadata.source}`, luminosity: "dark" })
};
} }
render() { render() {
if (!this.contextMenu) {
return null;
}
const { const {
entity, errorClass, remove, entity, errorClass, add, remove,
children, ...elemProps index, children, ...elemProps
} = this.props; } = this.props;
const className = cssNames("HotbarEntityIcon", this.props.className, { const className = cssNames("HotbarEntityIcon", this.props.className, {
interactive: true, interactive: true,
@ -93,16 +98,31 @@ export class HotbarEntityIcon extends React.Component<Props> {
const onOpen = async () => { const onOpen = async () => {
await entity.onContextMenuOpen(this.contextMenu); await entity.onContextMenuOpen(this.contextMenu);
}; };
const isActive = this.isActive(entity);
const isPersisted = this.isPersisted(entity);
const menuItems = this.contextMenu?.menuItems.filter((menuItem) => !menuItem.onlyVisibleForSource || menuItem.onlyVisibleForSource === entity.metadata.source); const menuItems = this.contextMenu?.menuItems.filter((menuItem) => !menuItem.onlyVisibleForSource || menuItem.onlyVisibleForSource === entity.metadata.source);
if (!isPersisted) {
menuItems.unshift({
title: "Pin to Hotbar",
icon: "push_pin",
onClick: () => add(entity, index)
});
} else {
menuItems.unshift({
title: "Unpin from Hotbar",
icon: "push_pin",
onClick: () => remove(entity.metadata.uid)
});
}
return ( return (
<HotbarIcon <HotbarIcon
uid={entity.getId()} uid={entity.metadata.uid}
title={entity.getName()} title={entity.metadata.name}
source={`${entity.metadata.source || "local"}`} source={entity.metadata.source}
className={className} className={className}
active={this.isActive(entity)} active={isActive}
remove={remove}
onMenuOpen={onOpen} onMenuOpen={onOpen}
menuItems={menuItems} menuItems={menuItems}
{...elemProps} {...elemProps}

View File

@ -36,11 +36,6 @@
border-radius: 6px; border-radius: 6px;
} }
&.active {
box-shadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px var(--textColorAccent);
transition: all 0s 0.8s;
}
&.disabled { &.disabled {
opacity: 0.4; opacity: 0.4;
cursor: default; cursor: default;
@ -53,10 +48,14 @@
} }
} }
&.active, &.interactive:hover { &.isDragging {
img { box-shadow: none;
opacity: 1;
} }
div.MuiAvatar-root {
&.active {
box-shadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px var(--textColorAccent);
transition: all 0s 0.8s;
} }
&:hover { &:hover {
@ -64,12 +63,9 @@
box-shadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px #ffffff30; box-shadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px #ffffff30;
} }
} }
&.isDragging {
box-shadow: none;
} }
> .led { .led {
position: absolute; position: absolute;
left: 3px; left: 3px;
top: 3px; top: 3px;

View File

@ -38,7 +38,6 @@ interface Props extends DOMAttributes<HTMLElement> {
uid: string; uid: string;
title: string; title: string;
source: string; source: string;
remove: (uid: string) => void;
onMenuOpen?: () => void; onMenuOpen?: () => void;
className?: IClassName; className?: IClassName;
active?: boolean; active?: boolean;
@ -86,7 +85,7 @@ function getNameParts(name: string): string[] {
} }
export const HotbarIcon = observer(({menuItems = [], ...props}: Props) => { export const HotbarIcon = observer(({menuItems = [], ...props}: Props) => {
const { uid, title, className, source, active, remove, disabled, onMenuOpen, children, ...rest } = props; const { uid, title, active, className, source, disabled, onMenuOpen, children, ...rest } = props;
const id = `hotbarIcon-${uid}`; const id = `hotbarIcon-${uid}`;
const [menuOpen, setMenuOpen] = useState(false); const [menuOpen, setMenuOpen] = useState(false);
@ -135,12 +134,6 @@ export const HotbarIcon = observer(({ menuItems = [], ...props }: Props) => {
toggleMenu(); toggleMenu();
}} }}
close={() => toggleMenu()}> close={() => toggleMenu()}>
<MenuItem key="remove-from-hotbar" onClick={(evt) => {
evt.stopPropagation();
remove(uid);
}}>
<Icon material="clear" small interactive={true} title="Remove from hotbar"/> Remove from Hotbar
</MenuItem>
{ menuItems.map((menuItem) => { { menuItems.map((menuItem) => {
return ( return (
<MenuItem key={menuItem.title} onClick={() => onMenuItemClick(menuItem) }> <MenuItem key={menuItem.title} onClick={() => onMenuItemClick(menuItem) }>

View File

@ -28,11 +28,12 @@ import { HotbarEntityIcon } from "./hotbar-entity-icon";
import { cssNames, IClassName } from "../../utils"; import { cssNames, IClassName } from "../../utils";
import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
import { defaultHotbarCells, HotbarItem, HotbarStore } from "../../../common/hotbar-store"; import { defaultHotbarCells, HotbarItem, HotbarStore } from "../../../common/hotbar-store";
import { catalogEntityRunContext } from "../../api/catalog-entity"; import { CatalogEntity, catalogEntityRunContext } from "../../api/catalog-entity";
import { DragDropContext, Draggable, Droppable, DropResult } from "react-beautiful-dnd"; import { DragDropContext, Draggable, Droppable, DropResult } from "react-beautiful-dnd";
import { HotbarSelector } from "./hotbar-selector"; import { HotbarSelector } from "./hotbar-selector";
import { HotbarCell } from "./hotbar-cell"; import { HotbarCell } from "./hotbar-cell";
import { HotbarIcon } from "./hotbar-icon"; import { HotbarIcon } from "./hotbar-icon";
import { computed } from "mobx";
interface Props { interface Props {
className?: IClassName; className?: IClassName;
@ -64,6 +65,10 @@ export class HotbarMenu extends React.Component<Props> {
const from = parseInt(source.droppableId); const from = parseInt(source.droppableId);
const to = parseInt(destination.droppableId); const to = parseInt(destination.droppableId);
if (!this.hotbar.items[from]) { // Dropped non-persisted item
this.hotbar.items[from] = this.items[from];
}
HotbarStore.getInstance().restackItems(from, to); HotbarStore.getInstance().restackItems(from, to);
} }
@ -73,14 +78,38 @@ export class HotbarMenu extends React.Component<Props> {
hotbar.removeFromHotbar(uid); hotbar.removeFromHotbar(uid);
} }
addItem(entity: CatalogEntity, index = -1) {
const hotbar = HotbarStore.getInstance();
hotbar.addToHotbar(entity, index);
}
getMoveAwayDirection(entityId: string, cellIndex: number) { getMoveAwayDirection(entityId: string, cellIndex: number) {
const draggableItemIndex = this.hotbar.items.findIndex(item => item?.entity.uid == entityId); const draggableItemIndex = this.hotbar.items.findIndex(item => item?.entity.uid == entityId);
return draggableItemIndex > cellIndex ? "animateDown" : "animateUp"; return draggableItemIndex > cellIndex ? "animateDown" : "animateUp";
} }
@computed get items() {
const items = this.hotbar.items;
const activeEntity = catalogEntityRegistry.activeEntity;
if (!activeEntity) return items;
const emptyIndex = items.indexOf(null);
if (emptyIndex === -1) return items;
if (items.find((item) => item?.entity?.uid === activeEntity.metadata.uid)) return items;
const modifiedItems = [...items];
modifiedItems.splice(emptyIndex, 1, { entity: { uid: activeEntity.metadata.uid }});
return modifiedItems;
}
renderGrid() { renderGrid() {
return this.hotbar.items.map((item, index) => { return this.items.map((item, index) => {
const entity = this.getEntity(item); const entity = this.getEntity(item);
return ( return (
@ -116,17 +145,18 @@ export class HotbarMenu extends React.Component<Props> {
{entity ? ( {entity ? (
<HotbarEntityIcon <HotbarEntityIcon
key={index} key={index}
index={index}
entity={entity} entity={entity}
onClick={() => entity.onRun(catalogEntityRunContext)} onClick={() => entity.onRun(catalogEntityRunContext)}
className={cssNames({ isDragging: snapshot.isDragging })} className={cssNames({ isDragging: snapshot.isDragging })}
remove={this.removeItem} remove={this.removeItem}
add={this.addItem}
/> />
) : ( ) : (
<HotbarIcon <HotbarIcon
uid={item.entity.uid} uid={item.entity.uid}
title={item.entity.name} title={item.entity.name}
source={item.entity.source} source={item.entity.source}
remove={this.removeItem}
disabled disabled
/> />
)} )}
@ -151,7 +181,7 @@ export class HotbarMenu extends React.Component<Props> {
return ( return (
<div className={cssNames("HotbarMenu flex column", className)}> <div className={cssNames("HotbarMenu flex column", className)}>
<div className="HotbarItems flex column gaps"> <div className="HotbarItems flex column gaps">
<DragDropContext onDragEnd={this.onDragEnd}> <DragDropContext onDragEnd={this.onDragEnd.bind(this)}>
{this.renderGrid()} {this.renderGrid()}
</DragDropContext> </DragDropContext>
</div> </div>

View File

@ -24,6 +24,7 @@ import { observer } from "mobx-react";
import { Select } from "../select"; import { Select } from "../select";
import { computed } from "mobx"; import { computed } from "mobx";
import { HotbarStore } from "../../../common/hotbar-store"; import { HotbarStore } from "../../../common/hotbar-store";
import { hotbarDisplayLabel } from "./hotbar-display-label";
import { CommandOverlay } from "../command-palette"; import { CommandOverlay } from "../command-palette";
import { ConfirmDialog } from "../confirm-dialog"; import { ConfirmDialog } from "../confirm-dialog";
@ -31,7 +32,7 @@ import { ConfirmDialog } from "../confirm-dialog";
export class HotbarRemoveCommand extends React.Component { export class HotbarRemoveCommand extends React.Component {
@computed get options() { @computed get options() {
return HotbarStore.getInstance().hotbars.map((hotbar) => { return HotbarStore.getInstance().hotbars.map((hotbar) => {
return { value: hotbar.id, label: hotbar.name }; return { value: hotbar.id, label: hotbarDisplayLabel(hotbar.id) };
}); });
} }

View File

@ -26,6 +26,7 @@ import { Badge } from "../badge";
import { Hotbar, HotbarStore } from "../../../common/hotbar-store"; import { Hotbar, HotbarStore } from "../../../common/hotbar-store";
import { CommandOverlay } from "../command-palette"; import { CommandOverlay } from "../command-palette";
import { HotbarSwitchCommand } from "./hotbar-switch-command"; import { HotbarSwitchCommand } from "./hotbar-switch-command";
import { hotbarDisplayIndex } from "./hotbar-display-label";
import { MaterialTooltip } from "../+catalog/material-tooltip/material-tooltip"; import { MaterialTooltip } from "../+catalog/material-tooltip/material-tooltip";
interface Props { interface Props {
@ -34,7 +35,6 @@ interface Props {
export function HotbarSelector({ hotbar }: Props) { export function HotbarSelector({ hotbar }: Props) {
const store = HotbarStore.getInstance(); const store = HotbarStore.getInstance();
const activeIndexDisplay = store.activeHotbarIndex + 1;
return ( return (
<div className="HotbarSelector flex align-center"> <div className="HotbarSelector flex align-center">
@ -44,7 +44,7 @@ export function HotbarSelector({ hotbar }: Props) {
<Badge <Badge
id="hotbarIndex" id="hotbarIndex"
small small
label={activeIndexDisplay} label={hotbarDisplayIndex(store.activeHotbarId)}
onClick={() => CommandOverlay.open(<HotbarSwitchCommand />)} onClick={() => CommandOverlay.open(<HotbarSwitchCommand />)}
/> />
</MaterialTooltip> </MaterialTooltip>

View File

@ -27,6 +27,7 @@ import { HotbarStore } from "../../../common/hotbar-store";
import { CommandOverlay } from "../command-palette"; import { CommandOverlay } from "../command-palette";
import { HotbarAddCommand } from "./hotbar-add-command"; import { HotbarAddCommand } from "./hotbar-add-command";
import { HotbarRemoveCommand } from "./hotbar-remove-command"; import { HotbarRemoveCommand } from "./hotbar-remove-command";
import { hotbarDisplayLabel } from "./hotbar-display-label";
@observer @observer
export class HotbarSwitchCommand extends React.Component { export class HotbarSwitchCommand extends React.Component {
@ -36,7 +37,7 @@ export class HotbarSwitchCommand extends React.Component {
@computed get options() { @computed get options() {
const hotbarStore = HotbarStore.getInstance(); const hotbarStore = HotbarStore.getInstance();
const options = hotbarStore.hotbars.map((hotbar) => { const options = hotbarStore.hotbars.map((hotbar) => {
return { value: hotbar.id, label: hotbar.name }; return { value: hotbar.id, label: hotbarDisplayLabel(hotbar.id) };
}); });
options.push({ value: HotbarSwitchCommand.addActionId, label: "Add hotbar ..." }); options.push({ value: HotbarSwitchCommand.addActionId, label: "Add hotbar ..." });

View File

@ -1,7 +1,23 @@
// Type definitions for command-exists 1.2 /**
// Project: https://github.com/mathisonian/command-exists * Copyright (c) 2021 OpenLens Authors
// Definitions by: BendingBender <https://github.com/BendingBender> *
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped * 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 = commandExists; export = commandExists;

20
types/dom.d.ts vendored
View File

@ -1,3 +1,23 @@
/**
* 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 {}; export {};
declare global { declare global {

22
types/font-face.d.ts vendored
View File

@ -1,5 +1,23 @@
// https://www.w3.org/TR/css-font-loading/ /**
// https://developer.mozilla.org/en-US/docs/Web/API/FontFace * 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 {}; export {};
declare global { declare global {

21
types/mocks.d.ts vendored
View File

@ -1,4 +1,23 @@
// Black-boxed modules without type safety /**
* 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.
*/
declare module "mac-ca" declare module "mac-ca"
declare module "win-ca" declare module "win-ca"
declare module "@hapi/call" declare module "@hapi/call"

View File

@ -1818,11 +1818,6 @@
resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.10.0.tgz#5cb0dff2a5f616fc8e0c61b482bf01fa20a03cec" resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.10.0.tgz#5cb0dff2a5f616fc8e0c61b482bf01fa20a03cec"
integrity sha512-ZAbqul7QAKpM2h1PFGa5ETN27ulmqtj0QviYHasw9LffvXZvVHuraOx/FOsIPPDNGZN0Qo1nASxxSfMYOtSoCw== integrity sha512-ZAbqul7QAKpM2h1PFGa5ETN27ulmqtj0QviYHasw9LffvXZvVHuraOx/FOsIPPDNGZN0Qo1nASxxSfMYOtSoCw==
"@types/universal-analytics@^0.4.4":
version "0.4.4"
resolved "https://registry.yarnpkg.com/@types/universal-analytics/-/universal-analytics-0.4.4.tgz#496a52b92b599a0112bec7c12414062de6ea8449"
integrity sha512-9g3F0SGxVr4UDd6y07bWtFnkpSSX1Ake7U7AGHgSFrwM6pF53/fV85bfxT2JLWS/3sjLCcyzoYzQlCxpkVo7wA==
"@types/url-parse@^1.4.3": "@types/url-parse@^1.4.3":
version "1.4.3" version "1.4.3"
resolved "https://registry.yarnpkg.com/@types/url-parse/-/url-parse-1.4.3.tgz#fba49d90f834951cb000a674efee3d6f20968329" resolved "https://registry.yarnpkg.com/@types/url-parse/-/url-parse-1.4.3.tgz#fba49d90f834951cb000a674efee3d6f20968329"
@ -5448,6 +5443,11 @@ escodegen@^1.14.1, escodegen@^1.8.1:
optionalDependencies: optionalDependencies:
source-map "~0.6.1" source-map "~0.6.1"
eslint-plugin-header@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz#6ce512432d57675265fac47292b50d1eff11acd6"
integrity sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==
eslint-plugin-react@^7.21.5: eslint-plugin-react@^7.21.5:
version "7.21.5" version "7.21.5"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz#50b21a412b9574bfe05b21db176e8b7b3b15bff3" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz#50b21a412b9574bfe05b21db176e8b7b3b15bff3"