feat: show private workspaces in My Workspaces

This commit is contained in:
sokumon 2025-11-03 10:46:12 +05:30
parent dc45418aa8
commit 219ba386ab
7 changed files with 98 additions and 73 deletions

View file

@ -7,11 +7,12 @@ context("Workspace 2.0", () => {
it("Navigate to page from sidebar", () => {
cy.visit("/app/build");
cy.get(".codex-editor__redactor .ce-block");
cy.get('.sidebar-item-container[item-title="Website"]').first().click();
cy.location("pathname").should("eq", "/app/website");
cy.get('.sidebar-item-container[item-title="Page"]').first().click();
cy.location("pathname").should("eq", "/app/page");
});
it("Create Private Page", () => {
cy.visit("/app/build");
cy.intercept({
method: "POST",
url: "api/method/frappe.desk.doctype.workspace.workspace.new_page",
@ -27,61 +28,16 @@ context("Workspace 2.0", () => {
cy.get_open_dialog().find(".btn-primary").click();
// check if sidebar item is added in pubic section
cy.get('.sidebar-item-container[item-title="Test Private Page"]').should(
"have.attr",
"item-public",
"0"
);
cy.get('.sidebar-item-container[item-title="Test Private Page"]');
cy.wait(300);
cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
cy.wait(300);
cy.get('.sidebar-item-container[item-title="Test Private Page"]').should(
"have.attr",
"item-public",
"0"
);
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(".btn-new-workspace").click();
cy.fill_field("title", "Test Child Page", "Data");
cy.fill_field("parent", "Test Private Page", "Select");
cy.fill_field("type", "Workspace", "Select");
cy.get_open_dialog().find(".modal-header").click();
cy.wait(300);
cy.get_open_dialog().find(".btn-primary").click();
// check if sidebar item is added in pubic section
cy.get('.sidebar-item-container[item-title="Test Child Page"]').should(
"have.attr",
"item-public",
"0"
);
cy.wait(300);
cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
cy.wait(300);
cy.get('.sidebar-item-container[item-title="Test Child Page"]').should(
"have.attr",
"item-public",
"0"
);
cy.get('.sidebar-item-container[item-title="Test Private Page"]');
cy.wait("@new_page");
});
it("Add New Block", () => {
cy.get('.sidebar-item-container[item-title="Test Private Page"]').as("sidebar-item");
cy.get("@sidebar-item").find(".standard-sidebar-item").first().click({ force: true });
cy.get(".btn-edit-workspace").click({ force: true });
cy.get(".ce-block").click().type("{enter}");

View file

@ -25,19 +25,11 @@ context("Workspace Blocks", () => {
cy.get_open_dialog().find(".btn-primary").click();
// check if sidebar item is added in private section
cy.get('.sidebar-item-container[item-title="Test Block Page"]').should(
"have.attr",
"item-public",
"0"
);
cy.get('.sidebar-item-container[item-title="Test Block Page"]');
cy.wait(300);
cy.get('.standard-actions .btn-primary[data-label="Save"]').click();
cy.wait(300);
cy.get('.sidebar-item-container[item-title="Test Block Page"]').should(
"have.attr",
"item-public",
"0"
);
cy.get('.sidebar-item-container[item-title="Test Block Page"]');
cy.wait("@new_page");
});

View file

@ -6,7 +6,9 @@ from json import loads
import frappe
from frappe import _
from frappe.boot import get_sidebar_items
from frappe.desk.desktop import get_workspace_sidebar_items, save_new_widget
from frappe.desk.doctype.workspace_sidebar.workspace_sidebar import add_to_my_workspace
from frappe.desk.utils import validate_route_conflict
from frappe.model.document import Document
from frappe.model.rename_doc import rename_doc
@ -294,7 +296,10 @@ def new_page(new_page):
doc.sequence_id = last_sequence_id(doc) + 1
doc.save(ignore_permissions=True)
return get_workspace_sidebar_items()
# add to workspace sidebar items
if not doc.public:
add_to_my_workspace(doc)
return {"workspace_pages": get_workspace_sidebar_items(), "sidebar_items": get_sidebar_items()}
@frappe.whitelist()

View file

@ -6,7 +6,6 @@ from json import JSONDecodeError, dumps, loads
import frappe
from frappe import _
from frappe.desk.doctype.workspace.workspace import is_workspace_manager
from frappe.model.document import Document
from frappe.modules.utils import create_directory_on_app_path
@ -52,6 +51,10 @@ class WorkspaceSidebar(Document):
frappe.throw(_("You need to be Workspace Manager to delete a public workspace."))
def is_workspace_manager():
return "Workspace Manager" in frappe.get_roles()
def create_workspace_sidebar_for_workspaces():
from frappe.query_builder import DocType
@ -98,3 +101,19 @@ def add_sidebar_items(sidebar_title, sidebar_items):
w.items = items
w.save()
return w
def add_to_my_workspace(workspace):
private_sidebar = frappe.get_doc("Workspace Sidebar", "My Workspaces")
workspace_sidebar = {
"label": workspace.title,
"type": "Link",
"link_to": f"{workspace.title}-{workspace.for_user}",
"link_type": "Workspace",
"icon": workspace.icon,
}
private_sidebar.append("items", workspace_sidebar)
private_sidebar.save()

View file

@ -58,12 +58,18 @@ frappe.ui.Sidebar = class Sidebar {
}
setup(workspace_title) {
this.workspace_title = workspace_title;
this.check_for_private_workspace(workspace_title);
this.prepare();
this.$sidebar.attr("data-title", this.workspace_title);
this.sidebar_header = new frappe.ui.SidebarHeader(this);
this.make_sidebar();
this.setup_complete = true;
}
check_for_private_workspace(workspace_title) {
if (workspace_title == "private") {
this.workspace_title = "My Workspaces";
}
}
setup_events() {
const me = this;
frappe.router.on("change", function (router) {
@ -239,12 +245,6 @@ frappe.ui.Sidebar = class Sidebar {
this.set_active_workspace_item();
}
reload() {
return frappe.workspace.get_pages().then((r) => {
frappe.boot.sidebar_pages = r;
this.setup_pages();
});
}
set_height() {
$(".body-sidebar").css("height", window.innerHeight + "px");
$(".overlay").css("height", window.innerHeight + "px");
@ -274,7 +274,13 @@ frappe.ui.Sidebar = class Sidebar {
let route = frappe.get_route();
if (frappe.get_route()[0] == "setup-wizard") return;
if (route[0] == "Workspaces") {
let workspace = route[1];
let workspace;
if (!route[1]) {
workspace = "My Workspaces";
} else {
workspace = route[1];
}
frappe.app.sidebar.setup(workspace);
} else if (route[0] == "List" || route[0] == "Form") {
let doctype = route[1];

View file

@ -550,6 +550,7 @@ frappe.views.Workspace = class Workspace {
}
create_page(new_page) {
const me = this;
return new Promise((resolve) => {
frappe.call({
method: "frappe.desk.doctype.workspace.workspace.new_page",
@ -565,11 +566,18 @@ frappe.views.Workspace = class Workspace {
indicator: "green",
});
}
frappe.boot.sidebar_pages = r.message;
if (!frappe.boot.app_data_map["private"] && new_page.public === 0) {
this.sidebar.apps_switcher.add_private_app();
if (r.message) {
frappe.boot.sidebar_pages = r.message.workspace_pages;
frappe.boot.workspaces = r.message.workspace_pages;
me.workspaces = frappe.boot.workspaces.pages;
me.setup_pages(frappe.boot.sidebar_pages.pages);
frappe.boot.workspace_sidebar_item = r.message.sidebar_items;
}
if (new_page.public === 0) {
frappe.app.sidebar.setup("private");
}
resolve();
}
},
@ -577,6 +585,31 @@ frappe.views.Workspace = class Workspace {
});
}
setup_pages(all_pages) {
all_pages.forEach((page) => {
page.is_editable = !page.public || this.has_access;
if (typeof page.content == "string") {
page.content = JSON.parse(page.content);
}
});
if (all_pages) {
frappe.workspaces = {};
frappe.workspace_list = [];
frappe.workspace_map = {};
for (let page of all_pages) {
frappe.workspaces[frappe.router.slug(page.name)] = {
name: page.name,
public: page.public,
};
if (!page.app && page.module) {
page.app = frappe.boot.module_app[frappe.slug(page.module)];
}
frappe.workspace_map[page.name] = page;
frappe.workspace_list.push(page);
}
}
}
initialize_editorjs(blocks) {
this.tools = {
header: {
@ -722,7 +755,7 @@ frappe.views.Workspace = class Workspace {
this._page = null;
return this.get_pages().then((r) => {
frappe.boot.sidebar_pages = r;
this.sidebar.setup_pages();
this.setup_pages(frappe.boot.workspaces.pages);
this.show();
if (this.undo) this.undo.readOnly = true;
});

View file

@ -0,0 +1,14 @@
{
"app": "frappe",
"creation": "2025-11-03 03:11:08.482620",
"docstatus": 0,
"doctype": "Workspace Sidebar",
"header_icon": "user",
"idx": 0,
"items": [],
"modified": "2025-11-03 10:44:42.883207",
"modified_by": "Administrator",
"name": "My Workspaces",
"owner": "Administrator",
"title": "My Workspaces"
}