From b57c7cf393b96a3aa580a2aeaac6454689c73d39 Mon Sep 17 00:00:00 2001 From: Carita Date: Wed, 7 Aug 2024 13:18:37 -0700 Subject: [PATCH] #2088 Include actions in properties title editor (#2089) Signed-off-by: Carita Ou --- .../components/title-editor-test.js | 38 ++++++++++++-- .../paramDefs/action_paramDef.json | 7 ++- .../actions/button/button.jsx | 1 + .../components/title-editor/title-editor.jsx | 30 ++++++++++-- .../components/title-editor/title-editor.scss | 28 ++++++++++- .../src/common-properties/form/Form.js | 8 ++- .../src/common-properties/form/PropertyDef.js | 10 +++- .../src/common-properties/form/TitleInfo.js | 49 +++++++++++++++++++ .../properties-main/properties-main.jsx | 1 + .../properties-main/properties-main.scss | 3 ++ .../parameterDefs/action_paramDef.json | 7 ++- 11 files changed, 168 insertions(+), 14 deletions(-) create mode 100644 canvas_modules/common-canvas/src/common-properties/form/TitleInfo.js diff --git a/canvas_modules/common-canvas/__tests__/common-properties/components/title-editor-test.js b/canvas_modules/common-canvas/__tests__/common-properties/components/title-editor-test.js index d6275de62d..8857e4d0ba 100644 --- a/canvas_modules/common-canvas/__tests__/common-properties/components/title-editor-test.js +++ b/canvas_modules/common-canvas/__tests__/common-properties/components/title-editor-test.js @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Elyra Authors + * Copyright 2017-2024 Elyra Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,12 @@ import { expect } from "chai"; import { expect as expectJest } from "@jest/globals"; import sinon from "sinon"; import { renderWithIntl } from "../../_utils_/intl-utils"; -import { fireEvent } from "@testing-library/react"; +import { fireEvent, within } from "@testing-library/react"; -const controller = new Controller(); +import propertyUtilsRTL from "../../_utils_/property-utilsRTL"; +import ACTION_PARAMDEF from "../../test_resources/paramDefs/action_paramDef.json"; + +let controller = new Controller(); controller.setTitle("test title"); const form = { componentId: "test-id" @@ -400,3 +403,32 @@ describe("title-editor renders correctly", () => { expect(titleEditor).to.have.length(0); }); }); + +describe("Title editor actions", () => { + let renderedObject; + beforeEach(() => { + renderedObject = propertyUtilsRTL.flyoutEditorForm(ACTION_PARAMDEF); + controller = new Controller(); + }); + + it("title editor should render actions if defined", () => { + const spyPropertyActionHandler = sinon.spy(); + renderedObject = propertyUtilsRTL.flyoutEditorForm(ACTION_PARAMDEF, null, { actionHandler: spyPropertyActionHandler }, { appData: appData }); + const { container } = renderedObject.wrapper; + const actions = container.querySelector(".properties-title-editor-actions"); + const buttons = within(actions).getAllByRole("button"); + expect(buttons.length).to.equal(2); + + expect(buttons[0].textContent).to.equal("Increment"); + expect(buttons[1].textContent).to.equal("Decrement"); + + fireEvent.click(buttons[0]); + + expect(spyPropertyActionHandler.calledOnce).to.equal(true); + expect(spyPropertyActionHandler.calledWith( + ACTION_PARAMDEF.uihints.title_info.action_refs[0], + appData, + { parameter_ref: "number" } + )).to.be.true; + }); +}); diff --git a/canvas_modules/common-canvas/__tests__/test_resources/paramDefs/action_paramDef.json b/canvas_modules/common-canvas/__tests__/test_resources/paramDefs/action_paramDef.json index 899be402d2..d6934ecbae 100644 --- a/canvas_modules/common-canvas/__tests__/test_resources/paramDefs/action_paramDef.json +++ b/canvas_modules/common-canvas/__tests__/test_resources/paramDefs/action_paramDef.json @@ -155,6 +155,12 @@ "label": { "default": "Action Test" }, + "title_info": { + "action_refs": [ + "increment", + "decrement" + ] + }, "parameter_info": [ { "parameter_ref": "number", @@ -360,7 +366,6 @@ } ], "action_info": [ - { "id": "increment", "label": { diff --git a/canvas_modules/common-canvas/src/common-properties/actions/button/button.jsx b/canvas_modules/common-canvas/src/common-properties/actions/button/button.jsx index 8de19976e1..3181cdcb20 100644 --- a/canvas_modules/common-canvas/src/common-properties/actions/button/button.jsx +++ b/canvas_modules/common-canvas/src/common-properties/actions/button/button.jsx @@ -82,6 +82,7 @@ class ButtonAction extends React.Component { kind={actionButtonKind} onClick={this.applyAction} disabled={disabled} + title={this.props.action.label.text} > {this.props.action.label.text} diff --git a/canvas_modules/common-canvas/src/common-properties/components/title-editor/title-editor.jsx b/canvas_modules/common-canvas/src/common-properties/components/title-editor/title-editor.jsx index 86cb26b0a6..c1d985184a 100644 --- a/canvas_modules/common-canvas/src/common-properties/components/title-editor/title-editor.jsx +++ b/canvas_modules/common-canvas/src/common-properties/components/title-editor/title-editor.jsx @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Elyra Authors + * Copyright 2017-2024 Elyra Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,14 +17,16 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; import { connect } from "react-redux"; -import { setTitle } from "./../../actions"; import Isvg from "react-inlinesvg"; import { get } from "lodash"; +import classNames from "classnames"; +import { Help, Edit, Close } from "@carbon/react/icons"; import { TextInput, Button, Layer } from "@carbon/react"; + +import { setTitle } from "./../../actions"; import { MESSAGE_KEYS, CONDITION_MESSAGE_TYPE } from "./../../constants/constants"; import * as PropertyUtils from "./../../util/property-utils"; -import classNames from "classnames"; -import { Help, Edit, Close } from "@carbon/react/icons"; +import ActionFactory from "../../actions/action-factory.js"; class TitleEditor extends Component { @@ -92,6 +94,24 @@ class TitleEditor extends Component { this.props.setTitle(newTitle); } + createTitleActions() { + if (this.props.titleInfo && this.props.titleInfo.Title.actionIds().length > 0) { + this.actionFactory = new ActionFactory(this.props.controller); + const actions = []; + this.props.titleInfo.Title.actionIds().forEach((actionRef, idx) => { + const actionMetadata = this.props.controller.getAction({ name: actionRef }); + const action = this.actionFactory.generateAction(`${actionRef}-${idx}`, actionMetadata); + actions.push(
+ {action} +
); + }); + return (
+ {actions} +
); + } + return null; + } + render() { if (this.props.title === null) { return null; @@ -204,6 +224,7 @@ class TitleEditor extends Component { {titleValidationTypes.includes(get(this.state.titleValidation, "type")) ? null : propertiesTitleEdit} {!this.headingEnabled && !titleValidationTypes.includes(get(this.state.titleValidation, "type")) ? helpButton : null} + {this.createTitleActions()} ); } @@ -219,6 +240,7 @@ TitleEditor.propTypes = { heading: PropTypes.string, showHeading: PropTypes.bool, rightFlyoutTabsView: PropTypes.bool, + titleInfo: PropTypes.object, title: PropTypes.string, // set by redux setTitle: PropTypes.func // set by redux }; diff --git a/canvas_modules/common-canvas/src/common-properties/components/title-editor/title-editor.scss b/canvas_modules/common-canvas/src/common-properties/components/title-editor/title-editor.scss index df62a552da..f2c2852dcf 100644 --- a/canvas_modules/common-canvas/src/common-properties/components/title-editor/title-editor.scss +++ b/canvas_modules/common-canvas/src/common-properties/components/title-editor/title-editor.scss @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Elyra Authors + * Copyright 2017-2024 Elyra Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,32 @@ font-size: 0; padding: $spacing-05 0; border-bottom: 1px $layer-accent-01 solid; + + .properties-title-editor-actions { + padding: $spacing-05 0 0 $spacing-05; + + .properties-action-button { + padding-bottom: $spacing-05; + width: 100%; + + button { + width: 100%; + overflow: hidden; + white-space: nowrap; + display: block; + text-overflow: ellipsis; + } + + .cds--btn { // Override Carbon padding within a button to allow more text to display + --cds-layout-density-padding-inline-local: 0; + padding: 6px 15px; + } + } + + .properties-action-image { + padding: 0; + } + } } .properties-title-right-flyout-tabs-view { diff --git a/canvas_modules/common-canvas/src/common-properties/form/Form.js b/canvas_modules/common-canvas/src/common-properties/form/Form.js index 826d1746f2..639915b3d6 100644 --- a/canvas_modules/common-canvas/src/common-properties/form/Form.js +++ b/canvas_modules/common-canvas/src/common-properties/form/Form.js @@ -24,7 +24,7 @@ import { Size } from "../constants/form-constants"; import { CONTAINER_TYPE } from "../constants/constants"; export default class Form { - constructor(componentId, label, labelEditable, help, editorSize, pixelWidth, uiItems, buttons, data, conditions, resources, icon, heading) { + constructor(componentId, label, labelEditable, help, editorSize, pixelWidth, uiItems, buttons, data, conditions, resources, icon, heading, title) { this.componentId = componentId; this.label = label; this.labelEditable = labelEditable; @@ -38,6 +38,9 @@ export default class Form { this.resources = resources; this.icon = icon; this.heading = heading; + if (title) { + this.title = title; + } } /** @@ -79,7 +82,8 @@ export default class Form { translateMessages(conditions, l10nProvider), resources, propDef.icon, - l10nProvider.l10nResource(propDef.heading) + l10nProvider.l10nResource(propDef.heading), + propDef.titleMetadata ); } return null; diff --git a/canvas_modules/common-canvas/src/common-properties/form/PropertyDef.js b/canvas_modules/common-canvas/src/common-properties/form/PropertyDef.js index 531d816566..37ea96bd8a 100644 --- a/canvas_modules/common-canvas/src/common-properties/form/PropertyDef.js +++ b/canvas_modules/common-canvas/src/common-properties/form/PropertyDef.js @@ -14,6 +14,7 @@ * limitations under the License. */ +import { TitleMetadata } from "./TitleInfo"; import { GroupMetadata } from "./GroupInfo"; import { ActionMetadata } from "./ActionInfo"; import { ParameterMetadata } from "./ParameterInfo"; @@ -24,7 +25,9 @@ import { ResourceDef } from "../util/L10nProvider"; import { propertyOf } from "lodash"; export class PropertyDef { - constructor(cname, icon, editorSize, pixelWidth, label, labelEditable, help, description, structureMetadata, parameterMetadata, groupMetadata, actionMetadata, heading) { + constructor(cname, icon, editorSize, pixelWidth, label, labelEditable, help, + description, structureMetadata, parameterMetadata, groupMetadata, + actionMetadata, heading, titleMetadata) { this.name = cname; this.icon = icon; this.editorSize = editorSize; @@ -38,6 +41,7 @@ export class PropertyDef { this.groupMetadata = groupMetadata; this.actionMetadata = actionMetadata; this.heading = heading; + this.titleMetadata = titleMetadata; } /** @@ -61,6 +65,7 @@ export class PropertyDef { propertyOf(uihints)("parameter_info"), propertyOf(uihints)("ui_parameters")); const actionMetadata = ActionMetadata.makeActionMetadata(propertyOf(uihints)("action_info")); const groupMetadata = GroupMetadata.makeGroupMetadata(propertyOf(uihints)("group_info"), parameterMetadata.getParameters()); + const titleMetadata = TitleMetadata.makeTitleMetadata(propertyOf(uihints)("title_info")); const label = titleDefinition && titleDefinition.title ? titleDefinition.title : null; const labelEditable = titleDefinition && typeof titleDefinition.editable !== "undefined" ? titleDefinition.editable : DEFAULT_LABEL_EDITABLE; @@ -78,7 +83,8 @@ export class PropertyDef { parameterMetadata, groupMetadata, actionMetadata, - propertyOf(uihints)("label") + propertyOf(uihints)("label"), + titleMetadata ); } } diff --git a/canvas_modules/common-canvas/src/common-properties/form/TitleInfo.js b/canvas_modules/common-canvas/src/common-properties/form/TitleInfo.js new file mode 100644 index 0000000000..43b4dca2bb --- /dev/null +++ b/canvas_modules/common-canvas/src/common-properties/form/TitleInfo.js @@ -0,0 +1,49 @@ +/* + * Copyright 2024 Elyra Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { propertyOf } from "lodash"; + +class Title { + constructor(title) { + this.actions = title.action_refs || []; + } + + static makeTitle(uiGroup) { + if (uiGroup) { + return new Title( + propertyOf(uiGroup)("action_refs") + ); + } + return null; + } + + actionIds() { + return this.actions; + } +} + +export class TitleMetadata { + constructor(title) { + this.Title = title; + } + + static makeTitleMetadata(title) { + if (title) { + return new TitleMetadata(new Title(title)); + } + return null; + } +} diff --git a/canvas_modules/common-canvas/src/common-properties/properties-main/properties-main.jsx b/canvas_modules/common-canvas/src/common-properties/properties-main/properties-main.jsx index 98a4b7172d..01a7ef77c6 100644 --- a/canvas_modules/common-canvas/src/common-properties/properties-main/properties-main.jsx +++ b/canvas_modules/common-canvas/src/common-properties/properties-main/properties-main.jsx @@ -477,6 +477,7 @@ class PropertiesMain extends React.Component { icon={formData.icon} heading={formData.heading} showHeading={this.props.propertiesConfig.heading} + titleInfo={formData.title} rightFlyoutTabsView={this.props.propertiesConfig.categoryView === CATEGORY_VIEW.TABS} />); diff --git a/canvas_modules/common-canvas/src/common-properties/properties-main/properties-main.scss b/canvas_modules/common-canvas/src/common-properties/properties-main/properties-main.scss index 422e0578e9..9264ff8280 100644 --- a/canvas_modules/common-canvas/src/common-properties/properties-main/properties-main.scss +++ b/canvas_modules/common-canvas/src/common-properties/properties-main/properties-main.scss @@ -25,6 +25,9 @@ $properties-modal-buttons-height: $spacing-10; overflow: hidden; border-left: 1px solid $layer-accent-01; outline: none; + display: flex; + flex-direction: column; + &.properties-small { width: $common-properties-small-flyout-width; } diff --git a/canvas_modules/harness/test_resources/parameterDefs/action_paramDef.json b/canvas_modules/harness/test_resources/parameterDefs/action_paramDef.json index 899be402d2..d6934ecbae 100644 --- a/canvas_modules/harness/test_resources/parameterDefs/action_paramDef.json +++ b/canvas_modules/harness/test_resources/parameterDefs/action_paramDef.json @@ -155,6 +155,12 @@ "label": { "default": "Action Test" }, + "title_info": { + "action_refs": [ + "increment", + "decrement" + ] + }, "parameter_info": [ { "parameter_ref": "number", @@ -360,7 +366,6 @@ } ], "action_info": [ - { "id": "increment", "label": {