diff --git a/designer/client/package-lock.json b/designer/client/package-lock.json
index 1b7539f899a..f46693d865d 100644
--- a/designer/client/package-lock.json
+++ b/designer/client/package-lock.json
@@ -21,7 +21,7 @@
"@mui/icons-material": "5.15.7",
"@mui/lab": "5.0.0-alpha.165",
"@mui/material": "5.15.7",
- "@touk/federated-component": "1.0.0",
+ "@touk/federated-component": "1.1.0",
"@touk/window-manager": "1.9.0",
"ace-builds": "1.34.2",
"axios": "1.7.5",
@@ -6109,10 +6109,9 @@
}
},
"node_modules/@touk/federated-component": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@touk/federated-component/-/federated-component-1.0.0.tgz",
- "integrity": "sha512-ibliSr5T1pbM8S8M0NqUGJlBQJSmBeDTuO1fcPRQ97XO+Ai+9tQ00qUaCr0tI43cdTXLlkunXW+K5IlM4Krx+Q==",
- "hasInstallScript": true,
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@touk/federated-component/-/federated-component-1.1.0.tgz",
+ "integrity": "sha512-pYHL8d4RWxONtW3+PJT/1AzaS9cmtyKLd9VXhEM+dIL0DMIe2IkvB12W/yZUBeB1mW8bWlG/vpthL0lD8yV44Q==",
"peerDependencies": {
"react": "^17 || ^18",
"react-dom": "^17 || ^18"
@@ -32692,9 +32691,9 @@
"dev": true
},
"@touk/federated-component": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@touk/federated-component/-/federated-component-1.0.0.tgz",
- "integrity": "sha512-ibliSr5T1pbM8S8M0NqUGJlBQJSmBeDTuO1fcPRQ97XO+Ai+9tQ00qUaCr0tI43cdTXLlkunXW+K5IlM4Krx+Q=="
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@touk/federated-component/-/federated-component-1.1.0.tgz",
+ "integrity": "sha512-pYHL8d4RWxONtW3+PJT/1AzaS9cmtyKLd9VXhEM+dIL0DMIe2IkvB12W/yZUBeB1mW8bWlG/vpthL0lD8yV44Q=="
},
"@touk/federated-types": {
"version": "1.1.0",
diff --git a/designer/client/package.json b/designer/client/package.json
index 89dd719feb2..9bba27fe7e0 100644
--- a/designer/client/package.json
+++ b/designer/client/package.json
@@ -14,7 +14,7 @@
"@mui/icons-material": "5.15.7",
"@mui/lab": "5.0.0-alpha.165",
"@mui/material": "5.15.7",
- "@touk/federated-component": "1.0.0",
+ "@touk/federated-component": "1.1.0",
"@touk/window-manager": "1.9.0",
"ace-builds": "1.34.2",
"axios": "1.7.5",
diff --git a/designer/client/src/components/RemoteComponent.tsx b/designer/client/src/components/RemoteComponent.tsx
index 6c28c975a2b..ddca29f0e1b 100644
--- a/designer/client/src/components/RemoteComponent.tsx
+++ b/designer/client/src/components/RemoteComponent.tsx
@@ -1,8 +1,9 @@
-import React from "react";
+import React, { useMemo } from "react";
import LoaderSpinner from "./spinner/Spinner";
import { FederatedComponent, FederatedComponentProps, getFederatedComponentLoader } from "@touk/federated-component";
import { NuThemeProvider } from "../containers/theme/nuThemeProvider";
import SystemUtils from "../common/SystemUtils";
+import { useWindows, WindowKind } from "../windowManager";
export const loadExternalReactModule = getFederatedComponentLoader({ Wrapper: NuThemeProvider });
export const loadExternalReactModuleWithAuth = getFederatedComponentLoader({
@@ -13,6 +14,35 @@ export const loadExternalReactModuleWithAuth = getFederatedComponentLoader({
window["loadExternalReactModule"] = loadExternalReactModule;
window["loadExternalReactModuleWithAuth"] = loadExternalReactModuleWithAuth;
-export const RemoteComponent =
>(props: FederatedComponentProps
) => (
- {...props} fallback={} buildHash={__BUILD_HASH__} />
-);
+export type RemoteToolbarContentProps = {
+ openRemoteModuleWindow: >(props: P & { url?: string; title?: string }) => void;
+};
+
+function RemoteComponentRender
, T = unknown>(props: FederatedComponentProps
, ref: React.ForwardedRef) {
+ const { open } = useWindows();
+ const sharedContext = useMemo(
+ () => ({
+ openRemoteModuleWindow: ({ title, ...props }) =>
+ open({
+ kind: WindowKind.remote,
+ title,
+ meta: props,
+ }),
+ }),
+ [open],
+ );
+
+ return (
+
+ ref={ref}
+ {...sharedContext}
+ {...props}
+ fallback={}
+ buildHash={__BUILD_HASH__}
+ />
+ );
+}
+
+export const RemoteComponent = React.forwardRef(RemoteComponentRender) as , T = unknown>(
+ props: FederatedComponentProps
& React.RefAttributes,
+) => React.ReactElement;
diff --git a/designer/client/src/components/RemoteModuleDialog.tsx b/designer/client/src/components/RemoteModuleDialog.tsx
new file mode 100644
index 00000000000..4d44d822dab
--- /dev/null
+++ b/designer/client/src/components/RemoteModuleDialog.tsx
@@ -0,0 +1,61 @@
+import { ModuleUrl } from "@touk/federated-component";
+import { WindowContentProps } from "@touk/window-manager";
+import type { FooterButtonProps } from "@touk/window-manager/cjs/components/window/footer";
+import React, { useCallback, useMemo, useRef } from "react";
+import { useTranslation } from "react-i18next";
+import { WindowContent, WindowKind } from "../windowManager";
+import { LoadingButtonTypes } from "../windowManager/LoadingButton";
+import { RemoteComponent } from "./RemoteComponent";
+
+export type RemoteModuleDialogProps = NonNullable;
+export type RemoteModuleDialogRef = NonNullable<{
+ closeAction?: () => Promise;
+ adjustButtons: (buttons: { closeButton: FooterButtonProps; confirmButton: FooterButtonProps }) => FooterButtonProps[];
+}>;
+
+export function RemoteModuleDialog>({
+ close,
+ ...props
+}: WindowContentProps): JSX.Element {
+ const {
+ data: { meta: passProps },
+ } = props;
+
+ const ref = useRef();
+
+ const closeAction = useCallback(async () => {
+ await Promise.all([ref.current?.closeAction?.()]);
+ close();
+ }, [close]);
+
+ const { t } = useTranslation();
+
+ const closeButton = useMemo(
+ () => ({
+ title: t("dialog.button.cancel", "cancel"),
+ action: closeAction,
+ className: LoadingButtonTypes.secondaryButton,
+ }),
+ [closeAction, t],
+ );
+
+ const confirmButton = useMemo(
+ () => ({
+ title: t("dialog.button.ok", "OK"),
+ action: closeAction,
+ }),
+ [closeAction, t],
+ );
+
+ return (
+
+ ref={ref} {...passProps} />
+
+ );
+}
+
+export default RemoteModuleDialog;
diff --git a/designer/client/src/components/graph/node-modal/fragment-input-definition/settings/variants/fields/StyledSettingsComponnets.tsx b/designer/client/src/components/graph/node-modal/fragment-input-definition/settings/variants/fields/StyledSettingsComponnets.tsx
index 741d527aeab..c1212443023 100644
--- a/designer/client/src/components/graph/node-modal/fragment-input-definition/settings/variants/fields/StyledSettingsComponnets.tsx
+++ b/designer/client/src/components/graph/node-modal/fragment-input-definition/settings/variants/fields/StyledSettingsComponnets.tsx
@@ -16,7 +16,9 @@ export const SettingLabelStyled = styled(FormLabel)(({ theme }) => ({
color: theme.palette.text.secondary,
fontSize: "12px",
fontWeight: "400",
- flexBasis: "30%",
+ ".MuiFormControl-root &": {
+ flexBasis: "30%",
+ },
}));
export const ListItemContainer = styled("div")`
diff --git a/designer/client/src/components/toolbarComponents/DefaultToolbarPanel.tsx b/designer/client/src/components/toolbarComponents/DefaultToolbarPanel.tsx
index 98e723cca39..57286f2cc99 100644
--- a/designer/client/src/components/toolbarComponents/DefaultToolbarPanel.tsx
+++ b/designer/client/src/components/toolbarComponents/DefaultToolbarPanel.tsx
@@ -1,10 +1,9 @@
-import React, { PropsWithChildren, ReactElement, useMemo } from "react";
+import React, { PropsWithChildren, ReactElement } from "react";
import { useTranslation } from "react-i18next";
-import { splitUrl } from "@touk/federated-component";
-import { ToolbarButtons } from "./toolbarButtons";
+import { RemoteComponent } from "../RemoteComponent";
import { ToolbarConfig } from "../toolbarSettings/types";
+import { ToolbarButtons } from "./toolbarButtons";
import { ToolbarWrapper } from "./toolbarWrapper/ToolbarWrapper";
-import { RemoteComponent } from "../RemoteComponent";
export type ToolbarPanelProps = PropsWithChildren>;
@@ -22,8 +21,6 @@ export function DefaultToolbarPanel(props: ToolbarPanelProps): ReactElement {
}
function RemoteToolbarContent(props: ToolbarPanelProps): ReactElement {
- const { componentUrl, ...passProps } = props;
- const [url, scope] = useMemo(() => splitUrl(componentUrl), [componentUrl]);
-
- return ;
+ const { componentUrl, additionalParams, ...passProps } = props;
+ return ;
}
diff --git a/designer/client/src/components/toolbarComponents/toolbarWrapper/ToolbarWrapper.tsx b/designer/client/src/components/toolbarComponents/toolbarWrapper/ToolbarWrapper.tsx
index e78e5e1b95c..e3209976ae4 100644
--- a/designer/client/src/components/toolbarComponents/toolbarWrapper/ToolbarWrapper.tsx
+++ b/designer/client/src/components/toolbarComponents/toolbarWrapper/ToolbarWrapper.tsx
@@ -25,7 +25,7 @@ export const TOOLBAR_WRAPPER_CLASSNAME = "toolbar-wrapper";
export function ToolbarWrapper(props: ToolbarWrapperProps): React.JSX.Element | null {
const theme = useTheme();
- const { title, children, id, onClose, onExpand, onCollapse, color = theme.palette.background.paper, disableCollapse } = props;
+ const { title, children, id, onClose, onExpand, onCollapse, color, disableCollapse } = props;
const handlerProps = useDragHandler();
const dispatch = useDispatch();
@@ -59,7 +59,7 @@ export function ToolbarWrapper(props: ToolbarWrapperProps): React.JSX.Element |
borderRadius: theme.spacing(0.5),
}}
expanded={!isCollapsedLocal}
- color={color}
+ color={color || theme.palette.background.paper}
width={SIDEBAR_WIDTH}
data-testid={id}
{...(isCollapsible ? {} : handlerProps)}
@@ -67,7 +67,7 @@ export function ToolbarWrapper(props: ToolbarWrapperProps): React.JSX.Element |
{(isCollapsible || onClose) && (
{
if (e.key === "Enter") {
@@ -82,6 +82,7 @@ export function ToolbarWrapper(props: ToolbarWrapperProps): React.JSX.Element |
textTransform={"uppercase"}
variant={"overline"}
sx={{
+ color: color ? "inherit" : undefined,
"::after": {
// force line height for empty
content: "' '",
diff --git a/designer/client/src/components/toolbarSettings/types.ts b/designer/client/src/components/toolbarSettings/types.ts
index 130c3b2f7dc..05346232a32 100644
--- a/designer/client/src/components/toolbarSettings/types.ts
+++ b/designer/client/src/components/toolbarSettings/types.ts
@@ -11,6 +11,7 @@ export interface ToolbarConfig {
color?: string;
buttonsVariant?: ButtonsVariant;
disableCollapse?: boolean;
+ additionalParams?: Record;
}
export type ToolbarsConfig = Partial>;
diff --git a/designer/client/src/components/toolbars/creator/CreatorPanel.tsx b/designer/client/src/components/toolbars/creator/CreatorPanel.tsx
index 58f7deffbdf..53eae31ce26 100644
--- a/designer/client/src/components/toolbars/creator/CreatorPanel.tsx
+++ b/designer/client/src/components/toolbars/creator/CreatorPanel.tsx
@@ -1,14 +1,35 @@
+import { ModuleUrl } from "@touk/federated-component";
import { isEmpty } from "lodash";
import React, { useCallback, useState } from "react";
+import { ErrorBoundary } from "react-error-boundary";
import { useTranslation } from "react-i18next";
+import { EventTrackingSelector, getEventTrackingProps } from "../../../containers/event-tracking";
+import { RemoteComponent } from "../../RemoteComponent";
import { SearchIcon } from "../../table/SearchFilter";
+import { SearchInputWithIcon } from "../../themed/SearchInput";
import { ToolbarPanelProps } from "../../toolbarComponents/DefaultToolbarPanel";
import { ToolbarWrapper } from "../../toolbarComponents/toolbarWrapper/ToolbarWrapper";
import ToolBox from "./ToolBox";
-import { SearchInputWithIcon } from "../../themed/SearchInput";
-import { EventTrackingSelector, getEventTrackingProps } from "../../../containers/event-tracking";
-export function CreatorPanel(props: ToolbarPanelProps): JSX.Element {
+type CreatorPanelProps = ToolbarPanelProps & {
+ additionalParams?: {
+ addGroupElement?: ModuleUrl;
+ };
+};
+
+const AddGroupElement = >(props: P) => {
+ const { t } = useTranslation();
+ return props.url ? (
+
+
+
+ ) : null;
+};
+
+export function CreatorPanel({ additionalParams, ...props }: CreatorPanelProps): JSX.Element {
const { t } = useTranslation();
const [filter, setFilter] = useState("");
const clearFilter = useCallback(() => setFilter(""), []);
@@ -24,7 +45,28 @@ export function CreatorPanel(props: ToolbarPanelProps): JSX.Element {
>
-
+ (
+
+ )}
+ addTreeElement={({ name }) => (
+
+ )}
+ />
);
}
diff --git a/designer/client/src/components/toolbars/creator/ToolBox.tsx b/designer/client/src/components/toolbars/creator/ToolBox.tsx
index 787c16d4776..def6637eb36 100644
--- a/designer/client/src/components/toolbars/creator/ToolBox.tsx
+++ b/designer/client/src/components/toolbars/creator/ToolBox.tsx
@@ -1,16 +1,15 @@
+import { lighten, styled } from "@mui/material";
+import { getLuminance } from "@mui/system/colorManipulator";
import React, { useMemo } from "react";
+import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import "react-treeview/react-treeview.css";
import { filterComponentsByLabel } from "../../../common/ProcessDefinitionUtils";
+import { blendDarken, blendLighten } from "../../../containers/theme/helpers";
import { getProcessDefinitionData } from "../../../reducers/selectors/settings";
import { ComponentGroup } from "../../../types";
-import { ToolboxComponentGroup } from "./ToolboxComponentGroup";
import Tool from "./Tool";
-import { useTranslation } from "react-i18next";
-import { lighten, styled } from "@mui/material";
-
-import { blendDarken, blendLighten } from "../../../containers/theme/helpers";
-import { getLuminance } from "@mui/system/colorManipulator";
+import { ToolboxComponentGroup } from "./ToolboxComponentGroup";
const StyledToolbox = styled("div")(({ theme }) => ({
fontSize: "14px",
@@ -78,6 +77,7 @@ const StyledToolbox = styled("div")(({ theme }) => ({
padding: theme.spacing(0.75, 0.5, 0.75, 4),
border: "none",
borderRight: 0,
+ userSelect: "none",
"&.disabled": {
opacity: 0.4,
cursor: "not-allowed !important",
@@ -88,7 +88,7 @@ const StyledToolbox = styled("div")(({ theme }) => ({
cursor: "grabbing",
},
- "&:hover": {
+ "&:hover, &:focus-within": {
backgroundColor: theme.palette.action.hover,
color: lighten(theme.palette.text.primary, 0.2),
},
@@ -104,7 +104,13 @@ const StyledToolbox = styled("div")(({ theme }) => ({
},
}));
-export default function ToolBox(props: { filter: string }): JSX.Element {
+type ToolBoxProps = {
+ filter: string;
+ addTreeElement?: (group: ComponentGroup) => React.ReactElement | null;
+ addGroupLabelElement?: (group: ComponentGroup) => React.ReactElement | null;
+};
+
+export default function ToolBox(props: ToolBoxProps): JSX.Element {
const processDefinitionData = useSelector(getProcessDefinitionData);
const { t } = useTranslation();
@@ -126,6 +132,8 @@ export default function ToolBox(props: { filter: string }): JSX.Element {
componentGroup={componentGroup}
highlights={filters}
flatten={groups.length === 1}
+ addTreeElement={props.addTreeElement?.(componentGroup)}
+ addGroupLabelElement={props.addGroupLabelElement?.(componentGroup)}
/>
))
) : (
diff --git a/designer/client/src/components/toolbars/creator/ToolboxComponentGroup.tsx b/designer/client/src/components/toolbars/creator/ToolboxComponentGroup.tsx
index 0480c3ae9e0..4397aee00e1 100644
--- a/designer/client/src/components/toolbars/creator/ToolboxComponentGroup.tsx
+++ b/designer/client/src/components/toolbars/creator/ToolboxComponentGroup.tsx
@@ -28,10 +28,12 @@ interface Props {
componentGroup: ComponentGroup;
highlights?: string[];
flatten?: boolean;
+ addTreeElement?: React.ReactElement | null;
+ addGroupLabelElement?: React.ReactElement | null;
}
export function ToolboxComponentGroup(props: Props): JSX.Element {
- const { componentGroup, highlights = [], flatten } = props;
+ const { componentGroup, highlights = [], flatten, addGroupLabelElement, addTreeElement } = props;
const dispatch = useDispatch();
const closedComponentGroups = useSelector(getClosedComponentGroups);
const { name } = componentGroup;
@@ -53,6 +55,7 @@ export function ToolboxComponentGroup(props: Props): JSX.Element {
{name}
+ {addGroupLabelElement}
),
- [highlighted, name, toggle, toggleForceCollapsed],
+ [addGroupLabelElement, highlighted, name, toggle, toggleForceCollapsed],
);
const elements = useMemo(
@@ -89,6 +93,7 @@ export function ToolboxComponentGroup(props: Props): JSX.Element {
onClick={highlighted ? toggleForceCollapsed : toggle}
>
{elements}
+ {addTreeElement}
);
}
diff --git a/designer/client/src/containers/Auth/strategies/RemoteAuthStrategy/RemoteAuthStrategy.tsx b/designer/client/src/containers/Auth/strategies/RemoteAuthStrategy/RemoteAuthStrategy.tsx
index 27f85b7f576..d73cd088d19 100644
--- a/designer/client/src/containers/Auth/strategies/RemoteAuthStrategy/RemoteAuthStrategy.tsx
+++ b/designer/client/src/containers/Auth/strategies/RemoteAuthStrategy/RemoteAuthStrategy.tsx
@@ -1,4 +1,4 @@
-import { ModuleString, ModuleUrl, splitUrl } from "@touk/federated-component";
+import { ModuleUrl } from "@touk/federated-component";
import React, { FunctionComponent, PropsWithChildren } from "react";
import { PendingPromise } from "../../../../common/PendingPromise";
import SystemUtils from "../../../../common/SystemUtils";
@@ -14,20 +14,11 @@ type RemoteAuthProviderProps = PropsWithChildren<{
onInit: AuthLibCallback;
}>;
-function createAuthWrapper(
- {
- url,
- scope,
- }: {
- url: ModuleUrl;
- scope: ModuleString;
- },
- onInit: AuthLibCallback,
-): FunctionComponent {
+function createAuthWrapper(url: ModuleUrl, onInit: AuthLibCallback): FunctionComponent {
return function Wrapper({ children }: PropsWithChildren) {
return (
- url={url} scope={scope} onInit={onInit}>
+ url={url} onInit={onInit}>
{children}
@@ -65,15 +56,8 @@ export const RemoteAuthStrategy: StrategyConstructor = class RemoteAuthStrategy
constructor(private settings: RemoteAuthenticationSettings) {}
- private get urlWithScope(): {
- scope: ModuleString;
- url: ModuleUrl;
- } {
- const [url, scope] = splitUrl(this.settings.moduleUrl as ModuleUrl);
- return {
- url,
- scope,
- };
+ private get urlWithScope(): ModuleUrl {
+ return this.settings.moduleUrl as ModuleUrl;
}
private onError?: (error: AuthErrorCodes) => void = () => {
diff --git a/designer/client/src/containers/Auth/strategies/RemoteAuthStrategy/externalAuthModule.ts b/designer/client/src/containers/Auth/strategies/RemoteAuthStrategy/externalAuthModule.ts
index a26b1db595f..200128009e4 100644
--- a/designer/client/src/containers/Auth/strategies/RemoteAuthStrategy/externalAuthModule.ts
+++ b/designer/client/src/containers/Auth/strategies/RemoteAuthStrategy/externalAuthModule.ts
@@ -1,4 +1,4 @@
-import { ComponentType, PropsWithChildren } from "react";
+import { ForwardRefExoticComponent, PropsWithChildren, PropsWithoutRef, RefAttributes } from "react";
import { Module } from "@touk/federated-component";
interface RedirectState {
@@ -40,7 +40,7 @@ export interface ExternalAuthModule extends Module {
/**
* provides auth context for hooks
*/
- default: ComponentType>;
+ default: ForwardRefExoticComponent> & RefAttributes>;
/**
* returns auth client from context
*/
diff --git a/designer/client/src/containers/theme/nuTheme.tsx b/designer/client/src/containers/theme/nuTheme.tsx
index 35292c65956..f582563e995 100644
--- a/designer/client/src/containers/theme/nuTheme.tsx
+++ b/designer/client/src/containers/theme/nuTheme.tsx
@@ -178,28 +178,37 @@ export const nuTheme = (mode: PaletteMode, setMode: Dispatch globalStyles(theme),
},
MuiFormControl: {
+ defaultProps: {
+ variant: "standard",
+ },
styleOverrides: {
- root: {
- display: "flex",
- flexDirection: "row",
- margin: "16px 0",
+ root: ({ ownerState }) => {
+ if (ownerState.variant === "standard") {
+ return {
+ display: "flex",
+ flexDirection: "row",
+ margin: "16px 0",
+ ".MuiFormLabel-root": {
+ display: "flex",
+ flexBasis: formLabelWidth,
+ maxWidth: "20em",
+ overflowWrap: "anywhere",
+ marginTop: "9px",
+ },
+ };
+ }
},
},
},
MuiFormLabel: {
+ defaultProps: {
+ focused: false,
+ },
styleOverrides: {
root: ({ theme }) => ({
...theme.typography.body2,
- display: "flex",
- marginTop: "9px",
- flexBasis: formLabelWidth,
- maxWidth: "20em",
- overflowWrap: "anywhere",
}),
},
- defaultProps: {
- focused: false,
- },
},
MuiFormHelperText: {
styleOverrides: {
diff --git a/designer/client/src/windowManager/ContentGetter.tsx b/designer/client/src/windowManager/ContentGetter.tsx
index 05ccc81dd31..8d2fdd8d49e 100644
--- a/designer/client/src/windowManager/ContentGetter.tsx
+++ b/designer/client/src/windowManager/ContentGetter.tsx
@@ -8,6 +8,7 @@ import { NuThemeProvider } from "../containers/theme/nuThemeProvider";
import { WindowContent } from "./WindowContent";
import { WindowKind } from "./WindowKind";
import AddAttachmentDialog from "../components/modals/AddAttachmentDialog";
+import RemoteModuleDialog from "../components/RemoteModuleDialog";
const AddProcessDialog = loadable(() => import("../components/AddProcessDialog"), { fallback: });
const NodeDetails = loadable(() => import("../components/graph/node-modal/node/NodeDetails"), {
@@ -97,6 +98,8 @@ const contentGetter: React.FC> = (props) => {
return ;
case WindowKind.survey:
return ;
+ case WindowKind.remote:
+ return ;
case WindowKind.scenarioDetails:
return ;
case WindowKind.addComment:
diff --git a/designer/client/src/windowManager/WindowContent.tsx b/designer/client/src/windowManager/WindowContent.tsx
index e22f8e812a6..da28eb6d363 100644
--- a/designer/client/src/windowManager/WindowContent.tsx
+++ b/designer/client/src/windowManager/WindowContent.tsx
@@ -13,7 +13,7 @@ function cleanList>(elements: (T | null | undefin
return elements.filter(Boolean) as T[];
}
-type WindowContentProps = Omit &
+export type WindowContentProps = Omit &
PropsWithChildren<{
icon?: ReactElement;
subheader?: ReactElement;
diff --git a/designer/client/src/windowManager/WindowKind.tsx b/designer/client/src/windowManager/WindowKind.tsx
index 984fcfd2fb9..c03f0381fd6 100644
--- a/designer/client/src/windowManager/WindowKind.tsx
+++ b/designer/client/src/windowManager/WindowKind.tsx
@@ -22,4 +22,5 @@ export enum WindowKind {
modifyActivityComment,
addAttachment,
editProperties,
+ remote,
}
diff --git a/designer/server/src/main/scala/pl/touk/nussknacker/ui/config/scenariotoolbar/ToolbarPanelConfig.scala b/designer/server/src/main/scala/pl/touk/nussknacker/ui/config/scenariotoolbar/ToolbarPanelConfig.scala
index fe0f8b3b614..3245fea184c 100644
--- a/designer/server/src/main/scala/pl/touk/nussknacker/ui/config/scenariotoolbar/ToolbarPanelConfig.scala
+++ b/designer/server/src/main/scala/pl/touk/nussknacker/ui/config/scenariotoolbar/ToolbarPanelConfig.scala
@@ -52,7 +52,9 @@ final case class ToolbarPanelConfig(
title: Option[String],
buttonsVariant: Option[ToolbarButtonVariant],
buttons: Option[List[ToolbarButtonConfig]],
- hidden: Option[ToolbarCondition]
+ hidden: Option[ToolbarCondition],
+ // for custom toolbar components
+ additionalParams: Option[Map[String, String]]
) {
if (ToolbarPanelTypeConfig.requiresIdParam(`type`)) {
diff --git a/designer/server/src/main/scala/pl/touk/nussknacker/ui/process/ScenarioToolbarService.scala b/designer/server/src/main/scala/pl/touk/nussknacker/ui/process/ScenarioToolbarService.scala
index 0b8d2736e05..9ea0033c591 100644
--- a/designer/server/src/main/scala/pl/touk/nussknacker/ui/process/ScenarioToolbarService.scala
+++ b/designer/server/src/main/scala/pl/touk/nussknacker/ui/process/ScenarioToolbarService.scala
@@ -65,9 +65,10 @@ object ToolbarPanel {
`type`: ToolbarPanelType,
title: Option[String],
buttonsVariant: Option[ToolbarButtonVariant],
- buttons: Option[List[ToolbarButton]]
+ buttons: Option[List[ToolbarButton]],
+ additionalParams: Option[Map[String, String]]
): ToolbarPanel =
- ToolbarPanel(`type`.toString, title, buttonsVariant, buttons)
+ ToolbarPanel(`type`.toString, title, buttonsVariant, buttons, additionalParams)
def fromConfig(config: ToolbarPanelConfig, scenario: ScenarioWithDetailsEntity[_]): ToolbarPanel =
ToolbarPanel(
@@ -80,7 +81,8 @@ object ToolbarPanel {
verifyCondition(button.hidden, scenario)
})
.map(button => ToolbarButton.fromConfig(button, scenario))
- )
+ ),
+ config.additionalParams
)
}
@@ -90,7 +92,8 @@ final case class ToolbarPanel(
id: String,
title: Option[String],
buttonsVariant: Option[ToolbarButtonVariant],
- buttons: Option[List[ToolbarButton]]
+ buttons: Option[List[ToolbarButton]],
+ additionalParams: Option[Map[String, String]]
)
object ToolbarButton {
diff --git a/designer/server/src/test/scala/pl/touk/nussknacker/ui/api/ProcessesResourcesSpec.scala b/designer/server/src/test/scala/pl/touk/nussknacker/ui/api/ProcessesResourcesSpec.scala
index 9a3bc3c9388..9a1dd78adb9 100644
--- a/designer/server/src/test/scala/pl/touk/nussknacker/ui/api/ProcessesResourcesSpec.scala
+++ b/designer/server/src/test/scala/pl/touk/nussknacker/ui/api/ProcessesResourcesSpec.scala
@@ -1223,9 +1223,9 @@ class ProcessesResourcesSpec
toolbar shouldBe ScenarioToolbarSettings(
id = s"${toolbarConfig.uuidCode}-not-archived-scenario",
List(
- ToolbarPanel(SearchPanel, None, None, None),
- ToolbarPanel(TipsPanel, None, None, None),
- ToolbarPanel(CreatorPanel, None, None, None)
+ ToolbarPanel(SearchPanel, None, None, None, None),
+ ToolbarPanel(TipsPanel, None, None, None, None),
+ ToolbarPanel(CreatorPanel, None, None, None, None)
),
List(),
List(
@@ -1246,7 +1246,8 @@ class ProcessesResourcesSpec
disabled = false
)
)
- )
+ ),
+ None
)
),
List()
diff --git a/designer/server/src/test/scala/pl/touk/nussknacker/ui/config/scenariotoolbar/CategoriesScenarioToolbarsConfigParserSpec.scala b/designer/server/src/test/scala/pl/touk/nussknacker/ui/config/scenariotoolbar/CategoriesScenarioToolbarsConfigParserSpec.scala
index 1f2e04a6304..9d9a2c82a1d 100644
--- a/designer/server/src/test/scala/pl/touk/nussknacker/ui/config/scenariotoolbar/CategoriesScenarioToolbarsConfigParserSpec.scala
+++ b/designer/server/src/test/scala/pl/touk/nussknacker/ui/config/scenariotoolbar/CategoriesScenarioToolbarsConfigParserSpec.scala
@@ -17,7 +17,7 @@ class CategoriesScenarioToolbarsConfigParserSpec extends AnyFlatSpec with Matche
|processToolbarConfig {
| defaultConfig {
| topLeft: [
- | { type: "tips-panel", hidden: { fragment: true } }
+ | { type: "tips-panel", hidden: { fragment: true }, additionalParams: { customParam1: "value1" } }
| ]
| topRight: [
| {
@@ -56,7 +56,17 @@ class CategoriesScenarioToolbarsConfigParserSpec extends AnyFlatSpec with Matche
it should "properly create scenario toolbar configuration" in {
val defaultToolbarConfig = ScenarioToolbarsConfig(
None,
- List(ToolbarPanelConfig(TipsPanel, None, None, None, None, Some(ToolbarCondition(Some(true), None, None)))),
+ List(
+ ToolbarPanelConfig(
+ TipsPanel,
+ None,
+ None,
+ None,
+ None,
+ Some(ToolbarCondition(Some(true), None, None)),
+ Some(Map("customParam1" -> "value1"))
+ )
+ ),
Nil,
List(
ToolbarPanelConfig(
@@ -93,8 +103,9 @@ class CategoriesScenarioToolbarsConfigParserSpec extends AnyFlatSpec with Matche
None,
None
)
- )
+ ),
),
+ None,
None
)
),
@@ -103,7 +114,17 @@ class CategoriesScenarioToolbarsConfigParserSpec extends AnyFlatSpec with Matche
val categoryToolbarConfig = ScenarioToolbarsConfig(
Some(UUID.fromString("58f1acff-d864-4d66-9f86-0fa7319f7043")),
- List(ToolbarPanelConfig(TipsPanel, None, None, None, None, Some(ToolbarCondition(Some(true), None, None)))),
+ List(
+ ToolbarPanelConfig(
+ TipsPanel,
+ None,
+ None,
+ None,
+ None,
+ Some(ToolbarCondition(Some(true), None, None)),
+ Some(Map("customParam1" -> "value1"))
+ )
+ ),
Nil,
List(
ToolbarPanelConfig(
@@ -116,10 +137,11 @@ class CategoriesScenarioToolbarsConfigParserSpec extends AnyFlatSpec with Matche
ToolbarButtonConfig(ToolbarButtonConfigType.ProcessSave, None, None, None, None, None, None)
)
),
+ None,
None
)
),
- List(ToolbarPanelConfig(ActivitiesPanel, None, None, None, None, None))
+ List(ToolbarPanelConfig(ActivitiesPanel, None, None, None, None, None, None))
)
val testingConfigs = Table(
diff --git a/designer/server/src/test/scala/pl/touk/nussknacker/ui/process/ConfigScenarioToolbarServiceSpec.scala b/designer/server/src/test/scala/pl/touk/nussknacker/ui/process/ConfigScenarioToolbarServiceSpec.scala
index 2aefd305ba4..b997e1cf699 100644
--- a/designer/server/src/test/scala/pl/touk/nussknacker/ui/process/ConfigScenarioToolbarServiceSpec.scala
+++ b/designer/server/src/test/scala/pl/touk/nussknacker/ui/process/ConfigScenarioToolbarServiceSpec.scala
@@ -198,8 +198,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
ScenarioToolbarSettings(
id,
List(
- ToolbarPanel(CreatorPanel, None, None, None),
- ToolbarPanel(ActivitiesPanel, None, None, None),
+ ToolbarPanel(CreatorPanel, None, None, None, None),
+ ToolbarPanel(ActivitiesPanel, None, None, None, None),
),
Nil,
List(
@@ -234,7 +234,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
disabled = false
)
)
- )
+ ),
+ None
),
ToolbarPanel(
"buttons2",
@@ -244,7 +245,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
List(
ToolbarButton(ProcessCancel, None, None, None, None, disabled = false)
)
- )
+ ),
+ None
)
),
List.empty,
@@ -253,8 +255,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
ScenarioToolbarSettings(
id,
List(
- ToolbarPanel(CreatorPanel, None, None, None),
- ToolbarPanel(ActivitiesPanel, None, None, None)
+ ToolbarPanel(CreatorPanel, None, None, None, None),
+ ToolbarPanel(ActivitiesPanel, None, None, None, None)
),
Nil,
List(
@@ -289,7 +291,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
disabled = false
)
)
- )
+ ),
+ None
)
),
List.empty,
@@ -298,7 +301,7 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
ScenarioToolbarSettings(
id,
List(
- ToolbarPanel(ActivitiesPanel, None, None, None),
+ ToolbarPanel(ActivitiesPanel, None, None, None, None),
),
Nil,
List(
@@ -333,7 +336,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
disabled = false
)
)
- )
+ ),
+ None
),
ToolbarPanel(
"buttons1",
@@ -344,7 +348,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
ToolbarButton(ProcessDeploy, None, None, None, None, disabled = false),
ToolbarButton(ProcessPDF, None, None, None, None, disabled = false)
)
- )
+ ),
+ None
),
ToolbarPanel(
"buttons2",
@@ -354,7 +359,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
List(
ToolbarButton(ProcessCancel, None, None, None, None, disabled = false)
)
- )
+ ),
+ None
)
),
List.empty,
@@ -363,8 +369,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
ScenarioToolbarSettings(
id,
List(
- ToolbarPanel(CreatorPanel, None, None, None),
- ToolbarPanel(ActivitiesPanel, None, None, None)
+ ToolbarPanel(CreatorPanel, None, None, None, None),
+ ToolbarPanel(ActivitiesPanel, None, None, None, None)
),
Nil,
List(
@@ -399,7 +405,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
disabled = true
)
)
- )
+ ),
+ None
),
ToolbarPanel(
"buttons1",
@@ -409,7 +416,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
List(
ToolbarButton(ProcessDeploy, None, None, None, None, disabled = false)
)
- )
+ ),
+ None
)
),
List.empty,
@@ -418,7 +426,7 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
ScenarioToolbarSettings(
id,
List(
- ToolbarPanel(TipsPanel, None, None, None)
+ ToolbarPanel(TipsPanel, None, None, None, None)
),
Nil,
List(
@@ -453,7 +461,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
disabled = false
)
)
- )
+ ),
+ None
),
ToolbarPanel(
"buttons2",
@@ -463,7 +472,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
List(
ToolbarButton(ProcessCancel, None, None, None, None, disabled = false)
)
- )
+ ),
+ None
)
),
Nil
@@ -472,7 +482,7 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
ScenarioToolbarSettings(
id,
List(
- ToolbarPanel(ActivitiesPanel, None, None, None)
+ ToolbarPanel(ActivitiesPanel, None, None, None, None)
),
Nil,
List(
@@ -507,7 +517,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
disabled = false
)
)
- )
+ ),
+ None
),
ToolbarPanel(
"buttons2",
@@ -517,7 +528,8 @@ class ConfigScenarioToolbarServiceSpec extends AnyFlatSpec with Matchers {
List(
ToolbarButton(ProcessCancel, None, None, None, None, disabled = false)
)
- )
+ ),
+ None
)
),
List.empty,