diff --git a/cypress/integration/workspace.js b/cypress/integration/workspace.js
index fbff451305..a12d86b3d6 100644
--- a/cypress/integration/workspace.js
+++ b/cypress/integration/workspace.js
@@ -2,7 +2,6 @@ context('Workspace 2.0', () => {
before(() => {
cy.visit('/login');
cy.login();
- cy.visit('/app/website');
});
it('Navigate to page from sidebar', () => {
@@ -13,6 +12,11 @@ context('Workspace 2.0', () => {
});
it('Create Private Page', () => {
+ cy.intercept({
+ method: 'POST',
+ url: 'api/method/frappe.desk.doctype.workspace.workspace.new_page'
+ }).as('new_page');
+
cy.get('.codex-editor__redactor .ce-block');
cy.get('.custom-actions button[data-label="Create%20Workspace"]').click();
cy.fill_field('title', 'Test Private Page', 'Data');
@@ -27,12 +31,100 @@ context('Workspace 2.0', () => {
cy.wait(300);
cy.get('.sidebar-item-container[item-name="Test Private Page"]').should('have.attr', 'item-public', '0');
- cy.wait(500);
+ cy.wait('@new_page');
+ });
+
+ it('Create Child Page', () => {
+ cy.intercept({
+ method: 'POST',
+ url: 'api/method/frappe.desk.doctype.workspace.workspace.new_page'
+ }).as('new_page');
+
+ cy.get('.codex-editor__redactor .ce-block');
+ cy.get('.custom-actions button[data-label="Create%20Workspace"]').click();
+ cy.fill_field('title', 'Test Child Page', 'Data');
+ cy.fill_field('parent', 'Test Private Page', 'Select');
+ cy.fill_field('icon', 'edit', 'Icon');
+ cy.get_open_dialog().find('.modal-header').click();
+ cy.get_open_dialog().find('.btn-primary').click();
+
+ // check if sidebar item is added in pubic section
+ cy.get('.sidebar-item-container[item-name="Test Child Page"]').should('have.attr', 'item-public', '0');
+
+ cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
+ cy.wait(300);
+ cy.get('.sidebar-item-container[item-name="Test Child Page"]').should('have.attr', 'item-public', '0');
+
+ cy.wait('@new_page');
+ });
+
+ it('Duplicate Page', () => {
+ cy.intercept({
+ method: 'POST',
+ url: 'api/method/frappe.desk.doctype.workspace.workspace.duplicate_page'
+ }).as('page_duplicated');
+
cy.get('.codex-editor__redactor .ce-block');
cy.get('.standard-actions .btn-secondary[data-label=Edit]').click();
+
+ cy.get('.sidebar-item-container[item-name="Test Private Page"]').as('sidebar-item');
+
+ cy.get('@sidebar-item').find('.standard-sidebar-item').first().click();
+ cy.get('@sidebar-item').find('.dropdown-btn').first().click();
+ cy.get('@sidebar-item').find('.dropdown-list .dropdown-item').contains('Duplicate').first().click({force: true});
+
+ cy.get_open_dialog().fill_field('title', 'Duplicate Page', 'Data');
+ cy.click_modal_primary_button('Duplicate');
+
+ cy.wait('@page_duplicated');
+ });
+
+ it('Drag Sidebar Item', () => {
+ cy.intercept({
+ method: 'POST',
+ url: 'api/method/frappe.desk.doctype.workspace.workspace.sort_pages'
+ }).as('page_sorted');
+
+ cy.get('.sidebar-item-container[item-name="Duplicate Page"]').as('sidebar-item');
+
+ cy.get('@sidebar-item').find('.standard-sidebar-item').first().click();
+ cy.get('@sidebar-item').find('.drag-handle').first().move({ deltaX: 0, deltaY: 100 });
+
+ cy.get('.sidebar-item-container[item-name="Build"]').as('sidebar-item');
+
+ cy.get('@sidebar-item').find('.standard-sidebar-item').first().click();
+ cy.get('@sidebar-item').find('.drag-handle').first().move({ deltaX: 0, deltaY: 100 });
+
+ cy.wait('@page_sorted');
+ });
+
+ it('Edit Page Detail', () => {
+ cy.intercept({
+ method: 'POST',
+ url: 'api/method/frappe.desk.doctype.workspace.workspace.update_page'
+ }).as('page_updated');
+
+ cy.get('.sidebar-item-container[item-name="Test Private Page"]').as('sidebar-item');
+
+ cy.get('@sidebar-item').find('.standard-sidebar-item').first().click();
+ cy.get('@sidebar-item').find('.dropdown-btn').first().click();
+ cy.get('@sidebar-item').find('.dropdown-list .dropdown-item').contains('Edit').first().click({force: true});
+
+ cy.get_open_dialog().fill_field('title', ' 1', 'Data');
+ cy.get_open_dialog().find('input[data-fieldname="is_public"]').check();
+ cy.click_modal_primary_button('Update');
+
+ cy.get('.standard-sidebar-section:first .sidebar-item-container[item-name="Test Private Page"]').should('not.exist');
+ cy.get('.standard-sidebar-section:last .sidebar-item-container[item-name="Test Private Page 1"]').should('exist');
+
+ cy.wait('@page_updated');
});
it('Add New Block', () => {
+ cy.get('.sidebar-item-container[item-name="Duplicate Page"]').as('sidebar-item');
+
+ cy.get('@sidebar-item').find('.standard-sidebar-item').first().click();
+
cy.get('.ce-block').click().type('{enter}');
cy.get('.block-list-container .block-list-item').contains('Heading').click();
cy.get(":focus").type('Header');
@@ -70,19 +162,24 @@ context('Workspace 2.0', () => {
cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
});
- it('Delete Private Page', () => {
+ it('Delete Duplicate Page', () => {
+ cy.intercept({
+ method: 'POST',
+ url: 'api/method/frappe.desk.doctype.workspace.workspace.delete_page'
+ }).as('page_deleted');
+
cy.get('.codex-editor__redactor .ce-block');
cy.get('.standard-actions .btn-secondary[data-label=Edit]').click();
- cy.get('.sidebar-item-container[item-name="Test Private Page"]')
+ cy.get('.sidebar-item-container[item-name="Duplicate Page"]')
.find('.sidebar-item-control .setting-btn').click();
- cy.get('.sidebar-item-container[item-name="Test Private Page"]')
+ cy.get('.sidebar-item-container[item-name="Duplicate Page"]')
.find('.dropdown-item[title="Delete Workspace"]').click({force: true});
cy.wait(300);
cy.get('.modal-footer > .standard-actions > .btn-modal-primary:visible').first().click();
- cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
- cy.get('.codex-editor__redactor .ce-block');
- cy.get('.sidebar-item-container[item-name="Test Private Page"]').should('not.exist');
+ cy.get('.sidebar-item-container[item-name="Duplicate Page"]').should('not.exist');
+
+ cy.wait('@page_deleted');
});
});
\ No newline at end of file
diff --git a/frappe/desk/doctype/workspace/workspace.py b/frappe/desk/doctype/workspace/workspace.py
index a2dbcbfbe2..284fecbe31 100644
--- a/frappe/desk/doctype/workspace/workspace.py
+++ b/frappe/desk/doctype/workspace/workspace.py
@@ -80,7 +80,14 @@ class Workspace(Document):
# remove duplicate before adding
for idx, link in enumerate(self.links):
- if link.label == card.get("label") and link.type == "Card Break":
+ if link.get("label") == card.get("label") and link.get("type") == "Card Break":
+ # count and set number of links for the card if link_count is 0
+ if link.link_count == 0:
+ for count, card_link in enumerate(self.links[idx + 1 :]):
+ if card_link.get("type") == "Card Break":
+ break
+ link.link_count = count + 1
+
del self.links[idx : idx + link.link_count + 1]
self.append(
@@ -199,21 +206,31 @@ def update_page(name, title, icon, parent, public):
doc.sequence_id = frappe.db.count("Workspace", {"public": public}, cache=True)
doc.public = public
doc.for_user = "" if public else doc.for_user or frappe.session.user
- doc.label = "{0}-{1}".format(title, doc.for_user) if doc.for_user else title
+ doc.label = new_name = "{0}-{1}".format(title, doc.for_user) if doc.for_user else title
doc.save(ignore_permissions=True)
- if name != doc.label:
- rename_doc("Workspace", name, doc.label, force=True, ignore_permissions=True)
+ if name != new_name:
+ rename_doc("Workspace", name, new_name, force=True, ignore_permissions=True)
# update new name and public in child pages
if child_docs:
for child in child_docs:
child_doc = frappe.get_doc("Workspace", child.name)
child_doc.parent_page = doc.title
- child_doc.public = doc.public
+ if child_doc.public != public:
+ child_doc.public = public
+ child_doc.for_user = "" if public else child_doc.for_user or frappe.session.user
+ child_doc.label = new_child_name = (
+ "{0}-{1}".format(child_doc.title, child_doc.for_user)
+ if child_doc.for_user
+ else child_doc.title
+ )
child_doc.save(ignore_permissions=True)
- return {"name": doc.title, "public": doc.public, "label": doc.label}
+ if child.name != new_child_name:
+ rename_doc("Workspace", child.name, new_child_name, force=True, ignore_permissions=True)
+
+ return {"name": title, "public": public, "label": new_name}
@frappe.whitelist()
diff --git a/frappe/public/js/frappe/form/toolbar.js b/frappe/public/js/frappe/form/toolbar.js
index e55eb9fdeb..6841640341 100644
--- a/frappe/public/js/frappe/form/toolbar.js
+++ b/frappe/public/js/frappe/form/toolbar.js
@@ -323,7 +323,7 @@ frappe.ui.form.Toolbar = class Toolbar {
}
// New
- if(p[CREATE] && !this.frm.meta.issingle) {
+ if (p[CREATE] && !this.frm.meta.issingle && !this.frm.meta.in_create) {
this.page.add_menu_item(__("New {0}", [__(me.frm.doctype)]), function() {
frappe.new_doc(me.frm.doctype, true);
}, true, {
diff --git a/frappe/public/js/frappe/views/workspace/blocks/block.js b/frappe/public/js/frappe/views/workspace/blocks/block.js
index 9605d30c81..1df6b707fe 100644
--- a/frappe/public/js/frappe/views/workspace/blocks/block.js
+++ b/frappe/public/js/frappe/views/workspace/blocks/block.js
@@ -7,7 +7,7 @@ export default class Block {
make(block, block_name, widget_type = block) {
let block_data = this.config.page_data[block+'s'].items.find(obj => {
- return frappe.utils.unescape_html(obj.label) == frappe.utils.unescape_html(block_name);
+ return frappe.utils.unescape_html(obj.label) == frappe.utils.unescape_html(__(block_name));
});
if (!block_data) return false;
this.wrapper.innerHTML = '';
diff --git a/frappe/public/js/frappe/views/workspace/blocks/card.js b/frappe/public/js/frappe/views/workspace/blocks/card.js
index 9ce6ce8b4d..4b46b12890 100644
--- a/frappe/public/js/frappe/views/workspace/blocks/card.js
+++ b/frappe/public/js/frappe/views/workspace/blocks/card.js
@@ -31,7 +31,7 @@ export default class Card extends Block {
this.new('card', 'links');
if (this.data && this.data.card_name) {
- let has_data = this.make('card', __(this.data.card_name), 'links');
+ let has_data = this.make('card', this.data.card_name, 'links');
if (!has_data) return;
}
diff --git a/frappe/public/js/frappe/views/workspace/blocks/chart.js b/frappe/public/js/frappe/views/workspace/blocks/chart.js
index ccef1fa15f..cb688f48ed 100644
--- a/frappe/public/js/frappe/views/workspace/blocks/chart.js
+++ b/frappe/public/js/frappe/views/workspace/blocks/chart.js
@@ -32,7 +32,7 @@ export default class Chart extends Block {
this.new('chart');
if (this.data && this.data.chart_name) {
- let has_data = this.make('chart', __(this.data.chart_name));
+ let has_data = this.make('chart', this.data.chart_name);
if (!has_data) return;
}
diff --git a/frappe/public/js/frappe/views/workspace/blocks/onboarding.js b/frappe/public/js/frappe/views/workspace/blocks/onboarding.js
index c0ba529853..c76141996f 100644
--- a/frappe/public/js/frappe/views/workspace/blocks/onboarding.js
+++ b/frappe/public/js/frappe/views/workspace/blocks/onboarding.js
@@ -73,7 +73,7 @@ export default class Onboarding extends Block {
make(block, block_name) {
let block_data = this.config.page_data['onboardings'].items.find(obj => {
- return obj.label == block_name;
+ return obj.label == __(block_name);
});
if (!block_data) return false;
this.wrapper.innerHTML = '';
diff --git a/frappe/public/js/frappe/views/workspace/blocks/shortcut.js b/frappe/public/js/frappe/views/workspace/blocks/shortcut.js
index 2be5da0d4b..ef9bfa8cf9 100644
--- a/frappe/public/js/frappe/views/workspace/blocks/shortcut.js
+++ b/frappe/public/js/frappe/views/workspace/blocks/shortcut.js
@@ -51,7 +51,7 @@ export default class Shortcut extends Block {
this.new('shortcut');
if (this.data && this.data.shortcut_name) {
- let has_data = this.make('shortcut', __(this.data.shortcut_name));
+ let has_data = this.make('shortcut', this.data.shortcut_name);
if (!has_data) return;
}
diff --git a/frappe/public/js/frappe/widgets/widget_dialog.js b/frappe/public/js/frappe/widgets/widget_dialog.js
index d1ba75227b..bba29ffaf9 100644
--- a/frappe/public/js/frappe/widgets/widget_dialog.js
+++ b/frappe/public/js/frappe/widgets/widget_dialog.js
@@ -228,30 +228,35 @@ class CardDialog extends WidgetDialog {
}
process_data(data) {
- data.links.map((item, idx) => {
- let message = '';
- let row = idx+1;
+ let message = '';
- if (!item.link_type) {
- message = "Following fields have missing values: