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
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:
55
apps/web/core/components/power-k/menus/builder.tsx
Normal file
55
apps/web/core/components/power-k/menus/builder.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { Command } from "cmdk";
|
||||
// local imports
|
||||
import { PowerKModalCommandItem } from "../ui/modal/command-item";
|
||||
import { PowerKMenuEmptyState } from "./empty-state";
|
||||
|
||||
type Props<T> = {
|
||||
heading?: string;
|
||||
items: T[];
|
||||
onSelect: (item: T) => void;
|
||||
getIcon?: (item: T) => React.ComponentType<{ className?: string }>;
|
||||
getIconNode?: (item: T) => React.ReactNode;
|
||||
getKey: (item: T) => string;
|
||||
getLabel: (item: T) => React.ReactNode;
|
||||
getValue: (item: T) => string;
|
||||
isSelected?: (item: T) => boolean;
|
||||
emptyText?: string;
|
||||
};
|
||||
|
||||
export function PowerKMenuBuilder<T>({
|
||||
heading,
|
||||
items,
|
||||
onSelect,
|
||||
getIcon,
|
||||
getIconNode,
|
||||
getKey,
|
||||
getLabel,
|
||||
getValue,
|
||||
isSelected,
|
||||
emptyText,
|
||||
}: Props<T>) {
|
||||
if (items.length === 0) return <PowerKMenuEmptyState emptyText={emptyText} />;
|
||||
|
||||
return (
|
||||
<Command.Group heading={heading}>
|
||||
{items.map((item) => (
|
||||
<PowerKModalCommandItem
|
||||
key={getKey(item)}
|
||||
icon={getIcon?.(item)}
|
||||
iconNode={getIconNode?.(item)}
|
||||
value={getValue(item)}
|
||||
label={getLabel(item)}
|
||||
isSelected={isSelected?.(item)}
|
||||
onSelect={() => onSelect(item)}
|
||||
/>
|
||||
))}
|
||||
</Command.Group>
|
||||
);
|
||||
}
|
||||
34
apps/web/core/components/power-k/menus/cycles.tsx
Normal file
34
apps/web/core/components/power-k/menus/cycles.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// plane imports
|
||||
import { CyclesOutline } from "@makeplane/propel/icons";
|
||||
import type { ICycle } from "@plane/types";
|
||||
// local imports
|
||||
import { PowerKMenuBuilder } from "./builder";
|
||||
|
||||
type Props = {
|
||||
cycles: ICycle[];
|
||||
onSelect: (cycle: ICycle) => void;
|
||||
value?: string | null;
|
||||
};
|
||||
|
||||
export const PowerKCyclesMenu = observer(function PowerKCyclesMenu({ cycles, onSelect, value }: Props) {
|
||||
return (
|
||||
<PowerKMenuBuilder
|
||||
items={cycles}
|
||||
getIcon={() => CyclesOutline}
|
||||
getKey={(cycle) => cycle.id}
|
||||
getValue={(cycle) => cycle.name}
|
||||
getLabel={(cycle) => cycle.name}
|
||||
isSelected={(cycle) => value === cycle.id}
|
||||
onSelect={onSelect}
|
||||
emptyText="No cycles found"
|
||||
/>
|
||||
);
|
||||
});
|
||||
15
apps/web/core/components/power-k/menus/empty-state.tsx
Normal file
15
apps/web/core/components/power-k/menus/empty-state.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
|
||||
type Props = {
|
||||
emptyText?: string;
|
||||
};
|
||||
|
||||
export function PowerKMenuEmptyState({ emptyText = "No results found" }: Props) {
|
||||
return <div className="px-3 py-8 text-center text-13 text-tertiary">{emptyText}</div>;
|
||||
}
|
||||
37
apps/web/core/components/power-k/menus/labels.tsx
Normal file
37
apps/web/core/components/power-k/menus/labels.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// plane imports
|
||||
import type { IIssueLabel } from "@plane/types";
|
||||
// local imports
|
||||
import { PowerKMenuBuilder } from "./builder";
|
||||
|
||||
type Props = {
|
||||
labels: IIssueLabel[];
|
||||
onSelect: (label: IIssueLabel) => void;
|
||||
value?: string[];
|
||||
};
|
||||
|
||||
export const PowerKLabelsMenu = observer(function PowerKLabelsMenu({ labels, onSelect, value }: Props) {
|
||||
return (
|
||||
<PowerKMenuBuilder
|
||||
items={labels}
|
||||
getIconNode={(label) => (
|
||||
<span className="grid size-3.5 shrink-0 place-items-center">
|
||||
<span className="size-2.5 rounded-full" style={{ backgroundColor: label.color }} />
|
||||
</span>
|
||||
)}
|
||||
getKey={(label) => label.id}
|
||||
getValue={(label) => label.name}
|
||||
getLabel={(label) => label.name}
|
||||
isSelected={(label) => !!value?.includes(label.id)}
|
||||
onSelect={onSelect}
|
||||
emptyText="No labels found"
|
||||
/>
|
||||
);
|
||||
});
|
||||
55
apps/web/core/components/power-k/menus/members.tsx
Normal file
55
apps/web/core/components/power-k/menus/members.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { Command } from "cmdk";
|
||||
import { observer } from "mobx-react";
|
||||
// plane imports
|
||||
|
||||
import { Avatar } from "@makeplane/propel/components/avatar";
|
||||
import { getFileURL } from "@plane/utils";
|
||||
// hooks
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
// local imports
|
||||
import { PowerKModalCommandItem } from "../ui/modal/command-item";
|
||||
|
||||
type Props = {
|
||||
handleSelect: (assigneeId: string) => void;
|
||||
heading?: string;
|
||||
userIds: string[] | undefined;
|
||||
value: string[];
|
||||
};
|
||||
|
||||
export const PowerKMembersMenu = observer(function PowerKMembersMenu(props: Props) {
|
||||
const { handleSelect, heading, userIds, value } = props;
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
|
||||
return (
|
||||
<Command.Group heading={heading}>
|
||||
{userIds?.map((memberId) => {
|
||||
const memberDetails = getUserDetails(memberId);
|
||||
if (!memberDetails) return;
|
||||
|
||||
return (
|
||||
<PowerKModalCommandItem
|
||||
key={memberId}
|
||||
iconNode={
|
||||
<Avatar
|
||||
alt={memberDetails?.display_name}
|
||||
fallback={memberDetails?.display_name?.[0]?.toUpperCase()}
|
||||
src={getFileURL(memberDetails?.avatar_url ?? "")}
|
||||
size="xs"
|
||||
/>
|
||||
}
|
||||
isSelected={value.includes(memberId)}
|
||||
label={memberDetails?.display_name}
|
||||
onSelect={() => handleSelect(memberId)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Command.Group>
|
||||
);
|
||||
});
|
||||
34
apps/web/core/components/power-k/menus/modules.tsx
Normal file
34
apps/web/core/components/power-k/menus/modules.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// plane imports
|
||||
import { ModuleStatusIcon } from "@plane/propel/icons";
|
||||
import type { IModule } from "@plane/types";
|
||||
// local imports
|
||||
import { PowerKMenuBuilder } from "./builder";
|
||||
|
||||
type Props = {
|
||||
modules: IModule[];
|
||||
onSelect: (module: IModule) => void;
|
||||
value?: string[];
|
||||
};
|
||||
|
||||
export const PowerKModulesMenu = observer(function PowerKModulesMenu({ modules, onSelect, value }: Props) {
|
||||
return (
|
||||
<PowerKMenuBuilder
|
||||
items={modules}
|
||||
getKey={(module) => module.id}
|
||||
getIconNode={(module) => <ModuleStatusIcon status={module.status ?? "backlog"} className="size-3.5 shrink-0" />}
|
||||
getValue={(module) => module.name}
|
||||
getLabel={(module) => module.name}
|
||||
isSelected={(module) => !!value?.includes(module.id)}
|
||||
onSelect={onSelect}
|
||||
emptyText="No modules found"
|
||||
/>
|
||||
);
|
||||
});
|
||||
36
apps/web/core/components/power-k/menus/projects.tsx
Normal file
36
apps/web/core/components/power-k/menus/projects.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
// components
|
||||
import { Logo } from "@plane/propel/emoji-icon-picker";
|
||||
// plane imports
|
||||
import type { TPartialProject } from "@plane/types";
|
||||
// local imports
|
||||
import { PowerKMenuBuilder } from "./builder";
|
||||
|
||||
type Props = {
|
||||
projects: TPartialProject[];
|
||||
onSelect: (project: TPartialProject) => void;
|
||||
};
|
||||
|
||||
export function PowerKProjectsMenu({ projects, onSelect }: Props) {
|
||||
return (
|
||||
<PowerKMenuBuilder
|
||||
items={projects}
|
||||
getKey={(project) => project.id}
|
||||
getIconNode={(project) => (
|
||||
<span className="shrink-0">
|
||||
<Logo logo={project.logo_props} size={14} />
|
||||
</span>
|
||||
)}
|
||||
getValue={(project) => project.name}
|
||||
getLabel={(project) => project.name}
|
||||
onSelect={onSelect}
|
||||
emptyText="No projects found"
|
||||
/>
|
||||
);
|
||||
}
|
||||
36
apps/web/core/components/power-k/menus/settings.tsx
Normal file
36
apps/web/core/components/power-k/menus/settings.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// local imports
|
||||
import { PowerKMenuBuilder } from "./builder";
|
||||
|
||||
type TSettingItem = {
|
||||
key: string;
|
||||
icon: React.ComponentType<{ className?: string }>;
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
settings: TSettingItem[];
|
||||
onSelect: (setting: TSettingItem) => void;
|
||||
};
|
||||
|
||||
export const PowerKSettingsMenu = observer(function PowerKSettingsMenu({ settings, onSelect }: Props) {
|
||||
return (
|
||||
<PowerKMenuBuilder
|
||||
items={settings}
|
||||
getKey={(setting) => setting.key}
|
||||
getIcon={(setting) => setting.icon}
|
||||
getValue={(setting) => setting.label}
|
||||
getLabel={(setting) => setting.label}
|
||||
onSelect={onSelect}
|
||||
emptyText="No settings found"
|
||||
/>
|
||||
);
|
||||
});
|
||||
32
apps/web/core/components/power-k/menus/views.tsx
Normal file
32
apps/web/core/components/power-k/menus/views.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { WorkItemsOutline } from "@makeplane/propel/icons";
|
||||
// plane imports
|
||||
import type { IProjectView } from "@plane/types";
|
||||
// local imports
|
||||
import { PowerKMenuBuilder } from "./builder";
|
||||
|
||||
type Props = {
|
||||
views: IProjectView[];
|
||||
onSelect: (view: IProjectView) => void;
|
||||
};
|
||||
|
||||
export const PowerKViewsMenu = observer(function PowerKViewsMenu({ views, onSelect }: Props) {
|
||||
return (
|
||||
<PowerKMenuBuilder
|
||||
items={views}
|
||||
getKey={(view) => view.id}
|
||||
getIcon={() => WorkItemsOutline}
|
||||
getValue={(view) => view.name}
|
||||
getLabel={(view) => view.name}
|
||||
onSelect={onSelect}
|
||||
emptyText="No views found"
|
||||
/>
|
||||
);
|
||||
});
|
||||
34
apps/web/core/components/power-k/menus/workspaces.tsx
Normal file
34
apps/web/core/components/power-k/menus/workspaces.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
// plane imports
|
||||
import type { IWorkspace } from "@plane/types";
|
||||
// components
|
||||
import { WorkspaceLogo } from "@/components/workspace/logo";
|
||||
// local imports
|
||||
import { PowerKMenuBuilder } from "./builder";
|
||||
|
||||
type Props = {
|
||||
workspaces: IWorkspace[];
|
||||
onSelect: (workspace: IWorkspace) => void;
|
||||
};
|
||||
|
||||
export function PowerKWorkspacesMenu({ workspaces, onSelect }: Props) {
|
||||
return (
|
||||
<PowerKMenuBuilder
|
||||
items={workspaces}
|
||||
getKey={(workspace) => workspace.id}
|
||||
getIconNode={(workspace) => (
|
||||
<WorkspaceLogo logo={workspace.logo_url} name={workspace.name} classNames="shrink-0" />
|
||||
)}
|
||||
getValue={(workspace) => workspace.name}
|
||||
getLabel={(workspace) => workspace.name}
|
||||
onSelect={onSelect}
|
||||
emptyText="No workspaces found"
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user