diff --git a/assets/flow-builder-action-customer-group.png b/assets/flow-builder-action-customer-group.png new file mode 100644 index 000000000..1fd4004bf Binary files /dev/null and b/assets/flow-builder-action-customer-group.png differ diff --git a/assets/flow-builder-action-error.png b/assets/flow-builder-action-error.png new file mode 100644 index 000000000..95977ebdf Binary files /dev/null and b/assets/flow-builder-action-error.png differ diff --git a/assets/flow-builder-action-no-label.png b/assets/flow-builder-action-no-label.png index c664704c4..092938691 100644 Binary files a/assets/flow-builder-action-no-label.png and b/assets/flow-builder-action-no-label.png differ diff --git a/assets/flow-builder-action-then.png b/assets/flow-builder-action-then.png index bb0f44c7d..33c381919 100644 Binary files a/assets/flow-builder-action-then.png and b/assets/flow-builder-action-then.png differ diff --git a/assets/flow-builder-demo.gif b/assets/flow-builder-demo.gif index 62bdcaf9d..00eadb7c8 100644 Binary files a/assets/flow-builder-demo.gif and b/assets/flow-builder-demo.gif differ diff --git a/assets/flow-builder-tag-result.png b/assets/flow-builder-tag-result.png index ee5d77fc6..3c15f68cf 100644 Binary files a/assets/flow-builder-tag-result.png and b/assets/flow-builder-tag-result.png differ diff --git a/assets/flow-builder-tag.png b/assets/flow-builder-tag.png index 8545c70bb..f810ea889 100644 Binary files a/assets/flow-builder-tag.png and b/assets/flow-builder-tag.png differ diff --git a/assets/flow-builder-trigger-action.png b/assets/flow-builder-trigger-action.png index 46267e16d..9d8ba8f1b 100644 Binary files a/assets/flow-builder-trigger-action.png and b/assets/flow-builder-trigger-action.png differ diff --git a/assets/flow-builder-trigger-drop.png b/assets/flow-builder-trigger-drop.png index 629a26ece..417c17632 100644 Binary files a/assets/flow-builder-trigger-drop.png and b/assets/flow-builder-trigger-drop.png differ diff --git a/guides/plugins/plugins/framework/flow/add-flow-builder-action.md b/guides/plugins/plugins/framework/flow/add-flow-builder-action.md index 83df3ef0c..2d162a1b0 100644 --- a/guides/plugins/plugins/framework/flow/add-flow-builder-action.md +++ b/guides/plugins/plugins/framework/flow/add-flow-builder-action.md @@ -314,7 +314,7 @@ Well done, you are successfully created your custom action in Backend in PHP. After we are done with the PHP code, `action.create.tag` is received from the response of `/api/_info/flow-actions.json`. However, the custom action displays in the action list without label. These further steps in Administration will help you show the action label and add configuration for it. -To see action list, we select a Trigger, for example [Example\Event] from the Trigger drop-down in the Flow tab. After that, we choose option `ACTION (THEN)`. A action component appears with action list. +To see action list, we select a Trigger, for example [example\event] from the Trigger drop-down in the Flow tab. After that, we choose option `ACTION (THEN)`. A action component appears with action list. ![Flow Builder trigger](../../../../../assets/flow-builder-trigger-drop.png) @@ -323,114 +323,168 @@ To see action list, we select a Trigger, for example [Example\Event] from the Tr ![Flow Builder trigger](../../../../../assets/flow-builder-action-no-label.png) ### Step 1: Show action label in action list - -First, we need to define some information like `icon`, `label`, `actionName` of action in `main.js`. To be consistent with the custom action defined in our PHP code, also create an action name called `CREATE_TAG` to represent `action.create.tag`, which gets from the response of `/api/_info/flow-actions.json`. +First, we need to define some information like `constants`, `snippets` to show on action list. To be consistent with the custom action defined in our PHP code, also create an action name called `CREATE_TAG` to represent `action.create.tag`, which gets from the response of `/api/_info/flow-actions.json`. ![Flow Builder action services list](../../../../../assets/flow-builder-action-sevices-list.png) ```jsx -// /src/Resources/app/administration/src/main.js -Shopware.Service('flowBuilderService').addIcons({ - addEntityTag: 'regular-tag', +// src/Resources/app/administration/src/constant/create-tag-action.constant.js +export const ACTION = Object.freeze({ + CREATE_TAG: 'action.create.tag', }); -Shopware.Service('flowBuilderService').addLabels({ - addEntityTag: 'sw-flow.actions.addTag', -}); +export const GROUP = 'customer' -Shopware.Service('flowBuilderService').addActionNames({ - ADD_TAG: 'action.create.tag', -}); +export default { + ACTION, GROUP +}; ``` And then add snippets for labels: ```jsx -// /src/Resources/app/administration/src/snippet/en-GB.json +// src/Resources/app/administration/src/snippet/en-GB.json { - "sw-flow": { - "actions": { - "addTag": 'Create tag' - } + "create-tag-action": { + "titleCreateTag": "Create tag", + "labelTags": "Tags", + "placeholderTags": "Enter tags", + "buttonSaveAction": "Save action", + "buttonAddAction": "Add action", + "descriptionTags": "Tags: {tags}" } } ``` Do it as the same with `de-DE.json` file for translation of DE language. -**Grouping Actions** - -If you want your action on the Tag group, add this line to the `main.js` file above. - -```jsx - -Shopware.Service('flowBuilderService').addActionGroupMapping({ - 'action.create.tag': 'tag', -}); -``` - -Otherwise, by default, it will be on the General group. - -| Group Name | Group Headline | -| :--- | :--- | -| general | General| -| tag | Tag | -| customer | Customer | -| order | Order | - -Here is the result for the after the **Step 1**. - -![Choose a Flow Builder Action](../../../../../assets/flow-builder-trigger-action.png) - -### Step 2: Add configuration for action - -First, we need to customize `modalName` computed for the configuration modal to ensure your selected action matches your new action. After that, the description should be generated from your custom description. In the core, we had `getActionDescriptions` method, which handles description generation, so you have to override that method to show the action in the configuration description. +After that we also need to override the `sw-flow-sequence-action` component in the core: ```jsx // /src/Resources/app/administration/src/extension/sw-flow-sequence-action/index.js +import { ACTION, GROUP } from '../../constant/create-tag-action.constant'; + const { Component } = Shopware; Component.override('sw-flow-sequence-action', { computed: { + // Not necessary if you use an existing group + // Push the `groups` method in computed if you are defining a new group + groups() { + this.actionGroups.unshift(GROUP); + + return this.$super('groups'); + }, + modalName() { - if (this.selectedAction === this.flowBuilderService.getActionName('ADD_TAG')) { - return 'swag-example-plugin-modal'; + if (this.selectedAction === ACTION.CREATE_TAG) { + return 'sw-flow-create-tag-modal'; } return this.$super('modalName'); }, + + actionDescription() { + const actionDescriptionList = this.$super('actionDescription'); + + return { + ...actionDescriptionList, + [ACTION.CREATE_TAG] : (config) => this.getCreateTagDescription(config), + }; + }, }, methods: { - getActionDescriptions(sequence) { - if (sequence.actionName === this.flowBuilderService.getActionName('ADD_TAG')) { - const tags = config.tags.join(', '); + getCreateTagDescription(config) { + const tags = config.tags.join(', '); - // The description of new action will be show here. - return this.$tc('swag-example-plugin.descriptionTags', 0, { - tags - }); + return this.$tc('create-tag-action.descriptionTags', 0, { + tags + }); + }, + + getActionTitle(actionName) { + if (actionName === ACTION.CREATE_TAG) { + return { + value: actionName, + icon: 'regular-tag', + label: this.$tc('create-tag-action.titleCreateTag'), + group: GROUP, + } } - return this.$super('getActionDescriptions', sequence); - + return this.$super('getActionTitle', actionName); }, }, }); + +``` + +Do not forget import the file to the entry file `main.js`: + +```jsx +// /src/Resources/app/administration/src/main.js +import './extension/sw-flow-sequence-action'; ``` -Then, we need a modal to save your action config. For example, we create a component `swag-example-plugin-modal`. +**Grouping Actions** + +As you can see, we already defined the constant for the group in `create-tag-action.constant.js` +```jsx +export const GROUP = 'customer' +``` + +The new action `action.create.tag` will be shown on the Customer group. + +![Choose a Flow Builder Action](../../../../../assets/flow-builder-action-customer-group.png) + +It will be on the General group by default if it is not defined. + +And here is a list of group names you should take a look at: + +| Group Name | Group Headline | +| :--- | :--- | +| general | General| +| tag | Tag | +| customer | Customer | +| order | Order | + + +### Step 2: Add configuration for action + +Currently, If you click to the Create tag action, the bellow error will be shown on the console. That means we're going right way. + +![Choose a Flow Builder Action](../../../../../assets/flow-builder-action-error.png) + +Because in `sw-flow-sequence-action` we expect that the new modal has name `sw-flow-create-tag-modal`. + +```jsx +modalName() { + if (this.selectedAction === ACTION.CREATE_TAG) { + return 'sw-flow-create-tag-modal'; + } + + return this.$super('modalName'); +}, +``` + +To define the modal, just create new folder `sw-flow-create-tag-modal` in `src/Resources/app/administration/src/component` and create some files following: #### JavaScript file ```jsx -// /src/Resources/app/administration/src/component/swag-example-plugin-modal/index.js -import template from './swag-example-plugin-modal.html.twig'; -const { Component } = Shopware; +// /src/Resources/app/administration/src/component/sw-flow-create-tag-modal/index.js +import template from './sw-flow-create-tag-modal.html.twig'; +const { EntityCollection, Criteria } = Shopware.Data; +const { Component, Context } = Shopware; -Component.register('swag-example-plugin-modal', { +Component.register('sw-flow-create-tag-modal', { template, + inject: [ + 'repositoryFactory', + ], + props: { sequence: { type: Object, @@ -440,33 +494,92 @@ Component.register('swag-example-plugin-modal', { data() { return { - tags: [], + tagCollection: [], }; }, + computed: { + tagRepository() { + return this.repositoryFactory.create('tag'); + }, + + tagCriteria() { + const criteria = new Criteria(1, 25); + const { config } = this.sequence; + const tagIds = Object.keys(config.tagIds); + if (tagIds.length) { + criteria.addFilter(Criteria.equalsAny('id', tagIds)); + } + + return criteria; + }, + }, + created() { this.createdComponent(); }, methods: { createdComponent() { - this.tags = this.sequence?.config?.tags || []; + this.tagCollection = this.createTagCollection(); + + const { config, id } = this.sequence; + if (id && config?.tagIds) { + this.getTagCollection(); + } + }, + + getTagCollection() { + return this.tagRepository.search(this.tagCriteria) + .then(tags => { + this.tagCollection = tags; + }) + .catch(() => { + this.tagCollection = []; + }); + }, + + createTagCollection() { + return new EntityCollection( + this.tagRepository.route, + this.tagRepository.entityName, + Context.api, + ); }, onClose() { this.$emit('modal-close'); }, + onAddTag(data) { + this.tagCollection.add(data); + }, + + onRemoveTag(data) { + this.tagCollection.remove(data); + }, + + getConfig() { + const tagIds = {}; + this.tagCollection.forEach(tag => { + Object.assign(tagIds, { + [tag.id]: tag.name, + }); + }); + + return { + tagIds, + }; + }, + onAddAction() { - const sequence = { + const config = this.getConfig(); + const data = { ...this.sequence, - config: { - ...this.config, - tags: this.tags - }, + config, }; - this.$emit('process-finish', sequence); + this.$emit('process-finish', data); }, }, }); @@ -474,51 +587,64 @@ Component.register('swag-example-plugin-modal', { #### Twig template file -```twig -// /src/Resources/app/administration/src/component/swag-example-plugin-modal/swag-example-plugin-modal.html.twig -{% block swag_example_plugin_modal %} - - {% block swag_example_plugin_modal_content %} - - {% endblock %} - - {% block swag_example_plugin_modal_footer %} - - {% endblock %} - +```jsx +// /src/Resources/app/administration/src/component/sw-flow-create-tag-modal/sw-flow-create-tag-modal.html.twig +{% block create_tag_action_modal %} + + {% block create_tag_action_modal_content %} + + {% endblock %} + + {% block create_tag_action_modall_footer %} + + {% endblock %} + {% endblock %} ``` +Pleaes update the file `main.js` like this: + +```jsx +// /src/Resources/app/administration/src/main.js +import './extension/sw-flow-sequence-action'; +import './component/sw-flow-create-tag-modal'; +``` + Here is the final result ![Flow Builder create tag](../../../../../assets/flow-builder-tag.png) @@ -551,16 +677,18 @@ Component.register('sw-flow-sequence-action', { return; } - const actionName = this.flowBuilderService.getActionName('ADD_TAG') + const actionName = this.flowBuilderService.getActionName('CREATE_TAG'); if (value === actionName) { this.selectedAction = actionName; const config = { - tags: 'VIP, New customer' + tagIds: { + 'tag_id_1': 'Vip', + 'tag_id_2': 'New Customer', + }, }; // Config can be a result from an API. - this.onSaveActionSuccess({ config }); return; }