Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] configurable process toolbars #1702

Merged
merged 15 commits into from
Jul 1, 2021
Merged
166 changes: 166 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,172 @@ categoriesConfig: {
For each category you have to define its processing type (`streaming` in examples above). You can read about processing
types and their configurations below.

### Process Toolbar Configuration

Toolbars and buttons at process window are configurable, you can configure params:

* uuid - optional uuid identifier which determines unique code for FE localstorage cache,
default: null - we generate uuid from hashcode config
* topLeft - optional top left panel, default: empty list
* bottomLeft - optional bottom left panel, default: empty list
* topRight - optional top right panel, default: empty list
* bottomRight - optional bottom right panel, default: empty list

Example configuration:

```
processToolbarConfig {
defaultConfig {
topLeft: [
{ type: "tips-panel" }
]
topRight: [
{
type: "process-info-panel"
buttons: [
{ type: "process-save", disabled: { subprocess: false, archived: true, type: "oneof" } }
{ type: "custom-link", title: "Metrics for $processName", url: "/metrics/$processId" }
]
}
]
}
}
```

We can also create special configuration for each category by:
```
processToolbarConfig {
categoryConfig {
"CategoryName" {
id: "58f1acff-d864-4d66-9f86-0fa7319f7043"
topLeft: [
{ type: "creator-panel", hidden: {subprocess: true, archived: false, type: "allof"} }
]
}
}
}
```

#### Toolbar Panel Conditioning

Configuration allow us to:
* hiding panels
* hiding or disabling buttons

Each of this function can be configured by condition expression where we can use three parameters:
* `subprocess: boolean` - if true then condition match only subprocess, by default ignored
* `archived: boolean` - if true then condition match only archived, by default ignored
* `type: allof / oneof` - information about that checked will be only one condition or all conditions

#### Toolbar Panel Templating

Configuration allows to templating params like:
* `name` - available only on Buttons
* `title`- available on Panels and Buttons
* `url` - available only on CustomLink and CustomAction buttons
* `icon`- available only on Buttons

Right now we allow to template two elements:
* process id -`$processId`
* process name - `$processName`

Example usage:
* `title: "Metrics for $processName"`
* `name: "deploy $processName"`
* `url: "/metrics/$processId" `
* `icon: "/assets/process-icon-$processId"`

#### Default Process Panel Configuration

```
processToolbarConfig {
defaultConfig {
topLeft: [
{ type: "tips-panel" }
{ type: "creator-panel", hidden: { archived: true } }
{ type: "versions-panel" }
{ type: "comments-panel" }
{ type: "attachments-panel" }
]
topRight: [
{
type: "process-info-panel"
buttons: [
{ type: "process-save", title: "Save changes", disabled: { archived: true } }
{ type: "process-deploy", disabled: { subprocess: true, archived: true, type: "oneof" } }
{ type: "process-cancel", disabled: { subprocess: true, archived: true, type: "oneof" } }
{ type: "custom-link", name: "metrics", icon: "/assets/buttons/metrics.svg", url: "/metrics/$processName", disabled: { subprocess: true } }
]
}
{
id: "view-panel"
type: "buttons-panel"
title: "view"
buttons: [
{ type: "view-business-view" }
{ type: "view-zoom-in" }
{ type: "view-zoom-out" }
{ type: "view-reset" }
]
}
{
id: "edit-panel"
type: "buttons-panel"
title: "edit"
hidden: { archived: true }
buttonsVariant: "small"
buttons: [
{ type: "edit-undo" }
{ type: "edit-redo" }
{ type: "edit-copy" }
{ type: "edit-paste" }
{ type: "edit-delete" }
{ type: "edit-layout" }
]
}
{
id: "process-panel"
type: "buttons-panel"
title: "process"
buttons: [
{ type: "process-properties", hidden: { subprocess: true } }
{ type: "process-compare" }
{ type: "process-migrate", disabled: { archived: true } }
{ type: "process-import", disabled: { archived: true } }
{ type: "process-json" }
{ type: "process-pdf" }
{ type: "process-archive", hidden: { archived: true } }
{ type: "process-unarchive", hidden: { archived: false } }
]
}
{
id: "test-panel"
type: "buttons-panel"
title: "test"
hidden: { subprocess: true }
buttons: [
{ type: "test-from-file", disabled: { archived: true } }
{ type: "test-generate", disabled: { archived: true } }
{ type: "test-counts" }
{ type: "test-hide" }
]
}
{
id: "group-panel"
type: "buttons-panel"
title: "group"
hidden: { archived: true }
buttons: [
{ type: "group" }
{ type: "ungroup" }
]
}
{ type: "details-panel" }
]
}
}
```

###Monitoring config
```
metricsSettings {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package pl.touk.nussknacker.engine.util.config

import java.io.File
import java.net.{URI, URL, URLConnection, URLStreamHandler, URLStreamHandlerFactory}
import java.net.{URI, URL}
import com.typesafe.config.Config
import net.ceedubs.ficus.{FicusConfig, SimpleFicusConfig}
import net.ceedubs.ficus.readers._

import java.util.UUID
import scala.language.implicitConversions
import scala.util.Try

Expand All @@ -21,6 +22,9 @@ object CustomFicusInstances extends AnyValReaders with StringReader with SymbolR

implicit val urlValueReader: ValueReader[URL] = uriValueReader.map(_.toURL)

implicit val uuidValueReader: ValueReader[UUID] = ValueReader[String]
.map(value => UUID.fromString(value))

implicit def toFicusConfig(config: Config): FicusConfig = SimpleFicusConfig(config)

}
1 change: 1 addition & 0 deletions ui/client/actions/nk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export * from "./urlChange"
export * from "./zoom"
export * from "./nodeDetails"
export {saveProcess} from "./processUtils/saveProcess"
export {loadProcessToolbarsConfiguration} from "./loadProcessToolbarsConfiguration"
10 changes: 10 additions & 0 deletions ui/client/actions/nk/loadProcessToolbarsConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {ThunkAction} from "../reduxTypes"
import HttpService from "../../http/HttpService"

export function loadProcessToolbarsConfiguration(processId): ThunkAction {
return (dispatch) =>
HttpService.fetchProcessToolbarsConfiguration(processId).then((response) => dispatch({
type: "PROCESS_TOOLBARS_CONFIGURATION_LOADED",
data: response.data,
}))
}
9 changes: 8 additions & 1 deletion ui/client/actions/nk/toolbars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {getToolbarsInitData} from "../../reducers/selectors/toolbars"
import {ToolbarsSide} from "../../reducers/toolbars"
import {ThunkAction} from "../reduxTypes"
import {Toolbar} from "../../components/toolbarComponents/toolbar"
import {WithId} from "../../types/common"
import {ToolbarsConfig} from "../../components/toolbarSettings/types"

export type ToolbarPosition = [ToolbarsSide | string, number]

Expand All @@ -11,8 +13,12 @@ type MoveToolbarAction = { type: "MOVE_TOOLBAR", from: ToolbarPosition, to: Tool
type ToggleToolbarAction = { type: "TOGGLE_TOOLBAR", id: string, isCollapsed: boolean }
type ToggleToolboxGroupAction = { type: "TOGGLE_NODE_TOOLBOX_GROUP", nodeGroup: string }
type ToggleAllToolbarsAction = { type: "TOGGLE_ALL_TOOLBARS", isCollapsed: boolean }
type ProcessToolbarsConfigurationAction = { type: "PROCESS_TOOLBARS_CONFIGURATION_LOADED", data: WithId<ToolbarsConfig> }

export const toggleAllToolbars = (isCollapsed: boolean): ToggleAllToolbarsAction => ({type: "TOGGLE_ALL_TOOLBARS", isCollapsed})
export const toggleAllToolbars = (isCollapsed: boolean): ToggleAllToolbarsAction => ({
type: "TOGGLE_ALL_TOOLBARS",
isCollapsed
})

export const resetToolbars = (): ThunkAction => {
return (dispatch, getState) => {
Expand Down Expand Up @@ -57,3 +63,4 @@ export type ToolbarActions =
| ToggleToolbarAction
| ToggleAllToolbarsAction
| ToggleToolboxGroupAction
| ProcessToolbarsConfigurationAction
24 changes: 24 additions & 0 deletions ui/client/components/UrlIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, {PropsWithChildren, useEffect, useState} from "react"
import * as LoaderUtils from "../common/LoaderUtils"
import {absoluteBePath} from "../common/UrlUtils"

function UrlIcon({path, title, children}: PropsWithChildren<{path?: string, title?: string}>) {
const [error, setError] = useState(!path)

useEffect(() => {
setError(!path)
}, [path])

if (error) {
return <>{children}</>
}

try {
const svgContent = LoaderUtils.loadSvgContent(path)
return <div dangerouslySetInnerHTML={{__html: svgContent}}/>
} catch (e) {
return <img onError={() => setError(true)} src={absoluteBePath(path)} title={title} />
}
}

export default UrlIcon
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@ interface Props {
write?: boolean,
change?: boolean,
deploy?: boolean,
hide?: boolean,
}

export function CapabilitiesToolbarButton({deploy, change, write, ...props}: ToolbarButtonProps & Props): JSX.Element | null {
export function CapabilitiesToolbarButton({deploy, change, write, disabled, hide, ...props}: ToolbarButtonProps & Props): JSX.Element | null {
const capabilities = useSelector(getCapabilities)
const checks = {deploy, change, write}
const hiddenByCapabilities = Object.keys(capabilities).some(key => checks[key] && !capabilities[key])

if (Object.keys(capabilities).some(key => checks[key] && !capabilities[key])) {
if (hide && hiddenByCapabilities) {
return null
}

return <ToolbarButton {...props}/>
const overridesProps = {...props, ...{disabled: disabled || hiddenByCapabilities}}

return <ToolbarButton {...overridesProps} />
}
20 changes: 8 additions & 12 deletions ui/client/components/toolbarSettings/TOOLBAR_COMPONENTS_MAP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,22 @@ import {CreatorPanel} from "../toolbars/creator/CreatorPanel"
import {DefaultToolbarPanel, ToolbarPanelProps} from "../toolbarComponents/DefaultToolbarPanel"
import DetailsPanel from "../toolbars/details/DetailsPanel"
import ProcessInfo from "../toolbars/status/ProcessInfo"
import TestPanel from "../toolbars/test/TestPanel"
import {UserSettingsPanel} from "../toolbars/UserSettingsPanel"
import {VersionsPanel} from "../toolbars/VersionsPanel"

export const TOOLBAR_COMPONENTS_MAP: Record<string, ComponentType<ToolbarPanelProps>> = {
DefaultPanel: DefaultToolbarPanel,

// only small changes from default
"TEST-PANEL": TestPanel,

// custom with buttons
"PROCESS-INFO": ProcessInfo,
"process-info-panel": ProcessInfo,

// no buttons at all
"DETAILS-PANEL": DetailsPanel,
"TIPS-PANEL": TipsPanel,
"CREATOR-PANEL": CreatorPanel,
"VERSIONS-PANEL": VersionsPanel,
"COMMENTS-PANEL": CommentsPanel,
"ATTACHMENTS-PANEL": AttachmentsPanel,
"USER-SETTINGS-PANEL": UserSettingsPanel,
"details-panel": DetailsPanel,
"tips-panel": TipsPanel,
"creator-panel": CreatorPanel,
"versions-panel": VersionsPanel,
"comments-panel": CommentsPanel,
"attachments-panel": AttachmentsPanel,
"user-settings-panel": UserSettingsPanel,
}

19 changes: 9 additions & 10 deletions ui/client/components/toolbarSettings/buttons/BuiltinButtonTypes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
export enum BuiltinButtonTypes {
processSave = "process-save",
deploy = "deploy",
deployCanel = "deploy-canel",
deployMetrics = "deploy-metrics",
processDeploy = "process-deploy",
processCancel = "process-cancel",
editUndo = "edit-undo",
editRedo = "edit-redo",
editCopy = "edit-copy",
Expand All @@ -11,21 +10,21 @@ export enum BuiltinButtonTypes {
editLayout = "edit-layout",
group = "group",
ungroup = "ungroup",
editProperties = "edit-properties",
processProperties = "process-properties",
processCompare = "process-compare",
processMigrate = "process-migrate",
processImport = "process-import",
processJSON = "process-JSON",
processPDF = "process-PDF",
processJSON = "process-json",
processPDF = "process-pdf",
processArchiveToggle = "process-archive-toggle",
processArchive = "process-archive",
processUnarchive = "process-unarchive",
testFromFile = "test-fromFile",
testFromFile = "test-from-file",
testGenerate = "test-generate",
testCounts = "test-counts",
testHide = "test-hide",
viewBussinesView = "view-bussinesView",
viewZoomIn = "view-zoomIn",
viewZoomOut = "view-zoomOut",
viewBusinessView = "view-business-view",
viewZoomIn = "view-zoom-in",
viewZoomOut = "view-zoom-out",
viewReset = "view-reset"
}
Loading