From fd3f25cc4ea1a96a867ef363840d5d8f0742009f Mon Sep 17 00:00:00 2001 From: Juho Heikka Date: Thu, 7 Oct 2021 17:47:21 +0300 Subject: [PATCH] Change onBeforeHook to receive an run event Run event can be cancelled by calling event.preventDefault(); Signed-off-by: Juho Heikka --- src/common/catalog/catalog-run-event.ts | 44 +++++++++++++++++++ src/extensions/renderer-api/catalog.ts | 6 +-- src/renderer/api/catalog-entity-registry.ts | 15 ++++--- .../components/+catalog/catalog.test.tsx | 21 +++++---- 4 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 src/common/catalog/catalog-run-event.ts diff --git a/src/common/catalog/catalog-run-event.ts b/src/common/catalog/catalog-run-event.ts new file mode 100644 index 0000000000..6861e1e1dc --- /dev/null +++ b/src/common/catalog/catalog-run-event.ts @@ -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 type { CatalogEntity } from "../catalog"; + +export class CatalogRunEvent { + private _preventDefaulted: boolean; + private _target: CatalogEntity; + + get preventDefaulted() { + return this._preventDefaulted; + } + + get target() { + return this._target; + } + + constructor({ target }: { target: CatalogEntity }) { + this._preventDefaulted = false; + this._target = target; + } + + preventDefault() { + this._preventDefaulted = true; + } +} diff --git a/src/extensions/renderer-api/catalog.ts b/src/extensions/renderer-api/catalog.ts index feccc79353..3a18bd24a8 100644 --- a/src/extensions/renderer-api/catalog.ts +++ b/src/extensions/renderer-api/catalog.ts @@ -53,9 +53,9 @@ export class CatalogEntityRegistry { /** * Add a onBeforeRun hook to a catalog entities. If `onBeforeRun` was previously * added then it will not be added again. - * @param onBeforeRun The function will receive the catalog entity as a parameter. - * Hook function should return a boolean that determines if the running sequence - * should continue to onRun. + * @param onBeforeRun The function will receive the catalog run event as a parameter. + * event target will be the catalog entity. onBeforeRun hook can call event.preventDefault() + * to stop run sequence * @returns A function to remove that hook */ addOnBeforeRun(onBeforeRun: CatalogEntityOnBeforeRun): Disposer { diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index 1d57693b3f..536ab1bf33 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -29,9 +29,10 @@ import { Disposer, iter } from "../utils"; import { once } from "lodash"; import logger from "../../common/logger"; import { catalogEntityRunContext } from "./catalog-entity"; +import { CatalogRunEvent } from "../../common/catalog/catalog-run-event"; export type EntityFilter = (entity: CatalogEntity) => any; -export type CatalogEntityOnBeforeRun = (entity: CatalogEntity) => boolean | Promise; +export type CatalogEntityOnBeforeRun = ((event: CatalogRunEvent) => void) | ((event: CatalogRunEvent) => Promise); export class CatalogEntityRegistry { @observable protected activeEntityId: string | undefined = undefined; @@ -190,7 +191,7 @@ export class CatalogEntityRegistry { } /** - * Runs all the registered `onBeforeRun` hooks, short circuiting on the first falsy returned/resolved valued + * Runs all the registered `onBeforeRun` hooks, short circuiting on the first event that's preventDefaulted * @param entity The entity to run the hooks on * @returns Whether the entities `onRun` method should be executed */ @@ -199,9 +200,13 @@ export class CatalogEntityRegistry { for (const onBeforeRun of this.onBeforeRunHooks) { try { - if (!await onBeforeRun(entity)) { - return false; - } + const runEvent = new CatalogRunEvent({ target: entity }); + + await onBeforeRun(runEvent); + + const shouldContinue = !runEvent.preventDefaulted; + + return shouldContinue; } catch (error) { logger.warn(`[CATALOG-ENTITY-REGISTRY]: entity ${entity.getId()} onBeforeRun threw an error`, error); diff --git a/src/renderer/components/+catalog/catalog.test.tsx b/src/renderer/components/+catalog/catalog.test.tsx index 89986bbf76..f71b04f50f 100644 --- a/src/renderer/components/+catalog/catalog.test.tsx +++ b/src/renderer/components/+catalog/catalog.test.tsx @@ -129,8 +129,8 @@ describe("", () => { .mockImplementation(() => catalogEntityItem); catalogEntityRegistry.addOnBeforeRun( - (entity) => { - expect(entity).toMatchInlineSnapshot(` + (event) => { + expect(event.target).toMatchInlineSnapshot(` Object { "apiVersion": "api", "enabled": true, @@ -175,7 +175,7 @@ describe("", () => { userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); }); - it("onBeforeRun return false => onRun wont be triggered", (done) => { + it("onBeforeRun prevents event => onRun wont be triggered", (done) => { const catalogCategoryRegistry = new CatalogCategoryRegistry(); const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry); const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry); @@ -192,13 +192,12 @@ describe("", () => { .mockImplementation(() => catalogEntityItem); catalogEntityRegistry.addOnBeforeRun( - () => { + (e) => { setTimeout(() => { expect(onRun).not.toHaveBeenCalled(); done(); }, 500); - - return false; + e.preventDefault(); } ); @@ -253,7 +252,7 @@ describe("", () => { userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); }); - it("addOnRunHook return a promise and resolve true => onRun()", (done) => { + it("addOnRunHook return a promise and does not prevent run event => onRun()", (done) => { const catalogCategoryRegistry = new CatalogCategoryRegistry(); const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry); const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry); @@ -271,7 +270,7 @@ describe("", () => { catalogEntityRegistry.addOnBeforeRun( async () => { - return true; + // no op } ); @@ -287,7 +286,7 @@ describe("", () => { userEvent.click(screen.getByTestId("detail-panel-hot-bar-icon")); }); - it("addOnRunHook return a promise and resolve false => onRun() wont be triggered", (done) => { + it("addOnRunHook return a promise and prevents event wont be triggered", (done) => { const catalogCategoryRegistry = new CatalogCategoryRegistry(); const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry); const catalogEntityStore = new CatalogEntityStore(catalogEntityRegistry); @@ -304,7 +303,7 @@ describe("", () => { .mockImplementation(() => catalogEntityItem); catalogEntityRegistry.addOnBeforeRun( - async () => { + async (e) => { expect(onRun).not.toBeCalled(); setTimeout(() => { @@ -312,7 +311,7 @@ describe("", () => { done(); }, 500); - return false; + e.preventDefault(); } );