mirror of
https://github.com/makeplane/plane.git
synced 2026-02-09 07:38:52 -06:00
[WEB-4429] fix: url path generation #7317
This commit is contained in:
@@ -318,3 +318,39 @@ export const copyTextToClipboard = async (text: string): Promise<void> => {
|
||||
}
|
||||
await navigator.clipboard.writeText(text);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Joins URL path segments properly, removing duplicate slashes
|
||||
* @param {...string} segments - URL path segments to join
|
||||
* @returns {string} Properly joined URL path
|
||||
* @example
|
||||
* joinUrlPath("/workspace", "/projects") => "/workspace/projects"
|
||||
* joinUrlPath("/workspace", "projects") => "/workspace/projects"
|
||||
* joinUrlPath("workspace", "projects") => "workspace/projects"
|
||||
* joinUrlPath("/workspace/", "/projects/") => "/workspace/projects/"
|
||||
*/
|
||||
export const joinUrlPath = (...segments: string[]): string => {
|
||||
if (segments.length === 0) return "";
|
||||
|
||||
// Filter out empty segments
|
||||
const validSegments = segments.filter((segment) => segment !== "");
|
||||
if (validSegments.length === 0) return "";
|
||||
|
||||
// Join segments and normalize slashes
|
||||
const joined = validSegments
|
||||
.map((segment, index) => {
|
||||
// Remove leading slashes from all segments except the first
|
||||
if (index > 0) {
|
||||
segment = segment.replace(/^\/+/, "");
|
||||
}
|
||||
// Remove trailing slashes from all segments except the last
|
||||
if (index < validSegments.length - 1) {
|
||||
segment = segment.replace(/\/+$/, "");
|
||||
}
|
||||
return segment;
|
||||
})
|
||||
.join("/");
|
||||
|
||||
// Clean up any duplicate slashes that might have been created
|
||||
return joined.replace(/\/+/g, "/");
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Disclosure } from "@headlessui/react";
|
||||
// plane imports
|
||||
import { EUserWorkspaceRoles } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { cn } from "@plane/utils";
|
||||
import { cn, joinUrlPath } from "@plane/utils";
|
||||
// hooks
|
||||
import { useUserSettings } from "@/hooks/store";
|
||||
|
||||
@@ -72,7 +72,11 @@ const SettingsSidebarNavItem = observer((props: TSettingsSidebarNavItemProps) =>
|
||||
{renderChildren ? (
|
||||
<div className={buttonClass}>{titleElement}</div>
|
||||
) : (
|
||||
<Link href={`/${workspaceSlug}/${setting.href}`} className={buttonClass} onClick={() => toggleSidebar(true)}>
|
||||
<Link
|
||||
href={joinUrlPath("/", workspaceSlug, setting.href)}
|
||||
className={buttonClass}
|
||||
onClick={() => toggleSidebar(true)}
|
||||
>
|
||||
{titleElement}
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@@ -46,10 +46,11 @@ export const SettingsSidebar = observer((props: SettingsSidebarProps) => {
|
||||
<SettingsSidebarHeader customHeader={customHeader} />
|
||||
{/* Navigation */}
|
||||
<div className="divide-y divide-custom-border-100 overflow-x-hidden w-full h-full overflow-y-scroll">
|
||||
{categories.map((category) => (
|
||||
<div key={category} className="py-3">
|
||||
<span className="text-sm font-semibold text-custom-text-350 capitalize mb-2">{t(category)}</span>
|
||||
{groupedSettings[category].length > 0 && (
|
||||
{categories.map((category) => {
|
||||
if (groupedSettings[category].length === 0) return null;
|
||||
return (
|
||||
<div key={category} className="py-3">
|
||||
<span className="text-sm font-semibold text-custom-text-350 capitalize mb-2">{t(category)}</span>
|
||||
<div className="relative flex flex-col gap-0.5 h-full mt-2">
|
||||
{groupedSettings[category].map(
|
||||
(setting) =>
|
||||
@@ -66,9 +67,9 @@ export const SettingsSidebar = observer((props: SettingsSidebarProps) => {
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user