-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: command palette file structure * fix: identifier search
- Loading branch information
1 parent
d14ca3a
commit aea9a40
Showing
19 changed files
with
741 additions
and
754 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { Command } from "cmdk"; | ||
import { FileText, GithubIcon, MessageSquare, Rocket } from "lucide-react"; | ||
// mobx store | ||
import { useMobxStore } from "lib/mobx/store-provider"; | ||
// ui | ||
import { DiscordIcon } from "@plane/ui"; | ||
|
||
type Props = { | ||
closePalette: () => void; | ||
}; | ||
|
||
export const CommandPaletteHelpActions: React.FC<Props> = (props) => { | ||
const { closePalette } = props; | ||
|
||
const { | ||
commandPalette: { toggleShortcutModal }, | ||
} = useMobxStore(); | ||
|
||
return ( | ||
<Command.Group heading="Help"> | ||
<Command.Item | ||
onSelect={() => { | ||
closePalette(); | ||
toggleShortcutModal(true); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<Rocket className="h-3.5 w-3.5" /> | ||
Open keyboard shortcuts | ||
</div> | ||
</Command.Item> | ||
<Command.Item | ||
onSelect={() => { | ||
closePalette(); | ||
window.open("https://docs.plane.so/", "_blank"); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<FileText className="h-3.5 w-3.5" /> | ||
Open Plane documentation | ||
</div> | ||
</Command.Item> | ||
<Command.Item | ||
onSelect={() => { | ||
closePalette(); | ||
window.open("https://discord.com/invite/A92xrEGCge", "_blank"); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<DiscordIcon className="h-4 w-4" color="rgb(var(--color-text-200))" /> | ||
Join our Discord | ||
</div> | ||
</Command.Item> | ||
<Command.Item | ||
onSelect={() => { | ||
closePalette(); | ||
window.open("https://github.com/makeplane/plane/issues/new/choose", "_blank"); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<GithubIcon className="h-4 w-4" color="rgb(var(--color-text-200))" /> | ||
Report a bug | ||
</div> | ||
</Command.Item> | ||
<Command.Item | ||
onSelect={() => { | ||
closePalette(); | ||
(window as any)?.$crisp.push(["do", "chat:open"]); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<MessageSquare className="h-3.5 w-3.5" /> | ||
Chat with us | ||
</div> | ||
</Command.Item> | ||
</Command.Group> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export * from "./issue-actions"; | ||
export * from "./help-actions"; | ||
export * from "./project-actions"; | ||
export * from "./search-results"; | ||
export * from "./theme-actions"; | ||
export * from "./workspace-settings-actions"; |
166 changes: 166 additions & 0 deletions
166
web/components/command-palette/actions/issue-actions/actions-list.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import { useRouter } from "next/router"; | ||
import { observer } from "mobx-react-lite"; | ||
import { Command } from "cmdk"; | ||
import { LinkIcon, Signal, Trash2, UserMinus2, UserPlus2 } from "lucide-react"; | ||
// mobx store | ||
import { useMobxStore } from "lib/mobx/store-provider"; | ||
// hooks | ||
import useToast from "hooks/use-toast"; | ||
// ui | ||
import { DoubleCircleIcon, UserGroupIcon } from "@plane/ui"; | ||
// helpers | ||
import { copyTextToClipboard } from "helpers/string.helper"; | ||
// types | ||
import { IIssue } from "types"; | ||
|
||
type Props = { | ||
closePalette: () => void; | ||
issueDetails: IIssue | undefined; | ||
pages: string[]; | ||
setPages: (pages: string[]) => void; | ||
setPlaceholder: (placeholder: string) => void; | ||
setSearchTerm: (searchTerm: string) => void; | ||
}; | ||
|
||
export const CommandPaletteIssueActions: React.FC<Props> = observer((props) => { | ||
const { closePalette, issueDetails, pages, setPages, setPlaceholder, setSearchTerm } = props; | ||
|
||
const router = useRouter(); | ||
const { workspaceSlug, projectId } = router.query; | ||
|
||
const { | ||
commandPalette: { toggleCommandPaletteModal, toggleDeleteIssueModal }, | ||
issueDetail: { updateIssue }, | ||
user: { currentUser }, | ||
} = useMobxStore(); | ||
|
||
const { setToastAlert } = useToast(); | ||
|
||
const handleUpdateIssue = async (formData: Partial<IIssue>) => { | ||
if (!workspaceSlug || !projectId || !issueDetails) return; | ||
|
||
const payload = { ...formData }; | ||
await updateIssue(workspaceSlug.toString(), projectId.toString(), issueDetails.id, payload).catch((e) => { | ||
console.error(e); | ||
}); | ||
}; | ||
|
||
const handleIssueAssignees = (assignee: string) => { | ||
if (!issueDetails || !assignee) return; | ||
|
||
closePalette(); | ||
const updatedAssignees = issueDetails.assignees ?? []; | ||
|
||
if (updatedAssignees.includes(assignee)) updatedAssignees.splice(updatedAssignees.indexOf(assignee), 1); | ||
else updatedAssignees.push(assignee); | ||
|
||
handleUpdateIssue({ assignees: updatedAssignees }); | ||
}; | ||
|
||
const deleteIssue = () => { | ||
toggleCommandPaletteModal(false); | ||
toggleDeleteIssueModal(true); | ||
}; | ||
|
||
const copyIssueUrlToClipboard = () => { | ||
if (!router.query.issueId) return; | ||
|
||
const url = new URL(window.location.href); | ||
copyTextToClipboard(url.href) | ||
.then(() => { | ||
setToastAlert({ | ||
type: "success", | ||
title: "Copied to clipboard", | ||
}); | ||
}) | ||
.catch(() => { | ||
setToastAlert({ | ||
type: "error", | ||
title: "Some error occurred", | ||
}); | ||
}); | ||
}; | ||
|
||
return ( | ||
<Command.Group heading="Issue actions"> | ||
<Command.Item | ||
onSelect={() => { | ||
setPlaceholder("Change state..."); | ||
setSearchTerm(""); | ||
setPages([...pages, "change-issue-state"]); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<DoubleCircleIcon className="h-3.5 w-3.5" /> | ||
Change state... | ||
</div> | ||
</Command.Item> | ||
<Command.Item | ||
onSelect={() => { | ||
setPlaceholder("Change priority..."); | ||
setSearchTerm(""); | ||
setPages([...pages, "change-issue-priority"]); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<Signal className="h-3.5 w-3.5" /> | ||
Change priority... | ||
</div> | ||
</Command.Item> | ||
<Command.Item | ||
onSelect={() => { | ||
setPlaceholder("Assign to..."); | ||
setSearchTerm(""); | ||
setPages([...pages, "change-issue-assignee"]); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<UserGroupIcon className="h-3.5 w-3.5" /> | ||
Assign to... | ||
</div> | ||
</Command.Item> | ||
<Command.Item | ||
onSelect={() => { | ||
handleIssueAssignees(currentUser?.id ?? ""); | ||
setSearchTerm(""); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
{issueDetails?.assignees.includes(currentUser?.id ?? "") ? ( | ||
<> | ||
<UserMinus2 className="h-3.5 w-3.5" /> | ||
Un-assign from me | ||
</> | ||
) : ( | ||
<> | ||
<UserPlus2 className="h-3.5 w-3.5" /> | ||
Assign to me | ||
</> | ||
)} | ||
</div> | ||
</Command.Item> | ||
<Command.Item onSelect={deleteIssue} className="focus:outline-none"> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<Trash2 className="h-3.5 w-3.5" /> | ||
Delete issue | ||
</div> | ||
</Command.Item> | ||
<Command.Item | ||
onSelect={() => { | ||
closePalette(); | ||
copyIssueUrlToClipboard(); | ||
}} | ||
className="focus:outline-none" | ||
> | ||
<div className="flex items-center gap-2 text-custom-text-200"> | ||
<LinkIcon className="h-3.5 w-3.5" /> | ||
Copy issue URL | ||
</div> | ||
</Command.Item> | ||
</Command.Group> | ||
); | ||
}); |
79 changes: 79 additions & 0 deletions
79
web/components/command-palette/actions/issue-actions/change-assignee.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { useRouter } from "next/router"; | ||
import { observer } from "mobx-react-lite"; | ||
import { Command } from "cmdk"; | ||
import { Check } from "lucide-react"; | ||
// mobx store | ||
import { useMobxStore } from "lib/mobx/store-provider"; | ||
// ui | ||
import { Avatar } from "@plane/ui"; | ||
// types | ||
import { IIssue } from "types"; | ||
|
||
type Props = { | ||
closePalette: () => void; | ||
issue: IIssue; | ||
}; | ||
|
||
export const ChangeIssueAssignee: React.FC<Props> = observer((props) => { | ||
const { closePalette, issue } = props; | ||
// router | ||
const router = useRouter(); | ||
const { workspaceSlug, projectId } = router.query; | ||
// store | ||
const { | ||
issueDetail: { updateIssue }, | ||
projectMember: { projectMembers }, | ||
} = useMobxStore(); | ||
|
||
const options = | ||
projectMembers?.map(({ member }) => ({ | ||
value: member.id, | ||
query: member.display_name, | ||
content: ( | ||
<> | ||
<div className="flex items-center gap-2"> | ||
<Avatar name={member.display_name} src={member.avatar} showTooltip={false} /> | ||
{member.display_name} | ||
</div> | ||
{issue.assignees.includes(member.id) && ( | ||
<div> | ||
<Check className="h-3 w-3" /> | ||
</div> | ||
)} | ||
</> | ||
), | ||
})) ?? []; | ||
|
||
const handleUpdateIssue = async (formData: Partial<IIssue>) => { | ||
if (!workspaceSlug || !projectId || !issue) return; | ||
|
||
const payload = { ...formData }; | ||
await updateIssue(workspaceSlug.toString(), projectId.toString(), issue.id, payload).catch((e) => { | ||
console.error(e); | ||
}); | ||
}; | ||
|
||
const handleIssueAssignees = (assignee: string) => { | ||
const updatedAssignees = issue.assignees ?? []; | ||
|
||
if (updatedAssignees.includes(assignee)) updatedAssignees.splice(updatedAssignees.indexOf(assignee), 1); | ||
else updatedAssignees.push(assignee); | ||
|
||
handleUpdateIssue({ assignees: updatedAssignees }); | ||
closePalette(); | ||
}; | ||
|
||
return ( | ||
<> | ||
{options.map((option: any) => ( | ||
<Command.Item | ||
key={option.value} | ||
onSelect={() => handleIssueAssignees(option.value)} | ||
className="focus:outline-none" | ||
> | ||
{option.content} | ||
</Command.Item> | ||
))} | ||
</> | ||
); | ||
}); |
56 changes: 56 additions & 0 deletions
56
web/components/command-palette/actions/issue-actions/change-priority.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { useRouter } from "next/router"; | ||
import { observer } from "mobx-react-lite"; | ||
import { Command } from "cmdk"; | ||
import { Check } from "lucide-react"; | ||
// mobx store | ||
import { useMobxStore } from "lib/mobx/store-provider"; | ||
// ui | ||
import { PriorityIcon } from "@plane/ui"; | ||
// types | ||
import { IIssue, TIssuePriorities } from "types"; | ||
// constants | ||
import { PRIORITIES } from "constants/project"; | ||
|
||
type Props = { | ||
closePalette: () => void; | ||
issue: IIssue; | ||
}; | ||
|
||
export const ChangeIssuePriority: React.FC<Props> = observer((props) => { | ||
const { closePalette, issue } = props; | ||
|
||
const router = useRouter(); | ||
const { workspaceSlug, projectId } = router.query; | ||
|
||
const { | ||
issueDetail: { updateIssue }, | ||
} = useMobxStore(); | ||
|
||
const submitChanges = async (formData: Partial<IIssue>) => { | ||
if (!workspaceSlug || !projectId || !issue) return; | ||
|
||
const payload = { ...formData }; | ||
await updateIssue(workspaceSlug.toString(), projectId.toString(), issue.id, payload).catch((e) => { | ||
console.error(e); | ||
}); | ||
}; | ||
|
||
const handleIssueState = (priority: TIssuePriorities) => { | ||
submitChanges({ priority }); | ||
closePalette(); | ||
}; | ||
|
||
return ( | ||
<> | ||
{PRIORITIES.map((priority) => ( | ||
<Command.Item key={priority} onSelect={() => handleIssueState(priority)} className="focus:outline-none"> | ||
<div className="flex items-center space-x-3"> | ||
<PriorityIcon priority={priority} /> | ||
<span className="capitalize">{priority ?? "None"}</span> | ||
</div> | ||
<div>{priority === issue.priority && <Check className="h-3 w-3" />}</div> | ||
</Command.Item> | ||
))} | ||
</> | ||
); | ||
}); |
Oops, something went wrong.