snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:14:58 +05:00
commit 23059a1de3
5252 changed files with 573834 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { useCallback } from "react";
import { LogOutOutline, MailOutline } from "@makeplane/propel/icons";
// plane imports
import { useTranslation } from "@plane/i18n";
import { setToast, TOAST_TYPE } from "@plane/propel/toast";
// components
import type { TPowerKCommandConfig } from "@/components/power-k/core/types";
// hooks
import { useUser } from "@/hooks/store/user";
import { useAppRouter } from "@/hooks/use-app-router";
/**
* Account commands - Account related commands
*/
export const usePowerKAccountCommands = (): TPowerKCommandConfig[] => {
// navigation
const router = useAppRouter();
// store
const { signOut } = useUser();
// translation
const { t } = useTranslation();
const handleSignOut = useCallback(() => {
signOut().catch(() =>
setToast({
type: TOAST_TYPE.ERROR,
title: t("auth.sign_out.toast.error.title"),
message: t("auth.sign_out.toast.error.message"),
})
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [signOut]);
return [
{
id: "workspace_invites",
type: "action",
group: "account",
i18n_title: "power_k.account_actions.workspace_invites",
icon: MailOutline,
action: () => router.push("/invitations"),
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "sign_out",
type: "action",
group: "account",
i18n_title: "power_k.account_actions.sign_out",
icon: LogOutOutline,
action: handleSignOut,
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
];
};

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
// local imports
import type { TPowerKCommandConfig } from "../core/types";
import { usePowerKContextBasedActions } from "../ui/pages/context-based";
import { usePowerKAccountCommands } from "./account-commands";
import { usePowerKCreationCommands } from "./creation/root";
import { usePowerKHelpCommands } from "./help-commands";
import { usePowerKMiscellaneousCommands } from "./miscellaneous-commands";
import { usePowerKNavigationCommands } from "./navigation/root";
import { usePowerKPreferencesCommands } from "./preferences-commands";
export const useProjectsAppPowerKCommands = (): TPowerKCommandConfig[] => {
const navigationCommands = usePowerKNavigationCommands();
const creationCommands = usePowerKCreationCommands();
const contextualCommands = usePowerKContextBasedActions();
const accountCommands = usePowerKAccountCommands();
const miscellaneousCommands = usePowerKMiscellaneousCommands();
const preferencesCommands = usePowerKPreferencesCommands();
const helpCommands = usePowerKHelpCommands();
return [
...navigationCommands,
...creationCommands,
...contextualCommands,
...accountCommands,
...miscellaneousCommands,
...preferencesCommands,
...helpCommands,
];
};

View File

@@ -0,0 +1,163 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { SquarePlus } from "lucide-react";
import {
CreateFolderOutline,
CyclesOutline,
DocumentationOutline,
ModuleOutline,
WorkItemsOutline,
} from "@makeplane/propel/icons";
// plane imports
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
// components
import { EUserProjectRoles } from "@plane/types";
import type { TPowerKCommandConfig, TPowerKContext } from "@/components/power-k/core/types";
// hooks
import { useCommandPalette } from "@/hooks/store/use-command-palette";
import { useProject } from "@/hooks/store/use-project";
import { useUser } from "@/hooks/store/user";
import { useInstance } from "@/hooks/store/use-instance";
export type TPowerKCreationCommandKeys =
| "create_work_item"
| "create_page"
| "create_view"
| "create_cycle"
| "create_module"
| "create_project"
| "create_workspace";
/**
* Creation commands - Create any entity in the app
*/
export const usePowerKCreationCommandsRecord = (): Record<TPowerKCreationCommandKeys, TPowerKCommandConfig> => {
// store
const { config } = useInstance();
const {
canPerformAnyCreateAction,
permission: { allowPermissions },
} = useUser();
const { workspaceProjectIds, getPartialProjectById } = useProject();
const {
toggleCreateIssueModal,
toggleCreateProjectModal,
toggleCreateCycleModal,
toggleCreateModuleModal,
toggleCreateViewModal,
toggleCreatePageModal,
} = useCommandPalette();
// derived values
const canCreateWorkItem = canPerformAnyCreateAction && workspaceProjectIds && workspaceProjectIds.length > 0;
const canCreateProject = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
const hasProjectMemberLevelPermissions = (ctx: TPowerKContext) =>
allowPermissions(
[EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER],
EUserPermissionsLevel.PROJECT,
ctx.params.workspaceSlug?.toString(),
ctx.params.projectId?.toString()
);
const isWorkspaceCreationDisabled = config?.is_workspace_creation_disabled ?? false;
const getProjectDetails = (ctx: TPowerKContext) =>
ctx.params.projectId ? getPartialProjectById(ctx.params.projectId.toString()) : undefined;
return {
create_work_item: {
id: "create_work_item",
type: "action",
group: "create",
i18n_title: "power_k.creation_actions.create_work_item",
icon: WorkItemsOutline,
keySequence: "ni",
action: () => toggleCreateIssueModal(true),
isEnabled: () => Boolean(canCreateWorkItem),
isVisible: () => Boolean(canCreateWorkItem),
closeOnSelect: true,
},
create_page: {
id: "create_page",
type: "action",
group: "create",
i18n_title: "power_k.creation_actions.create_page",
icon: DocumentationOutline,
keySequence: "nd",
action: () => toggleCreatePageModal({ isOpen: true }),
isEnabled: (ctx) => Boolean(getProjectDetails(ctx)?.page_view && hasProjectMemberLevelPermissions(ctx)),
isVisible: (ctx) =>
Boolean(ctx.params.projectId && getProjectDetails(ctx)?.page_view && hasProjectMemberLevelPermissions(ctx)),
closeOnSelect: true,
},
create_view: {
id: "create_view",
type: "action",
group: "create",
i18n_title: "power_k.creation_actions.create_view",
icon: WorkItemsOutline,
keySequence: "nv",
action: () => toggleCreateViewModal(true),
isEnabled: (ctx) => Boolean(getProjectDetails(ctx)?.issue_views_view && hasProjectMemberLevelPermissions(ctx)),
isVisible: (ctx) =>
Boolean(
ctx.params.projectId && getProjectDetails(ctx)?.issue_views_view && hasProjectMemberLevelPermissions(ctx)
),
closeOnSelect: true,
},
create_cycle: {
id: "create_cycle",
type: "action",
group: "create",
i18n_title: "power_k.creation_actions.create_cycle",
icon: CyclesOutline,
keySequence: "nc",
action: () => toggleCreateCycleModal(true),
isEnabled: (ctx) => Boolean(getProjectDetails(ctx)?.cycle_view && hasProjectMemberLevelPermissions(ctx)),
isVisible: (ctx) =>
Boolean(ctx.params.projectId && getProjectDetails(ctx)?.cycle_view && hasProjectMemberLevelPermissions(ctx)),
closeOnSelect: true,
},
create_module: {
id: "create_module",
type: "action",
group: "create",
i18n_title: "power_k.creation_actions.create_module",
icon: ModuleOutline,
keySequence: "nm",
action: () => toggleCreateModuleModal(true),
isEnabled: (ctx) => Boolean(getProjectDetails(ctx)?.module_view && hasProjectMemberLevelPermissions(ctx)),
isVisible: (ctx) =>
Boolean(ctx.params.projectId && getProjectDetails(ctx)?.module_view && hasProjectMemberLevelPermissions(ctx)),
closeOnSelect: true,
},
create_project: {
id: "create_project",
type: "action",
group: "create",
i18n_title: "power_k.creation_actions.create_project",
icon: CreateFolderOutline,
keySequence: "np",
action: () => toggleCreateProjectModal(true),
isEnabled: () => Boolean(canCreateProject),
isVisible: () => Boolean(canCreateProject),
closeOnSelect: true,
},
create_workspace: {
id: "create_workspace",
type: "action",
group: "create",
i18n_title: "power_k.creation_actions.create_workspace",
icon: SquarePlus,
action: (ctx) => ctx.router.push("/create-workspace"),
isEnabled: () => Boolean(!isWorkspaceCreationDisabled),
isVisible: () => Boolean(!isWorkspaceCreationDisabled),
closeOnSelect: true,
},
};
};

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
// types
import type { TPowerKCommandConfig } from "@/components/power-k/core/types";
// local imports
import { usePowerKCreationCommandsRecord } from "./command";
import type { TPowerKCreationCommandKeys } from "./command";
export const usePowerKCreationCommands = (): TPowerKCommandConfig[] => {
const optionsList: Record<TPowerKCreationCommandKeys, TPowerKCommandConfig> = usePowerKCreationCommandsRecord();
return [
optionsList["create_work_item"],
optionsList["create_page"],
optionsList["create_view"],
optionsList["create_cycle"],
optionsList["create_module"],
optionsList["create_project"],
optionsList["create_workspace"],
];
};

View File

@@ -0,0 +1,73 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { ChatOutline, DocumentationOutline, Github, RocketOutline } from "@makeplane/propel/icons";
// components
import type { TPowerKCommandConfig } from "@/components/power-k/core/types";
// hooks
import { usePowerK } from "@/hooks/store/use-power-k";
/**
* Help commands - Help related commands
*/
export const usePowerKHelpCommands = (): TPowerKCommandConfig[] => {
// store
const { toggleShortcutsListModal } = usePowerK();
return [
{
id: "open_keyboard_shortcuts",
type: "action",
group: "help",
i18n_title: "power_k.help_actions.open_keyboard_shortcuts",
icon: RocketOutline,
modifierShortcut: "cmd+/",
action: () => toggleShortcutsListModal(true),
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "open_plane_documentation",
type: "action",
group: "help",
i18n_title: "power_k.help_actions.open_plane_documentation",
icon: DocumentationOutline,
action: () => {
window.open("https://docs.plane.so/", "_blank", "noopener,noreferrer");
},
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "join_forum",
type: "action",
group: "help",
i18n_title: "power_k.help_actions.join_forum",
icon: ChatOutline,
action: () => {
window.open("https://forum.plane.so", "_blank", "noopener,noreferrer");
},
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "report_bug",
type: "action",
group: "help",
i18n_title: "power_k.help_actions.report_bug",
icon: Github,
action: () => {
window.open("https://github.com/makeplane/plane/issues/new/choose", "_blank", "noopener,noreferrer");
},
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
];
};

View File

@@ -0,0 +1,91 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { useCallback } from "react";
import { LeftSidePaneOutline, LinkOutline, SearchOutline } from "@makeplane/propel/icons";
import { useTranslation } from "@plane/i18n";
// plane imports
import { setToast, TOAST_TYPE } from "@plane/propel/toast";
import { copyTextToClipboard } from "@plane/utils";
// components
import type { TPowerKCommandConfig } from "@/components/power-k/core/types";
// hooks
import { useAppTheme } from "@/hooks/store/use-app-theme";
import { usePowerK } from "@/hooks/store/use-power-k";
export const usePowerKMiscellaneousCommands = (): TPowerKCommandConfig[] => {
// store hooks
const { toggleSidebar } = useAppTheme();
const { topNavInputRef, topNavSearchInputRef } = usePowerK();
// translation
const { t } = useTranslation();
const copyCurrentPageUrlToClipboard = useCallback(() => {
const url = new URL(window.location.href);
copyTextToClipboard(url.href)
.then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: t("power_k.miscellaneous_actions.copy_current_page_url_toast_success"),
});
})
.catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: t("power_k.miscellaneous_actions.copy_current_page_url_toast_error"),
});
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const focusTopNavSearch = useCallback(() => {
// Focus PowerK input if available, otherwise focus regular search input
if (topNavSearchInputRef?.current) {
topNavSearchInputRef.current.focus();
} else if (topNavInputRef?.current) {
topNavInputRef.current.focus();
}
}, [topNavInputRef, topNavSearchInputRef]);
return [
{
id: "toggle_app_sidebar",
group: "miscellaneous",
type: "action",
i18n_title: "power_k.miscellaneous_actions.toggle_app_sidebar",
icon: LeftSidePaneOutline,
action: () => toggleSidebar(),
modifierShortcut: "cmd+b",
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "copy_current_page_url",
group: "miscellaneous",
type: "action",
i18n_title: "power_k.miscellaneous_actions.copy_current_page_url",
icon: LinkOutline,
action: copyCurrentPageUrlToClipboard,
modifierShortcut: "cmd+shift+c",
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "focus_top_nav_search",
group: "miscellaneous",
type: "action",
i18n_title: "power_k.miscellaneous_actions.focus_top_nav_search",
icon: SearchOutline,
action: focusTopNavSearch,
modifierShortcut: "cmd+f",
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
];
};

View File

@@ -0,0 +1,538 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import {
ActivityOutline,
ArchiveOutline,
BarOutline,
CyclesOutline,
DocumentationOutline,
EditOutline,
HomeOutline,
InboxOutline,
IntakeOutline,
ModuleOutline,
ProjectsOutline,
SettingsOutline,
WorkItemsOutline,
} from "@makeplane/propel/icons";
// plane imports
import { EUserPermissionsLevel } from "@plane/constants";
import type { ICycle, IModule, IPartialProject, IProjectView, IWorkspace } from "@plane/types";
import { EUserProjectRoles, EUserWorkspaceRoles } from "@plane/types";
// components
import type { TPowerKCommandConfig, TPowerKContext } from "@/components/power-k/core/types";
import { handlePowerKNavigate } from "@/components/power-k/utils/navigation";
// hooks
import { useProject } from "@/hooks/store/use-project";
import { useUser } from "@/hooks/store/user";
export type TPowerKNavigationCommandKeys =
| "open_workspace"
| "nav_home"
| "nav_inbox"
| "nav_your_work"
| "nav_account_settings"
| "open_project"
| "nav_projects_list"
| "nav_all_workspace_work_items"
| "nav_assigned_workspace_work_items"
| "nav_created_workspace_work_items"
| "nav_subscribed_workspace_work_items"
| "nav_workspace_analytics"
| "nav_workspace_drafts"
| "nav_workspace_archives"
| "open_workspace_setting"
| "nav_workspace_settings"
| "nav_project_work_items"
| "open_project_cycle"
| "nav_project_cycles"
| "open_project_module"
| "nav_project_modules"
| "open_project_view"
| "nav_project_views"
| "nav_project_pages"
| "nav_project_intake"
| "nav_project_archives"
| "open_project_setting"
| "nav_project_settings";
/**
* Navigation commands - Navigate to all pages in the app
*/
export const usePowerKNavigationCommandsRecord = (): Record<TPowerKNavigationCommandKeys, TPowerKCommandConfig> => {
// store hooks
const {
data: currentUser,
permission: { allowPermissions },
} = useUser();
const { getPartialProjectById } = useProject();
// derived values
const hasWorkspaceMemberLevelPermissions = (ctx: TPowerKContext) =>
allowPermissions(
[EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER],
EUserPermissionsLevel.WORKSPACE,
ctx.params.workspaceSlug?.toString()
);
const hasProjectMemberLevelPermissions = (ctx: TPowerKContext) =>
allowPermissions(
[EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER],
EUserPermissionsLevel.PROJECT,
ctx.params.workspaceSlug?.toString(),
ctx.params.projectId?.toString()
);
const baseWorkspaceConditions = (ctx: TPowerKContext) => Boolean(ctx.params.workspaceSlug?.toString());
const baseProjectConditions = (ctx: TPowerKContext) =>
Boolean(ctx.params.workspaceSlug?.toString() && ctx.params.projectId?.toString());
const getContextProject = (ctx: TPowerKContext) => getPartialProjectById(ctx.params.projectId?.toString());
return {
open_workspace: {
id: "open_workspace",
type: "change-page",
group: "navigation",
i18n_title: "power_k.navigation_actions.open_workspace",
icon: ProjectsOutline,
keySequence: "ow",
page: "open-workspace",
onSelect: (data, ctx) => {
const workspaceDetails = data as IWorkspace;
handlePowerKNavigate(ctx, [workspaceDetails.slug]);
},
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_home: {
id: "nav_home",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_home",
icon: HomeOutline,
keySequence: "gh",
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString()]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_inbox: {
id: "nav_inbox",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_inbox",
icon: InboxOutline,
keySequence: "gx",
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "notifications"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_your_work: {
id: "nav_your_work",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_your_work",
icon: ActivityOutline,
keySequence: "gy",
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "profile", currentUser?.id]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx) && hasWorkspaceMemberLevelPermissions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx) && hasWorkspaceMemberLevelPermissions(ctx),
closeOnSelect: true,
},
nav_account_settings: {
id: "nav_account_settings",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_account_settings",
icon: SettingsOutline,
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "settings", "account"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
open_project: {
id: "open_project",
type: "change-page",
group: "navigation",
i18n_title: "power_k.navigation_actions.open_project",
icon: ProjectsOutline,
keySequence: "op",
page: "open-project",
onSelect: (data, ctx) => {
const projectDetails = data as IPartialProject;
handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "projects", projectDetails.id, "issues"]);
},
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_projects_list: {
id: "nav_projects_list",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_projects_list",
icon: ProjectsOutline,
keySequence: "gp",
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "projects"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_all_workspace_work_items: {
id: "nav_all_workspace_work_items",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_all_workspace_work_items",
icon: WorkItemsOutline,
action: (ctx) =>
handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "workspace-views", "all-issues"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_assigned_workspace_work_items: {
id: "nav_assigned_workspace_work_items",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_assigned_workspace_work_items",
icon: WorkItemsOutline,
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "workspace-views", "assigned"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_created_workspace_work_items: {
id: "nav_created_workspace_work_items",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_created_workspace_work_items",
icon: WorkItemsOutline,
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "workspace-views", "created"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_subscribed_workspace_work_items: {
id: "nav_subscribed_workspace_work_items",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_subscribed_workspace_work_items",
icon: WorkItemsOutline,
action: (ctx) =>
handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "workspace-views", "subscribed"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx),
closeOnSelect: true,
},
nav_workspace_analytics: {
id: "nav_workspace_analytics",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_workspace_analytics",
icon: BarOutline,
keySequence: "ga",
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "analytics", "overview"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx) && hasWorkspaceMemberLevelPermissions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx) && hasWorkspaceMemberLevelPermissions(ctx),
closeOnSelect: true,
},
nav_workspace_drafts: {
id: "nav_workspace_drafts",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_workspace_drafts",
icon: EditOutline,
keySequence: "gj",
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "drafts"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx) && hasWorkspaceMemberLevelPermissions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx) && hasWorkspaceMemberLevelPermissions(ctx),
closeOnSelect: true,
},
nav_workspace_archives: {
id: "nav_workspace_archives",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_workspace_archives",
icon: ArchiveOutline,
keySequence: "gr",
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "projects", "archives"]),
isEnabled: (ctx) =>
baseWorkspaceConditions(ctx) && !baseProjectConditions(ctx) && hasWorkspaceMemberLevelPermissions(ctx),
isVisible: (ctx) =>
baseWorkspaceConditions(ctx) && !baseProjectConditions(ctx) && hasWorkspaceMemberLevelPermissions(ctx),
closeOnSelect: true,
},
open_workspace_setting: {
id: "open_workspace_setting",
type: "change-page",
group: "navigation",
i18n_title: "power_k.navigation_actions.open_workspace_setting",
icon: SettingsOutline,
keySequence: "os",
page: "open-workspace-setting",
onSelect: (data, ctx) => {
const settingsHref = data as string;
handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), settingsHref]);
},
isEnabled: (ctx) => baseWorkspaceConditions(ctx) && !baseProjectConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx) && !baseProjectConditions(ctx),
closeOnSelect: true,
},
nav_workspace_settings: {
id: "nav_workspace_settings",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_workspace_settings",
icon: SettingsOutline,
keySequence: "gs",
action: (ctx) => handlePowerKNavigate(ctx, [ctx.params.workspaceSlug?.toString(), "settings"]),
isEnabled: (ctx) => baseWorkspaceConditions(ctx) && !baseProjectConditions(ctx),
isVisible: (ctx) => baseWorkspaceConditions(ctx) && !baseProjectConditions(ctx),
closeOnSelect: true,
},
nav_project_work_items: {
id: "nav_project_work_items",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_project_work_items",
icon: WorkItemsOutline,
keySequence: "gi",
action: (ctx) =>
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"issues",
]),
isEnabled: (ctx) => baseProjectConditions(ctx),
isVisible: (ctx) => baseProjectConditions(ctx),
closeOnSelect: true,
},
open_project_cycle: {
id: "open_project_cycle",
type: "change-page",
group: "navigation",
i18n_title: "power_k.navigation_actions.open_project_cycle",
icon: CyclesOutline,
keySequence: "oc",
page: "open-project-cycle",
onSelect: (data, ctx) => {
const cycleDetails = data as ICycle;
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"cycles",
cycleDetails.id,
]);
},
isEnabled: (ctx) =>
baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx) && !!getContextProject(ctx)?.cycle_view,
isVisible: (ctx) =>
baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx) && !!getContextProject(ctx)?.cycle_view,
closeOnSelect: true,
},
nav_project_cycles: {
id: "nav_project_cycles",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_project_cycles",
icon: CyclesOutline,
keySequence: "gc",
action: (ctx) =>
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"cycles",
]),
isEnabled: (ctx) =>
baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx) && !!getContextProject(ctx)?.cycle_view,
isVisible: (ctx) =>
baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx) && !!getContextProject(ctx)?.cycle_view,
closeOnSelect: true,
},
open_project_module: {
id: "open_project_module",
type: "change-page",
group: "navigation",
i18n_title: "power_k.navigation_actions.open_project_module",
icon: ModuleOutline,
keySequence: "om",
page: "open-project-module",
onSelect: (data, ctx) => {
const moduleDetails = data as IModule;
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"modules",
moduleDetails.id,
]);
},
isEnabled: (ctx) =>
baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx) && !!getContextProject(ctx)?.module_view,
isVisible: (ctx) =>
baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx) && !!getContextProject(ctx)?.module_view,
closeOnSelect: true,
},
nav_project_modules: {
id: "nav_project_modules",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_project_modules",
icon: ModuleOutline,
keySequence: "gm",
action: (ctx) =>
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"modules",
]),
isEnabled: (ctx) =>
baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx) && !!getContextProject(ctx)?.module_view,
isVisible: (ctx) =>
baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx) && !!getContextProject(ctx)?.module_view,
closeOnSelect: true,
},
open_project_view: {
id: "open_project_view",
type: "change-page",
group: "navigation",
i18n_title: "power_k.navigation_actions.open_project_view",
icon: WorkItemsOutline,
keySequence: "ov",
page: "open-project-view",
onSelect: (data, ctx) => {
const viewDetails = data as IProjectView;
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"views",
viewDetails.id,
]);
},
isEnabled: (ctx) => baseProjectConditions(ctx) && !!getContextProject(ctx)?.issue_views_view,
isVisible: (ctx) => baseProjectConditions(ctx) && !!getContextProject(ctx)?.issue_views_view,
closeOnSelect: true,
},
nav_project_views: {
id: "nav_project_views",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_project_views",
icon: WorkItemsOutline,
keySequence: "gv",
action: (ctx) =>
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"views",
]),
isEnabled: (ctx) => baseProjectConditions(ctx) && !!getContextProject(ctx)?.issue_views_view,
isVisible: (ctx) => baseProjectConditions(ctx) && !!getContextProject(ctx)?.issue_views_view,
closeOnSelect: true,
},
nav_project_pages: {
id: "nav_project_pages",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_project_pages",
icon: DocumentationOutline,
keySequence: "gd",
action: (ctx) =>
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"pages",
]),
isEnabled: (ctx) => baseProjectConditions(ctx) && !!getContextProject(ctx)?.page_view,
isVisible: (ctx) => baseProjectConditions(ctx) && !!getContextProject(ctx)?.page_view,
closeOnSelect: true,
},
nav_project_intake: {
id: "nav_project_intake",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_project_intake",
icon: IntakeOutline,
keySequence: "gk",
action: (ctx) =>
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"intake",
]),
isEnabled: (ctx) => baseProjectConditions(ctx) && !!getContextProject(ctx)?.inbox_view,
isVisible: (ctx) => baseProjectConditions(ctx) && !!getContextProject(ctx)?.inbox_view,
closeOnSelect: true,
},
nav_project_archives: {
id: "nav_project_archives",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_project_archives",
icon: ArchiveOutline,
keySequence: "gr",
action: (ctx) =>
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"projects",
ctx.params.projectId?.toString(),
"archives",
"issues",
]),
isEnabled: (ctx) => baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx),
isVisible: (ctx) => baseProjectConditions(ctx) && hasProjectMemberLevelPermissions(ctx),
closeOnSelect: true,
},
open_project_setting: {
id: "open_project_setting",
type: "change-page",
group: "navigation",
i18n_title: "power_k.navigation_actions.open_project_setting",
icon: SettingsOutline,
keySequence: "os",
page: "open-project-setting",
onSelect: (data, ctx) => {
const settingsHref = data as string;
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"settings",
"projects",
ctx.params.projectId?.toString(),
settingsHref,
]);
},
isEnabled: (ctx) => baseProjectConditions(ctx),
isVisible: (ctx) => baseProjectConditions(ctx),
closeOnSelect: true,
},
nav_project_settings: {
id: "nav_project_settings",
type: "action",
group: "navigation",
i18n_title: "power_k.navigation_actions.nav_project_settings",
icon: SettingsOutline,
keySequence: "gs",
action: (ctx) =>
handlePowerKNavigate(ctx, [
ctx.params.workspaceSlug?.toString(),
"settings",
"projects",
ctx.params.projectId?.toString(),
]),
isEnabled: (ctx) => baseProjectConditions(ctx),
isVisible: (ctx) => baseProjectConditions(ctx),
closeOnSelect: true,
},
};
};

View File

@@ -0,0 +1,51 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
// components
import type { TPowerKCommandConfig } from "@/components/power-k/core/types";
// local imports
import type { TPowerKNavigationCommandKeys } from "./commands";
import { usePowerKNavigationCommandsRecord } from "./commands";
export const usePowerKNavigationCommands = (): TPowerKCommandConfig[] => {
const optionsList: Record<TPowerKNavigationCommandKeys, TPowerKCommandConfig> = usePowerKNavigationCommandsRecord();
return [
// Open actions from lowest to highest scope
optionsList["open_project_cycle"],
optionsList["open_project_module"],
optionsList["open_project_view"],
optionsList["open_project_setting"],
optionsList["open_project"],
optionsList["open_workspace_setting"],
optionsList["open_workspace"],
// User-Level Navigation
optionsList["nav_home"],
optionsList["nav_inbox"],
optionsList["nav_your_work"],
// Project-Level Navigation (Only visible in project context)
optionsList["nav_project_work_items"],
optionsList["nav_project_pages"],
optionsList["nav_project_cycles"],
optionsList["nav_project_modules"],
optionsList["nav_project_views"],
optionsList["nav_project_intake"],
optionsList["nav_project_settings"],
optionsList["nav_project_archives"],
// Navigate to workspace-level pages
optionsList["nav_all_workspace_work_items"],
optionsList["nav_assigned_workspace_work_items"],
optionsList["nav_created_workspace_work_items"],
optionsList["nav_subscribed_workspace_work_items"],
optionsList["nav_workspace_analytics"],
optionsList["nav_workspace_settings"],
optionsList["nav_workspace_drafts"],
optionsList["nav_workspace_archives"],
optionsList["nav_projects_list"],
// Account-Level Navigation
optionsList["nav_account_settings"],
];
};

View File

@@ -0,0 +1,168 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { useCallback } from "react";
import { useTheme } from "next-themes";
import { Languages } from "lucide-react";
import { CalendarOutline, GlobeOutline, PaletteOutline } from "@makeplane/propel/icons";
// plane imports
import { useTranslation } from "@plane/i18n";
import { setToast, TOAST_TYPE } from "@plane/propel/toast";
import type { EStartOfTheWeek, TUserProfile } from "@plane/types";
// components
import type { TPowerKCommandConfig } from "@/components/power-k/core/types";
// hooks
import { useUser, useUserProfile } from "@/hooks/store/user";
/**
* Preferences commands - Preferences related commands
*/
export const usePowerKPreferencesCommands = (): TPowerKCommandConfig[] => {
// store hooks
const { setTheme } = useTheme();
const { updateCurrentUser } = useUser();
const { updateUserProfile, updateUserTheme } = useUserProfile();
// translation
const { t } = useTranslation();
const handleUpdateTheme = useCallback(
async (newTheme: string) => {
setTheme(newTheme);
return updateUserTheme({ theme: newTheme })
.then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Theme updated",
message: "Reloading to apply changes...",
});
// reload the page after showing the toast
window.location.reload();
return;
})
.catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: t("toast.error"),
message: t("power_k.preferences_actions.toast.theme.error"),
});
return;
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[setTheme, updateUserTheme]
);
const handleUpdateTimezone = useCallback(
(value: string) => {
updateCurrentUser({ user_timezone: value })
.then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: t("toast.success"),
message: t("power_k.preferences_actions.toast.timezone.success"),
});
return;
})
.catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: t("toast.error"),
message: t("power_k.preferences_actions.toast.timezone.error"),
});
return;
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[updateCurrentUser]
);
const handleUpdateUserProfile = useCallback(
(payload: Partial<TUserProfile>) => {
updateUserProfile(payload)
.then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: t("toast.success"),
message: t("power_k.preferences_actions.toast.generic.success"),
});
return;
})
.catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: t("toast.error"),
message: t("power_k.preferences_actions.toast.generic.error"),
});
return;
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[updateUserProfile]
);
return [
{
id: "update_interface_theme",
group: "preferences",
type: "change-page",
page: "update-theme",
i18n_title: "power_k.preferences_actions.update_theme",
icon: PaletteOutline,
onSelect: (data) => {
const theme = data as string;
void handleUpdateTheme(theme);
},
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "update_timezone",
group: "preferences",
page: "update-timezone",
type: "change-page",
i18n_title: "power_k.preferences_actions.update_timezone",
icon: GlobeOutline,
onSelect: (data) => {
const timezone = data as string;
handleUpdateTimezone(timezone);
},
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "update_start_of_week",
group: "preferences",
page: "update-start-of-week",
type: "change-page",
i18n_title: "power_k.preferences_actions.update_start_of_week",
icon: CalendarOutline,
onSelect: (data) => {
const startOfWeek = data as EStartOfTheWeek;
handleUpdateUserProfile({ start_of_the_week: startOfWeek });
},
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
{
id: "update_interface_language",
group: "preferences",
page: "update-language",
type: "change-page",
i18n_title: "power_k.preferences_actions.update_language",
icon: Languages,
onSelect: (data) => {
const language = data as string;
handleUpdateUserProfile({ language });
},
isEnabled: () => true,
isVisible: () => true,
closeOnSelect: true,
},
];
};