mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fully split apart the weblinks storage
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
ae32375beb
commit
037c62d426
27
package-lock.json
generated
27
package-lock.json
generated
@ -6416,6 +6416,7 @@
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@ -6673,6 +6674,7 @@
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
"integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"defer-to-connect": "^2.0.0"
|
||||
},
|
||||
@ -6941,6 +6943,7 @@
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||
"integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/http-cache-semantics": "*",
|
||||
"@types/keyv": "^3.1.4",
|
||||
@ -7199,7 +7202,8 @@
|
||||
"node_modules/@types/http-cache-semantics": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
|
||||
"integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ=="
|
||||
"integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/http-proxy": {
|
||||
"version": "1.17.10",
|
||||
@ -7325,6 +7329,7 @@
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
||||
"integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@ -7620,6 +7625,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
|
||||
"integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@ -10137,6 +10143,7 @@
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
|
||||
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10.6.0"
|
||||
}
|
||||
@ -10145,6 +10152,7 @@
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
|
||||
"integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"clone-response": "^1.0.2",
|
||||
"get-stream": "^5.1.0",
|
||||
@ -10162,6 +10170,7 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0"
|
||||
},
|
||||
@ -10176,6 +10185,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
@ -12008,6 +12018,7 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
|
||||
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
@ -16026,6 +16037,7 @@
|
||||
"version": "11.8.6",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
||||
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@sindresorhus/is": "^4.0.0",
|
||||
"@szmarczak/http-timer": "^4.0.5",
|
||||
@ -16648,6 +16660,7 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
|
||||
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"quick-lru": "^5.1.1",
|
||||
"resolve-alpn": "^1.0.0"
|
||||
@ -20779,7 +20792,8 @@
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
|
||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
@ -21079,6 +21093,7 @@
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz",
|
||||
"integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"json-buffer": "3.0.1"
|
||||
}
|
||||
@ -23742,6 +23757,7 @@
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
|
||||
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@ -27098,6 +27114,7 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
||||
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@ -28701,6 +28718,7 @@
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@ -29816,7 +29834,8 @@
|
||||
"node_modules/resolve-alpn": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
|
||||
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
|
||||
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/resolve-cwd": {
|
||||
"version": "3.0.0",
|
||||
@ -29860,6 +29879,7 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
|
||||
"integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lowercase-keys": "^2.0.0"
|
||||
},
|
||||
@ -34173,7 +34193,6 @@
|
||||
"filehound": "^1.17.6",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"got": "^11.8.6",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"handlebars": "^4.7.7",
|
||||
"history": "^4.10.1",
|
||||
|
||||
@ -143,7 +143,6 @@
|
||||
"filehound": "^1.17.6",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"got": "^11.8.6",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"handlebars": "^4.7.7",
|
||||
"history": "^4.10.1",
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
*/
|
||||
|
||||
import { getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import removeWeblinkInjectable from "../../features/weblinks/common/remove.injectable";
|
||||
import type { CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
|
||||
import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity";
|
||||
import productNameInjectable from "../vars/product-name.injectable";
|
||||
import weblinkStoreInjectable from "../weblinks-store/weblink-store.injectable";
|
||||
|
||||
export type WebLinkStatusPhase = "available" | "unavailable";
|
||||
|
||||
@ -34,13 +34,13 @@ export class WebLink extends CatalogEntity<CatalogEntityMetadata, WebLinkStatus,
|
||||
// NOTE: this is safe because `onContextMenuOpen` is only supposed to be called in the renderer
|
||||
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi("renderer");
|
||||
const productName = di.inject(productNameInjectable);
|
||||
const weblinkStore = di.inject(weblinkStoreInjectable);
|
||||
const removeWeblink = di.inject(removeWeblinkInjectable);
|
||||
|
||||
if (this.metadata.source === "local") {
|
||||
context.menuItems.push({
|
||||
title: "Delete",
|
||||
icon: "delete",
|
||||
onClick: async () => weblinkStore.removeById(this.getId()),
|
||||
onClick: () => removeWeblink(this.getId()),
|
||||
confirm: {
|
||||
message: `Remove Web Link "${this.getName()}" from ${productName}?`,
|
||||
},
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
/**
|
||||
* 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 createPersistentStorageInjectable from "../persistent-storage/create.injectable";
|
||||
import persistentStorageMigrationsInjectable from "../persistent-storage/migrations.injectable";
|
||||
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
||||
import { weblinkStoreMigrationInjectionToken } from "./migration-token";
|
||||
import { WeblinkStore } from "./weblink-store";
|
||||
|
||||
const weblinkStoreInjectable = getInjectable({
|
||||
id: "weblink-store",
|
||||
instantiate: (di) => new WeblinkStore({
|
||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
||||
migrations: di.inject(persistentStorageMigrationsInjectable, weblinkStoreMigrationInjectionToken),
|
||||
createPersistentStorage: di.inject(createPersistentStorageInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default weblinkStoreInjectable;
|
||||
@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { action, comparer, observable, runInAction } from "mobx";
|
||||
import * as uuid from "uuid";
|
||||
import type { CreatePersistentStorage, PersistentStorage } from "../persistent-storage/create.injectable";
|
||||
import type { Migrations } from "conf/dist/source/types";
|
||||
|
||||
export interface WeblinkData {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface WeblinkCreateOptions {
|
||||
id?: string;
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
|
||||
export interface WeblinkStoreModel {
|
||||
weblinks: WeblinkData[];
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
readonly storeMigrationVersion: string;
|
||||
readonly migrations: Migrations<Record<string, unknown>>;
|
||||
createPersistentStorage: CreatePersistentStorage;
|
||||
}
|
||||
|
||||
export class WeblinkStore {
|
||||
private readonly store: PersistentStorage;
|
||||
|
||||
readonly weblinks = observable.array<WeblinkData>();
|
||||
|
||||
constructor(private readonly dependencies: Dependencies) {
|
||||
this.store = this.dependencies.createPersistentStorage<WeblinkStoreModel>({
|
||||
configName: "lens-weblink-store",
|
||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||
syncOptions: {
|
||||
equals: comparer.structural,
|
||||
},
|
||||
projectVersion: this.dependencies.storeMigrationVersion,
|
||||
migrations: this.dependencies.migrations,
|
||||
fromStore: action(({ weblinks = [] }) => {
|
||||
this.weblinks.replace(weblinks);
|
||||
}),
|
||||
toJSON: () => ({
|
||||
weblinks: this.weblinks.toJSON(),
|
||||
}),
|
||||
});
|
||||
|
||||
this.store.loadAndStartSyncing();
|
||||
}
|
||||
|
||||
add(data: WeblinkCreateOptions) {
|
||||
return runInAction(() => {
|
||||
const {
|
||||
id = uuid.v4(),
|
||||
name,
|
||||
url,
|
||||
} = data;
|
||||
const weblink: WeblinkData = { id, name, url };
|
||||
|
||||
this.weblinks.push(weblink);
|
||||
|
||||
return weblink;
|
||||
});
|
||||
}
|
||||
|
||||
removeById(id: string) {
|
||||
runInAction(() => {
|
||||
this.weblinks.replace(this.weblinks.filter((w) => w.id !== id));
|
||||
});
|
||||
}
|
||||
}
|
||||
41
packages/core/src/features/weblinks/common/add.injectable.ts
Normal file
41
packages/core/src/features/weblinks/common/add.injectable.ts
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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 { action } from "mobx";
|
||||
import weblinksStateInjectable from "./state.injectable";
|
||||
import type { WeblinkData } from "./storage.injectable";
|
||||
import * as uuid from "uuid";
|
||||
import { getOrInsert } from "@k8slens/utilities";
|
||||
|
||||
export interface WeblinkCreateOptions {
|
||||
id?: string;
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export type AddWeblink = (data: WeblinkCreateOptions) => WeblinkData;
|
||||
|
||||
const addWeblinkInjectable = getInjectable({
|
||||
id: "add-weblink",
|
||||
instantiate: (di): AddWeblink => {
|
||||
const state = di.inject(weblinksStateInjectable);
|
||||
|
||||
return action((data) => {
|
||||
const {
|
||||
id = uuid.v4(),
|
||||
name,
|
||||
url,
|
||||
} = data;
|
||||
|
||||
if (state.has(id)) {
|
||||
throw new Error(`There already exists a weblink with id=${id}`);
|
||||
}
|
||||
|
||||
return getOrInsert(state, id, { id, name, url });
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default addWeblinkInjectable;
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { MigrationDeclaration } from "../persistent-storage/migrations.injectable";
|
||||
import type { MigrationDeclaration } from "../../../common/persistent-storage/migrations.injectable";
|
||||
|
||||
export const weblinkStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "weblink-store-migration-token",
|
||||
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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 { action } from "mobx";
|
||||
import weblinksStateInjectable from "./state.injectable";
|
||||
|
||||
export type RemoveWeblink = (id: string) => void;
|
||||
|
||||
const removeWeblinkInjectable = getInjectable({
|
||||
id: "remove-weblink",
|
||||
instantiate: (di): RemoveWeblink => {
|
||||
const state = di.inject(weblinksStateInjectable);
|
||||
|
||||
return action((id) => state.delete(id));
|
||||
},
|
||||
});
|
||||
|
||||
export default removeWeblinkInjectable;
|
||||
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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 { observable } from "mobx";
|
||||
import type { WeblinkData } from "./storage.injectable";
|
||||
|
||||
const weblinksStateInjectable = getInjectable({
|
||||
id: "weblinks-state",
|
||||
instantiate: () => observable.map<string, WeblinkData>(),
|
||||
});
|
||||
|
||||
export default weblinksStateInjectable;
|
||||
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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 { action, comparer, toJS } from "mobx";
|
||||
import createPersistentStorageInjectable from "../../../common/persistent-storage/create.injectable";
|
||||
import persistentStorageMigrationsInjectable from "../../../common/persistent-storage/migrations.injectable";
|
||||
import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable";
|
||||
import { weblinkStoreMigrationInjectionToken } from "./migration-token";
|
||||
import weblinksStateInjectable from "./state.injectable";
|
||||
|
||||
export interface WeblinkData {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface WeblinkStoreModel {
|
||||
weblinks: WeblinkData[];
|
||||
}
|
||||
|
||||
const weblinksPersistentStorageInjectable = getInjectable({
|
||||
id: "weblinks-persistent-storage",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(weblinksStateInjectable);
|
||||
const createPersistentStorage = di.inject(createPersistentStorageInjectable);
|
||||
|
||||
return createPersistentStorage<WeblinkStoreModel>({
|
||||
configName: "lens-weblink-store",
|
||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||
syncOptions: {
|
||||
equals: comparer.structural,
|
||||
},
|
||||
projectVersion: di.inject(storeMigrationVersionInjectable),
|
||||
migrations: di.inject(persistentStorageMigrationsInjectable, weblinkStoreMigrationInjectionToken),
|
||||
fromStore: action(({ weblinks = [] }) => {
|
||||
state.replace(weblinks.map(weblink => [weblink.id, weblink]));
|
||||
}),
|
||||
toJSON: () => ({
|
||||
weblinks: [...toJS(state).values()],
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default weblinksPersistentStorageInjectable;
|
||||
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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 { computed } from "mobx";
|
||||
import weblinksStateInjectable from "./state.injectable";
|
||||
|
||||
const weblinksInjectable = getInjectable({
|
||||
id: "weblinks",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(weblinksStateInjectable);
|
||||
|
||||
return computed(() => [...state.values()]);
|
||||
},
|
||||
});
|
||||
|
||||
export default weblinksInjectable;
|
||||
@ -4,10 +4,10 @@
|
||||
*/
|
||||
|
||||
import { docsUrl, forumsUrl } from "../../../common/vars";
|
||||
import type { WeblinkData } from "../../../common/weblinks-store/weblink-store";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token";
|
||||
import * as links from "../links";
|
||||
import { weblinkStoreMigrationInjectionToken } from "../common/migration-token";
|
||||
import * as links from "./links";
|
||||
import type { WeblinkData } from "../common/storage.injectable";
|
||||
|
||||
const v514WeblinkStoreMigrationInjectable = getInjectable({
|
||||
id: "v5.1.4-weblink-store-migration",
|
||||
@ -3,10 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { WeblinkData } from "../../../common/weblinks-store/weblink-store";
|
||||
import * as links from "../links";
|
||||
import * as links from "../../../features/weblinks/main/links";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token";
|
||||
import { weblinkStoreMigrationInjectionToken } from "../../../features/weblinks/common/migration-token";
|
||||
import type { WeblinkData } from "../common/storage.injectable";
|
||||
|
||||
const v545Beta1WeblinkStoreMigrationInjectable = getInjectable({
|
||||
id: "v5.4.5-beta.1-weblink-store-migration",
|
||||
@ -4,11 +4,11 @@
|
||||
*/
|
||||
|
||||
import { docsUrl, forumsUrl } from "../../../common/vars";
|
||||
import type { WeblinkData } from "../../../common/weblinks-store/weblink-store";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token";
|
||||
import { lensDocumentationWeblinkId, lensForumsWeblinkId } from "../links";
|
||||
import { weblinkStoreMigrationInjectionToken } from "../../../features/weblinks/common/migration-token";
|
||||
import { lensDocumentationWeblinkId, lensForumsWeblinkId } from "../../../features/weblinks/main/links";
|
||||
import { applicationInformationToken } from "@k8slens/application";
|
||||
import type { WeblinkData } from "../common/storage.injectable";
|
||||
|
||||
const currentVersionWeblinkStoreMigrationInjectable = getInjectable({
|
||||
id: "current-version-weblink-store-migration",
|
||||
@ -2,22 +2,20 @@
|
||||
* 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 { onLoadOfApplicationInjectionToken } from "@k8slens/application";
|
||||
import syncWeblinksInjectable from "../../catalog-sources/sync-weblinks.injectable";
|
||||
|
||||
const setupSyncingOfWeblinksInjectable = getInjectable({
|
||||
id: "setup-syncing-of-weblinks",
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import weblinksPersistentStorageInjectable from "../common/storage.injectable";
|
||||
|
||||
const loadWeblinkStorageInjectable = getInjectable({
|
||||
id: "load-weblink-storage",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const syncWeblinks = di.inject(syncWeblinksInjectable);
|
||||
const storage = di.inject(weblinksPersistentStorageInjectable);
|
||||
|
||||
syncWeblinks();
|
||||
storage.loadAndStartSyncing();
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default setupSyncingOfWeblinksInjectable;
|
||||
export default loadWeblinkStorageInjectable;
|
||||
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 { onLoadOfApplicationInjectionToken } from "@k8slens/application";
|
||||
import weblinkVerificationStartableStoppableInjectable from "./weblink-verification.injectable";
|
||||
import catalogEntityRegistryInjectable from "../../../main/catalog/entity-registry.injectable";
|
||||
import weblinkVerificationsInjectable from "./weblink-verifications.injectable";
|
||||
import { computed } from "mobx";
|
||||
import { iter } from "@k8slens/utilities";
|
||||
|
||||
const setupSyncingOfWeblinksInjectable = getInjectable({
|
||||
id: "setup-syncing-of-weblinks",
|
||||
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const weblinkVerificationStartableStoppable = di.inject(weblinkVerificationStartableStoppableInjectable);
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
const weblinkVerifications = di.inject(weblinkVerificationsInjectable);
|
||||
|
||||
weblinkVerificationStartableStoppable.start();
|
||||
catalogEntityRegistry.addComputedSource("weblinks", computed(() => (
|
||||
iter.chain(weblinkVerifications.values())
|
||||
.map(([weblink]) => weblink)
|
||||
.toArray()
|
||||
)));
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: onLoadOfApplicationInjectionToken,
|
||||
});
|
||||
|
||||
export default setupSyncingOfWeblinksInjectable;
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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 { beforeQuitOfBackEndInjectionToken } from "../../../main/start-main-application/runnable-tokens/phases";
|
||||
import weblinkVerificationStartableStoppableInjectable from "./weblink-verification.injectable";
|
||||
|
||||
const stopValidatingWeblinksInjectable = getInjectable({
|
||||
id: "stop-validating-weblinks",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const weblinkVerificationStartableStoppable = di.inject(weblinkVerificationStartableStoppableInjectable);
|
||||
|
||||
weblinkVerificationStartableStoppable.stop();
|
||||
|
||||
return undefined;
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeQuitOfBackEndInjectionToken,
|
||||
});
|
||||
|
||||
export default stopValidatingWeblinksInjectable;
|
||||
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "@k8slens/test-utils";
|
||||
import validateWeblinkInjectable from "./validate-weblink.injectable";
|
||||
|
||||
export default getGlobalOverride(validateWeblinkInjectable, () => async () => "available");
|
||||
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { chainSignal } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fetchInjectable from "../../../common/fetch/fetch.injectable";
|
||||
import { withTimeout } from "../../../common/fetch/timeout-controller";
|
||||
|
||||
export type ValidateWeblink = (url: string, signal: AbortSignal) => Promise<"available" | "unavailable">;
|
||||
|
||||
const validateWeblinkInjectable = getInjectable({
|
||||
id: "validate-weblink",
|
||||
instantiate: (di): ValidateWeblink => {
|
||||
const fetch = di.inject(fetchInjectable);
|
||||
|
||||
return async (url, signal) => {
|
||||
const timeout = withTimeout(20_000);
|
||||
|
||||
chainSignal(timeout, signal);
|
||||
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
signal: timeout.signal,
|
||||
});
|
||||
|
||||
if (res.status >= 200 && res.status < 500) {
|
||||
return "available";
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
} finally {
|
||||
timeout.abort();
|
||||
}
|
||||
|
||||
return "unavailable";
|
||||
};
|
||||
},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default validateWeblinkInjectable;
|
||||
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { Disposer } from "@k8slens/utilities";
|
||||
import { delay, disposer } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { random } from "lodash";
|
||||
import { reaction, runInAction } from "mobx";
|
||||
import { WebLink } from "../../../common/catalog-entities";
|
||||
import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable";
|
||||
import weblinksInjectable from "../common/weblinks.injectable";
|
||||
import validateWeblinkInjectable from "./validate-weblink.injectable";
|
||||
import weblinkVerificationsInjectable from "./weblink-verifications.injectable";
|
||||
|
||||
const sixtyMinutes = 60 * 60 * 1000;
|
||||
|
||||
const weblinkVerificationStartableStoppableInjectable = getInjectable({
|
||||
id: "weblink-verification-startable-stoppable",
|
||||
instantiate: (di) => {
|
||||
const weblinkVerifications = di.inject(weblinkVerificationsInjectable);
|
||||
const validateWeblink = di.inject(validateWeblinkInjectable);
|
||||
const weblinks = di.inject(weblinksInjectable);
|
||||
|
||||
const startPeriodicallyCheckingWebLink = (link: WebLink): Disposer => {
|
||||
const controller = new AbortController();
|
||||
const dispose = disposer(() => controller.abort());
|
||||
|
||||
void (async () => {
|
||||
for (;;) {
|
||||
const newStatus = await validateWeblink(link.spec.url, controller.signal);
|
||||
|
||||
runInAction(() => {
|
||||
link.status.phase = newStatus;
|
||||
});
|
||||
|
||||
const nextCheckAfter = sixtyMinutes + random(0, 5 * 60 * 1000, false);
|
||||
|
||||
await delay(nextCheckAfter, controller.signal);
|
||||
|
||||
if (controller.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
return dispose;
|
||||
};
|
||||
|
||||
return getStartableStoppable("weblink-verification", () => disposer(
|
||||
reaction(
|
||||
() => weblinks.get(),
|
||||
(links) => {
|
||||
const seenWeblinks = new Set<string>();
|
||||
|
||||
for (const weblinkData of links) {
|
||||
seenWeblinks.add(weblinkData.id);
|
||||
|
||||
if (!weblinkVerifications.has(weblinkData.id)) {
|
||||
const link = new WebLink({
|
||||
metadata: {
|
||||
uid: weblinkData.id,
|
||||
name: weblinkData.name,
|
||||
source: "local",
|
||||
labels: {},
|
||||
},
|
||||
spec: {
|
||||
url: weblinkData.url,
|
||||
},
|
||||
status: {
|
||||
phase: "available",
|
||||
active: true,
|
||||
},
|
||||
});
|
||||
|
||||
weblinkVerifications.set(weblinkData.id, [
|
||||
link,
|
||||
startPeriodicallyCheckingWebLink(link),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop checking and remove weblinks that are no longer in the store
|
||||
for (const [weblinkId, [, disposer]] of weblinkVerifications) {
|
||||
if (!seenWeblinks.has(weblinkId)) {
|
||||
disposer();
|
||||
weblinkVerifications.delete(weblinkId);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fireImmediately: true,
|
||||
},
|
||||
),
|
||||
() => {
|
||||
// Stop the validations
|
||||
for (const [, [, disposer]] of weblinkVerifications) {
|
||||
disposer();
|
||||
}
|
||||
},
|
||||
));
|
||||
},
|
||||
});
|
||||
|
||||
export default weblinkVerificationStartableStoppableInjectable;
|
||||
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { Disposer } from "@k8slens/utilities";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { observable } from "mobx";
|
||||
import type { WebLink } from "../../../common/catalog-entities";
|
||||
|
||||
const weblinkVerificationsInjectable = getInjectable({
|
||||
id: "weblink-verifications",
|
||||
instantiate: () => observable.map<string, [WebLink, Disposer]>(),
|
||||
});
|
||||
|
||||
export default weblinkVerificationsInjectable;
|
||||
@ -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 { beforeFrameStartsSecondInjectionToken } from "../../../renderer/before-frame-starts/tokens";
|
||||
import weblinksPersistentStorageInjectable from "../common/storage.injectable";
|
||||
|
||||
const loadWeblinkStorageInjectable = getInjectable({
|
||||
id: "load-weblink-storage",
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const storage = di.inject(weblinksPersistentStorageInjectable);
|
||||
|
||||
storage.loadAndStartSyncing();
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsSecondInjectionToken,
|
||||
});
|
||||
|
||||
export default loadWeblinkStorageInjectable;
|
||||
@ -1,6 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export { syncWeblinks } from "./weblinks";
|
||||
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* 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 { syncWeblinks } from "./weblinks";
|
||||
import weblinkStoreInjectable from "../../common/weblinks-store/weblink-store.injectable";
|
||||
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
||||
|
||||
const syncWeblinksInjectable = getInjectable({
|
||||
id: "sync-weblinks",
|
||||
|
||||
instantiate: (di) => syncWeblinks({
|
||||
weblinkStore: di.inject(weblinkStoreInjectable),
|
||||
catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default syncWeblinksInjectable;
|
||||
@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { computed, observable, reaction } from "mobx";
|
||||
import type { WeblinkStore } from "../../common/weblinks-store/weblink-store";
|
||||
import { WebLink } from "../../common/catalog-entities";
|
||||
import type { CatalogEntityRegistry } from "../catalog";
|
||||
import got from "got";
|
||||
import type { Disposer } from "@k8slens/utilities";
|
||||
import { random } from "lodash";
|
||||
|
||||
async function validateLink(link: WebLink) {
|
||||
try {
|
||||
const response = await got.get(link.spec.url, {
|
||||
throwHttpErrors: false,
|
||||
timeout: 20_000,
|
||||
});
|
||||
|
||||
if (response.statusCode >= 200 && response.statusCode < 500) {
|
||||
link.status.phase = "available";
|
||||
} else {
|
||||
link.status.phase = "unavailable";
|
||||
}
|
||||
} catch {
|
||||
link.status.phase = "unavailable";
|
||||
}
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
weblinkStore: WeblinkStore;
|
||||
catalogEntityRegistry: CatalogEntityRegistry;
|
||||
}
|
||||
|
||||
export const syncWeblinks = ({ weblinkStore, catalogEntityRegistry }: Dependencies) => () => {
|
||||
const webLinkEntities = observable.map<string, [WebLink, Disposer]>();
|
||||
|
||||
function periodicallyCheckLink(link: WebLink): Disposer {
|
||||
validateLink(link);
|
||||
|
||||
let interval: NodeJS.Timeout;
|
||||
const timeout = setTimeout(() => {
|
||||
interval = setInterval(() => validateLink(link), 60 * 60 * 1000); // every 60 minutes
|
||||
}, random(0, 5 * 60 * 1000, false)); // spread out over 5 minutes
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
clearInterval(interval);
|
||||
};
|
||||
}
|
||||
|
||||
reaction(() => weblinkStore.weblinks, (links) => {
|
||||
const seenWeblinks = new Set<string>();
|
||||
|
||||
for (const weblinkData of links) {
|
||||
seenWeblinks.add(weblinkData.id);
|
||||
|
||||
if (!webLinkEntities.has(weblinkData.id)) {
|
||||
const link = new WebLink({
|
||||
metadata: {
|
||||
uid: weblinkData.id,
|
||||
name: weblinkData.name,
|
||||
source: "local",
|
||||
labels: {},
|
||||
},
|
||||
spec: {
|
||||
url: weblinkData.url,
|
||||
},
|
||||
status: {
|
||||
phase: "available",
|
||||
active: true,
|
||||
},
|
||||
});
|
||||
|
||||
webLinkEntities.set(weblinkData.id, [
|
||||
link,
|
||||
periodicallyCheckLink(link),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop checking and remove weblinks that are no longer in the store
|
||||
for (const [weblinkId, [, disposer]] of webLinkEntities) {
|
||||
if (!seenWeblinks.has(weblinkId)) {
|
||||
disposer();
|
||||
webLinkEntities.delete(weblinkId);
|
||||
}
|
||||
}
|
||||
}, { fireImmediately: true });
|
||||
|
||||
catalogEntityRegistry.addComputedSource("weblinks", computed(() => Array.from(webLinkEntities.values(), ([link]) => link)));
|
||||
};
|
||||
@ -10,7 +10,7 @@ import spawnInjectable from "./child-process/spawn.injectable";
|
||||
import initializeExtensionsInjectable from "./start-main-application/runnables/initialize-extensions.injectable";
|
||||
import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable";
|
||||
import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable";
|
||||
import setupSyncingOfWeblinksInjectable from "./start-main-application/runnables/setup-syncing-of-weblinks.injectable";
|
||||
import setupSyncingOfWeblinksInjectable from "../features/weblinks/main/setup-syncing-of-weblinks.injectable";
|
||||
import setupDeepLinkingInjectable from "./electron-app/runnables/setup-deep-linking.injectable";
|
||||
import setupMainWindowVisibilityAfterActivationInjectable from "./electron-app/runnables/setup-main-window-visibility-after-activation.injectable";
|
||||
import setupDeviceShutdownInjectable from "./electron-app/runnables/setup-device-shutdown.injectable";
|
||||
|
||||
@ -7,15 +7,15 @@ import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Input } from "../input";
|
||||
import { isUrl } from "../input/input_validators";
|
||||
import type { WeblinkStore } from "../../../common/weblinks-store/weblink-store";
|
||||
import { computed, makeObservable, observable } from "mobx";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import commandOverlayInjectable from "../command-palette/command-overlay.injectable";
|
||||
import weblinkStoreInjectable from "../../../common/weblinks-store/weblink-store.injectable";
|
||||
import type { AddWeblink } from "../../../features/weblinks/common/add.injectable";
|
||||
import addWeblinkInjectable from "../../../features/weblinks/common/add.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
closeCommandOverlay: () => void;
|
||||
weblinkStore: WeblinkStore;
|
||||
addWeblink: AddWeblink;
|
||||
}
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ class NonInjectedWeblinkAddCommand extends React.Component<Dependencies> {
|
||||
}
|
||||
|
||||
onSubmit(name: string) {
|
||||
this.props.weblinkStore.add({
|
||||
this.props.addWeblink({
|
||||
name: name || this.url,
|
||||
url: this.url,
|
||||
});
|
||||
@ -97,6 +97,6 @@ export const WeblinkAddCommand = withInjectables<Dependencies>(NonInjectedWeblin
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
closeCommandOverlay: di.inject(commandOverlayInjectable).close,
|
||||
weblinkStore: di.inject(weblinkStoreInjectable),
|
||||
addWeblink: di.inject(addWeblinkInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -22,3 +22,11 @@ export function setTimeoutFor(controller: AbortController, timeout: number): voi
|
||||
|
||||
controller.signal.addEventListener("abort", () => clearTimeout(handle));
|
||||
}
|
||||
|
||||
export function chainSignal(target: AbortController, signal: AbortSignal) {
|
||||
if (signal.aborted) {
|
||||
target.abort();
|
||||
} else {
|
||||
signal.addEventListener("abort", (event) => target.abort(event));
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,11 +10,11 @@
|
||||
* @param timeout The number of milliseconds before resolving
|
||||
* @param failFast An abort controller instance to cause the delay to short-circuit
|
||||
*/
|
||||
export function delay(timeout = 1000, failFast?: AbortController): Promise<void> {
|
||||
export function delay(timeout = 1000, failFast?: AbortSignal): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const timeoutId = setTimeout(resolve, timeout);
|
||||
|
||||
failFast?.signal.addEventListener("abort", () => {
|
||||
failFast?.addEventListener("abort", () => {
|
||||
clearTimeout(timeoutId);
|
||||
resolve();
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user