diff --git a/apps/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx b/apps/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx
index d87cb4f69..e0e0af498 100644
--- a/apps/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx
+++ b/apps/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx
@@ -191,8 +191,7 @@ export function FavoriteFolder(props: Props) {
align="end"
disabled={isDragging || isMobile}
>
-
+
+
diff --git a/apps/web/core/components/workspace/sidebar/help-section/root.tsx b/apps/web/core/components/workspace/sidebar/help-section/root.tsx
index 6b23af1b2..7cadccf1c 100644
--- a/apps/web/core/components/workspace/sidebar/help-section/root.tsx
+++ b/apps/web/core/components/workspace/sidebar/help-section/root.tsx
@@ -32,7 +32,7 @@ export const HelpMenuRoot = observer(function HelpMenuRoot() {
,
isActive: isNeedHelpOpen,
@@ -59,23 +59,11 @@ export const HelpMenuRoot = observer(function HelpMenuRoot() {
-
-
+ toggleShortcutsListModal(true)}>
+ {t("keyboard_shortcuts")}
-
-
+ setProductUpdatesModalOpen(true)}>
+ {t("whats_new")}
window.open("https://forum.plane.so", "_blank", "noopener,noreferrer")}>
diff --git a/apps/web/core/components/workspace/sidebar/projects-list-item.tsx b/apps/web/core/components/workspace/sidebar/projects-list-item.tsx
index 9d0fa86c0..db15fd7c6 100644
--- a/apps/web/core/components/workspace/sidebar/projects-list-item.tsx
+++ b/apps/web/core/components/workspace/sidebar/projects-list-item.tsx
@@ -313,8 +313,7 @@ export const SidebarProjectsListItem = observer(function SidebarProjectsListItem
align="end"
disabled={isDragging || isMobile}
>
-
+
+
)}
<>
diff --git a/apps/web/core/components/workspace/sidebar/user-menu-root.tsx b/apps/web/core/components/workspace/sidebar/user-menu-root.tsx
index 95b78f56e..c5ea330db 100644
--- a/apps/web/core/components/workspace/sidebar/user-menu-root.tsx
+++ b/apps/web/core/components/workspace/sidebar/user-menu-root.tsx
@@ -59,7 +59,7 @@ export const UserMenuRoot = observer(function UserMenuRoot() {
className="flex items-center"
customButton={
{
- if (rootStore?.user?.data?.id) this.currentUserId = rootStore?.user?.data?.id;
- if (this.workspaceSlug !== rootStore.router.workspaceSlug) this.workspaceSlug = rootStore.router.workspaceSlug;
- if (this.teamspaceId !== rootStore.router.teamspaceId) this.teamspaceId = rootStore.router.teamspaceId;
- if (this.projectId !== rootStore.router.projectId) this.projectId = rootStore.router.projectId;
- if (this.cycleId !== rootStore.router.cycleId) this.cycleId = rootStore.router.cycleId;
- if (this.moduleId !== rootStore.router.moduleId) this.moduleId = rootStore.router.moduleId;
- if (this.viewId !== rootStore.router.viewId) this.viewId = rootStore.router.viewId;
- if (this.globalViewId !== rootStore.router.globalViewId) this.globalViewId = rootStore.router.globalViewId;
- if (this.userId !== rootStore.router.userId) this.userId = rootStore.router.userId;
- if (!isEmpty(rootStore?.state?.stateMap)) this.stateMap = rootStore?.state?.stateMap;
- if (!isEmpty(rootStore?.state?.projectStates)) this.stateDetails = rootStore?.state?.projectStates;
- if (!isEmpty(rootStore?.state?.workspaceStates)) this.workspaceStateDetails = rootStore?.state?.workspaceStates;
- if (!isEmpty(rootStore?.label?.labelMap)) this.labelMap = rootStore?.label?.labelMap;
- if (!isEmpty(rootStore?.memberRoot?.workspace?.workspaceMemberMap))
- this.workSpaceMemberRolesMap = rootStore?.memberRoot?.workspace?.memberMap || undefined;
- if (!isEmpty(rootStore?.memberRoot?.memberMap)) this.memberMap = rootStore?.memberRoot?.memberMap || undefined;
- if (!isEmpty(rootStore?.projectRoot?.project?.projectMap))
- this.projectMap = rootStore?.projectRoot?.project?.projectMap;
- if (!isEmpty(rootStore?.module?.moduleMap)) this.moduleMap = rootStore?.module?.moduleMap;
- if (!isEmpty(rootStore?.cycle?.cycleMap)) this.cycleMap = rootStore?.cycle?.cycleMap;
+ runInAction(() => {
+ if (rootStore?.user?.data?.id) this.currentUserId = rootStore?.user?.data?.id;
+ if (this.workspaceSlug !== rootStore.router.workspaceSlug) this.workspaceSlug = rootStore.router.workspaceSlug;
+ if (this.teamspaceId !== rootStore.router.teamspaceId) this.teamspaceId = rootStore.router.teamspaceId;
+ if (this.projectId !== rootStore.router.projectId) this.projectId = rootStore.router.projectId;
+ if (this.cycleId !== rootStore.router.cycleId) this.cycleId = rootStore.router.cycleId;
+ if (this.moduleId !== rootStore.router.moduleId) this.moduleId = rootStore.router.moduleId;
+ if (this.viewId !== rootStore.router.viewId) this.viewId = rootStore.router.viewId;
+ if (this.globalViewId !== rootStore.router.globalViewId) this.globalViewId = rootStore.router.globalViewId;
+ if (this.userId !== rootStore.router.userId) this.userId = rootStore.router.userId;
+ if (!isEmpty(rootStore?.state?.stateMap)) this.stateMap = rootStore?.state?.stateMap;
+ if (!isEmpty(rootStore?.state?.projectStates)) this.stateDetails = rootStore?.state?.projectStates;
+ if (!isEmpty(rootStore?.state?.workspaceStates)) this.workspaceStateDetails = rootStore?.state?.workspaceStates;
+ if (!isEmpty(rootStore?.label?.labelMap)) this.labelMap = rootStore?.label?.labelMap;
+ if (!isEmpty(rootStore?.memberRoot?.workspace?.workspaceMemberMap))
+ this.workSpaceMemberRolesMap = rootStore?.memberRoot?.workspace?.memberMap || undefined;
+ if (!isEmpty(rootStore?.memberRoot?.memberMap)) this.memberMap = rootStore?.memberRoot?.memberMap || undefined;
+ if (!isEmpty(rootStore?.projectRoot?.project?.projectMap))
+ this.projectMap = rootStore?.projectRoot?.project?.projectMap;
+ if (!isEmpty(rootStore?.module?.moduleMap)) this.moduleMap = rootStore?.module?.moduleMap;
+ if (!isEmpty(rootStore?.cycle?.cycleMap)) this.cycleMap = rootStore?.cycle?.cycleMap;
+ });
});
this.issues = new IssueStore();
diff --git a/apps/web/core/store/workspace/index.ts b/apps/web/core/store/workspace/index.ts
index 27bb4701e..cd7f1cf49 100644
--- a/apps/web/core/store/workspace/index.ts
+++ b/apps/web/core/store/workspace/index.ts
@@ -190,7 +190,9 @@ export class BaseWorkspaceRootStore implements IWorkspaceRootStore {
});
return workspaceResponse;
} finally {
- this.loader = false;
+ runInAction(() => {
+ this.loader = false;
+ });
}
};
diff --git a/packages/shared-state/src/store/work-item-filters/filter.store.ts b/packages/shared-state/src/store/work-item-filters/filter.store.ts
index f7826ccc9..be78621d2 100644
--- a/packages/shared-state/src/store/work-item-filters/filter.store.ts
+++ b/packages/shared-state/src/store/work-item-filters/filter.store.ts
@@ -4,7 +4,7 @@
* See the LICENSE file for details.
*/
-import { action, makeObservable, observable } from "mobx";
+import { action, makeObservable, observable, runInAction } from "mobx";
import { computedFn } from "mobx-utils";
// plane imports
import type { TExpressionOptions } from "@plane/constants";
@@ -49,6 +49,7 @@ export interface IWorkItemFilterStore {
export class WorkItemFilterStore implements IWorkItemFilterStore {
// observable
filters: IWorkItemFilterStore["filters"];
+ private _pendingFilters = new Map();
constructor() {
this.filters = new Map();
@@ -69,9 +70,10 @@ export class WorkItemFilterStore implements IWorkItemFilterStore {
* @param entityId - The entity id.
* @returns The filter instance.
*/
- getFilter: IWorkItemFilterStore["getFilter"] = computedFn((entityType, entityId) =>
- this.filters.get(this._getFilterKey(entityType, entityId))
- );
+ getFilter: IWorkItemFilterStore["getFilter"] = computedFn((entityType, entityId) => {
+ const key = this._getFilterKey(entityType, entityId);
+ return this.filters.get(key) ?? this._pendingFilters.get(key);
+ });
// ------------ actions ------------
@@ -80,7 +82,8 @@ export class WorkItemFilterStore implements IWorkItemFilterStore {
* If the instance already exists, updates its expression options to ensure they're current.
*/
getOrCreateFilter: IWorkItemFilterStore["getOrCreateFilter"] = action((params) => {
- const existingFilter = this.getFilter(params.entityType, params.entityId);
+ const filterKey = this._getFilterKey(params.entityType, params.entityId);
+ const existingFilter = this._pendingFilters.get(filterKey) ?? this.getFilter(params.entityType, params.entityId);
if (existingFilter) {
// Update expression options on existing filter to ensure they're current
if (params.expressionOptions) {
@@ -99,8 +102,13 @@ export class WorkItemFilterStore implements IWorkItemFilterStore {
// create new filter instance
const newFilter = this._initializeFilterInstance(params);
- const filterKey = this._getFilterKey(params.entityType, params.entityId);
- this.filters.set(filterKey, newFilter);
+ this._pendingFilters.set(filterKey, newFilter);
+ queueMicrotask(() => {
+ runInAction(() => {
+ this._pendingFilters.delete(filterKey);
+ this.filters.set(filterKey, newFilter);
+ });
+ });
return newFilter;
});
@@ -193,7 +201,9 @@ export class WorkItemFilterStore implements IWorkItemFilterStore {
* @param entityId - The entity id.
*/
deleteFilter: IWorkItemFilterStore["deleteFilter"] = action((entityType, entityId) => {
- this.filters.delete(this._getFilterKey(entityType, entityId));
+ const key = this._getFilterKey(entityType, entityId);
+ this._pendingFilters.delete(key);
+ this.filters.delete(key);
});
// ------------ private helpers ------------
diff --git a/packages/ui/src/drag-handle.tsx b/packages/ui/src/drag-handle.tsx
index dc67d087b..175e8c700 100644
--- a/packages/ui/src/drag-handle.tsx
+++ b/packages/ui/src/drag-handle.tsx
@@ -12,23 +12,24 @@ import { cn } from "./utils";
interface IDragHandle {
className?: string;
disabled?: boolean;
+ as?: "button" | "div";
}
export const DragHandle = forwardRef(function DragHandle(
props: IDragHandle,
- ref: React.ForwardedRef
+ ref: React.ForwardedRef
) {
- const { className, disabled = false } = props;
+ const { className, disabled = false, as: Component = "button" } = props;
if (disabled) {
return ;
}
return (
-
+
);
});
diff --git a/packages/ui/src/dropdowns/custom-menu.tsx b/packages/ui/src/dropdowns/custom-menu.tsx
index 7b202a3c7..5baeb907c 100644
--- a/packages/ui/src/dropdowns/custom-menu.tsx
+++ b/packages/ui/src/dropdowns/custom-menu.tsx
@@ -246,18 +246,17 @@ function CustomMenu(props: ICustomMenuDropdownProps) {
{({ open }) => (
<>
{customButton ? (
-
-
+ // oxlint-disable-next-line jsx_a11y/click-events-have-key-events oxlint-disable-next-line jsx_a11y/no-static-element-interactions
+
+ {customButton}
) : (
<>
@@ -462,32 +461,33 @@ function SubMenu(props: ICustomSubMenuProps) {
}
function MenuItem(props: ICustomMenuItemProps) {
- const { children, disabled = false, onClick, className } = props;
+ const { children, disabled = false, onClick, className, as: Component = "button" } = props;
const submenuContext = useSubMenu();
return (
{({ active, close }) => (
-
+
)}
);
diff --git a/packages/ui/src/dropdowns/custom-search-select.tsx b/packages/ui/src/dropdowns/custom-search-select.tsx
index 78eed100b..4dabb4a1b 100644
--- a/packages/ui/src/dropdowns/custom-search-select.tsx
+++ b/packages/ui/src/dropdowns/custom-search-select.tsx
@@ -99,22 +99,20 @@ export function CustomSearchSelect(props: ICustomSearchSelectProps) {
return (
<>
{customButton ? (
-
-
+
+ {customButton}
) : (
diff --git a/packages/ui/src/dropdowns/custom-select.tsx b/packages/ui/src/dropdowns/custom-select.tsx
index ef0724d67..ffd8f77dc 100644
--- a/packages/ui/src/dropdowns/custom-select.tsx
+++ b/packages/ui/src/dropdowns/custom-select.tsx
@@ -82,17 +82,15 @@ function CustomSelect(props: ICustomSelectProps) {
>
<>
{customButton ? (
-
-
+
+ {customButton}
) : (
diff --git a/packages/ui/src/dropdowns/helper.tsx b/packages/ui/src/dropdowns/helper.tsx
index 508686d1c..8ca48504a 100644
--- a/packages/ui/src/dropdowns/helper.tsx
+++ b/packages/ui/src/dropdowns/helper.tsx
@@ -94,6 +94,7 @@ export interface ICustomMenuItemProps {
disabled?: boolean;
onClick?: (args?: any) => void;
className?: string;
+ as?: "button" | "div";
}
export interface ICustomSelectItemProps {