Skip to content
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8a984a7
bring 4252 up to date
dobri1408 Mar 25, 2025
0cc0fd4
Merge branch 'main' into auto-save
dobri1408 Mar 25, 2025
38b1057
fix cypress
dobri1408 Mar 25, 2025
385834b
fix snapshots
dobri1408 Mar 25, 2025
6168544
Create 6864.feature
dobri1408 Mar 25, 2025
6a8d787
fix unit test
dobri1408 Mar 25, 2025
0443f7a
fix unit test
dobri1408 Mar 25, 2025
c3178ce
Merge branch 'main' into auto-save
dobri1408 Mar 25, 2025
f36ed6a
Merge branch 'main' into auto-save
dobri1408 Mar 25, 2025
528884a
Update packages/volto/news/6864.feature
dobri1408 Mar 26, 2025
32065c1
semantics
dobri1408 Mar 26, 2025
e9e1f4d
Merge branch 'auto-save' of https://github.com/plone/volto into auto-…
dobri1408 Mar 26, 2025
f468afb
semantics
dobri1408 Mar 26, 2025
d4e19c7
merge
dobri1408 Mar 26, 2025
523545f
fix logic
dobri1408 Mar 26, 2025
997022d
fix logic
dobri1408 Mar 26, 2025
9127860
snapshots
dobri1408 Mar 26, 2025
a0ec6c4
fix pnpm and snapshots
dobri1408 Mar 26, 2025
e5bcfd5
fix cy mistake
dobri1408 Mar 26, 2025
f96ed97
docs
dobri1408 Mar 26, 2025
499d103
revert to main
dobri1408 Mar 26, 2025
8b20095
Update blocks.md
dobri1408 Mar 26, 2025
c1209cf
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
a1bcd06
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
dba6368
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
f9d5ed1
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
383060d
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
6beafed
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
decc498
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
90951dd
add save icon
dobri1408 Mar 26, 2025
b86c3b0
Update blocks.md
dobri1408 Mar 26, 2025
ea4f5a3
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
c0a3b3e
Update docs/source/user-manual/blocks.md
dobri1408 Mar 26, 2025
67a1f04
Merge branch 'main' into auto-save
dobri1408 Mar 26, 2025
db70e10
fix conflicts
dobri1408 May 14, 2025
1f517f9
fix tests
dobri1408 May 14, 2025
1d01fc5
fix tests
dobri1408 May 14, 2025
df02429
Merge branch 'main' into auto-save
dobri1408 May 19, 2025
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
Binary file not shown.
Binary file not shown.
3 changes: 3 additions & 0 deletions docs/source/_static/user-manual/blocks/save.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions docs/source/user-manual/blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,41 @@ Volto features the [Pastanaga UI](https://github.com/plone/pastanaga), allowing
The blocks editor allows you to add, modify, reorder, and delete blocks given your requirements.
Blocks provide the user the ability to display content in a specific way, although they can also define behavior and have specific features.

(autosave-label)=

## Autosave

Volto provides an autosave mechanism that automatically captures your ongoing edits as you work on a page or content item.

Changes made in the blocks editor are periodically saved in the background to prevent data loss, even if the user navigates away or the browser unexpectedly closes.

Autosave stores changes locally in your browser using [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).
These changes remain available until you explicitly click the {guilabel}`Save` button <img alt="Save icon" src="../_static/user-manual/blocks/save.svg" class="inline">, at which point they are persisted to the server and the local storage is cleared.

Watch the video below for a quick demonstration.

````{only} not text
```{video} ../_static/user-manual/blocks/autosave-local.mp4
:alt: Autosave
```
````

### Autosave and edit conflicts

If another user edits and saves the same page while you're still working on it, Volto detects the conflict between your autosaved version and the newer version saved on the server.

In this case, when you return to the editor, Volto displays a message informing you that the page content has changed, but a previously autosaved version still exists.

You will be prompted to choose whether you want to restore your autosaved version or continue with the newer version from the server.
After making your choice, you can also undo that action.

````{only} not text
```{video} ../_static/user-manual/blocks/autosave-remote.mp4
```
````
:alt: Autosave conflicts
```


(manage-blocks-label)=

Expand Down
217 changes: 217 additions & 0 deletions packages/volto/cypress/tests/core/basic/autosave.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
describe('createContent Tests', () => {
beforeEach(() => {
cy.autologin();
cy.createContent({
contentType: 'Document',
contentId: 'comments-page',
contentTitle: 'Comments Page',
allow_discussion: true,
});
cy.setRegistry(
'plone.app.discussion.interfaces.IDiscussionSettings.globally_enabled',
true,
);
cy.createContent({
contentType: 'Document',
contentId: 'my-first-page',
contentTitle: 'My First Page',
});
cy.createContent({
contentType: 'Document',
contentId: 'my-second-page',
contentTitle: 'My Second Page',
});
});

it('As editor I can autosave when editing a content item', () => {
cy.visit('/my-first-page');

cy.log('adding a text block on the first page');

cy.navigate('/my-first-page/edit');
cy.getSlateEditorAndType('My first text').contains('My first text');
cy.wait(1000);

cy.visit('/my-second-page');

cy.log('adding a text block on the second page');
cy.navigate('/my-second-page/edit');

cy.getSlateEditorAndType('My second text').contains('My second text');
cy.wait(1000);

cy.log('visit first page and start editing');

cy.visit('/my-first-page');
cy.navigate('/my-first-page/edit');
cy.wait(1000);

cy.get('.toast-inner-content')
.contains('Autosaved content found')
.get('button.ui.icon.button.save.toast-box')
.eq(0)
.click();

cy.wait(1000);

cy.getSlate().contains('My first text');

cy.log('visit second page and start editing');

cy.visit('/my-second-page');
cy.navigate('/my-second-page/edit');
cy.wait(1000);

cy.get('.toast-inner-content')
.contains('Autosaved content found')
.get('button.ui.icon.button.save.toast-box')
.eq(0)
.click();

cy.wait(1000);

cy.getSlate().contains('My second text');
cy.reload();

cy.log(
'test is cancel load data will delete from storage (toast does not show)',
);
cy.get('.toast-inner-content')
.contains('Autosaved content found')
.get('button.ui.icon.button.save.toast-box')
.eq(1)
.click();

cy.wait(1000);
cy.reload();

cy.wait(1000);

cy.contains('Autosaved content found').should('not.exist');
});

it('As editor I can autosave when adding a content item', function () {
cy.visit('/');

cy.log(
'adding a Document content type and refresh to verify if content is autosaved and retrieved',
);
cy.get('#toolbar-add').click().get('#toolbar-add-document').click();
cy.getSlateTitle().type('Page 1 title');
cy.getSlateEditorAndType('Page 1 content').contains('Page 1 content');
cy.wait(1000);
cy.reload();

cy.log('test if autosaved toast shows retrieved data and click OK to load');
cy.get('.toast-inner-content')
.contains('Autosaved content found')
.get('button.ui.icon.button.save.toast-box')
.eq(0)
.click();

cy.wait(1000);

cy.log('test if autosaved data is loaded');
cy.getSlateTitle().contains('Page 1 title');
cy.getSlate().contains('Page 1 content');

cy.log(
'test if draft is autosaved after I cancel adding a new page content type',
);

cy.get('button.button.cancel').click();

cy.wait(1000);

cy.get('#toolbar-add').click().get('#toolbar-add-document').click();

cy.get('.toast-inner-content')
.contains('Autosaved content found')
.get('button.ui.icon.button.save.toast-box')
.eq(0)
.click();

cy.wait(1000);
cy.getSlateTitle().contains('Page 1 title');
cy.getSlate().contains('Page 1 content');

cy.wait(1000);

cy.log('test if page content type is added as new page after Toolbar Save');

cy.get('#toolbar-save').focus().click();
cy.wait(2000);
cy.contains('Page 1 title');
cy.wait(1000);

cy.log('test draft is deleted from local storage after save');

cy.visit('/');
cy.get('#toolbar-add').click().get('#toolbar-add-document').click();

cy.wait(1000);

cy.contains('Autosaved content found').should('not.exist');
});

it('As editor I can autosave comments', function () {
cy.log('adding a comment and refresh,');
cy.visit('/comments-page');
cy.get('textarea[id="field-comment"]').clear().type('This is a comment');
cy.wait(1000);
cy.reload();

cy.log('test if comment is retrieved from local storage');

cy.get('.toast-inner-content')
.contains('Autosaved content found')
.get('button.ui.icon.button.save.toast-box')
.eq(0)
.click();

cy.get('#field-comment').contains('This is a comment');

cy.wait(1000);
cy.reload();

cy.log(
'test if comment is deleted from local storage after selecting Cancel in the Autosave toast',
);

cy.get('.toast-inner-content')
.contains('Autosaved content found')
.get('button.ui.icon.button.save.toast-box')
.eq(1)
.click();

cy.wait(1000);
cy.reload();
cy.contains('Autosaved content found').should('not.exist');

cy.log('adding another comment and save it');

cy.get('textarea[id="field-comment"]')
.clear()
.type('This is a another comment');
cy.wait(1000);
cy.reload();

cy.get('.toast-inner-content')
.contains('Autosaved content found')
.get('button.ui.icon.button.save.toast-box')
.eq(0)
.click();

cy.wait(1000);

cy.get('button[type="submit"').click();

cy.get('.comment').contains('This is a another comment');

cy.log('test if the local storage comment was deleted after submit');

cy.wait(1000);
cy.reload();
cy.contains('Autosaved content found').should('not.exist');
});
});
15 changes: 15 additions & 0 deletions packages/volto/locales/ca/LC_MESSAGES/volto.po
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@ msgstr ""
msgid "Alternative url path → target url path (date and time of creation, manually created yes/no)"
msgstr ""

#. Default: "Another person edited this content, and it's currently displayed. Do you want to replace it with your autosaved content?"
#: helpers/Utils/withSaveAsDraft
msgid "Another person edited this content, and it's currently displayed. Do you want to replace it with your autosaved content?"
msgstr ""

#. Default: "Applied to subfolders"
#: components/manage/Rules/Rules
msgid "Applied to subfolders"
Expand Down Expand Up @@ -437,6 +442,11 @@ msgstr ""
msgid "Automatically"
msgstr ""

#. Default: "Autosaved content found"
#: helpers/Utils/withSaveAsDraft
msgid "Autosaved content found"
msgstr ""

#. Default: "Available"
#: components/manage/Controlpanels/AddonsControlpanel
msgid "Available"
Expand Down Expand Up @@ -1170,6 +1180,11 @@ msgstr "Realment voleu suprimir l'usuari {username}?"
msgid "Do you really want to delete this item?"
msgstr "Realment voleu suprimir aquest element?"

#. Default: "Do you want to restore your autosaved content?"
#: helpers/Utils/withSaveAsDraft
msgid "Do you want to restore your autosaved content?"
msgstr ""

#. Default: "Document"
#: components/manage/Multilingual/TranslationObject
#: components/manage/Sidebar/Sidebar
Expand Down
15 changes: 15 additions & 0 deletions packages/volto/locales/de/LC_MESSAGES/volto.po
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ msgstr "Alternativer Pfad muss mit einem Schrägstrich beginnen"
msgid "Alternative url path → target url path (date and time of creation, manually created yes/no)"
msgstr "Alternativer URL Pfad → Zielpfad (Datum und Zeit der Erstellung, manuell erstellt ja/nein)"

#. Default: "Another person edited this content, and it's currently displayed. Do you want to replace it with your autosaved content?"
#: helpers/Utils/withSaveAsDraft
msgid "Another person edited this content, and it's currently displayed. Do you want to replace it with your autosaved content?"
msgstr ""

#. Default: "Applied to subfolders"
#: components/manage/Rules/Rules
msgid "Applied to subfolders"
Expand Down Expand Up @@ -436,6 +441,11 @@ msgstr "Zuweisungen"
msgid "Automatically"
msgstr "automatisch"

#. Default: "Autosaved content found"
#: helpers/Utils/withSaveAsDraft
msgid "Autosaved content found"
msgstr ""

#. Default: "Available"
#: components/manage/Controlpanels/AddonsControlpanel
msgid "Available"
Expand Down Expand Up @@ -1169,6 +1179,11 @@ msgstr "Möchten Sie den Nutzer {username} wirklich löschen?"
msgid "Do you really want to delete this item?"
msgstr "Möchten Sie den Artikel wirklich löschen?"

#. Default: "Do you want to restore your autosaved content?"
#: helpers/Utils/withSaveAsDraft
msgid "Do you want to restore your autosaved content?"
msgstr ""

#. Default: "Document"
#: components/manage/Multilingual/TranslationObject
#: components/manage/Sidebar/Sidebar
Expand Down
15 changes: 15 additions & 0 deletions packages/volto/locales/en/LC_MESSAGES/volto.po
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,11 @@ msgstr ""
msgid "Alternative url path → target url path (date and time of creation, manually created yes/no)"
msgstr ""

#. Default: "Another person edited this content, and it's currently displayed. Do you want to replace it with your autosaved content?"
#: helpers/Utils/withSaveAsDraft
msgid "Another person edited this content, and it's currently displayed. Do you want to replace it with your autosaved content?"
msgstr ""

#. Default: "Applied to subfolders"
#: components/manage/Rules/Rules
msgid "Applied to subfolders"
Expand Down Expand Up @@ -431,6 +436,11 @@ msgstr ""
msgid "Automatically"
msgstr ""

#. Default: "Autosaved content found"
#: helpers/Utils/withSaveAsDraft
msgid "Autosaved content found"
msgstr ""

#. Default: "Available"
#: components/manage/Controlpanels/AddonsControlpanel
msgid "Available"
Expand Down Expand Up @@ -1164,6 +1174,11 @@ msgstr ""
msgid "Do you really want to delete this item?"
msgstr ""

#. Default: "Do you want to restore your autosaved content?"
#: helpers/Utils/withSaveAsDraft
msgid "Do you want to restore your autosaved content?"
msgstr ""

#. Default: "Document"
#: components/manage/Multilingual/TranslationObject
#: components/manage/Sidebar/Sidebar
Expand Down
Loading