feat: implement comments and activity panel in workspace

- Added CommentsPanel component for managing comments on documents.
- Integrated comment creation, deletion, and resolution functionalities.
- Implemented activity tracking for document interactions.
- Enhanced SketchPage with editing and saving capabilities.
- Introduced template management API endpoints for creating, sharing, and deleting templates.
- Added runtime validation report for frontend and backend.
- Created GettingStartedPanel for user onboarding with template options.
- Implemented Playwright E2E tests for accessibility and export functionality.
This commit is contained in:
Anurag Jangid 2026-10-22 21:18:10 +05:30
parent 6e354ba041
commit 809235e962
41 changed files with 2840 additions and 285 deletions

View file

@ -30,6 +30,7 @@ def _serialize(doc: dict[str, Any]) -> dict[str, Any]:
"title": doc["title"],
"template_id": doc.get("template_id"),
"stead_id": doc.get("stead_id"),
"parent_page_id": doc.get("parent_page_id"),
"content": doc.get("content", {}),
"created_by": doc["created_by"],
"created_at": doc["created_at"],
@ -61,6 +62,10 @@ async def create_document(
created_by: str,
data: DocumentCreate,
) -> dict[str, Any]:
if data.parent_page_id:
parent = await db[COLLECTION].find_one({"_id": data.parent_page_id, **access_query(owner_id)})
if parent is None or parent.get("type") == "stead":
raise ValueError("Parent page is not accessible or is not a page")
now = datetime.now(UTC)
doc_id = str(uuid.uuid4())
doc = {
@ -70,6 +75,7 @@ async def create_document(
"title": data.title,
"template_id": data.template_id,
"stead_id": data.stead_id,
"parent_page_id": data.parent_page_id,
"content": data.content,
"created_by": created_by,
"created_at": now,
@ -97,6 +103,7 @@ async def list_documents(
user_id: int,
doc_type: CreateType | None = None,
stead_id: str | None = None,
parent_page_id: str | None = None,
starred: bool | None = None,
sort: SortField = "updated_at",
) -> list[dict[str, Any]]:
@ -106,6 +113,8 @@ async def list_documents(
extras["type"] = doc_type
if stead_id:
extras["stead_id"] = stead_id
if parent_page_id:
extras["parent_page_id"] = parent_page_id
if starred is not None:
extras["starred"] = starred
if extras:
@ -156,6 +165,23 @@ async def update_document(
return None
if not can_edit(existing, user_id):
return None
if data.content is not None or data.title is not None:
from app.services.history_service import create_version
await create_version(
db,
existing,
user_id,
existing.get("created_by", "Collaborator"),
"Before update",
)
if "parent_page_id" in data.model_fields_set:
if data.parent_page_id == doc_id:
return None
if data.parent_page_id is not None:
parent = await db[COLLECTION].find_one({"_id": data.parent_page_id, **access_query(user_id)})
if parent is None or parent.get("type") == "stead":
return None
updates: dict[str, Any] = {"updated_at": datetime.now(UTC)}
if data.title is not None:
@ -164,6 +190,10 @@ async def update_document(
updates["content"] = data.content
if data.starred is not None:
updates["starred"] = data.starred
if data.stead_id is not None:
updates["stead_id"] = data.stead_id
if "parent_page_id" in data.model_fields_set:
updates["parent_page_id"] = data.parent_page_id
result = await db[COLLECTION].find_one_and_update(
{"_id": doc_id},