diff --git a/src/common/catalog-entities/web-link.ts b/src/common/catalog-entities/web-link.ts index 7e0f024421..e18b3ac931 100644 --- a/src/common/catalog-entities/web-link.ts +++ b/src/common/catalog-entities/web-link.ts @@ -19,11 +19,13 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { CatalogCategory, CatalogEntity, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog"; +import { CatalogCategory, CatalogEntity, CatalogEntityAddMenuContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog"; import { catalogCategoryRegistry } from "../catalog/catalog-category-registry"; +import { productName } from "../vars"; +import { WeblinkStore } from "../weblink-store"; export interface WebLinkStatus extends CatalogEntityStatus { - phase: "valid" | "invalid"; + phase: "available" | "unavailable"; } export type WebLinkSpec = { @@ -42,12 +44,17 @@ export class WebLink extends CatalogEntity WeblinkStore.getInstance().removeById(this.metadata.uid), + confirm: { + message: `Remove Web Link "${this.metadata.name}" from ${productName}?` + } + }); + } } } @@ -56,7 +63,7 @@ export class WebLinkCategory extends CatalogCategory { public readonly kind = "CatalogCategory"; public metadata = { name: "Web Links", - icon: "link" + icon: "public" }; public spec = { group: "entity.k8slens.dev", @@ -70,6 +77,21 @@ export class WebLinkCategory extends CatalogCategory { kind: "WebLink" } }; + public static onAdd?: () => void; + + constructor() { + super(); + + this.on("catalogAddMenu", (ctx: CatalogEntityAddMenuContext) => { + ctx.menuItems.push({ + icon: "public", + title: "Add web link", + onClick: () => { + WebLinkCategory.onAdd(); + } + }); + }); + } } catalogCategoryRegistry.add(new WebLinkCategory()); diff --git a/src/common/weblink-store.ts b/src/common/weblink-store.ts new file mode 100644 index 0000000000..0f66725545 --- /dev/null +++ b/src/common/weblink-store.ts @@ -0,0 +1,90 @@ +/** + * 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 { action, comparer, observable, makeObservable } from "mobx"; +import { BaseStore } from "./base-store"; +import migrations from "../migrations/hotbar-store"; +import * as uuid from "uuid"; +import { toJS } from "./utils"; + +export interface WeblinkData { + id: string; + name: string; + url: string; +} + +export interface WeblinkCreateOptions { + id?: string; + name: string; + url: string; +} + + +export interface WeblinkStoreModel { + weblinks: WeblinkData[]; +} + +export class WeblinkStore extends BaseStore { + @observable weblinks: WeblinkData[] = []; + + constructor() { + super({ + configName: "lens-weblink-store", + accessPropertiesByDotNotation: false, // To make dots safe in cluster context names + syncOptions: { + equals: comparer.structural, + }, + migrations, + }); + makeObservable(this); + } + + @action protected async fromStore(data: Partial = {}) { + this.weblinks = data.weblinks || []; + } + + add(data: WeblinkCreateOptions) { + const { + id = uuid.v4(), + name, + url + } = data; + + const weblink = { id, name, url }; + + this.weblinks.push(weblink as WeblinkData); + + return weblink as WeblinkData; + } + + @action + removeById(id: string) { + this.weblinks = this.weblinks.filter((w) => w.id !== id); + } + + toJSON(): WeblinkStoreModel { + const model: WeblinkStoreModel = { + weblinks: this.weblinks + }; + + return toJS(model); + } +} diff --git a/src/main/catalog-sources/index.ts b/src/main/catalog-sources/index.ts index 3f1a76790f..81f0182ca7 100644 --- a/src/main/catalog-sources/index.ts +++ b/src/main/catalog-sources/index.ts @@ -19,4 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +export { initializeWeblinks } from "./weblinks"; export { KubeconfigSyncManager } from "./kubeconfig-sync"; diff --git a/src/main/catalog-sources/weblinks.ts b/src/main/catalog-sources/weblinks.ts new file mode 100644 index 0000000000..b6b1ec5a39 --- /dev/null +++ b/src/main/catalog-sources/weblinks.ts @@ -0,0 +1,102 @@ +/** + * 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 { observable, reaction } from "mobx"; +import { WeblinkStore } from "../../common/weblink-store"; +import { WebLink } from "../../common/catalog-entities"; +import { catalogEntityRegistry } from "../catalog"; +import got from "got"; +import logger from "../logger"; +import { docsUrl, slackUrl } from "../../common/vars"; + +const defaultLinks = [ + { title: "Lens Website", url: "https://k8slens.dev" }, + { title: "Lens Documentation", url: docsUrl }, + { title: "Lens Community Slack", url: slackUrl }, + { title: "Kubernetes Documentation", url: "https://kubernetes.io/docs/home/" }, + { title: "Lens on Twitter", url: "https://twitter.com/k8slens" }, + { title: "Lens Official Blog", url: "https://medium.com/k8slens" } +].map((link) => ( + new WebLink({ + metadata: { + uid: link.url, + name: link.title, + source: "app", + labels: {} + }, + spec: { + url: link.url + }, + status: { + phase: "available", + active: true + } + }) +)); + +async function validateLink(link: WebLink) { + try { + const response = await got.get(link.spec.url, { + throwHttpErrors: false + }); + + if (response.statusCode >= 200 && response.statusCode < 500) { + link.status.phase = "available"; + } else { + link.status.phase = "unavailable"; + } + } catch(error) { + link.status.phase = "unavailable"; + } +} + + +export function initializeWeblinks() { + const weblinkStore = WeblinkStore.getInstance(); + const weblinks = observable.array(defaultLinks); + + reaction(() => weblinkStore.weblinks, (links) => { + weblinks.replace(links.map((data) => new WebLink({ + metadata: { + uid: data.id, + name: data.name, + source: "local", + labels: {} + }, + spec: { + url: data.url + }, + status: { + phase: "available", + active: true + } + }))); + weblinks.push(...defaultLinks); + + for (const link of weblinks) { + validateLink(link).catch((error) => { + logger.error(`failed to validate link ${link.spec.url}: %s`, error); + }); + } + }, {fireImmediately: true}); + + catalogEntityRegistry.addObservableSource("weblinks", weblinks); +} diff --git a/src/main/catalog/__tests__/catalog-entity-registry.test.ts b/src/main/catalog/__tests__/catalog-entity-registry.test.ts index fff3faa3d9..ee8450ae26 100644 --- a/src/main/catalog/__tests__/catalog-entity-registry.test.ts +++ b/src/main/catalog/__tests__/catalog-entity-registry.test.ts @@ -58,7 +58,7 @@ describe("CatalogEntityRegistry", () => { url: "https://k8slens.dev" }, status: { - phase: "valid" + phase: "available" } }); const invalidEntity = new InvalidEntity({ @@ -72,7 +72,7 @@ describe("CatalogEntityRegistry", () => { url: "https://k8slens.dev" }, status: { - phase: "valid" + phase: "available" } }); diff --git a/src/main/index.ts b/src/main/index.ts index aba3d73ce1..dc36de80dc 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -35,14 +35,10 @@ import { shellSync } from "./shell-sync"; import { mangleProxyEnv } from "./proxy-env"; import { registerFileProtocol } from "../common/register-protocol"; import logger from "./logger"; -import { ClusterStore } from "../common/cluster-store"; -import { UserStore } from "../common/user-store"; import { appEventBus } from "../common/event-bus"; import { ExtensionLoader } from "../extensions/extension-loader"; -import { ExtensionsStore } from "../extensions/extensions-store"; import { InstalledExtension, ExtensionDiscovery } from "../extensions/extension-discovery"; import type { LensExtensionId } from "../extensions/lens-extension"; -import { FilesystemProvisionerStore } from "./extension-filesystem"; import { installDeveloperTools } from "./developer-tools"; import { LensProtocolRouterMain } from "./protocol-handler"; import { disposer, getAppVersion, getAppVersionFromProxyServer } from "../common/utils"; @@ -51,7 +47,6 @@ import { startUpdateChecking } from "./app-updater"; import { IpcRendererNavigationEvents } from "../renderer/navigation/events"; import { pushCatalogToRenderer } from "./catalog-pusher"; import { catalogEntityRegistry } from "./catalog"; -import { HotbarStore } from "../common/hotbar-store"; import { HelmRepoManager } from "./helm/helm-repo-manager"; import { KubeconfigSyncManager } from "./catalog-sources"; import { handleWsUpgrade } from "./proxy/ws-upgrade"; @@ -128,24 +123,11 @@ app.on("ready", async () => { PrometheusProviderRegistry.createInstance(); initializers.initPrometheusProviderRegistry(); - const userStore = UserStore.createInstance(); - const clusterStore = ClusterStore.createInstance(); - const hotbarStore = HotbarStore.createInstance(); - const extensionsStore = ExtensionsStore.createInstance(); - const filesystemStore = FilesystemProvisionerStore.createInstance(); + await initializers.initializeStores(); + initializers.initializeWeblinks(); HelmRepoManager.createInstance(); // create the instance - logger.info("💾 Loading stores"); - // preload - await Promise.all([ - userStore.load(), - clusterStore.load(), - hotbarStore.load(), - extensionsStore.load(), - filesystemStore.load(), - ]); - const lensProxy = LensProxy.createInstance( handleWsUpgrade, req => ClusterManager.getInstance().getClusterForRequest(req), @@ -257,13 +239,13 @@ app.on("will-quit", (event) => { // This is called when the close button of the main window is clicked const lprm = LensProtocolRouterMain.getInstance(false); - + logger.info("APP:QUIT"); appEventBus.emit({ name: "app", action: "close" }); ClusterManager.getInstance(false)?.stop(); // close cluster connections KubeconfigSyncManager.getInstance(false)?.stopSync(); cleanup(); - + if (lprm) { // This is set to false here so that LPRM can wait to send future lens:// // requests until after it loads again @@ -272,7 +254,7 @@ app.on("will-quit", (event) => { if (blockQuit) { // Quit app on Cmd+Q (MacOS) - + event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.) return; // skip exit to make tray work, to quit go to app's global menu or tray's menu diff --git a/src/main/initializers/index.ts b/src/main/initializers/index.ts index 526b61d4ed..37ff00bd77 100644 --- a/src/main/initializers/index.ts +++ b/src/main/initializers/index.ts @@ -22,3 +22,5 @@ export * from "./registries"; export * from "./metrics-providers"; export * from "./ipc"; +export * from "./weblinks"; +export * from "./stores"; diff --git a/src/main/initializers/stores.ts b/src/main/initializers/stores.ts new file mode 100644 index 0000000000..4ea6322457 --- /dev/null +++ b/src/main/initializers/stores.ts @@ -0,0 +1,48 @@ +/** + * 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"; +import { ClusterStore } from "../../common/cluster-store"; +import { UserStore } from "../../common/user-store"; +import { ExtensionsStore } from "../../extensions/extensions-store"; +import { FilesystemProvisionerStore } from "../extension-filesystem"; +import { WeblinkStore } from "../../common/weblink-store"; +import logger from "../logger"; + +export async function initializeStores() { + const userStore = UserStore.createInstance(); + const clusterStore = ClusterStore.createInstance(); + const hotbarStore = HotbarStore.createInstance(); + const extensionsStore = ExtensionsStore.createInstance(); + const filesystemStore = FilesystemProvisionerStore.createInstance(); + const weblinkStore = WeblinkStore.createInstance(); + + logger.info("💾 Loading stores"); + // preload + await Promise.all([ + userStore.load(), + clusterStore.load(), + hotbarStore.load(), + extensionsStore.load(), + filesystemStore.load(), + weblinkStore.load() + ]); +} diff --git a/src/main/initializers/weblinks.ts b/src/main/initializers/weblinks.ts new file mode 100644 index 0000000000..2bd65d0894 --- /dev/null +++ b/src/main/initializers/weblinks.ts @@ -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. + */ + +export { initializeWeblinks } from "../catalog-sources"; diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 3824caa011..df0bd00feb 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -31,16 +31,12 @@ import * as LensExtensionsRendererApi from "../extensions/renderer-api"; import { render, unmountComponentAtNode } from "react-dom"; import { delay } from "../common/utils"; import { isMac, isDevelopment } from "../common/vars"; -import { HotbarStore } from "../common/hotbar-store"; import { ClusterStore } from "../common/cluster-store"; import { UserStore } from "../common/user-store"; import { ExtensionDiscovery } from "../extensions/extension-discovery"; import { ExtensionLoader } from "../extensions/extension-loader"; -import { ExtensionsStore } from "../extensions/extensions-store"; -import { FilesystemProvisionerStore } from "../main/extension-filesystem"; import { App } from "./components/app"; import { LensApp } from "./lens-app"; -import { ThemeStore } from "./theme.store"; import { HelmRepoManager } from "../main/helm/helm-repo-manager"; import { ExtensionInstallationStateStore } from "./components/+extensions/extension-install.store"; import { DefaultProps } from "./mui-base-theme"; @@ -77,33 +73,19 @@ export async function bootstrap(App: AppComponent) { initializers.intiKubeObjectDetailRegistry(); initializers.initWelcomeMenuRegistry(); initializers.initWorkloadsOverviewDetailRegistry(); + initializers.initCatalog(); initializers.initIpcRendererListeners(); ExtensionLoader.createInstance().init(); ExtensionDiscovery.createInstance().init(); - const userStore = UserStore.createInstance(); - const clusterStore = ClusterStore.createInstance(); - const extensionsStore = ExtensionsStore.createInstance(); - const filesystemStore = FilesystemProvisionerStore.createInstance(); - const themeStore = ThemeStore.createInstance(); - const hotbarStore = HotbarStore.createInstance(); + await initializers.initStores(); ExtensionInstallationStateStore.bindIpcListeners(); HelmRepoManager.createInstance(); // initialize the manager - // preload common stores - await Promise.all([ - userStore.load(), - hotbarStore.load(), - clusterStore.load(), - extensionsStore.load(), - filesystemStore.load(), - themeStore.init(), - ]); - // Register additional store listeners - clusterStore.registerIpcListener(); + ClusterStore.getInstance().registerIpcListener(); // init app's dependencies if any if (App.init) { diff --git a/src/renderer/components/+catalog/catalog.module.css b/src/renderer/components/+catalog/catalog.module.css index 38628cf878..b651814507 100644 --- a/src/renderer/components/+catalog/catalog.module.css +++ b/src/renderer/components/+catalog/catalog.module.css @@ -40,11 +40,11 @@ max-width: 100px; } -.connected { +.connected, .available { color: var(--colorSuccess); } -.disconnected, .deleting { +.disconnected, .deleting, .unavailable { color: var(--halfGray); } diff --git a/src/renderer/components/catalog-entities/weblink-add-command.tsx b/src/renderer/components/catalog-entities/weblink-add-command.tsx new file mode 100644 index 0000000000..04310ac46d --- /dev/null +++ b/src/renderer/components/catalog-entities/weblink-add-command.tsx @@ -0,0 +1,102 @@ +/** + * 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 { observer } from "mobx-react"; +import { CommandOverlay } from "../command-palette"; +import { Input } from "../input"; +import { isUrl } from "../input/input_validators"; +import { WeblinkStore } from "../../../common/weblink-store"; +import { computed, makeObservable, observable } from "mobx"; + +@observer +export class WeblinkAddCommand extends React.Component { + @observable url = ""; + @observable nameHidden = true; + @observable dirty = false; + + constructor(props: {}) { + super(props); + + makeObservable(this); + } + + onChangeUrl(url: string) { + this.dirty = true; + this.url = url; + } + + onSubmitUrl(url: string) { + this.dirty = true; + this.url = url; + this.nameHidden = false; + } + + onSubmit(name: string) { + WeblinkStore.getInstance().add({ + name: name || this.url, + url: this.url + }); + + CommandOverlay.close(); + } + + @computed get showValidation() { + return this.url?.length > 0; + } + + render() { + return ( + <> + this.onChangeUrl(v)} + onSubmit={(v) => this.onSubmitUrl(v)} + showValidationLine={true} /> + { this.nameHidden && ( + + Please provide a web link URL (Press "Enter" to continue or "Escape" to cancel) + + )} + { !this.nameHidden && ( + <> + this.onSubmit(v)} + dirty={true}/> + + Please provide a name for the web link (Press "Enter" to confirm or "Escape" to cancel) + + + )} + + ); + } +} diff --git a/src/renderer/components/input/input.tsx b/src/renderer/components/input/input.tsx index 5de07cb856..fa1692e988 100644 --- a/src/renderer/components/input/input.tsx +++ b/src/renderer/components/input/input.tsx @@ -261,7 +261,7 @@ export class Input extends React.Component { switch (evt.key) { case "Enter": - if (this.props.onSubmit && !modified && !evt.repeat && this.isValid) { + if (this.props.onSubmit && !modified && !evt.repeat && this.isValid()) { this.props.onSubmit(this.getValue(), evt); if (this.isUncontrolled) { diff --git a/src/renderer/initializers/catalog.tsx b/src/renderer/initializers/catalog.tsx new file mode 100644 index 0000000000..b9c56bc0c6 --- /dev/null +++ b/src/renderer/initializers/catalog.tsx @@ -0,0 +1,33 @@ +/** + * 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 { WebLinkCategory } from "../../common/catalog-entities"; +import { WeblinkAddCommand } from "../components/catalog-entities/weblink-add-command"; +import { CommandOverlay } from "../components/command-palette"; + +function initWebLinks() { + WebLinkCategory.onAdd = () => CommandOverlay.open(); +} + +export function initCatalog() { + initWebLinks(); +} diff --git a/src/renderer/initializers/index.ts b/src/renderer/initializers/index.ts index 0bb4eb611e..ed2d8e8575 100644 --- a/src/renderer/initializers/index.ts +++ b/src/renderer/initializers/index.ts @@ -26,4 +26,6 @@ export * from "./kube-object-menu-registry"; export * from "./registries"; export * from "./welcome-menu-registry"; export * from "./workloads-overview-detail-registry"; +export * from "./catalog"; +export * from "./stores"; export * from "./ipc"; diff --git a/src/renderer/initializers/stores.ts b/src/renderer/initializers/stores.ts new file mode 100644 index 0000000000..37bef7530a --- /dev/null +++ b/src/renderer/initializers/stores.ts @@ -0,0 +1,50 @@ +/** + * 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"; +import { ClusterStore } from "../../common/cluster-store"; +import { UserStore } from "../../common/user-store"; +import { ExtensionsStore } from "../../extensions/extensions-store"; +import { FilesystemProvisionerStore } from "../../main/extension-filesystem"; + +import { ThemeStore } from "../theme.store"; +import { WeblinkStore } from "../../common/weblink-store"; + +export async function initStores() { + const userStore = UserStore.createInstance(); + const clusterStore = ClusterStore.createInstance(); + const extensionsStore = ExtensionsStore.createInstance(); + const filesystemStore = FilesystemProvisionerStore.createInstance(); + const themeStore = ThemeStore.createInstance(); + const hotbarStore = HotbarStore.createInstance(); + const weblinkStore = WeblinkStore.createInstance(); + + // preload common stores + await Promise.all([ + userStore.load(), + hotbarStore.load(), + clusterStore.load(), + extensionsStore.load(), + filesystemStore.load(), + themeStore.init(), + weblinkStore.load() + ]); +}