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,74 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { observer } from "mobx-react";
// plane imports
import { setPromiseToast } from "@plane/propel/toast";
import type { IProject } from "@plane/types";
import { Switch } from "@makeplane/propel/components/switch";
// components
import { SettingsBoxedControlItem } from "@/components/settings/boxed-control-item";
// hooks
import { useProject } from "@/hooks/store/use-project";
type Props = {
description?: React.ReactNode;
disabled?: boolean;
projectId: string;
featureProperty: keyof IProject;
title: React.ReactNode;
value: boolean;
workspaceSlug: string;
};
export const ProjectSettingsFeatureControlItem = observer(function ProjectSettingsFeatureControlItem(props: Props) {
const { description, disabled, featureProperty, projectId, title, value, workspaceSlug } = props;
// store hooks
const { getProjectById, updateProject } = useProject();
// derived values
const currentProjectDetails = getProjectById(projectId);
const handleSubmit = () => {
if (!workspaceSlug || !projectId || !currentProjectDetails) return;
// making the request to update the project feature
const settingsPayload = {
[featureProperty]: !currentProjectDetails?.[featureProperty],
};
const updateProjectPromise = updateProject(workspaceSlug, projectId, settingsPayload);
setPromiseToast(updateProjectPromise, {
loading: "Updating project feature...",
success: {
title: "Success!",
message: () => "Project feature updated successfully.",
},
error: {
title: "Error!",
message: () => "Something went wrong while updating project feature. Please try again.",
},
});
void updateProjectPromise.then(() => {
return undefined;
});
};
return (
<SettingsBoxedControlItem
title={title}
description={description}
control={
<Switch
size="sm"
checked={value}
onCheckedChange={handleSubmit}
disabled={disabled}
aria-label={typeof title === "string" ? title : "Toggle project feature"}
/>
}
/>
);
});

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 { ArrowNarrowLeftOutline } from "@makeplane/propel/icons";
import { observer } from "mobx-react";
// plane imports
import { ROLE_DETAILS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { IconButton } from "@plane/propel/icon-button";
// hooks
import { useUserPermissions } from "@/hooks/store/user";
import { useAppRouter } from "@/hooks/use-app-router";
import { useProject } from "@/hooks/store/use-project";
import { useWorkspace } from "@/hooks/store/use-workspace";
type Props = {
projectId: string;
};
export const ProjectSettingsSidebarHeader = observer(function ProjectSettingsSidebarHeader(props: Props) {
const { projectId } = props;
// router
const router = useAppRouter();
// store hooks
const { getProjectRoleByWorkspaceSlugAndProjectId } = useUserPermissions();
const { currentWorkspace } = useWorkspace();
const { getPartialProjectById } = useProject();
// derived values
const projectDetails = getPartialProjectById(projectId);
const currentProjectRole = currentWorkspace?.slug
? getProjectRoleByWorkspaceSlugAndProjectId(currentWorkspace.slug, projectId)
: undefined;
// translation
const { t } = useTranslation();
if (!currentProjectRole) return null;
return (
<div className="shrink-0">
<div className="flex items-center gap-1 py-3 pr-5 pl-4 text-body-md-medium">
<IconButton
variant="ghost"
size="base"
icon={ArrowNarrowLeftOutline}
onClick={() => router.push(`/${currentWorkspace?.slug}/projects/${projectId}/issues/`)}
/>
<p>Project settings</p>
</div>
<div className="mt-1.5 flex items-center gap-2 truncate px-5 py-0.5">
<div className="grid size-8 shrink-0 place-items-center rounded bg-layer-2">
<Logo logo={projectDetails?.logo_props} size={20} />
</div>
<div className="truncate">
<p className="truncate text-body-sm-medium">{projectDetails?.name}</p>
<p className="truncate text-caption-md-regular">{t(ROLE_DETAILS[currentProjectRole].i18n_title)}</p>
</div>
</div>
</div>
);
});

View File

@@ -0,0 +1,7 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
export * from "./root";

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { observer } from "mobx-react";
import { usePathname } from "next/navigation";
import { useParams } from "react-router";
// plane imports
import {
EUserPermissionsLevel,
GROUPED_PROJECT_SETTINGS,
PROJECT_SETTINGS_CATEGORIES,
PROJECT_SETTINGS_CATEGORY_LABELS,
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
// components
import { SettingsSidebarItem } from "@/components/settings/sidebar/item";
// hooks
import { useUserPermissions } from "@/hooks/store/user";
// local imports
import { PROJECT_SETTINGS_ICONS } from "./item-icon";
type Props = {
projectId: string;
};
export const ProjectSettingsSidebarItemCategories = observer(function ProjectSettingsSidebarItemCategories(
props: Props
) {
const { projectId } = props;
// params
const { workspaceSlug } = useParams();
const pathname = usePathname();
// store hooks
const { allowPermissions } = useUserPermissions();
// translation
const { t } = useTranslation();
return (
<div className="mt-3 flex flex-col divide-y divide-subtle px-3">
{PROJECT_SETTINGS_CATEGORIES.map((category) => {
const categoryItems = GROUPED_PROJECT_SETTINGS[category];
const accessibleItems = categoryItems.filter((item) =>
allowPermissions(item.access, EUserPermissionsLevel.PROJECT, workspaceSlug, projectId)
);
if (accessibleItems.length === 0) return null;
return (
<div key={category} className="shrink-0 py-3 first:pt-0 last:pb-0">
<div className="p-2 text-caption-md-medium text-tertiary capitalize">
{t(PROJECT_SETTINGS_CATEGORY_LABELS[category])}
</div>
<div className="flex flex-col">
{accessibleItems.map((item) => {
const isItemActive =
item.href === ""
? pathname === `/${workspaceSlug}/settings/projects/${projectId}${item.href}/`
: new RegExp(`^/${workspaceSlug}/settings/projects/${projectId}${item.href}/`).test(pathname);
return (
<SettingsSidebarItem
key={item.key}
as="link"
href={`/${workspaceSlug}/settings/projects/${projectId}${item.href}/`}
isActive={isItemActive}
icon={PROJECT_SETTINGS_ICONS[item.key]}
label={t(item.i18n_label)}
/>
);
})}
</div>
</div>
);
})}
</div>
);
});

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { LucideIcon } from "lucide-react";
import {
CyclesOutline,
EstimateOutline,
IntakeOutline,
LabelsOutline,
MembersOutline,
ModuleOutline,
PagesOutline,
StateOutline,
TriggerOutline,
ViewsOutline,
} from "@makeplane/propel/icons";
// plane imports
import type { ISvgIcons } from "@plane/propel/icons";
import type { TProjectSettingsTabs } from "@plane/types";
// components
import { SettingIcon } from "@/components/icons/attachment";
export const PROJECT_SETTINGS_ICONS: Record<TProjectSettingsTabs, LucideIcon | React.FC<ISvgIcons>> = {
general: SettingIcon,
members: MembersOutline,
features_cycles: CyclesOutline,
features_modules: ModuleOutline,
features_views: ViewsOutline,
features_pages: PagesOutline,
features_intake: IntakeOutline,
states: StateOutline,
labels: LabelsOutline,
estimates: EstimateOutline,
automations: TriggerOutline,
};

View 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.
*/
// plane imports
import { ScrollArea } from "@plane/propel/scrollarea";
// local imports
import { ProjectSettingsSidebarHeader } from "./header";
import { ProjectSettingsSidebarItemCategories } from "./item-categories";
type Props = {
projectId: string;
};
export function ProjectSettingsSidebarRoot(props: Props) {
const { projectId } = props;
return (
<ScrollArea
scrollType="hover"
orientation="vertical"
size="sm"
rootClassName="shrink-0 animate-fade-in h-full w-[250px] bg-surface-1 border-r border-r-subtle overflow-y-scroll"
viewportClassName="pb-5"
>
<ProjectSettingsSidebarHeader projectId={projectId} />
<ProjectSettingsSidebarItemCategories projectId={projectId} />
</ScrollArea>
);
}