Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions backend/scripts/migrate_draft_to_slate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from plone import api
from plone.restapi.blocks import visit_blocks
from zope.component.hooks import setSite
from textwrap import indent
import json
import transaction

BLOCK_FIELDS = {
"icons_and_numbers": ["columns.text"],
"icons_and_text": ["description", "columns.text"],
"image_columns": ["description"],
"numbers": ["numbers.text"],
"slider": ["description"],
"text1": ["content"],
"text5": ["description", "text1", "text2", "content"],
"text6": ["content"],
"text7": ["content"],
}

def find_values(value: dict, fields):
for field in fields:
if "." in field:
field, rest = field.split(".", 1)
else:
rest = None
if field not in value:
continue
nextvalue = value[field]
if rest and isinstance(nextvalue, list):
for item in nextvalue:
yield from find_values(item, [rest])
else:
yield value, field, nextvalue


def process_entities(text, entityRanges, entityMap):
if len(entityRanges) == 1:
offset = entityRanges[0]["offset"]
length = entityRanges[0]["length"]
key = entityRanges[0]["key"]
pretext, linktext, posttext = text[:offset], text[offset:offset + length], text[offset + length:]
result = []
if pretext:
result.append({"text": pretext})
url = entityMap[str(key)]["data"]["url"]
result.append({
"type": "link",
"children": [{"text": linktext}],
"data": {"url": url}
})
if posttext:
result.append({"text": posttext})
return result
elif len(entityRanges) == 0:
return [{"text": text}]
else:
print(json.dumps(text, indent=4))
breakpoint()


def migrate_draft_to_slate(value, entityMap=None) -> list:
match value:
case {"blocks": [*blocks], "entityMap": entityMap}:
result = []
for block in blocks:
result.extend(migrate_draft_to_slate(block, entityMap))
return result
case {"type": blocktype, "text": text, "entityRanges": entityRanges}:
children = process_entities(text, entityRanges, entityMap)
match blocktype:
case "unstyled" | "align-left" | "buttons":
return [{"type": "p", "children": children}]
case "unordered-list-item":
return [{"type": "ul", "children": [{"li": {"children": [{"text": text}]}}]}]
case "blockquote":
return [{"type": "blockquote", "children": children}]
case _:
breakpoint()
raise Exception()
case _:
print(json.dumps(value, indent=4))
breakpoint()
raise Exception()


def migrate_items():
catalog = api.portal.get_tool(name="portal_catalog")
i = 0
for brain in catalog.unrestrictedSearchResults(block_types=list(BLOCK_FIELDS.keys())):
obj = brain.getObject()

for block in visit_blocks(obj, obj.blocks):
block_type = block.get("@type")
for container, field, value in find_values(block, BLOCK_FIELDS.get(block_type, [])):
if isinstance(value, list):
# no value, or already migrated
continue
elif value is None:
newvalue = []
else:
newvalue = migrate_draft_to_slate(value)
if newvalue != value:
container[field] = newvalue
obj._p_changed = True
i += 1
print(f"{brain.getPath()} / {block_type} / {field}")
print(indent(json.dumps(value, indent=4), " "))
print()
print(indent(json.dumps(newvalue, indent=4), " "))
print()

print(f"Total fields processed: {i}")
transaction.commit()

setSite(app.Plone)
migrate_items()
1 change: 1 addition & 0 deletions frontend/core
Submodule core added at 4239f5
16 changes: 5 additions & 11 deletions frontend/src/components/Blocks/IconsAndNumbers/Block/EditBlock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { flattenToAppURL } from '@plone/volto/helpers';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useIntl, defineMessages } from 'react-intl';
import { Input } from 'semantic-ui-react';
import { TextEditorWidget } from '@package/components/Widgets';
import { DetachedTextBlockEditor } from '@plone/volto-slate/blocks/Text/DetachedTextBlockEditor';

const messages = defineMessages({
titlePlaceholder: {
Expand Down Expand Up @@ -81,18 +81,12 @@ const EditBlock = ({
onClick={(e) => setFocusOn('text' + index)}
onKeyDown={() => setFocusOn('text' + index)}
>
<TextEditorWidget
data={data}
fieldName={'text'}
<DetachedTextBlockEditor
data={{ value: data.text }}
onChangeBlock={(block, { value }) => onChange(index, 'text', value)}
selected={selected && focusOn === 'text' + index}
onChangeBlock={(v) => {
onChange(index, 'text', v.text);
}}
readOnly={false}
placeholder={intl.formatMessage(messages.textPlaceholder)}
prevFocus={'number' + index}
setFocus={(f) => setFocusOn(f)}
showToolbar={true}
key={'text' + index}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
import React from 'react';
import redraft from 'redraft';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { flattenToAppURL } from '@plone/volto/helpers';

import config from '@plone/volto/registry';
import { TextBlockView } from '@plone/volto-slate/blocks/Text';

const ViewBlock = ({ data }) => {
const icon = data.iconImage; //data.icon
Expand All @@ -27,11 +25,7 @@ const ViewBlock = ({ data }) => {
{data.title && <div className="column-title">{data.title}</div>}

<div className="column-text">
{redraft(
data.text,
config.settings.richtextViewSettings.ToHTMLRenderers,
config.settings.richtextViewSettings.ToHTMLOptions,
)}
<TextBlockView data={{ value: data.text }} />
</div>
</div>
) : (
Expand Down
9 changes: 2 additions & 7 deletions frontend/src/components/Blocks/IconsAndNumbers/View.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';
import cx from 'classnames';
import { Container } from 'semantic-ui-react';
import redraft from 'redraft';
import { ListingLinkMore } from '@package/components';
import ViewNumberBlock from './Block/ViewBlock';
import config from '@plone/volto/registry';
import { TextBlockView } from '@plone/volto-slate/blocks/Text';

const View = ({ data }) => {
return (
Expand All @@ -20,11 +19,7 @@ const View = ({ data }) => {
{data.title && <div className="title">{data.title}</div>}
{data.description && (
<div className="description">
{redraft(
data.description,
config.settings.richtextViewSettings.ToHTMLRenderers,
config.settings.richtextViewSettings.ToHTMLOptions,
)}
<TextBlockView data={{ value: data.description }} />
</div>
)}
<div className="columns-wrapper">
Expand Down
16 changes: 5 additions & 11 deletions frontend/src/components/Blocks/IconsAndText/Block/EditBlock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { flattenToAppURL } from '@plone/volto/helpers';
import { UniversalLink } from '@plone/volto/components';
import { useIntl, defineMessages } from 'react-intl';
import { Input, TextArea } from 'semantic-ui-react';
import { TextEditorWidget } from '@package/components/Widgets';
import { DetachedTextBlockEditor } from '@plone/volto-slate/blocks/Text/DetachedTextBlockEditor';
import { Button } from '@package/components';

const messages = defineMessages({
Expand Down Expand Up @@ -92,18 +92,12 @@ const EditBlock = ({
onClick={(e) => setFocusOn('text' + index)}
onKeyDown={() => setFocusOn('text' + index)}
>
<TextEditorWidget
data={data}
fieldName={'text'}
<DetachedTextBlockEditor
data={{ value: data.text }}
onChangeBlock={(block, { value }) => onChange(index, 'text', value)}
selected={selected && focusOn === 'text' + index}
onChangeBlock={(v) => {
onChange(index, 'text', v.text);
}}
readOnly={false}
placeholder={intl.formatMessage(messages.textPlaceholder)}
prevFocus={'number' + index}
setFocus={(f) => setFocusOn(f)}
showToolbar={true}
key={'text' + index}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
import React from 'react';
import cx from 'classnames';
import redraft from 'redraft';
import { flattenToAppURL } from '@plone/volto/helpers';
import { UniversalLink } from '@plone/volto/components';
import { Button } from '@package/components';
import config from '@plone/volto/registry';
import { TextBlockView } from '@plone/volto-slate/blocks/Text';

const ViewBlock = ({ data, bg_color }) => {
const icon = data.iconImage; //data.icon
Expand Down Expand Up @@ -41,11 +40,7 @@ const ViewBlock = ({ data, bg_color }) => {
</div>
)}
<div className="column-text">
{redraft(
data.text,
config.settings.richtextViewSettings.ToHTMLRenderers,
config.settings.richtextViewSettings.ToHTMLOptions,
)}
<TextBlockView data={{ value: data.text }} />
</div>

{data.href_title && data.href?.length > 0 && (
Expand Down
16 changes: 7 additions & 9 deletions frontend/src/components/Blocks/IconsAndText/Edit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useIntl, defineMessages } from 'react-intl';
import { Input, Container } from 'semantic-ui-react';
import { SidebarPortal } from '@plone/volto/components';
import { ListingLinkMore } from '@package/components';
import { TextEditorWidget } from '@package/components/Widgets';
import { DetachedTextBlockEditor } from '@plone/volto-slate/blocks/Text/DetachedTextBlockEditor';
import EditColumnBlock from './Block/EditBlock';
import Sidebar from './Sidebar';

Expand Down Expand Up @@ -70,19 +70,17 @@ const Edit = (props) => {
}
/>
</div>
<TextEditorWidget
data={data}
fieldName="description"
onChangeBlock={(v) => {
<DetachedTextBlockEditor
data={{ value: data.description }}
onChangeBlock={(block, { value }) => {
onChangeBlock(block, {
...data,
description: v.description,
description: value,
});
}}
placeholder={intl.formatMessage(messages.textPlaceholder)}
setFocus={(f) => focusField(f)}
selected={focusOn === 'description'}
showToolbar={true}
readOnly={false}
placeholder={intl.formatMessage(messages.textPlaceholder)}
/>
</div>
<div className="columns-wrapper">
Expand Down
19 changes: 4 additions & 15 deletions frontend/src/components/Blocks/IconsAndText/View.jsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
import React from 'react';
import cx from 'classnames';
import redraft from 'redraft';
import { ListingLinkMore } from '@package/components';
import ViewBlock from './Block/ViewBlock';
import { Container } from 'semantic-ui-react';
import config from '@plone/volto/registry';
import { TextBlockView } from '@plone/volto-slate/blocks/Text';

const View = ({ data }) => {
const checkHasContent = (content) => {
if (content) {
let blocks = content.blocks.filter((block) => block?.text !== '');
return blocks.length > 0 ? true : false;
}
};
let content = (
<>
{(data.title || checkHasContent(data.description)) && (
{(data.title || data.description) && (
<div className="block-content-header">
{data.title && <div className={cx('title')}>{data.title}</div>}
{checkHasContent(data.description) && (
{data.description && (
<div className="description">
{redraft(
data.description,
config.settings.richtextViewSettings.ToHTMLRenderers,
config.settings.richtextViewSettings.ToHTMLOptions,
)}
<TextBlockView data={{ value: data.description }} />
</div>
)}
</div>
Expand Down
18 changes: 7 additions & 11 deletions frontend/src/components/Blocks/Numbers/Block/EditBlock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { flattenToAppURL } from '@plone/volto/helpers';
import { useIntl, defineMessages } from 'react-intl';
import { Input } from 'semantic-ui-react';
import { TextEditorWidget } from '@package/components/Widgets';
import { DetachedTextBlockEditor } from '@plone/volto-slate/blocks/Text/DetachedTextBlockEditor';

const messages = defineMessages({
titlePlaceholder: {
Expand Down Expand Up @@ -84,18 +84,14 @@ const EditBlock = ({
onClick={(e) => setFocusOn('text' + index)}
onKeyDown={() => setFocusOn('text' + index)}
>
<TextEditorWidget
data={data}
fieldName={'text'}
<DetachedTextBlockEditor
data={{ value: data.text }}
onChangeBlock={(block, { value }) =>
onChange(index, 'text', value)
}
selected={selected && focusOn === 'text' + index}
onChangeBlock={(v) => {
onChange(index, 'text', v.text);
}}
readOnly={false}
placeholder={intl.formatMessage(messages.textPlaceholder)}
prevFocus={'number' + index}
setFocus={(f) => setFocusOn(f)}
showToolbar={true}
key={'text' + index}
/>
</div>
</div>
Expand Down
9 changes: 2 additions & 7 deletions frontend/src/components/Blocks/Numbers/Block/ViewBlock.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
import React from 'react';
import redraft from 'redraft';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { flattenToAppURL } from '@plone/volto/helpers';
import config from '@plone/volto/registry';
import { TextBlockView } from '@plone/volto-slate/blocks/Text';

const ViewBlock = ({ data }) => {
return data.title || data.number ? (
Expand Down Expand Up @@ -33,11 +32,7 @@ const ViewBlock = ({ data }) => {
)}

<div className="number-text">
{redraft(
data.text,
config.settings.richtextViewSettings.ToHTMLRenderers,
config.settings.richtextViewSettings.ToHTMLOptions,
)}
<TextBlockView data={{ value: data.text }} />
</div>
</div>
</div>
Expand Down
Loading
Loading