UNPKG

@hawtio/react

Version:

A Hawtio reimplementation based on TypeScript + React.

612 lines (608 loc) 21.6 kB
import React__default from 'react'; import { ImportRemoteOptions } from '@module-federation/utilities'; /** * Components to be added to the header navbar * Can define either a single component type or * a component with a universal property. * * By default, components will only be displayed * if the plugin UI is also visible. However, setting * universal to 'true' will ensure the component * remains displayed regardless of which plugin is * given focus. */ interface UniversalHeaderItem { /** * The component that should be populated as * a dropdown item on the header bar. */ component: React__default.ComponentType<any>; /** * Should components remain visible on header even when * the plugin is not being displayed. */ universal: boolean; } type HeaderItem = React__default.ComponentType | UniversalHeaderItem; declare function isUniversalHeaderItem(item: HeaderItem): item is UniversalHeaderItem; /** * Type definition of the entry point for a Hawtio plugin. Such plugin (method) should use Hawtio API * to register plugin details with name, paths and components. * * This method is synchronous and should synchronously call one of the plugin registration methods: * * `addPlugin`: add `Plugin` object directly * * `addDeferredPlugin`: add a function returning a Promise resolving to a `Plugin` object * * `addUrl`: add a URL for an endpoint returning an array of `HawtioRemote` objects representing remote modules * loaded using Module Federation utilities */ type HawtioPlugin = () => void; /** * Type definition of a fully remote _plugin_ (function) that is called by Hawtio using @module-federation/utilities. * * This method should be asynchronous and return a Promise (with any value), so Hawtio can await for its resolution. */ type HawtioAsyncPlugin = () => Promise<unknown>; /** * Internal representation of a Hawtio plugin. */ type Plugin = { /** * Mandatory, unique plugin identifier */ id: string; /** * Title to be displayed in left PageSidebar */ title?: string; /** * Path for plugin's main component. Optional if the plugin only contributes header elements for example */ path?: string; /** * The order to be shown in the Hawtio sidebar. * * This only controls presentation and doesn't change the order of plugin to * be loaded. * * If it's not specified, it defaults to `100`. `0` ~ `30` are reserved for * the builtin plugins. */ order?: number; /** * If this plugin provides a login form component */ isLogin?: boolean; /** * Plugin's main component to be displayed inside `<HawtioPage>` */ component?: React__default.ComponentType; /** * Plugin's components to be added to `<HawtioHeaderToolbar>` */ headerItems?: HeaderItem[]; /** * Returns if this plugin should be activated. * This method needs to return a promise as the process of resolving if a plugin * should be activated may require information collected asynchronously such as * the existence of some MBeans, etc. */ isActive: () => Promise<boolean>; }; /** * Extension of Module Federation {@link ImportRemoteOptions} for single federated module. */ interface HawtioRemote extends ImportRemoteOptions { pluginEntry?: string; } /** * Interface through which `HawtioCore` should be available when importing it through `@hawtio/core/init` entry point. * * All the public methods of the implementing class will be available to other parts of `@hawtio/react`, but when * accessed through `IHawtio`, only part of the public API will be available. */ interface IHawtio { /** * Adds a Hawtio plugin directly using `Plugin` object. The plugin will be added to a list of plugins processed * at bootstrap time * @param plugin */ addPlugin(plugin: Plugin): IHawtio; /** * Adds a Hawtio plugin in a deferred way. Instead of passing `Plugin` object directly, we pass a function that * returns a Promise resolving (for example after `import()`) to actual `Plugin` or an array of `Plugin` objects. * @param id Plugin ID * @param deferred a function returning a Promise resolving to a `Plugin` or array of `Plugin` objects */ addDeferredPlugin(id: string, deferred: () => Promise<Plugin | Plugin[]>): IHawtio; /** * Adds a URL for discovering plugins. Single URL defines an endpoint that returns an array of modules/plugins * defined by {@link HawtioRemote} type. * * @param url An URL to fetch the plugin information from. When the URL is relative, it is using * `document.baseURI` as the base. */ addUrl(url: string): IHawtio; /** * Bootstraps Hawtio. This method needs to be called by all applications that are bundled with `webpack` (or * similar web bundler). * * This method returns a Promise. When resolved we can finally render the `<Hawtio>` React/PatternFly component */ bootstrap(): Promise<boolean>; } /** * Hawtio core service. * * This service provides the following functionalities: * - Base path provisioning * - Plugin loader and discovery mechanism * - Bootstrapping the application */ declare class HawtioCore implements IHawtio { /** * Hawtio base path. */ private basePath?; /** * List of URLs that the plugin loader will try and discover plugins from. */ private urls; /** * Holds all of the Hawtio plugins that need to be bootstrapped. */ private plugins; /** * Holds all of the Hawtio plugins which will be evaluated in deferred way. */ private deferredPlugins; /** * The Window Theme Listener callback function */ private windowThemeListener; /** * Flag set once the window theme listener has been added */ private windowListenerAdded; addPlugin(plugin: Plugin): HawtioCore; addDeferredPlugin(id: string, deferred: () => Promise<Plugin | Plugin[]>): HawtioCore; addUrl(url: string): HawtioCore; bootstrap(): Promise<boolean>; /** * Returns all plugins registered using different plugin registration methods. */ getPlugins(): Plugin[]; /** * Resolves which of registered plugins are active in current environment. * * There are two types of plugins: normal plugins and login plugins. * If it's normal, it's only resolved when the user is already logged in. * If it's login, it's only resolved when the user is not logged in yet, and thus * can only affects the login page. * * Therefore, this method depends on the login status provided by the `userService`. */ resolvePlugins(): Promise<Plugin[]>; /** * Sets the base path of the Hawtio console. * If the given path includes trailing '/', it will be trimmed. */ setBasePath(path: string): void; /** * Returns the base path of the Hawtio console without trailing '/'. */ getBasePath(): string | undefined; /** * Adds an event listener to the window theme to update * css values in the event of a change in theme */ addWindowThemeListener(): void; /** * Removes the event listener to the window theme */ removeWindowThemeListener(): void; /** * Returns the base URL specified in html/head/base element, href attribute. It should end with trailing '/'. * Specified base affects how `fetch()` global function works. * @private */ private documentBase; /** * Downloads plugins from any configured URLs and loads them. * It is invoked at Hawtio's bootstrapping. * * This plugin mechanism is implemented using [Webpack Module Federation](https://module-federation.github.io/). */ private loadPlugins; /** * Loads external plugins from the given URL. The URL endpoint is expected to * return an array of HawtioRemote objects. These are not strictly "Hawtio plugins", but rather * "remote entry points" that when called may register Hawtio plugins (with `hawtio.addPlugin()` or * `hawtio.addDeferredPlugin()`). */ private loadExternalPlugins; /** * Evaluate all deferred plugins, so they are added to `plugins` array of available plugins * @private */ private loadDeferredPlugins; private themeList; /** * Detect what theme the browser has been set to and * return 'dark' | 'light' */ private windowTheme; /** * Update the document root with the PatternFly dark class * see https://www.patternfly.org/developer-resources/dark-theme-handbook */ private updateFromTheme; } declare const hawtio: HawtioCore; declare const DEFAULT_APP_NAME = "Hawtio Management Console"; declare const DEFAULT_LOGIN_TITLE = "Log in to your account"; declare const HAWTCONFIG_JSON = "hawtconfig.json"; /** * The single user-customisable entrypoint for the Hawtio console configurations. */ type Hawtconfig = { /** * Configuration for branding & styles. */ branding?: BrandingConfig; /** * Configuration for the placement and structure of the UI */ appearance?: AppearanceConfig; /** * Configuration for the built-in login page. */ login?: LoginConfig; /** * Configuration for the About modal. */ about?: AboutConfig; /** * The user can explicitly disable plugins by specifying the plugin route paths. * * This option can be used if some of the built-in plugins are not desirable * for the custom installation of Hawtio console. */ disabledRoutes?: DisabledRoutes; /** * Configuration for JMX plugin. */ jmx?: JmxConfig; /** * Configuration for Hawtio Online. */ online?: OnlineConfig; }; /** * Branding configuration type. */ type BrandingConfig = { appName?: string; showAppName?: boolean; appLogoUrl?: string; css?: string; favicon?: string; }; /** * Appearance configuration type. */ type AppearanceConfig = { showHeader?: boolean; showBrand?: boolean; showUserHeader?: boolean; showSideBar?: boolean; }; /** * Login configuration type. */ type LoginConfig = { title?: string; description?: string; links?: LoginLink[]; }; /** * Configuration of a single link at the login page */ type LoginLink = { url: string; text: string; }; /** * About configuration type. */ type AboutConfig = { title?: string; description?: string; imgSrc?: string; backgroundImgSrc?: string; productInfo?: AboutProductInfo[]; copyright?: string; }; /** * Information about single _product_ or _component_ added to Hawtio application */ type AboutProductInfo = { name: string; value: string; }; /** * List of routes which should be disabled in a Hawtio application */ type DisabledRoutes = string[]; /** * JMX configuration type. */ type JmxConfig = { /** * This option can either disable workspace completely by setting `false`, or * specify an array of MBean paths in the form of * `<domain>/<prop1>=<value1>,<prop2>=<value2>,...` * to fine-tune which MBeans to load into workspace. * * Note that disabling workspace should also deactivate all the plugins that * depend on MBeans provided by workspace. * * @see https://github.com/hawtio/hawtio-next/issues/421 */ workspace?: boolean | string[]; }; /** * Hawtio Online configuration type. */ type OnlineConfig = { /** * Selector for OpenShift projects or Kubernetes namespaces. * * @see https://github.com/hawtio/hawtio-online/issues/64 */ projectSelector?: string; }; /** * Stages of initialization tasks performed by Hawtio and presented in `<HawtioInitialization>` component */ declare enum TaskState { started = 0, skipped = 1, finished = 2, error = 3 } /** * A structure to hold information about initialization tasks performed by Hawtio */ type InitializationTasks = Record<string, { ready: TaskState; group: string; }>; /** * Supported authentication methods */ type AuthenticationKind = /** * Basic authentication - requires preparation of `Authorization: Basic <base64(user:password)>` HTTP header */ 'basic' /** * Digest authentication - [Digest Access Authentication Scheme](https://www.rfc-editor.org/rfc/rfc2617#section-3), * uses several challenge parameters (realm, nonces, ...) */ | 'digest' /** * Form authentication - we need to know the URI to send the credentials to. It may be * `application/x-www-form-urlencoded` content (then we need to know the fields to use) or JSON with some schema. */ | 'form' /** * This may be tricky, because we can't control it at JavaScript level... */ | 'clientcert' /** * This is universal OpenID connect login type, so we need some information - should be configured * using `.well-known/openid-configuration` endpoint, but with additional parameters (to choose supported values * for some operations). */ | 'oidc' /** * _Native_ Keycloak authentication using `keycloak.js` library */ | 'keycloak' /** * Probably less standardized than `.well-known/openid-configuration`, but similar. We need to know the endpoints * to use for OAuth2 auth. */ | 'oauth2'; /** * State of authentication result which is used at login screen to show specific error message */ declare enum AuthenticationResult { /** successful authentication */ ok = 0, /** error due to initial configuration of the plugin */ configuration_error = 1, /** error due to communication error with IdP (for OIDC) */ connect_error = 2, /** error due to `window.isSecureContext` */ security_context_error = 3 } /** * Base type for authentication methods supported by Hawtio */ type AuthenticationMethod = { /** One of the supported methods. If a plugin augments given method, we should have one such method only */ method: AuthenticationKind; /** Name to be presented at login page for login method selection */ name?: string; /** Plugin specific method for performing login. For now it's for OAuth2/OIDC/Keycloak. This field is set up by auth plugin */ login?: () => Promise<AuthenticationResult>; }; /** * Configuration of Basic Authentication */ type BasicAuthenticationMethod = AuthenticationMethod & { /** Basic Authentication Realm - not sent with `Authorization`, but user should see it */ realm: string; }; /** * Configuration of FORM-based login configuration */ type FormAuthenticationMethod = AuthenticationMethod & { /** POST URL to send the credentials to */ url: string | URL; /** POST URL for logout endpoint */ logoutUrl: string | URL; /** * `application/x-www-form-urlencoded` or `application/json`. For JSON it's just object with two configurable fields */ type: 'form' | 'json'; /** * Field name for user name */ userField: string; /** * Field name for password * TODO: possibly encoded/encrypted? */ passwordField: string; }; /** * OpenID Connect authentication method configuration. * All details are specified in a type defined in OIDC plugin, but here we may define some generic fields */ type OidcAuthenticationMethod = AuthenticationMethod & {}; /** * Interface through which `ConfigManager` should be available when importing it through `@hawtio/core/init` entry point. * * We should keep public methods of the implementing class available to other parts of `@hawtio/react`, * but other NPM packages which use `@hawtio/react` should rather import `init` entry point and get access to * a subset of available methods. */ interface IConfigManager { /** * Add information about product that builds on `@hawtio/react`. It may be full application or part of the * application * * @param name Name of the component * @param value Value to show for the component name - usually a version */ addProductInfo(name: string, value: string): Promise<void>; /** * Track initialization task at selected {@link TaskState}. For proper usage, all tasks should first be * registered with `started` and finally with one of: * * `finished` * * `skipped` * * `error` * * @param item Initialization task name * @param state Initialization task state * @param group One of supported initialization task groups */ initItem(item: string, state: TaskState, group: 'config' | 'plugins' | 'finish'): void; } /** * This class provides API for configuration of `@hawtio/react` package */ declare class ConfigManager implements IConfigManager { /** Configuration object read from `hawtconfig.json` and/or built programmatically */ private config?; /** List of initialization tasks to be presented in `<HawtioInitialization>` component */ private initTasks; /** Listeners notified about initialization task state changes */ private initListeners; /** Configuration of available authentication methods, used by login-related components */ private authenticationConfig; /** Resolution method for `authenticationConfigPromise` */ private authenticationConfigReady; /** Promise resolved when authentication config is already read from external source */ private authenticationConfigPromise; addProductInfo(name: string, value: string): Promise<void>; initItem(item: string, ready: TaskState, group: 'config' | 'plugins' | 'finish'): void; /** * This method is called by `hawtio.bootstrap()`, so we have a single point where global (not plugin-specific) * configuration is loaded */ initialize(): Promise<boolean>; /** * Called by plugins to augment generic authentication method config. * Plugins may provide additional details, like location of OIDC provider. * @param config */ configureAuthenticationMethod(config: AuthenticationMethod): Promise<void>; /** * Get configured authentication methods - possibly augmented by plugins. This method should * be called from hooks and React components, so can be done only after hawtio.bootstrap() promise is * resolved. This ensures that plugins already finished their configuration. */ getAuthenticationConfig(): AuthenticationMethod[]; /** * Returns selected authentication method by name * @param method */ getAuthenticationMethod(method: string): AuthenticationMethod | undefined; /** * Set new `Hawtconfig` object as the configuration * @param config */ setHawtconfig(config: Hawtconfig): void; /** * Returns currently configured `Hawtconfig` object */ getHawtconfig(): Promise<Hawtconfig>; /** * Resets current `Hawtconfig` object to undefined state */ reset(): void; /** * Loads configuration from `hawtconfig.json`. * @private */ private loadConfig; /** * Plugins may use this method to change parts, or entire `hawtconfig.json` configuration. * @param configurer */ configure(configurer: (config: Hawtconfig) => void): Promise<void>; /** * Apply loaded configuration to application (titles, links, icons). Should be called during Hawtio bootstrap. */ applyBranding(): Promise<boolean>; /** * Alters `href` attribute of selected DOM element (for icons, styles) * @param id * @param path * @param moveToLast * @private */ private updateHref; isRouteEnabled(path: string): Promise<boolean>; /** * Filter loaded plugins, so only plugins which are not explicitly disabled in `hawtconfig.json` are used. * @param plugins */ filterEnabledPlugins(plugins: Plugin[]): Promise<Plugin[]>; /** * Returns current state of initialization tasks */ getInitializationTasks(): InitializationTasks; /** * Register a listener to be notified about state changes of initialization tasks * @param listener */ addInitListener(listener: (tasks: InitializationTasks) => void): void; /** * Unregister previously registered listener for state changes of initialization tasks * @param listener */ removeInitListener(listener: (tasks: InitializationTasks) => void): void; /** * Are all the initialization items completed? The returned promise will be asynchronously resolved when * initialization is finished. * * When the configuration is _ready_, Hawtio may proceed to rendering UI. */ ready(): Promise<boolean>; } declare const configManager: ConfigManager; export { type AppearanceConfig as A, type BrandingConfig as B, ConfigManager as C, DEFAULT_APP_NAME as D, type FormAuthenticationMethod as F, type Hawtconfig as H, type InitializationTasks as I, type JmxConfig as J, type LoginConfig as L, type OnlineConfig as O, type Plugin as P, TaskState as T, type UniversalHeaderItem as U, type HawtioPlugin as a, DEFAULT_LOGIN_TITLE as b, HAWTCONFIG_JSON as c, type LoginLink as d, type AboutConfig as e, type AboutProductInfo as f, type DisabledRoutes as g, type AuthenticationKind as h, AuthenticationResult as i, type AuthenticationMethod as j, type BasicAuthenticationMethod as k, type OidcAuthenticationMethod as l, type IConfigManager as m, configManager as n, type HeaderItem as o, isUniversalHeaderItem as p, type HawtioAsyncPlugin as q, type HawtioRemote as r, type IHawtio as s, HawtioCore as t, hawtio as u };