Skip to content

Commit 473932a

Browse files
[WEB-3291] dev: app sidebar revamp (#6578)
* chore: workspace constant and types updated * chore: workspace service, store and app theme store updated * dev: extended sidebar implementation and code refactor * chore: ux improvements * chore: sidebar preference endpoint updated * chore: sidebar preference endpoint updated * chore: sidebar preference endpoint updated * chore: code refactor * chore: code refactor * chore: radix-ui react-scroll-area added to plane ui package * chore: scrollbar color token added to tailwind config * dev: scroll area component * chore-scroll-area-component-improvement * fix: build error * chore: code refactor --------- Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
1 parent a9aeeb6 commit 473932a

File tree

25 files changed

+1153
-251
lines changed

25 files changed

+1153
-251
lines changed

apiserver/plane/app/views/workspace/user_preference.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ def get(self, request, slug):
3030
keys = [
3131
key
3232
for key, _ in WorkspaceUserPreference.UserPreferenceKeys.choices
33-
if key not in ["projects"]
3433
]
3534

3635
for preference in keys:
@@ -40,20 +39,28 @@ def get(self, request, slug):
4039
preference = WorkspaceUserPreference.objects.bulk_create(
4140
[
4241
WorkspaceUserPreference(
43-
key=key, user=request.user, workspace=workspace
42+
key=key, user=request.user, workspace=workspace, sort_order=(65535 + (i*10000))
4443
)
45-
for key in create_preference_keys
44+
for i, key in enumerate(create_preference_keys)
4645
],
4746
batch_size=10,
4847
ignore_conflicts=True,
4948
)
5049

51-
preference = WorkspaceUserPreference.objects.filter(
50+
preferences = WorkspaceUserPreference.objects.filter(
5251
user=request.user, workspace_id=workspace.id
53-
)
52+
).order_by("sort_order").values("key", "is_pinned", "sort_order")
53+
54+
55+
user_preferences = {}
5456

57+
for preference in preferences:
58+
user_preferences[(str(preference["key"]))] = {
59+
"is_pinned": preference["is_pinned"],
60+
"sort_order": preference["sort_order"],
61+
}
5562
return Response(
56-
preference.values("key", "is_pinned", "sort_order"),
63+
user_preferences,
5764
status=status.HTTP_200_OK,
5865
)
5966

apiserver/plane/db/models/workspace.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,13 @@ def __str__(self):
391391
class WorkspaceUserPreference(BaseModel):
392392
"""Preference for the workspace for a user"""
393393

394-
class UserPreferenceKeys(models.TextChoices):
395-
PROJECTS = "projects", "Projects"
396-
ANALYTICS = "analytics", "Analytics"
397-
CYCLES = "cycles", "Cycles"
394+
class UserPreferenceKeys(models.TextChoices):
398395
VIEWS = "views", "Views"
396+
ACTIVE_CYCLES = "active_cycles", "Active Cycles"
397+
ANALYTICS = "analytics", "Analytics"
398+
DRAFTS = "drafts", "Drafts"
399399
YOUR_WORK = "your_work", "Your Work"
400-
400+
ARCHIVES = "archives", "Archives"
401401

402402
workspace = models.ForeignKey(
403403
"db.Workspace",

packages/constants/src/workspace.ts

Lines changed: 87 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,48 +84,42 @@ export const WORKSPACE_SETTINGS = {
8484
i18n_label: "workspace_settings.settings.general.title",
8585
href: `/settings`,
8686
access: [EUserWorkspaceRoles.ADMIN],
87-
highlight: (pathname: string, baseUrl: string) =>
88-
pathname === `${baseUrl}/settings/`,
87+
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/`,
8988
},
9089
members: {
9190
key: "members",
9291
i18n_label: "workspace_settings.settings.members.title",
9392
href: `/settings/members`,
9493
access: [EUserWorkspaceRoles.ADMIN],
95-
highlight: (pathname: string, baseUrl: string) =>
96-
pathname === `${baseUrl}/settings/members/`,
94+
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/members/`,
9795
},
9896
"billing-and-plans": {
9997
key: "billing-and-plans",
10098
i18n_label: "workspace_settings.settings.billing_and_plans.title",
10199
href: `/settings/billing`,
102100
access: [EUserWorkspaceRoles.ADMIN],
103-
highlight: (pathname: string, baseUrl: string) =>
104-
pathname === `${baseUrl}/settings/billing/`,
101+
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/billing/`,
105102
},
106103
export: {
107104
key: "export",
108105
i18n_label: "workspace_settings.settings.exports.title",
109106
href: `/settings/exports`,
110107
access: [EUserWorkspaceRoles.ADMIN],
111-
highlight: (pathname: string, baseUrl: string) =>
112-
pathname === `${baseUrl}/settings/exports/`,
108+
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/exports/`,
113109
},
114110
webhooks: {
115111
key: "webhooks",
116112
i18n_label: "workspace_settings.settings.webhooks.title",
117113
href: `/settings/webhooks`,
118114
access: [EUserWorkspaceRoles.ADMIN],
119-
highlight: (pathname: string, baseUrl: string) =>
120-
pathname === `${baseUrl}/settings/webhooks/`,
115+
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/webhooks/`,
121116
},
122117
"api-tokens": {
123118
key: "api-tokens",
124119
i18n_label: "workspace_settings.settings.api_tokens.title",
125120
href: `/settings/api-tokens`,
126121
access: [EUserWorkspaceRoles.ADMIN],
127-
highlight: (pathname: string, baseUrl: string) =>
128-
pathname === `${baseUrl}/settings/api-tokens/`,
122+
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/api-tokens/`,
129123
},
130124
};
131125

@@ -256,3 +250,84 @@ export const DEFAULT_GLOBAL_VIEWS_LIST: {
256250
i18n_label: "default_global_view.subscribed",
257251
},
258252
];
253+
254+
export interface IWorkspaceSidebarNavigationItem {
255+
key: string;
256+
labelTranslationKey: string;
257+
href: string;
258+
access: EUserWorkspaceRoles[];
259+
}
260+
261+
export const WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS: Record<string, IWorkspaceSidebarNavigationItem> = {
262+
"your-work": {
263+
key: "your_work",
264+
labelTranslationKey: "your_work",
265+
href: `/profile/`,
266+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
267+
},
268+
views: {
269+
key: "views",
270+
labelTranslationKey: "views",
271+
href: `/workspace-views/all-issues/`,
272+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
273+
},
274+
"active-cycles": {
275+
key: "active_cycles",
276+
labelTranslationKey: "cycles",
277+
href: `/active-cycles/`,
278+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
279+
},
280+
analytics: {
281+
key: "analytics",
282+
labelTranslationKey: "analytics",
283+
href: `/analytics/`,
284+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
285+
},
286+
drafts: {
287+
key: "drafts",
288+
labelTranslationKey: "drafts",
289+
href: `/drafts/`,
290+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
291+
},
292+
archives: {
293+
key: "archives",
294+
labelTranslationKey: "archives",
295+
href: `/projects/archives/`,
296+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
297+
},
298+
};
299+
export const WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS_LINKS: IWorkspaceSidebarNavigationItem[] = [
300+
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["views"],
301+
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["active-cycles"],
302+
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["analytics"],
303+
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["your-work"],
304+
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["drafts"],
305+
WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS["archives"],
306+
];
307+
308+
export const WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS: Record<string, IWorkspaceSidebarNavigationItem> = {
309+
home: {
310+
key: "home",
311+
labelTranslationKey: "home.title",
312+
href: `/`,
313+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
314+
},
315+
notifications: {
316+
key: "notifications",
317+
labelTranslationKey: "notification.label",
318+
href: `/notifications/`,
319+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
320+
},
321+
projects: {
322+
key: "projects",
323+
labelTranslationKey: "projects",
324+
href: `/projects/`,
325+
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
326+
},
327+
};
328+
329+
export const WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS_LINKS: IWorkspaceSidebarNavigationItem[] = [
330+
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["home"],
331+
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["notifications"],
332+
WORKSPACE_SIDEBAR_STATIC_NAVIGATION_ITEMS["projects"],
333+
];

packages/hooks/src/use-outside-click-detector.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export const useOutsideClickDetector = (
88
const handleClick = (event: MouseEvent) => {
99
if (ref.current && !ref.current.contains(event.target as any)) {
1010
// check for the closest element with attribute name data-prevent-outside-click
11-
const preventOutsideClickElement = (
12-
event.target as unknown as HTMLElement | undefined
13-
)?.closest("[data-prevent-outside-click]");
11+
const preventOutsideClickElement = (event.target as unknown as HTMLElement | undefined)?.closest(
12+
"[data-prevent-outside-click]"
13+
);
1414
// if the closest element with attribute name data-prevent-outside-click is found, return
1515
if (preventOutsideClickElement) {
1616
return;

packages/types/src/workspace.d.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import type {
2-
ICycle,
3-
IProjectMember,
4-
IUser,
5-
IUserLite,
6-
IWorkspaceViewProps,
7-
} from "@plane/types";
1+
import type { ICycle, IProjectMember, IUser, IUserLite, IWorkspaceViewProps, TPaginationInfo } from "@plane/types";
82
import { EUserWorkspaceRoles } from "@plane/constants"; // TODO: check if importing this over here causes circular dependency
93
import { TUserPermissions } from "./enums";
104

@@ -229,3 +223,13 @@ export interface IWorkspaceAnalyticsResponse {
229223
export type TWorkspacePaginationInfo = TPaginationInfo & {
230224
results: IWorkspace[];
231225
};
226+
227+
export interface IWorkspaceSidebarNavigationItem {
228+
key?: string;
229+
is_pinned: boolean;
230+
sort_order: number;
231+
}
232+
233+
export interface IWorkspaceSidebarNavigation {
234+
[key: string]: IWorkspaceSidebarNavigationItem;
235+
}

packages/ui/src/icons/overview-icon.tsx

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,13 @@ import * as React from "react";
22

33
import { ISvgIcons } from "./type";
44

5-
export const OverviewIcon: React.FC<ISvgIcons> = ({ width = "16", height = "16", className = "" }) => (
6-
<svg
7-
width={width}
8-
height={height}
9-
className={className}
10-
viewBox="0 0 16 16"
11-
fill="none"
12-
xmlns="http://www.w3.org/2000/svg"
13-
>
5+
export const OverviewIcon: React.FC<ISvgIcons> = ({ className = "text-current", ...rest }) => (
6+
<svg viewBox="0 0 16 16" className={className} xmlns="http://www.w3.org/2000/svg" {...rest}>
147
<path
15-
fill-rule="evenodd"
16-
clip-rule="evenodd"
8+
fillRule="evenodd"
9+
clipRule="evenodd"
1710
d="M2.5 3C2.5 2.86739 2.55268 2.74021 2.64645 2.64645C2.74021 2.55268 2.86739 2.5 3 2.5H3.5C9.02267 2.5 13.5 6.97733 13.5 12.5V13C13.5 13.1326 13.4473 13.2598 13.3536 13.3536C13.2598 13.4473 13.1326 13.5 13 13.5H12.5C12.3674 13.5 12.2402 13.4473 12.1464 13.3536C12.0527 13.2598 12 13.1326 12 13V12.5C12 7.80533 8.19467 4 3.5 4H3C2.86739 4 2.74021 3.94732 2.64645 3.85355C2.55268 3.75979 2.5 3.63261 2.5 3.5V3ZM2.5 7.5C2.5 7.36739 2.55268 7.24022 2.64645 7.14645C2.74021 7.05268 2.86739 7 3 7H3.5C4.22227 7 4.93747 7.14226 5.60476 7.41866C6.27205 7.69506 6.87837 8.10019 7.38909 8.61091C7.89981 9.12164 8.30494 9.72795 8.58134 10.3952C8.85774 11.0625 9 11.7777 9 12.5V13C9 13.1326 8.94732 13.2598 8.85355 13.3536C8.75978 13.4473 8.63261 13.5 8.5 13.5H8C7.86739 13.5 7.74022 13.4473 7.64645 13.3536C7.55268 13.2598 7.5 13.1326 7.5 13V12.5C7.5 11.4391 7.07857 10.4217 6.32843 9.67157C5.57828 8.92143 4.56087 8.5 3.5 8.5H3C2.86739 8.5 2.74021 8.44732 2.64645 8.35355C2.55268 8.25978 2.5 8.13261 2.5 8V7.5ZM2.5 12.5C2.5 12.2348 2.60536 11.9804 2.79289 11.7929C2.98043 11.6054 3.23478 11.5 3.5 11.5C3.76522 11.5 4.01957 11.6054 4.20711 11.7929C4.39464 11.9804 4.5 12.2348 4.5 12.5C4.5 12.7652 4.39464 13.0196 4.20711 13.2071C4.01957 13.3946 3.76522 13.5 3.5 13.5C3.23478 13.5 2.98043 13.3946 2.79289 13.2071C2.60536 13.0196 2.5 12.7652 2.5 12.5Z"
18-
fill="#455068"
11+
fill="currentColor"
1912
/>
2013
</svg>
2114
);

0 commit comments

Comments
 (0)