Skip to content

Commit 42928a8

Browse files
committed
Merge branch 'master' of github.com:lensapp/lens into feature/protocol-handler
Signed-off-by: Sebastian Malton <[email protected]>
2 parents 96e3c52 + 2b22ec0 commit 42928a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+857
-653
lines changed

build/icons/512x512.png

12 KB
Loading

build/icons/[email protected]

51.2 KB
Loading

docs/extensions/capabilities/color-reference.md

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ You can use theme-based CSS Variables to style an extension according to the act
4343
## Button Colors
4444
- `--buttonPrimaryBackground`: button background color for primary actions.
4545
- `--buttonDefaultBackground`: default button background color.
46+
- `--buttonLightBackground`: light button background color.
4647
- `--buttonAccentBackground`: accent button background color.
4748
- `--buttonDisabledBackground`: disabled button background color.
4849

package.json

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "kontena-lens",
33
"productName": "Lens",
44
"description": "Lens - The Kubernetes IDE",
5-
"version": "4.1.0-alpha.2",
5+
"version": "4.1.0-beta.1",
66
"main": "static/build/main.js",
77
"copyright": "© 2020, Mirantis, Inc.",
88
"license": "MIT",
@@ -16,7 +16,7 @@
1616
"dev-run": "nodemon --watch static/build/main.js --exec \"electron --inspect .\"",
1717
"dev:main": "yarn run compile:main --watch",
1818
"dev:renderer": "yarn run webpack-dev-server --config webpack.renderer.ts",
19-
"dev:extension-types": "yarn run compile:extension-types --watch",
19+
"dev:extension-types": "yarn run compile:extension-types --watch --progress",
2020
"compile": "env NODE_ENV=production concurrently yarn:compile:*",
2121
"compile:main": "yarn run webpack --config webpack.main.ts",
2222
"compile:renderer": "yarn run webpack --config webpack.renderer.ts",
@@ -197,6 +197,7 @@
197197
"abort-controller": "^3.0.0",
198198
"array-move": "^3.0.0",
199199
"await-lock": "^2.1.0",
200+
"byline": "^5.0.0",
200201
"chalk": "^4.1.0",
201202
"chokidar": "^3.4.3",
202203
"command-exists": "1.2.9",
@@ -230,6 +231,7 @@
230231
"react": "^17.0.1",
231232
"react-dom": "^17.0.1",
232233
"react-router": "^5.2.0",
234+
"readable-web-to-node-stream": "^3.0.1",
233235
"request": "^2.88.2",
234236
"request-promise-native": "^1.0.8",
235237
"semver": "^7.3.2",
@@ -252,6 +254,7 @@
252254
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
253255
"@testing-library/jest-dom": "^5.11.5",
254256
"@testing-library/react": "^11.1.0",
257+
"@types/byline": "^4.2.32",
255258
"@types/chart.js": "^2.9.21",
256259
"@types/circular-dependency-plugin": "^5.0.1",
257260
"@types/color": "^3.0.1",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { EventEmitter } from "events";
2+
import { onCorrect, onceCorrect } from "../type-enforced-ipc";
3+
4+
describe("type enforced ipc tests", () => {
5+
describe("onCorrect tests", () => {
6+
it("should call the handler if the args are valid", () => {
7+
let called = false;
8+
const source = new EventEmitter();
9+
const listener = () => called = true;
10+
const verifier = (args: unknown[]): args is [] => true;
11+
const channel = "foobar";
12+
13+
onCorrect({ source, listener, verifier, channel });
14+
15+
source.emit(channel);
16+
expect(called).toBe(true);
17+
});
18+
19+
it("should not call the handler if the args are not valid", () => {
20+
let called = false;
21+
const source = new EventEmitter();
22+
const listener = () => called = true;
23+
const verifier = (args: unknown[]): args is [] => false;
24+
const channel = "foobar";
25+
26+
onCorrect({ source, listener, verifier, channel });
27+
28+
source.emit(channel);
29+
expect(called).toBe(false);
30+
});
31+
32+
it("should call the handler twice if the args are valid on two emits", () => {
33+
let called = 0;
34+
const source = new EventEmitter();
35+
const listener = () => called += 1;
36+
const verifier = (args: unknown[]): args is [] => true;
37+
const channel = "foobar";
38+
39+
onCorrect({ source, listener, verifier, channel });
40+
41+
source.emit(channel);
42+
source.emit(channel);
43+
expect(called).toBe(2);
44+
});
45+
46+
it("should call the handler twice if the args are [valid, invalid, valid]", () => {
47+
let called = 0;
48+
const source = new EventEmitter();
49+
const listener = () => called += 1;
50+
const results = [true, false, true];
51+
const verifier = (args: unknown[]): args is [] => results.pop();
52+
const channel = "foobar";
53+
54+
onCorrect({ source, listener, verifier, channel });
55+
56+
source.emit(channel);
57+
source.emit(channel);
58+
source.emit(channel);
59+
expect(called).toBe(2);
60+
});
61+
});
62+
63+
describe("onceCorrect tests", () => {
64+
it("should call the handler if the args are valid", () => {
65+
let called = false;
66+
const source = new EventEmitter();
67+
const listener = () => called = true;
68+
const verifier = (args: unknown[]): args is [] => true;
69+
const channel = "foobar";
70+
71+
onceCorrect({ source, listener, verifier, channel });
72+
73+
source.emit(channel);
74+
expect(called).toBe(true);
75+
});
76+
77+
it("should not call the handler if the args are not valid", () => {
78+
let called = false;
79+
const source = new EventEmitter();
80+
const listener = () => called = true;
81+
const verifier = (args: unknown[]): args is [] => false;
82+
const channel = "foobar";
83+
84+
onceCorrect({ source, listener, verifier, channel });
85+
86+
source.emit(channel);
87+
expect(called).toBe(false);
88+
});
89+
90+
it("should call the handler only once even if args are valid multiple times", () => {
91+
let called = 0;
92+
const source = new EventEmitter();
93+
const listener = () => called += 1;
94+
const verifier = (args: unknown[]): args is [] => true;
95+
const channel = "foobar";
96+
97+
onceCorrect({ source, listener, verifier, channel });
98+
99+
source.emit(channel);
100+
source.emit(channel);
101+
expect(called).toBe(1);
102+
});
103+
104+
it("should call the handler on only the first valid set of args", () => {
105+
let called = "";
106+
let verifierCalled = 0;
107+
const source = new EventEmitter();
108+
const listener = (info: any, arg: string) => called = arg;
109+
const verifier = (args: unknown[]): args is [string] => (++verifierCalled) % 3 === 0;
110+
const channel = "foobar";
111+
112+
onceCorrect({ source, listener, verifier, channel });
113+
114+
source.emit(channel, {}, "a");
115+
source.emit(channel, {}, "b");
116+
source.emit(channel, {}, "c");
117+
source.emit(channel, {}, "d");
118+
source.emit(channel, {}, "e");
119+
source.emit(channel, {}, "f");
120+
source.emit(channel, {}, "g");
121+
source.emit(channel, {}, "h");
122+
source.emit(channel, {}, "i");
123+
expect(called).toBe("c");
124+
});
125+
});
126+
});

src/common/ipc/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from "./ipc";
2+
export * from "./update-available";
3+
export * from "./type-enforced-ipc";

src/common/ipc.ts src/common/ipc/ipc.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
import { ipcMain, ipcRenderer, webContents, remote } from "electron";
66
import { toJS } from "mobx";
7-
import logger from "../main/logger";
8-
import { ClusterFrameInfo, clusterFrameMap } from "./cluster-frames";
7+
import logger from "../../main/logger";
8+
import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames";
99

1010
const subFramesChannel = "ipc:get-sub-frames";
1111

12-
export function handleRequest(channel: string, listener: (...args: any[]) => any) {
12+
export function handleRequest(channel: string, listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any) {
1313
ipcMain.handle(channel, listener);
1414
}
1515

src/common/ipc/type-enforced-ipc.ts

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { EventEmitter } from "events";
2+
import logger from "../../main/logger";
3+
4+
export type HandlerEvent<EM extends EventEmitter> = Parameters<Parameters<EM["on"]>[1]>[0];
5+
export type ListVerifier<T extends any[]> = (args: unknown[]) => args is T;
6+
export type Rest<T> = T extends [any, ...infer R] ? R : [];
7+
8+
/**
9+
* Adds a listener to `source` that waits for the first IPC message with the correct
10+
* argument data is sent.
11+
* @param channel The channel to be listened on
12+
* @param listener The function for the channel to be called if the args of the correct type
13+
* @param verifier The function to be called to verify that the args are the correct type
14+
*/
15+
export function onceCorrect<
16+
EM extends EventEmitter,
17+
L extends (event: HandlerEvent<EM>, ...args: any[]) => any
18+
>({
19+
source,
20+
channel,
21+
listener,
22+
verifier,
23+
}: {
24+
source: EM,
25+
channel: string | symbol,
26+
listener: L,
27+
verifier: ListVerifier<Rest<Parameters<L>>>,
28+
}): void {
29+
function handler(event: HandlerEvent<EM>, ...args: unknown[]): void {
30+
if (verifier(args)) {
31+
source.removeListener(channel, handler); // remove immediately
32+
33+
(async () => (listener(event, ...args)))() // might return a promise, or throw, or reject
34+
.catch((error: any) => logger.error("[IPC]: channel once handler threw error", { channel, error }));
35+
} else {
36+
logger.error("[IPC]: channel was emitted with invalid data", { channel, args });
37+
}
38+
}
39+
40+
source.on(channel, handler);
41+
}
42+
43+
/**
44+
* Adds a listener to `source` that checks to verify the arguments before calling the handler.
45+
* @param channel The channel to be listened on
46+
* @param listener The function for the channel to be called if the args of the correct type
47+
* @param verifier The function to be called to verify that the args are the correct type
48+
*/
49+
export function onCorrect<
50+
EM extends EventEmitter,
51+
L extends (event: HandlerEvent<EM>, ...args: any[]) => any
52+
>({
53+
source,
54+
channel,
55+
listener,
56+
verifier,
57+
}: {
58+
source: EM,
59+
channel: string | symbol,
60+
listener: L,
61+
verifier: ListVerifier<Rest<Parameters<L>>>,
62+
}): void {
63+
source.on(channel, (event, ...args: unknown[]) => {
64+
if (verifier(args)) {
65+
(async () => (listener(event, ...args)))() // might return a promise, or throw, or reject
66+
.catch(error => logger.error("[IPC]: channel on handler threw error", { channel, error }));
67+
} else {
68+
logger.error("[IPC]: channel was emitted with invalid data", { channel, args });
69+
}
70+
});
71+
}
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { UpdateInfo } from "electron-updater";
2+
3+
export const UpdateAvailableChannel = "update-available";
4+
export const AutoUpdateLogPrefix = "[UPDATE-CHECKER]";
5+
6+
/**
7+
* [<back-channel>, <update-info>]
8+
*/
9+
export type UpdateAvailableFromMain = [string, UpdateInfo];
10+
11+
export function areArgsUpdateAvailableFromMain(args: unknown[]): args is UpdateAvailableFromMain {
12+
if (args.length !== 2) {
13+
return false;
14+
}
15+
16+
if (typeof args[0] !== "string") {
17+
return false;
18+
}
19+
20+
if (typeof args[1] !== "object" || args[1] === null) {
21+
// TODO: improve this checking
22+
return false;
23+
}
24+
25+
return true;
26+
}
27+
28+
export type BackchannelArg = {
29+
doUpdate: false;
30+
} | {
31+
doUpdate: true;
32+
now: boolean;
33+
};
34+
35+
export type UpdateAvailableToBackchannel = [BackchannelArg];
36+
37+
export function areArgsUpdateAvailableToBackchannel(args: unknown[]): args is UpdateAvailableToBackchannel {
38+
if (args.length !== 1) {
39+
return false;
40+
}
41+
42+
if (typeof args[0] !== "object" || args[0] === null) {
43+
// TODO: improve this checking
44+
return false;
45+
}
46+
47+
return true;
48+
}

src/common/utils/delay.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import { AbortController } from "abort-controller";
22

33
/**
44
* Return a promise that will be resolved after at least `timeout` ms have
5-
* passed
5+
* passed. If `failFast` is provided then the promise is also resolved if it has
6+
* been aborted.
67
* @param timeout The number of milliseconds before resolving
8+
* @param failFast An abort controller instance to cause the delay to short-circuit
79
*/
810
export function delay(timeout = 1000, failFast?: AbortController): Promise<void> {
911
return new Promise(resolve => {

src/common/utils/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ export * from "./cloneJson";
1010
export * from "./delay";
1111
export * from "./debouncePromise";
1212
export * from "./defineGlobal";
13-
export * from "./delay";
1413
export * from "./getRandId";
1514
export * from "./splitArray";
1615
export * from "./saveToAppFiles";

0 commit comments

Comments
 (0)