//
// SPDX-License-Identifier: AGPL-3.0
-import * as React from 'react';
-import { Dispatch } from 'redux';
-import { RootStore, RootState } from '~/store/store';
+import React from 'react';
+import { Dispatch, Middleware } from 'redux';
+import { RootStore, RootState } from 'store/store';
+import { ResourcesState } from 'store/resources/resources';
+import { Location } from 'history';
+import { ServiceRepository } from "services/services";
-export type RouteListReducer = (startingList: React.ReactElement[]) => React.ReactElement[];
+export type ElementListReducer = (startingList: React.ReactElement[], itemClass?: string) => React.ReactElement[];
export type CategoriesListReducer = (startingList: string[]) => string[];
export type NavigateMatcher = (dispatch: Dispatch, getState: () => RootState, uuid: string) => boolean;
export type LocationChangeMatcher = (store: RootStore, pathname: string) => boolean;
+export type EnableNew = (location: Location, currentItemId: string, currentUserUUID: string | undefined, resources: ResourcesState) => boolean;
+export type MiddlewareListReducer = (startingList: Middleware[], services: ServiceRepository) => Middleware[];
+
+/* Workbench Plugin API
+
+ Code to your plugin should go into a subdirectory of 'plugins/'.
+
+ Your plugin should implement a "register" function, which will be
+ called with an object with the PluginConfig interface described
+ below. The register function may make in-place modifications to
+ the pluginConfig object, but to preserve composability, it is
+ strongly advised this should be limited to push()ing new values
+ onto the various lists of hooks.
+
+ To enable a plugin, edit 'plugins.tsx', import the register
+ function exported by the plugin, and add a call to the register
+ function following the examples in the comments. Then, build a new
+ Workbench package that includes the plugin.
+
+ Be aware that because plugins heavily leverage workbench, and in
+ fact must be compiled together, they are considered "derived works"
+ and so _must_ be license-compatible with AGPL-3.0.
+
+ */
export interface PluginConfig {
- // Customize the list of possible center panels by adding or removing Route components.
- centerPanelList: RouteListReducer[];
- // Customize the list of side panel categories
+ /* During initialization, each
+ * function in the callback list will be called with the list of
+ * react - router "Route" components that will be used select what should
+ * be displayed in the central panel based on the navigation bar.
+ *
+ * The callback function may add, edit, or remove items from this list,
+ * and return a new list of components, which will be passed to the next
+ * function in `centerPanelList`.
+ *
+ * The hooks are applied in `views/workbench/workbench.tsx`.
+ * */
+ centerPanelList: ElementListReducer[];
+
+ /* During initialization, each
+ * function in the callback list will be called with the list of strings
+ * that are the top-level categories in the left hand navigation tree.
+ *
+ * The callback function may add, edit, or remove items from this list,
+ * and return a new list of strings, which will be passed to the next
+ * function in `sidePanelCategories`.
+ *
+ * The hooks are applied in `store/side-panel-tree/side-panel-tree-actions.ts`.
+ * */
sidePanelCategories: CategoriesListReducer[];
- // Add to the list of possible dialogs by adding dialog components.
+ /* This is a list of additional dialog box components.
+ * Dialogs are components that are wrapped using the "withDialog()" method.
+ *
+ * These are added to the list in `views/workbench/workbench.tsx`.
+ * */
dialogs: React.ReactElement[];
- // Add navigation actions for identifiers
+ /* This is a list of additional navigation matchers.
+ * These are callbacks that are called by the navigateTo(uuid) method to
+ * set the path in the navigation bar to display the desired resource.
+ * Each handler should return "true" if the uuid was handled and "false or "undefined" if not.
+ *
+ * These are used in `store/navigation/navigation-action.tsx`.
+ * */
navigateToHandlers: NavigateMatcher[];
- // Add handlers for navigation actions
+ /* This is a list of additional location change matchers.
+ * These are callbacks called when the URL in the navigation bar changes
+ * (this could be in response to "navigateTo()" or due to the user
+ * entering/changing the URL directly).
+ *
+ * The Route components in centerPanelList should
+ * automatically change in response to navigation. The
+ * purpose of these handlers is trigger additional loading,
+ * such as fetching the object contents that will be
+ * displayed.
+ *
+ * Each handler should return "true" if the path was handled and "false or "undefined" if not.
+ *
+ * These are used in `routes/route-change-handlers.ts`.
+ */
locationChangeHandlers: LocationChangeMatcher[];
+
+ /* Replace the left side of the app bar. Normally, this displays
+ * the site banner.
+ *
+ * Note: unlike most of the other hooks, this is not composable.
+ * This completely replaces that section of the app bar. Multiple
+ * plugins setting this value will conflict.
+ *
+ * Used in 'views-components/main-app-bar/main-app-bar.tsx'
+ */
+ appBarLeft?: React.ReactElement;
+
+ /* Replace the middle part of the app bar. Normally, this displays
+ * the search bar.
+ *
+ * Note: unlike most of the other hooks, this is not composable.
+ * This completely replaces that section of the app bar. Multiple
+ * plugins setting this value will conflict.
+ *
+ * Used in 'views-components/main-app-bar/main-app-bar.tsx'
+ */
+ appBarMiddle?: React.ReactElement;
+
+ /* Replace the right part of the app bar. Normally, this displays
+ * the admin menu and help menu.
+ * (Note: the user menu can be customized separately using accountMenuList)
+ *
+ * Note: unlike most of the other hooks, this is not composable.
+ * This completely replaces that section of the app bar. Multiple
+ * plugins setting this value will conflict.
+ *
+ * Used in 'views-components/main-app-bar/main-app-bar.tsx'
+ */
+ appBarRight?: React.ReactElement;
+
+ /* During initialization, each
+ * function in the callback list will be called with the menu items that
+ * will appear in the "user account" menu.
+ *
+ * The callback function may add, edit, or remove items from this list,
+ * and return a new list of menu items, which will be passed to the next
+ * function in `accountMenuList`.
+ *
+ * The hooks are applied in 'views-components/main-app-bar/account-menu.tsx'.
+ * */
+ accountMenuList: ElementListReducer[];
+
+ /* Each function in this list is called to determine if the the "NEW" button
+ * should be enabled or disabled. If any function returns "true", the button
+ * (and corresponding drop-down menu) will be enabled.
+ *
+ * The hooks are applied in 'views-components/side-panel-button/side-panel-button.tsx'.
+ * */
+ enableNewButtonMatchers: EnableNew[];
+
+ /* During initialization, each
+ * function in the callback list will be called with the menu items that
+ * will appear in the "NEW" dropdown menu.
+ *
+ * The callback function may add, edit, or remove items from this list,
+ * and return a new list of menu items, which will be passed to the next
+ * function in `newButtonMenuList`.
+ *
+ * The hooks are applied in 'views-components/side-panel-button/side-panel-button.tsx'.
+ * */
+ newButtonMenuList: ElementListReducer[];
+
+ /* Add Middlewares to the Redux store.
+ *
+ * Middlewares intercept redux actions before they get to the reducer, and
+ * may produce side effects. For example, the REQUEST_ITEMS action is intercepted by a middleware to
+ * trigger a load of data table contents.
+ *
+ * https://redux.js.org/tutorials/fundamentals/part-4-store#middleware
+ *
+ * Used in 'store/store.ts'
+ * */
+ middlewares: MiddlewareListReducer[];
}