From e9fc09825ba2ae258feb77864491d97d94c585b4 Mon Sep 17 00:00:00 2001 From: dobri1408 <50819975+dobri1408@users.noreply.github.com> Date: Fri, 24 Mar 2023 18:56:25 +0200 Subject: [PATCH] (feat): Possibility to copy/cut/paste blocks within section group block - refs #157469 --- Jenkinsfile | 12 +-- package.json | 2 +- src/components/manage/Blocks/Group/Edit.jsx | 97 +++++++++++++++++++-- 3 files changed, 99 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0429c7d..450b2cc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -41,19 +41,19 @@ pipeline { "ES lint": { node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-eslint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci:alpha eslint''' + sh '''docker run -i --rm --name="$BUILD_TAG-eslint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci eslint''' } }, "Style lint": { node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-stylelint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci:alpha stylelint''' + sh '''docker run -i --rm --name="$BUILD_TAG-stylelint" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci stylelint''' } }, "Prettier": { node(label: 'docker') { - sh '''docker run -i --rm --name="$BUILD_TAG-prettier" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci:alpha prettier''' + sh '''docker run -i --rm --name="$BUILD_TAG-prettier" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci prettier''' } } ) @@ -77,8 +77,8 @@ pipeline { node(label: 'docker') { script { try { - sh '''docker pull plone/volto-addon-ci:alpha''' - sh '''docker run -i --name="$BUILD_TAG-volto" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci:alpha''' + sh '''docker pull plone/volto-addon-ci''' + sh '''docker run -i --name="$BUILD_TAG-volto" -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e VOLTO=$VOLTO plone/volto-addon-ci''' sh '''rm -rf xunit-reports''' sh '''mkdir -p xunit-reports''' sh '''docker cp $BUILD_TAG-volto:/opt/frontend/my-volto-project/coverage xunit-reports/''' @@ -126,7 +126,7 @@ pipeline { script { try { sh '''docker pull eeacms/plone-backend; docker run --rm -d --name="$BUILD_TAG-plone" -e SITE="Plone" -e PROFILES="eea.kitkat:testing" eeacms/plone-backend''' - sh '''docker pull plone/volto-addon-ci:alpha; docker run -i --name="$BUILD_TAG-cypress" --link $BUILD_TAG-plone:plone -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e DEPENDENCIES="$DEPENDENCIES" -e NODE_ENV=development -e VOLTO=$VOLTO plone/volto-addon-ci:alpha cypress''' + sh '''docker pull plone/volto-addon-ci; docker run -i --name="$BUILD_TAG-cypress" --link $BUILD_TAG-plone:plone -e NAMESPACE="$NAMESPACE" -e GIT_NAME=$GIT_NAME -e GIT_BRANCH="$BRANCH_NAME" -e GIT_CHANGE_ID="$CHANGE_ID" -e DEPENDENCIES="$DEPENDENCIES" -e NODE_ENV=development -e VOLTO=$VOLTO plone/volto-addon-ci cypress''' } finally { try { sh '''rm -rf cypress-reports cypress-results cypress-coverage''' diff --git a/package.json b/package.json index 0830146..fa0250f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eeacms/volto-group-block", - "version": "5.0.1", + "version": "6.0.0", "description": "volto-group-block: Volto block to be used to group other blocks", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team", diff --git a/src/components/manage/Blocks/Group/Edit.jsx b/src/components/manage/Blocks/Group/Edit.jsx index 9af7dd3..f8baf3f 100644 --- a/src/components/manage/Blocks/Group/Edit.jsx +++ b/src/components/manage/Blocks/Group/Edit.jsx @@ -1,12 +1,16 @@ import React, { useState } from 'react'; -import { isEmpty } from 'lodash'; +import { isEmpty, without } from 'lodash'; import { BlocksForm, SidebarPortal, Icon, BlockDataForm, + BlocksToolbar, } from '@plone/volto/components'; -import { emptyBlocksForm } from '@plone/volto/helpers'; +import { + emptyBlocksForm, + getBlocksLayoutFieldname, +} from '@plone/volto/helpers'; import delightedSVG from '@plone/volto/icons/delighted.svg'; import dissatisfiedSVG from '@plone/volto/icons/dissatisfied.svg'; import PropTypes from 'prop-types'; @@ -28,15 +32,72 @@ const Edit = (props) => { manage, formDescription, } = props; + const onSelectBlock = (id, isMultipleSelection, event, activeBlock) => { + let newMultiSelected = []; + let selected = id; + + if (isMultipleSelection) { + selected = null; + const blocksLayoutFieldname = getBlocksLayoutFieldname(data?.data); + const blocks_layout = data?.data[blocksLayoutFieldname].items; + if (event.shiftKey) { + const anchor = + multiSelected.length > 0 + ? blocks_layout.indexOf(multiSelected[0]) + : blocks_layout.indexOf(activeBlock); + const focus = blocks_layout.indexOf(id); + if (anchor === focus) { + newMultiSelected = [id]; + } else if (focus > anchor) { + newMultiSelected = [...blocks_layout.slice(anchor, focus + 1)]; + } else { + newMultiSelected = [...blocks_layout.slice(focus, anchor + 1)]; + } + } + if ((event.ctrlKey || event.metaKey) && !event.shiftKey) { + if (multiSelected.includes(id)) { + selected = null; + newMultiSelected = without(multiSelected, id); + } else { + newMultiSelected = [...(multiSelected || []), id]; + } + } + } + setSelectedBlock(selected); + setMultiSelected(newMultiSelected); + }; const metadata = props.metadata || props.properties; + const [multiSelected, setMultiSelected] = useState([]); const data_blocks = data?.data?.blocks; const properties = isEmpty(data_blocks) ? emptyBlocksForm() : data.data; const [selectedBlock, setSelectedBlock] = useState( properties.blocks_layout.items[0], ); - + const changeBlockData = (newBlockData) => { + let pastedBlocks = newBlockData.blocks_layout.items.filter((blockID) => { + if (data?.data?.blocks_layout.items.find((x) => x === blockID)) + return false; + return true; + }); + const selectedIndex = + data.data.blocks_layout.items.indexOf(selectedBlock) + 1; + onChangeBlock(block, { + ...data, + data: { + ...data?.data, + ...newBlockData, + blocks_layout: { + items: [ + ...data.data.blocks_layout.items.slice(0, selectedIndex), + ...pastedBlocks, + ...data.data.blocks_layout.items.slice(selectedIndex), + ], + }, + }, + }); + }; React.useEffect(() => { if ( isEmpty(data_blocks) && @@ -165,6 +226,28 @@ const Edit = (props) => { > {data.title || 'Section'} + {selected ? ( + { + setMultiSelected(blockIds); + }} + formData={data.data} + onSelectBlock={(id, l, e) => { + const isMultipleSelection = e + ? e.shiftKey || e.ctrlKey || e.metaKey + : false; + + onSelectBlock(id, isMultipleSelection, e, selectedBlock); + }} + onChangeBlocks={(newBlockData) => { + changeBlockData(newBlockData); + }} + /> + ) : ( + '' + )} { allowedBlocks={data.allowedBlocks} title={data.placeholder} description={instructions} - onSelectBlock={(id) => { - setSelectedBlock(id); + onSelectBlock={(id, l, e) => { + const isMultipleSelection = e + ? e.shiftKey || e.ctrlKey || e.metaKey + : false; + onSelectBlock(id, isMultipleSelection, e, selectedBlock); }} onChangeFormData={(newFormData) => { onChangeBlock(block, { @@ -223,6 +309,7 @@ const Edit = (props) => { )} } + multiSelected={multiSelected.includes(blockProps.block)} > {editBlock}