mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add implementation for asking boolean over processes
Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
1b46ccd18b
commit
e2de1449d5
@ -300,7 +300,12 @@ describe("installing update using tray", () => {
|
||||
});
|
||||
|
||||
it("asks user to install update immediately", () => {
|
||||
expect(askBooleanMock).toHaveBeenCalledWith("Do you want to install update some-version?");
|
||||
expect(askBooleanMock).toHaveBeenCalledWith({
|
||||
id: "install-update",
|
||||
title: "Update Available",
|
||||
question:
|
||||
"Version some-version of Lens IDE is available and ready to be installed. Would you like to update now?",
|
||||
});
|
||||
});
|
||||
|
||||
describe("when user answers to install the update", () => {
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Channel } from "../channel/channel-injection-token";
|
||||
import { channelInjectionToken } from "../channel/channel-injection-token";
|
||||
|
||||
type AskBooleanAnswerChannel = Channel<{ id: string; value: boolean }>;
|
||||
|
||||
const askBooleanAnswerChannelInjectable = getInjectable({
|
||||
id: "ask-boolean-answer-channel",
|
||||
|
||||
instantiate: (): AskBooleanAnswerChannel => ({
|
||||
id: "ask-boolean-answer",
|
||||
}),
|
||||
|
||||
injectionToken: channelInjectionToken,
|
||||
});
|
||||
|
||||
export default askBooleanAnswerChannelInjectable;
|
||||
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Channel } from "../channel/channel-injection-token";
|
||||
import { channelInjectionToken } from "../channel/channel-injection-token";
|
||||
|
||||
export interface AskBooleanQuestionParameters { id: string; title: string; question: string }
|
||||
export type AskBooleanQuestionChannel = Channel<AskBooleanQuestionParameters>;
|
||||
|
||||
const askBooleanQuestionChannelInjectable = getInjectable({
|
||||
id: "ask-boolean-question-channel",
|
||||
|
||||
instantiate: (): AskBooleanQuestionChannel => ({
|
||||
id: "ask-boolean-question",
|
||||
}),
|
||||
|
||||
injectionToken: channelInjectionToken,
|
||||
});
|
||||
|
||||
export default askBooleanQuestionChannelInjectable;
|
||||
336
src/main/ask-boolean/__snapshots__/ask-boolean.test.ts.snap
Normal file
336
src/main/ask-boolean/__snapshots__/ask-boolean.test.ts.snap
Normal file
@ -0,0 +1,336 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ask-boolean given started when asking multiple questions renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
>
|
||||
<div
|
||||
class="Animate opacity notification flex info"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
<div
|
||||
class="flex column gaps"
|
||||
data-testid="ask-boolean-some-question-id"
|
||||
>
|
||||
<b>
|
||||
some-title
|
||||
</b>
|
||||
<p>
|
||||
Some question
|
||||
</p>
|
||||
<div
|
||||
class="flex gaps row align-left box grow"
|
||||
>
|
||||
<button
|
||||
class="Button light"
|
||||
data-testid="ask-boolean-some-question-id-button-yes"
|
||||
type="button"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
class="Button active outlined"
|
||||
data-testid="ask-boolean-some-question-id-button-no"
|
||||
type="button"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-ask-boolean-for-some-question-id"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Animate opacity notification flex info"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
<div
|
||||
class="flex column gaps"
|
||||
data-testid="ask-boolean-some-other-question-id"
|
||||
>
|
||||
<b>
|
||||
some-other-title
|
||||
</b>
|
||||
<p>
|
||||
Some other question
|
||||
</p>
|
||||
<div
|
||||
class="flex gaps row align-left box grow"
|
||||
>
|
||||
<button
|
||||
class="Button light"
|
||||
data-testid="ask-boolean-some-other-question-id-button-yes"
|
||||
type="button"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
class="Button active outlined"
|
||||
data-testid="ask-boolean-some-other-question-id-button-no"
|
||||
type="button"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-ask-boolean-for-some-other-question-id"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`ask-boolean given started when asking multiple questions when answering to first question renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
>
|
||||
<div
|
||||
class="Animate opacity notification flex info"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
<div
|
||||
class="flex column gaps"
|
||||
data-testid="ask-boolean-some-other-question-id"
|
||||
>
|
||||
<b>
|
||||
some-other-title
|
||||
</b>
|
||||
<p>
|
||||
Some other question
|
||||
</p>
|
||||
<div
|
||||
class="flex gaps row align-left box grow"
|
||||
>
|
||||
<button
|
||||
class="Button light"
|
||||
data-testid="ask-boolean-some-other-question-id-button-yes"
|
||||
type="button"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
class="Button active outlined"
|
||||
data-testid="ask-boolean-some-other-question-id-button-no"
|
||||
type="button"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-ask-boolean-for-some-other-question-id"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`ask-boolean given started when asking question renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
>
|
||||
<div
|
||||
class="Animate opacity notification flex info"
|
||||
style="--enter-duration: 100ms; --leave-duration: 100ms;"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon material focusable"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="info_outline"
|
||||
>
|
||||
info_outline
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
<div
|
||||
class="message box grow"
|
||||
>
|
||||
<div
|
||||
class="flex column gaps"
|
||||
data-testid="ask-boolean-some-question-id"
|
||||
>
|
||||
<b>
|
||||
some-title
|
||||
</b>
|
||||
<p>
|
||||
Some question
|
||||
</p>
|
||||
<div
|
||||
class="flex gaps row align-left box grow"
|
||||
>
|
||||
<button
|
||||
class="Button light"
|
||||
data-testid="ask-boolean-some-question-id-button-yes"
|
||||
type="button"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
class="Button active outlined"
|
||||
data-testid="ask-boolean-some-question-id-button-no"
|
||||
type="button"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="box"
|
||||
>
|
||||
<i
|
||||
class="Icon close material interactive focusable"
|
||||
data-testid="close-notification-for-ask-boolean-for-some-question-id"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="icon"
|
||||
data-icon-name="close"
|
||||
>
|
||||
close
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`ask-boolean given started when asking question when user answers "no" renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`ask-boolean given started when asking question when user answers "yes" renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`ask-boolean given started when asking question when user closes notification without answering the question renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Notifications flex column align-flex-end"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
37
src/main/ask-boolean/ask-boolean-promise.injectable.ts
Normal file
37
src/main/ask-boolean/ask-boolean-promise.injectable.ts
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
|
||||
const askBooleanPromiseInjectable = getInjectable({
|
||||
id: "ask-boolean-promise",
|
||||
|
||||
instantiate: (di, questionId: string) => {
|
||||
void questionId;
|
||||
|
||||
let resolve: (value: boolean) => void;
|
||||
let _promise: Promise<boolean>;
|
||||
|
||||
return ({
|
||||
get promise() {
|
||||
return _promise;
|
||||
},
|
||||
|
||||
clear: () => {
|
||||
_promise = new Promise(_resolve => {
|
||||
resolve = _resolve;
|
||||
});
|
||||
},
|
||||
|
||||
resolve: (value: boolean) => {
|
||||
resolve(value); },
|
||||
});
|
||||
},
|
||||
|
||||
lifecycle: lifecycleEnum.keyedSingleton({
|
||||
getInstanceKey: (di, questionId: string) => questionId,
|
||||
}),
|
||||
});
|
||||
|
||||
export default askBooleanPromiseInjectable;
|
||||
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { channelListenerInjectionToken } from "../../common/channel/channel-listener-injection-token";
|
||||
import askBooleanAnswerChannelInjectable from "../../common/ask-boolean/ask-boolean-answer-channel.injectable";
|
||||
import askBooleanPromiseInjectable from "./ask-boolean-promise.injectable";
|
||||
|
||||
const askBooleanReturnValueListenerInjectable = getInjectable({
|
||||
id: "ask-boolean-return-value-listener",
|
||||
|
||||
instantiate: (di) => ({
|
||||
channel: di.inject(askBooleanAnswerChannelInjectable),
|
||||
|
||||
handler: ({ id, value }) => {
|
||||
const returnValuePromise = di.inject(askBooleanPromiseInjectable, id);
|
||||
|
||||
returnValuePromise.resolve(value);
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: channelListenerInjectionToken,
|
||||
});
|
||||
|
||||
export default askBooleanReturnValueListenerInjectable;
|
||||
@ -3,12 +3,37 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { sendToAgnosticChannelInjectionToken } from "../../common/channel/send-to-agnostic-channel-injection-token";
|
||||
import askBooleanQuestionChannelInjectable from "../../common/ask-boolean/ask-boolean-question-channel.injectable";
|
||||
import askBooleanPromiseInjectable from "./ask-boolean-promise.injectable";
|
||||
|
||||
export type AskBoolean = (question: string) => Promise<boolean>;
|
||||
export type AskBoolean = ({
|
||||
id,
|
||||
title,
|
||||
question,
|
||||
}: {
|
||||
id: string;
|
||||
title: string;
|
||||
question: string;
|
||||
}) => Promise<boolean>;
|
||||
|
||||
const askBooleanInjectable = getInjectable({
|
||||
id: "ask-boolean",
|
||||
instantiate: (di): AskBoolean => async (question: string) => false,
|
||||
|
||||
instantiate: (di): AskBoolean => {
|
||||
const sendToAgnosticChannel = di.inject(sendToAgnosticChannelInjectionToken);
|
||||
const askBooleanChannel = di.inject(askBooleanQuestionChannelInjectable);
|
||||
|
||||
return async ({ id, title, question }) => {
|
||||
const returnValuePromise = di.inject(askBooleanPromiseInjectable, id);
|
||||
|
||||
returnValuePromise.clear();
|
||||
|
||||
await sendToAgnosticChannel(askBooleanChannel, { id, title, question });
|
||||
|
||||
return await returnValuePromise.promise;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default askBooleanInjectable;
|
||||
|
||||
201
src/main/ask-boolean/ask-boolean.test.ts
Normal file
201
src/main/ask-boolean/ask-boolean.test.ts
Normal file
@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import type { AskBoolean } from "./ask-boolean.injectable";
|
||||
import askBooleanInjectable from "./ask-boolean.injectable";
|
||||
import { getPromiseStatus } from "../../common/test-utils/get-promise-status";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
|
||||
describe("ask-boolean", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let askBoolean: AskBoolean;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
askBoolean = applicationBuilder.dis.mainDi.inject(askBooleanInjectable);
|
||||
});
|
||||
|
||||
describe("given started", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
describe("when asking question", () => {
|
||||
let actualPromise: Promise<boolean>;
|
||||
|
||||
beforeEach(() => {
|
||||
actualPromise = askBoolean({
|
||||
id: "some-question-id",
|
||||
title: "some-title",
|
||||
question: "Some question",
|
||||
});
|
||||
});
|
||||
|
||||
it("does not resolve yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows notification", () => {
|
||||
const notification = rendered.getByTestId("ask-boolean-some-question-id");
|
||||
|
||||
expect(notification).not.toBeUndefined();
|
||||
});
|
||||
|
||||
describe('when user answers "yes"', () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("ask-boolean-some-question-id-button-yes");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show notification anymore", () => {
|
||||
const notification = rendered.queryByTestId("ask-boolean-some-question-id");
|
||||
|
||||
expect(notification).toBeNull();
|
||||
});
|
||||
|
||||
it("resolves", async () => {
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user answers "no"', () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("ask-boolean-some-question-id-button-no");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show notification anymore", () => {
|
||||
const notification = rendered.queryByTestId("ask-boolean-some-question-id");
|
||||
|
||||
expect(notification).toBeNull();
|
||||
});
|
||||
|
||||
it("resolves", async () => {
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when user closes notification without answering the question", () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("close-notification-for-ask-boolean-for-some-question-id");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show notification anymore", () => {
|
||||
const notification = rendered.queryByTestId("ask-boolean-some-question-id");
|
||||
|
||||
expect(notification).toBeNull();
|
||||
});
|
||||
|
||||
it("resolves", async () => {
|
||||
const actual = await actualPromise;
|
||||
|
||||
expect(actual).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when asking multiple questions", () => {
|
||||
let firstQuestionPromise: Promise<boolean>;
|
||||
let secondQuestionPromise: Promise<boolean>;
|
||||
|
||||
beforeEach(() => {
|
||||
firstQuestionPromise = askBoolean({
|
||||
id: "some-question-id",
|
||||
title: "some-title",
|
||||
question: "Some question",
|
||||
});
|
||||
|
||||
secondQuestionPromise = askBoolean({
|
||||
id: "some-other-question-id",
|
||||
title: "some-other-title",
|
||||
question: "Some other question",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows notification for first question", () => {
|
||||
const notification = rendered.getByTestId("ask-boolean-some-question-id");
|
||||
|
||||
expect(notification).not.toBeUndefined();
|
||||
});
|
||||
|
||||
it("shows notification for second question", () => {
|
||||
const notification = rendered.getByTestId("ask-boolean-some-other-question-id");
|
||||
|
||||
expect(notification).not.toBeUndefined();
|
||||
});
|
||||
|
||||
describe("when answering to first question", () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("ask-boolean-some-question-id-button-no");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show notification for first question anymore", () => {
|
||||
const notification = rendered.queryByTestId("ask-boolean-some-question-id");
|
||||
|
||||
expect(notification).toBeNull();
|
||||
});
|
||||
|
||||
it("still shows notification for second question", () => {
|
||||
const notification = rendered.getByTestId("ask-boolean-some-other-question-id");
|
||||
|
||||
expect(notification).not.toBeUndefined();
|
||||
});
|
||||
|
||||
it("resolves first question", async () => {
|
||||
const actual = await firstQuestionPromise;
|
||||
|
||||
expect(actual).toBe(false);
|
||||
});
|
||||
|
||||
it("does not resolve second question yet", async () => {
|
||||
const promiseStatus = await getPromiseStatus(secondQuestionPromise);
|
||||
|
||||
expect(promiseStatus.fulfilled).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -76,7 +76,11 @@ const checkForUpdatesTrayItemInjectable = getInjectable({
|
||||
return;
|
||||
}
|
||||
|
||||
const userWantsToInstallUpdate = await askBoolean(`Do you want to install update ${version}?`);
|
||||
const userWantsToInstallUpdate = await askBoolean({
|
||||
id: "install-update",
|
||||
title: "Update available",
|
||||
question: `Version ${version} of Lens IDE is available and ready to be installed. Would you like to update now?`,
|
||||
});
|
||||
|
||||
if (userWantsToInstallUpdate) {
|
||||
quitAndInstallUpdate();
|
||||
|
||||
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { channelListenerInjectionToken } from "../../common/channel/channel-listener-injection-token";
|
||||
import type { AskBooleanQuestionParameters } from "../../common/ask-boolean/ask-boolean-question-channel.injectable";
|
||||
import askBooleanQuestionChannelInjectable from "../../common/ask-boolean/ask-boolean-question-channel.injectable";
|
||||
import showInfoNotificationInjectable from "../components/notifications/show-info-notification.injectable";
|
||||
import { Button } from "../components/button";
|
||||
import React from "react";
|
||||
import { sendToAgnosticChannelInjectionToken } from "../../common/channel/send-to-agnostic-channel-injection-token";
|
||||
import askBooleanAnswerChannelInjectable from "../../common/ask-boolean/ask-boolean-answer-channel.injectable";
|
||||
import notificationsStoreInjectable from "../components/notifications/notifications-store.injectable";
|
||||
|
||||
const askBooleanQuestionChannelListenerInjectable = getInjectable({
|
||||
id: "ask-boolean-question-channel-listener",
|
||||
|
||||
instantiate: (di) => {
|
||||
const questionChannel = di.inject(askBooleanQuestionChannelInjectable);
|
||||
const showInfoNotification = di.inject(showInfoNotificationInjectable);
|
||||
const sendToAgnosticChannel = di.inject(sendToAgnosticChannelInjectionToken);
|
||||
const answerChannel = di.inject(askBooleanAnswerChannelInjectable);
|
||||
const notificationsStore = di.inject(notificationsStoreInjectable);
|
||||
|
||||
const sendAnswerFor = (id: string) => (value: boolean) => {
|
||||
sendToAgnosticChannel(answerChannel, { id, value });
|
||||
};
|
||||
|
||||
const closeNotification = (notificationId: string) => {
|
||||
notificationsStore.remove(notificationId);
|
||||
};
|
||||
|
||||
const sendAnswerAndCloseNotificationFor = (sendAnswer: (value: boolean) => void, notificationId: string) => (value: boolean) => () => {
|
||||
sendAnswer(value);
|
||||
closeNotification(notificationId);
|
||||
};
|
||||
|
||||
return {
|
||||
channel: questionChannel,
|
||||
|
||||
handler: ({ id: questionId, title, question }: AskBooleanQuestionParameters) => {
|
||||
const notificationId = `ask-boolean-for-${questionId}`;
|
||||
|
||||
const sendAnswer = sendAnswerFor(questionId);
|
||||
const sendAnswerAndCloseNotification = sendAnswerAndCloseNotificationFor(sendAnswer, notificationId);
|
||||
|
||||
showInfoNotification(
|
||||
<AskBoolean
|
||||
id={questionId}
|
||||
title={title}
|
||||
message={question}
|
||||
onNo={sendAnswerAndCloseNotification(false)}
|
||||
onYes={sendAnswerAndCloseNotification(true)}
|
||||
/>,
|
||||
|
||||
{
|
||||
id: notificationId,
|
||||
timeout: 0,
|
||||
onClose: () => sendAnswer(false),
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: channelListenerInjectionToken,
|
||||
});
|
||||
|
||||
export default askBooleanQuestionChannelListenerInjectable;
|
||||
|
||||
const AskBoolean = ({
|
||||
id,
|
||||
title,
|
||||
message,
|
||||
onNo,
|
||||
onYes,
|
||||
}: {
|
||||
id: string;
|
||||
title: string;
|
||||
message: string;
|
||||
onNo: () => void;
|
||||
onYes: () => void;
|
||||
}) => (
|
||||
<div className="flex column gaps" data-testid={`ask-boolean-${id}`}>
|
||||
<b>{title}</b>
|
||||
<p>{message}</p>
|
||||
|
||||
<div className="flex gaps row align-left box grow">
|
||||
<Button
|
||||
light
|
||||
label="Yes"
|
||||
onClick={onYes}
|
||||
data-testid={`ask-boolean-${id}-button-yes`}
|
||||
/>
|
||||
|
||||
<Button
|
||||
active
|
||||
outlined
|
||||
label="No"
|
||||
data-testid={`ask-boolean-${id}-button-no`}
|
||||
onClick={onNo}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -3,19 +3,24 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { notificationsStore, NotificationStatus } from "./notifications.store";
|
||||
import type { NotificationMessage, Notification } from "./notifications.store";
|
||||
import { NotificationStatus } from "./notifications.store";
|
||||
import notificationsStoreInjectable from "./notifications-store.injectable";
|
||||
|
||||
const showInfoNotificationInjectable = getInjectable({
|
||||
id: "show-info-notification",
|
||||
|
||||
instantiate: () => (message: string) =>
|
||||
instantiate: (di) => {
|
||||
const notificationsStore = di.inject(notificationsStoreInjectable);
|
||||
|
||||
return (message: NotificationMessage, customOpts: Partial<Omit<Notification, "message">> = {}) =>
|
||||
notificationsStore.add({
|
||||
status: NotificationStatus.INFO,
|
||||
timeout: 5000,
|
||||
message,
|
||||
}),
|
||||
|
||||
causesSideEffects: true,
|
||||
...customOpts,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default showInfoNotificationInjectable;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user