[WEB-1956] fix: Keyboard shortcuts (#5134)
* fix: shortcuts * fix: naming * fix: structure optimization
This commit is contained in:
parent
c2b5464e40
commit
e7948eabf2
5 changed files with 90 additions and 19 deletions
|
|
@ -46,7 +46,7 @@ export const CommandModal: React.FC = observer(() => {
|
|||
// hooks
|
||||
const { getProjectById, workspaceProjectIds } = useProject();
|
||||
const { isMobile } = usePlatformOS();
|
||||
const { canPerformWorkspaceCreateActions } = useUser();
|
||||
const { canPerformAnyCreateAction } = useUser();
|
||||
// states
|
||||
const [placeholder, setPlaceholder] = useState("Type a command or search...");
|
||||
const [resultsCount, setResultsCount] = useState(0);
|
||||
|
|
@ -286,7 +286,7 @@ export const CommandModal: React.FC = observer(() => {
|
|||
{workspaceSlug &&
|
||||
workspaceProjectIds &&
|
||||
workspaceProjectIds.length > 0 &&
|
||||
canPerformWorkspaceCreateActions && (
|
||||
canPerformAnyCreateAction && (
|
||||
<Command.Group heading="Issue">
|
||||
<Command.Item
|
||||
onSelect={() => {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,12 @@ export const CommandPalette: FC = observer(() => {
|
|||
const { toggleSidebar } = useAppTheme();
|
||||
const { setTrackElement } = useEventTracker();
|
||||
const { platform } = usePlatformOS();
|
||||
const { data: currentUser, canPerformProjectCreateActions, canPerformWorkspaceCreateActions } = useUser();
|
||||
const {
|
||||
data: currentUser,
|
||||
canPerformProjectCreateActions,
|
||||
canPerformWorkspaceCreateActions,
|
||||
canPerformAnyCreateAction,
|
||||
} = useUser();
|
||||
const {
|
||||
issues: { removeIssue },
|
||||
} = useIssuesStore();
|
||||
|
|
@ -120,6 +125,18 @@ export const CommandPalette: FC = observer(() => {
|
|||
[canPerformWorkspaceCreateActions]
|
||||
);
|
||||
|
||||
const performAnyProjectCreateActions = useCallback(
|
||||
(showToast: boolean = true) => {
|
||||
if (!canPerformAnyCreateAction && showToast)
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "You don't have permission to perform this action.",
|
||||
});
|
||||
return canPerformAnyCreateAction;
|
||||
},
|
||||
[canPerformAnyCreateAction]
|
||||
);
|
||||
|
||||
const shortcutsList: {
|
||||
global: Record<string, { title: string; description: string; action: () => void }>;
|
||||
workspace: Record<string, { title: string; description: string; action: () => void }>;
|
||||
|
|
@ -222,7 +239,10 @@ export const CommandPalette: FC = observer(() => {
|
|||
}
|
||||
} else if (!isAnyModalOpen) {
|
||||
setTrackElement("Shortcut key");
|
||||
if (Object.keys(shortcutsList.global).includes(keyPressed) && performWorkspaceCreateActions())
|
||||
if (
|
||||
Object.keys(shortcutsList.global).includes(keyPressed) &&
|
||||
((!projectId && performAnyProjectCreateActions()) || performProjectCreateActions())
|
||||
)
|
||||
shortcutsList.global[keyPressed].action();
|
||||
// workspace authorized actions
|
||||
else if (
|
||||
|
|
@ -244,6 +264,7 @@ export const CommandPalette: FC = observer(() => {
|
|||
}
|
||||
},
|
||||
[
|
||||
performAnyProjectCreateActions,
|
||||
performProjectCreateActions,
|
||||
performWorkspaceCreateActions,
|
||||
copyIssueUrlToClipboard,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import { renderFormattedPayloadDate, getDate } from "@/helpers/date-time.helper"
|
|||
import { getChangedIssuefields, getDescriptionPlaceholder } from "@/helpers/issue.helper";
|
||||
import { shouldRenderProject } from "@/helpers/project.helper";
|
||||
// hooks
|
||||
import { useProjectEstimates, useInstance, useIssueDetail, useProject, useWorkspace } from "@/hooks/store";
|
||||
import { useProjectEstimates, useInstance, useIssueDetail, useProject, useWorkspace, useUser } from "@/hooks/store";
|
||||
import useKeypress from "@/hooks/use-keypress";
|
||||
import { useProjectIssueProperties } from "@/hooks/use-project-issue-properties";
|
||||
// services
|
||||
|
|
@ -121,6 +121,8 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||
const workspaceStore = useWorkspace();
|
||||
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug?.toString())?.id as string;
|
||||
const { config } = useInstance();
|
||||
const { projectsWithCreatePermissions } = useUser();
|
||||
|
||||
const { getProjectById } = useProject();
|
||||
const { areEstimateEnabledByProjectId } = useProjectEstimates();
|
||||
|
||||
|
|
@ -341,7 +343,8 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||
rules={{
|
||||
required: true,
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
render={({ field: { value, onChange } }) =>
|
||||
projectsWithCreatePermissions && projectsWithCreatePermissions[value!] ? (
|
||||
<div className="h-7">
|
||||
<ProjectDropdown
|
||||
value={value}
|
||||
|
|
@ -354,7 +357,10 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||
tabIndex={getTabIndex("project_id")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<h3 className="text-xl font-medium text-custom-text-200">{data?.id ? "Update" : "Create"} Issue</h3>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ export interface IUserStore {
|
|||
// computed
|
||||
canPerformProjectCreateActions: boolean;
|
||||
canPerformWorkspaceCreateActions: boolean;
|
||||
canPerformAnyCreateAction: boolean;
|
||||
projectsWithCreatePermissions: { [projectId: string]: number } | null;
|
||||
}
|
||||
|
||||
export class UserStore implements IUserStore {
|
||||
|
|
@ -91,6 +93,8 @@ export class UserStore implements IUserStore {
|
|||
// computed
|
||||
canPerformProjectCreateActions: computed,
|
||||
canPerformWorkspaceCreateActions: computed,
|
||||
canPerformAnyCreateAction: computed,
|
||||
projectsWithCreatePermissions: computed,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +140,26 @@ export class UserStore implements IUserStore {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description fetches the prjects with write permissions
|
||||
* @returns {{[projectId: string]: number} || null}
|
||||
*/
|
||||
fetchProjectsWithCreatePermissions() {
|
||||
const allWorkspaceRoles =
|
||||
this.membership.workspaceProjectsRole &&
|
||||
this.membership.workspaceProjectsRole[this.membership.router.workspaceSlug || ""];
|
||||
return (
|
||||
(allWorkspaceRoles &&
|
||||
Object.keys(allWorkspaceRoles)
|
||||
.filter((key) => allWorkspaceRoles[key] >= EUserProjectRoles.MEMBER)
|
||||
.reduce(
|
||||
(res: { [projectId: string]: number }, key: string) => ((res[key] = allWorkspaceRoles[key]), res),
|
||||
{}
|
||||
)) ||
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description updates the current user
|
||||
* @param data
|
||||
|
|
@ -229,6 +253,23 @@ export class UserStore implements IUserStore {
|
|||
this.store.resetOnSignOut();
|
||||
};
|
||||
|
||||
/**
|
||||
* @description returns projects where user has permissions
|
||||
* @returns {{[projectId: string]: number} || null}
|
||||
*/
|
||||
get projectsWithCreatePermissions() {
|
||||
return this.fetchProjectsWithCreatePermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description returns true if user has permissions to write in any project
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get canPerformAnyCreateAction() {
|
||||
const filteredProjects = this.fetchProjectsWithCreatePermissions();
|
||||
return filteredProjects ? Object.keys(filteredProjects).length > 0 : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description tells if user has project create actions permissions
|
||||
* @returns {boolean}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { ProjectMemberService } from "@/services/project";
|
|||
import { UserService } from "@/services/user.service";
|
||||
// plane web store
|
||||
import { CoreRootStore } from "../root.store";
|
||||
import { IRouterStore } from "../router.store";
|
||||
|
||||
export interface IUserMembershipStore {
|
||||
// observables
|
||||
|
|
@ -47,6 +48,8 @@ export interface IUserMembershipStore {
|
|||
leaveWorkspace: (workspaceSlug: string) => Promise<void>;
|
||||
joinProject: (workspaceSlug: string, projectIds: string[]) => Promise<any>;
|
||||
leaveProject: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
|
||||
router: IRouterStore;
|
||||
}
|
||||
|
||||
export class UserMembershipStore implements IUserMembershipStore {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue