dev: handled the project details and workitem identifier in user favorites and recents (#4097)

This commit is contained in:
guru_sainath
2025-09-12 16:45:18 +05:30
committed by GitHub
parent f11f5d43dc
commit 4cc6a40f99
22 changed files with 416 additions and 345 deletions

View File

@@ -12,7 +12,7 @@ from asgiref.sync import sync_to_async
# Module imports
from plane.db.models import User
from plane.graphql.permissions.workspace import IsAuthenticated
from plane.graphql.types.users import UserType
from plane.graphql.types.user import UserType
@strawberry.type

View File

@@ -12,7 +12,7 @@ from strawberry.types import Info
# Module imports
from plane.db.models import Profile, WorkspaceMember
from plane.graphql.permissions.workspace import IsAuthenticated
from plane.graphql.types.users import ProfileType, ProfileUpdateInputType
from plane.graphql.types.user import ProfileType, ProfileUpdateInputType
@strawberry.type

View File

@@ -16,7 +16,7 @@ from strawberry.types import Info
from plane.db.models import UserFavorite, UserRecentVisit
from plane.graphql.helpers.teamspace import project_member_filter_via_teamspaces_async
from plane.graphql.permissions.workspace import IsAuthenticated, WorkspaceBasePermission
from plane.graphql.types.users import UserFavoriteType, UserRecentVisitType, UserType
from plane.graphql.types.user import UserFavoriteType, UserRecentVisitType, UserType
from plane.graphql.utils.timezone.user import user_timezone_converter
@@ -51,6 +51,7 @@ class UserFavoritesQuery:
| (Q(project__isnull=False) & Q(project_teamspace_filter.query)),
~Q(entity_type="view"),
)
.prefetch_related("project")
.order_by("-created_at")
.distinct()
)
@@ -76,6 +77,7 @@ class UserRecentVisitQuery:
recent_visits = await sync_to_async(
lambda: list(
UserRecentVisit.objects.filter(workspace__slug=slug, user_id=user_id)
.prefetch_related("project")
.exclude(entity_name__in=["view", "workspace_page"])
.order_by("-visited_at")
)
@@ -105,6 +107,7 @@ class UserRecentVisitQuery:
deleted_at=await user_timezone_converter(
user, visit.deleted_at if visit.deleted_at else None
),
project_details=visit.project,
)
for visit in recent_visits
]

View File

@@ -10,7 +10,7 @@ from strawberry.permission import PermissionExtension
# Module Imports
from plane.db.models import Profile
from plane.graphql.types.users import ProfileType
from plane.graphql.types.user import ProfileType
from plane.graphql.permissions.workspace import IsAuthenticated

View File

@@ -15,7 +15,7 @@ from asgiref.sync import sync_to_async
# Module Imports
from plane.db.models import Cycle, Issue, CycleUserProperties
from plane.graphql.types.users import UserType
from plane.graphql.types.user import UserType
@strawberry_django.type(Cycle)

View File

@@ -4,7 +4,7 @@ from typing import Optional
import strawberry
# module imports
from plane.graphql.types.users import UserType, ProfileType
from plane.graphql.types.user import UserType, ProfileType
from plane.graphql.types.workspace import WorkspaceType
from plane.graphql.types.device import DeviceInformationType

View File

@@ -11,7 +11,7 @@ from asgiref.sync import sync_to_async
# Module Imports
from plane.db.models import IssueActivity
from plane.graphql.types.users import UserLiteType
from plane.graphql.types.user import UserLiteType
from plane.graphql.utils.timezone import user_timezone_converter

View File

@@ -15,7 +15,7 @@ from strawberry.scalars import JSON
# Module Imports
from plane.db.models import IssueComment
from plane.graphql.types.users import UserLiteType
from plane.graphql.types.user import UserLiteType
from plane.graphql.utils.timezone import user_timezone_converter

View File

@@ -9,7 +9,7 @@ from asgiref.sync import sync_to_async
# Module Imports
from plane.db.models import IntakeIssue, IssueActivity
from plane.graphql.types.users import UserLiteType
from plane.graphql.types.user import UserLiteType
from plane.graphql.utils.timezone import user_timezone_converter

View File

@@ -15,7 +15,7 @@ from strawberry.scalars import JSON
# Module Imports
from plane.db.models import IssueComment
from plane.graphql.types.users import UserLiteType
from plane.graphql.types.user import UserLiteType
from plane.graphql.utils.timezone import user_timezone_converter

View File

@@ -11,7 +11,7 @@ from asgiref.sync import sync_to_async
# Module Imports
from plane.db.models import IssueActivity
from plane.graphql.types.users import UserLiteType
from plane.graphql.types.user import UserLiteType
from plane.graphql.utils.timezone import user_timezone_converter

View File

@@ -14,7 +14,7 @@ from strawberry.scalars import JSON
# Module Imports
from plane.db.models import IssueComment
from plane.graphql.types.users import UserLiteType
from plane.graphql.types.user import UserLiteType
from plane.graphql.utils.timezone import user_timezone_converter

View File

@@ -11,7 +11,7 @@ from strawberry.scalars import JSON
# Module Imports
from plane.graphql.utils.timezone import user_timezone_converter
from plane.db.models import Module, Issue, ModuleUserProperties
from plane.graphql.types.users import UserType
from plane.graphql.types.user import UserType
# Third-party library imports
from asgiref.sync import sync_to_async

View File

@@ -13,7 +13,7 @@ from strawberry.scalars import JSON
from plane.db.models import Issue, Notification
from plane.graphql.types.project import ProjectType
from plane.graphql.types.users import UserType
from plane.graphql.types.user import UserType
from plane.graphql.utils.issue_activity import issue_activity_comment_string
# Module imports

View File

@@ -172,7 +172,7 @@ class NestedParentPageLiteType:
is_description_empty: bool
@strawberry.field
def owned_by(self) -> list[ProjectLiteType]:
def owned_by(self) -> list[strawberry.ID]:
return self.owned_by_id
@strawberry.field

View File

@@ -126,8 +126,8 @@ class ProjectMemberType:
@strawberry_django.type(Project)
class ProjectLiteType:
id: strawberry.ID
name: str
identifier: str
is_member: Optional[bool]
logo_props: JSON
id: Optional[strawberry.ID] = None
name: Optional[str] = None
identifier: Optional[str] = None
is_member: Optional[bool] = False
logo_props: Optional[JSON] = None

View File

@@ -1 +1,4 @@
from .base import UserType, UserLiteType, ProfileType, ProfileUpdateInputType
from .delete import UserDeleteType, UserDeleteInputType
from .favorite import UserFavoriteType, UserFavoriteEntityData
from .recent import UserRecentVisitType, UserRecentVisitEntityData

View File

@@ -0,0 +1,116 @@
# Python imports
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional
# Strawberry imports
import strawberry
import strawberry_django
# Django Imports
from asgiref.sync import sync_to_async
from strawberry.scalars import JSON
from strawberry.types import Info
# Module imports
from plane.db.models import (
Profile,
User,
Workspace,
)
@strawberry_django.type(User)
class UserType:
id: strawberry.ID
avatar: Optional[str]
cover_image: Optional[str]
date_joined: datetime
display_name: str
email: str
first_name: str
last_name: str
is_active: bool
is_bot: bool
is_email_verified: bool
user_timezone: str
username: str
is_password_autoset: bool
last_login_medium: str
avatar_url: Optional[str]
cover_image_url: Optional[str]
@strawberry_django.type(User)
class UserLiteType:
id: Optional[strawberry.ID] = None
first_name: Optional[str] = None
last_name: Optional[str] = None
avatar: Optional[str] = None
avatar_url: Optional[str] = None
is_bot: bool = False
display_name: Optional[str] = None
@strawberry.input
@dataclass
class ProfileUpdateInputType:
mobile_timezone_auto_set: Optional[bool] = field(default_factory=lambda: None)
is_mobile_onboarded: Optional[bool] = field(default_factory=lambda: None)
mobile_onboarding_step: Optional[JSON] = field(default_factory=lambda: None)
@strawberry_django.type(Profile)
class ProfileType:
id: strawberry.ID
user: strawberry.ID
theme: JSON
is_tour_completed: bool
onboarding_step: JSON
use_case: Optional[str]
role: Optional[str]
is_onboarded: bool
last_workspace_id: Optional[strawberry.ID]
billing_address_country: JSON
billing_address: Optional[str]
has_billing_address: bool
company_name: str
mobile_timezone_auto_set: bool
is_mobile_onboarded: bool
mobile_onboarding_step = Optional[JSON]
@strawberry.field
def user(self) -> int:
return self.user_id
@strawberry.field
async def last_workspace_id(self, info: Info) -> Optional[strawberry.ID]:
if (
self.last_workspace_id is not None
and await sync_to_async(
Workspace.objects.filter(
pk=self.last_workspace_id,
workspace_member__member_id=info.context.user.id,
workspace_member__is_active=True,
).exists
)()
):
return self.last_workspace_id
# Query the fallback workspace for the current user if last_workspace_id is null
fallback_workspace = await sync_to_async(
Workspace.objects.filter(
workspace_member__member_id=info.context.user.id,
workspace_member__is_active=True,
)
.order_by("created_at")
.first
)()
if fallback_workspace:
profile = await sync_to_async(Profile.objects.get)(id=self.id)
profile.last_workspace_id = fallback_workspace.id
await sync_to_async(profile.save)()
return fallback_workspace.id
return None

View File

@@ -0,0 +1,143 @@
# Python imports
from datetime import datetime
from typing import Optional
# Strawberry imports
import strawberry
import strawberry_django
# Django Imports
from asgiref.sync import sync_to_async
from strawberry.scalars import JSON
# Module imports
from plane.db.models import (
Cycle,
Issue,
IssueView,
Module,
Page,
Project,
UserFavorite,
)
from plane.graphql.utils.timezone import user_timezone_converter
from plane.graphql.types.project import ProjectLiteType
@strawberry.type
class UserFavoriteEntityData:
id: Optional[strawberry.ID] = None
name: Optional[str] = None
logo_props: Optional[JSON] = None
is_epic: Optional[bool] = False
workitem_identifier: Optional[str] = None
@strawberry_django.type(UserFavorite)
class UserFavoriteType:
id: strawberry.ID
entity_type: str
entity_identifier: Optional[str]
name: Optional[str]
is_folder: bool
sequence: float
parent: Optional[strawberry.ID]
created_at: Optional[datetime]
updated_at: Optional[datetime]
deleted_at: Optional[datetime]
project: Optional[strawberry.ID]
@strawberry.field
def workspace(self) -> int:
return self.workspace_id
@strawberry.field
def project(self) -> int:
return self.project_id
@strawberry.field
def project_details(self) -> ProjectLiteType:
if self.project:
return self.project
return ProjectLiteType()
@strawberry.field
def created_at(self, info) -> Optional[datetime]:
converted_date = user_timezone_converter(info.context.user, self.created_at)
return converted_date
@strawberry.field
def updated_at(self, info) -> Optional[datetime]:
converted_date = user_timezone_converter(info.context.user, self.updated_at)
return converted_date
@strawberry.field
async def entity_data(self) -> Optional[UserFavoriteEntityData]:
# where entity_identifier is project_id and entity_type is project
if self.entity_identifier and self.entity_type == "project":
project = await sync_to_async(
Project.objects.filter(id=self.entity_identifier).first
)()
if project:
return UserFavoriteEntityData(
id=project.id, name=project.name, logo_props=project.logo_props
)
return None
# where entity_identifier is cycle_id and entity_type is cycle
elif self.entity_identifier and self.entity_type == "cycle":
cycle = await sync_to_async(
Cycle.objects.filter(id=self.entity_identifier).first
)()
if cycle:
return UserFavoriteEntityData(
id=cycle.id, name=cycle.name, logo_props=cycle.logo_props
)
return None
# where entity_identifier is module id and entity_type is module
elif self.entity_identifier and self.entity_type == "module":
module = await sync_to_async(
Module.objects.filter(id=self.entity_identifier).first
)()
if module:
return UserFavoriteEntityData(
id=module.id, name=module.name, logo_props=module.logo_props
)
return None
# where entity_identifier is issue id and entity_type is issue
elif self.entity_identifier and self.entity_type == "issue":
issue = await sync_to_async(
Issue.objects.filter(id=self.entity_identifier).first
)()
if issue:
workitem_identifier = f"{self.project.identifier}-{issue.sequence_id}"
return UserFavoriteEntityData(
id=issue.id,
name=issue.name,
logo_props=None,
workitem_identifier=workitem_identifier,
)
return None
# where entity_identifier is issue_view id and entity_type is issue_view
elif self.entity_identifier and self.entity_type == "view":
issue_view = await sync_to_async(
IssueView.objects.filter(id=self.entity_identifier).first
)()
if issue_view:
return UserFavoriteEntityData(
id=issue_view.id,
name=issue_view.name,
logo_props=issue_view.logo_props,
)
return None
# where entity_identifier is page id and entity_type is page
elif self.entity_identifier and self.entity_type == "page":
page = await sync_to_async(
Page.objects.filter(id=self.entity_identifier).first
)()
if page:
return UserFavoriteEntityData(
id=page.id, name=page.name, logo_props=page.logo_props
)
return None
# where entity_identifier and entity_type is None
return None

View File

@@ -0,0 +1,130 @@
# Python imports
from datetime import datetime
from typing import Optional
# Strawberry imports
import strawberry
import strawberry_django
# Django Imports
from asgiref.sync import sync_to_async
from django.db.models import Q
from strawberry.scalars import JSON
# Module imports
from plane.db.models import (
Cycle,
Issue,
IssueView,
Module,
Page,
Project,
UserRecentVisit,
)
from plane.graphql.types.project import ProjectLiteType
@strawberry.type
class UserRecentVisitEntityData:
id: Optional[strawberry.ID] = None
name: Optional[str] = None
logo_props: Optional[JSON] = None
is_epic: Optional[bool] = False
workitem_identifier: Optional[str] = None
@strawberry_django.type(UserRecentVisit)
class UserRecentVisitType:
id: strawberry.ID
entity_identifier: str
entity_name: str
user: strawberry.ID
visited_at: Optional[datetime]
workspace: Optional[strawberry.ID]
project: Optional[strawberry.ID]
project_details: Optional[ProjectLiteType]
created_by: Optional[strawberry.ID]
updated_by: Optional[strawberry.ID]
created_at: Optional[datetime]
updated_at: Optional[datetime]
deleted_at: Optional[datetime]
@strawberry.field
async def entity_data(self) -> Optional[UserRecentVisitEntityData]:
# where entity_identifier is project_id and entity_name is project
if self.entity_identifier and self.entity_name == "project":
project = await sync_to_async(
Project.objects.filter(id=self.entity_identifier).first
)()
if project:
return UserRecentVisitEntityData(
id=project.id, name=project.name, logo_props=project.logo_props
)
return None
# where entity_identifier is cycle_id and entity_name is cycle
elif self.entity_identifier and self.entity_name == "cycle":
cycle = await sync_to_async(
Cycle.objects.filter(id=self.entity_identifier).first
)()
if cycle:
return UserRecentVisitEntityData(
id=cycle.id, name=cycle.name, logo_props=cycle.logo_props
)
return None
# where entity_identifier is module id and entity_name is module
elif self.entity_identifier and self.entity_name == "module":
module = await sync_to_async(
Module.objects.filter(id=self.entity_identifier).first
)()
if module:
return UserRecentVisitEntityData(
id=module.id, name=module.name, logo_props=module.logo_props
)
return None
# where entity_identifier is issue id and entity_name is issue
elif self.entity_identifier and self.entity_name == "issue":
issue_base_query = Issue.objects.filter(id=self.entity_identifier)
issue = await sync_to_async(issue_base_query.first)()
if issue:
epic_issue = await sync_to_async(
issue_base_query.filter(
project__project_projectfeature__is_epic_enabled=True
)
.filter(Q(type__isnull=False) & Q(type__is_epic=True))
.first
)()
workitem_identifier = (
f"{self.project_details.identifier}-{issue.sequence_id}"
)
return UserRecentVisitEntityData(
id=issue.id,
name=issue.name,
logo_props=None,
is_epic=epic_issue is not None,
workitem_identifier=workitem_identifier,
)
return None
# where entity_identifier is issue_view id and entity_name is issue_view
elif self.entity_identifier and self.entity_name == "view":
issue_view = await sync_to_async(
IssueView.objects.filter(id=self.entity_identifier).first
)()
if issue_view:
return UserRecentVisitEntityData(
id=issue_view.id,
name=issue_view.name,
logo_props=issue_view.logo_props,
)
return None
# where entity_identifier is page id and entity_name is page
elif self.entity_identifier and self.entity_name == "page":
page = await sync_to_async(
Page.objects.filter(id=self.entity_identifier).first
)()
if page:
return UserRecentVisitEntityData(
id=page.id, name=page.name, logo_props=page.logo_props
)
return None
# where entity_identifier and entity_name is None
return None

View File

@@ -1,324 +0,0 @@
# Python imports
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional
# Strawberry imports
import strawberry
import strawberry_django
# Django Imports
from asgiref.sync import sync_to_async
from django.db.models import Q
from strawberry.scalars import JSON
from strawberry.types import Info
# Module imports
from plane.db.models import (
Cycle,
Issue,
IssueView,
Module,
Page,
Profile,
Project,
User,
UserFavorite,
UserRecentVisit,
Workspace,
)
from plane.graphql.utils.timezone import user_timezone_converter
@strawberry_django.type(User)
class UserType:
id: strawberry.ID
avatar: Optional[str]
cover_image: Optional[str]
date_joined: datetime
display_name: str
email: str
first_name: str
last_name: str
is_active: bool
is_bot: bool
is_email_verified: bool
user_timezone: str
username: str
is_password_autoset: bool
last_login_medium: str
avatar_url: Optional[str]
cover_image_url: Optional[str]
@strawberry_django.type(User)
class UserLiteType:
id: Optional[strawberry.ID] = None
first_name: Optional[str] = None
last_name: Optional[str] = None
avatar: Optional[str] = None
avatar_url: Optional[str] = None
is_bot: bool = False
display_name: Optional[str] = None
@strawberry.input
@dataclass
class ProfileUpdateInputType:
mobile_timezone_auto_set: Optional[bool] = field(default_factory=lambda: None)
is_mobile_onboarded: Optional[bool] = field(default_factory=lambda: None)
mobile_onboarding_step: Optional[JSON] = field(default_factory=lambda: None)
@strawberry_django.type(Profile)
class ProfileType:
id: strawberry.ID
user: strawberry.ID
theme: JSON
is_tour_completed: bool
onboarding_step: JSON
use_case: Optional[str]
role: Optional[str]
is_onboarded: bool
last_workspace_id: Optional[strawberry.ID]
billing_address_country: JSON
billing_address: Optional[str]
has_billing_address: bool
company_name: str
mobile_timezone_auto_set: bool
is_mobile_onboarded: bool
mobile_onboarding_step = Optional[JSON]
@strawberry.field
def user(self) -> int:
return self.user_id
@strawberry.field
async def last_workspace_id(self, info: Info) -> Optional[strawberry.ID]:
if (
self.last_workspace_id is not None
and await sync_to_async(
Workspace.objects.filter(
pk=self.last_workspace_id,
workspace_member__member_id=info.context.user.id,
workspace_member__is_active=True,
).exists
)()
):
return self.last_workspace_id
# Query the fallback workspace for the current user if last_workspace_id is null
fallback_workspace = await sync_to_async(
Workspace.objects.filter(
workspace_member__member_id=info.context.user.id,
workspace_member__is_active=True,
)
.order_by("created_at")
.first
)()
if fallback_workspace:
profile = await sync_to_async(Profile.objects.get)(id=self.id)
profile.last_workspace_id = fallback_workspace.id
await sync_to_async(profile.save)()
return fallback_workspace.id
return None
# user favorite
@strawberry.type
class UserFavoriteEntityData:
id: Optional[strawberry.ID]
name: Optional[str]
logo_props: Optional[JSON]
is_epic: Optional[bool] = False
@strawberry_django.type(UserFavorite)
class UserFavoriteType:
id: strawberry.ID
entity_type: str
entity_identifier: Optional[str]
name: Optional[str]
is_folder: bool
sequence: float
parent: Optional[strawberry.ID]
created_at: Optional[datetime]
updated_at: Optional[datetime]
deleted_at: Optional[datetime]
project: Optional[strawberry.ID]
@strawberry.field
def project(self) -> int:
return self.project_id
@strawberry.field
def created_at(self, info) -> Optional[datetime]:
converted_date = user_timezone_converter(info.context.user, self.created_at)
return converted_date
@strawberry.field
def updated_at(self, info) -> Optional[datetime]:
converted_date = user_timezone_converter(info.context.user, self.updated_at)
return converted_date
@strawberry.field
async def entity_data(self) -> Optional[UserFavoriteEntityData]:
# where entity_identifier is project_id and entity_type is project
if self.entity_identifier and self.entity_type == "project":
project = await sync_to_async(
Project.objects.filter(id=self.entity_identifier).first
)()
if project:
return UserFavoriteEntityData(
id=project.id, name=project.name, logo_props=project.logo_props
)
return None
# where entity_identifier is cycle_id and entity_type is cycle
elif self.entity_identifier and self.entity_type == "cycle":
cycle = await sync_to_async(
Cycle.objects.filter(id=self.entity_identifier).first
)()
if cycle:
return UserFavoriteEntityData(
id=cycle.id, name=cycle.name, logo_props=cycle.logo_props
)
return None
# where entity_identifier is module id and entity_type is module
elif self.entity_identifier and self.entity_type == "module":
module = await sync_to_async(
Module.objects.filter(id=self.entity_identifier).first
)()
if module:
return UserFavoriteEntityData(
id=module.id, name=module.name, logo_props=module.logo_props
)
return None
# where entity_identifier is issue id and entity_type is issue
elif self.entity_identifier and self.entity_type == "issue":
issue = await sync_to_async(
Issue.objects.filter(id=self.entity_identifier).first
)()
if issue:
return UserFavoriteEntityData(
id=issue.id, name=issue.name, logo_props=None
)
return None
# where entity_identifier is issue_view id and entity_type is issue_view
elif self.entity_identifier and self.entity_type == "view":
issue_view = await sync_to_async(
IssueView.objects.filter(id=self.entity_identifier).first
)()
if issue_view:
return UserFavoriteEntityData(
id=issue_view.id,
name=issue_view.name,
logo_props=issue_view.logo_props,
)
return None
# where entity_identifier is page id and entity_type is page
elif self.entity_identifier and self.entity_type == "page":
page = await sync_to_async(
Page.objects.filter(id=self.entity_identifier).first
)()
if page:
return UserFavoriteEntityData(
id=page.id, name=page.name, logo_props=page.logo_props
)
return None
# where entity_identifier and entity_type is None
return None
# user recent visit
@strawberry_django.type(UserRecentVisit)
class UserRecentVisitType:
id: strawberry.ID
entity_identifier: str
entity_name: str
user: strawberry.ID
visited_at: Optional[datetime]
workspace: Optional[strawberry.ID]
project: Optional[strawberry.ID]
created_by: Optional[strawberry.ID]
updated_by: Optional[strawberry.ID]
created_at: Optional[datetime]
updated_at: Optional[datetime]
deleted_at: Optional[datetime]
@strawberry.field
async def entity_data(self) -> Optional[UserFavoriteEntityData]:
# where entity_identifier is project_id and entity_name is project
if self.entity_identifier and self.entity_name == "project":
project = await sync_to_async(
Project.objects.filter(id=self.entity_identifier).first
)()
if project:
return UserFavoriteEntityData(
id=project.id, name=project.name, logo_props=project.logo_props
)
return None
# where entity_identifier is cycle_id and entity_name is cycle
elif self.entity_identifier and self.entity_name == "cycle":
cycle = await sync_to_async(
Cycle.objects.filter(id=self.entity_identifier).first
)()
if cycle:
return UserFavoriteEntityData(
id=cycle.id, name=cycle.name, logo_props=cycle.logo_props
)
return None
# where entity_identifier is module id and entity_name is module
elif self.entity_identifier and self.entity_name == "module":
module = await sync_to_async(
Module.objects.filter(id=self.entity_identifier).first
)()
if module:
return UserFavoriteEntityData(
id=module.id, name=module.name, logo_props=module.logo_props
)
return None
# where entity_identifier is issue id and entity_name is issue
elif self.entity_identifier and self.entity_name == "issue":
issue_base_query = Issue.objects.filter(id=self.entity_identifier)
issue = await sync_to_async(issue_base_query.first)()
if issue:
epic_issue = await sync_to_async(
issue_base_query.filter(
project__project_projectfeature__is_epic_enabled=True
)
.filter(Q(type__isnull=False) & Q(type__is_epic=True))
.first
)()
return UserFavoriteEntityData(
id=issue.id,
name=issue.name,
logo_props=None,
is_epic=epic_issue is not None,
)
return None
# where entity_identifier is issue_view id and entity_name is issue_view
elif self.entity_identifier and self.entity_name == "view":
issue_view = await sync_to_async(
IssueView.objects.filter(id=self.entity_identifier).first
)()
if issue_view:
return UserFavoriteEntityData(
id=issue_view.id,
name=issue_view.name,
logo_props=issue_view.logo_props,
)
return None
# where entity_identifier is page id and entity_name is page
elif self.entity_identifier and self.entity_name == "page":
page = await sync_to_async(
Page.objects.filter(id=self.entity_identifier).first
)()
if page:
return UserFavoriteEntityData(
id=page.id, name=page.name, logo_props=page.logo_props
)
return None
# where entity_identifier and entity_name is None
return None

View File

@@ -14,7 +14,7 @@ from strawberry.types import Info
# Module Imports
from plane.db.models import Workspace, WorkspaceMember
from plane.graphql.types.users import UserType
from plane.graphql.types.user import UserType
from plane.graphql.utils.timezone import user_timezone_converter