sync: canary cahnges to preview
This commit is contained in:
commit
4f5272c8af
23 changed files with 88 additions and 29 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "admin",
|
"name": "admin",
|
||||||
"description": "Admin UI for Plane",
|
"description": "Admin UI for Plane",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "live",
|
"name": "live",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"description": "A realtime collaborative server powers Plane's rich text editor",
|
"description": "A realtime collaborative server powers Plane's rich text editor",
|
||||||
"main": "./src/server.ts",
|
"main": "./src/server.ts",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "plane-api",
|
"name": "plane-api",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "API server powering Plane's backend"
|
"description": "API server powering Plane's backend"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "space",
|
"name": "space",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { Disclosure } from "@headlessui/react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EUserWorkspaceRoles } from "@plane/types";
|
import { EUserWorkspaceRoles } from "@plane/types";
|
||||||
import { cn } from "@plane/utils";
|
import { cn, joinUrlPath } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { useUserSettings } from "@/hooks/store";
|
import { useUserSettings } from "@/hooks/store";
|
||||||
|
|
||||||
|
|
@ -72,7 +72,11 @@ const SettingsSidebarNavItem = observer((props: TSettingsSidebarNavItemProps) =>
|
||||||
{renderChildren ? (
|
{renderChildren ? (
|
||||||
<div className={buttonClass}>{titleElement}</div>
|
<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}
|
{titleElement}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,11 @@ export const SettingsSidebar = observer((props: SettingsSidebarProps) => {
|
||||||
<SettingsSidebarHeader customHeader={customHeader} />
|
<SettingsSidebarHeader customHeader={customHeader} />
|
||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
<div className="divide-y divide-custom-border-100 overflow-x-hidden w-full h-full overflow-y-scroll">
|
<div className="divide-y divide-custom-border-100 overflow-x-hidden w-full h-full overflow-y-scroll">
|
||||||
{categories.map((category) => (
|
{categories.map((category) => {
|
||||||
<div key={category} className="py-3">
|
if (groupedSettings[category].length === 0) return null;
|
||||||
<span className="text-sm font-semibold text-custom-text-350 capitalize mb-2">{t(category)}</span>
|
return (
|
||||||
{groupedSettings[category].length > 0 && (
|
<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">
|
<div className="relative flex flex-col gap-0.5 h-full mt-2">
|
||||||
{groupedSettings[category].map(
|
{groupedSettings[category].map(
|
||||||
(setting) =>
|
(setting) =>
|
||||||
|
|
@ -66,9 +67,9 @@ export const SettingsSidebar = observer((props: SettingsSidebarProps) => {
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
);
|
||||||
))}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "web",
|
"name": "web",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "plane",
|
"name": "plane",
|
||||||
"description": "Open-source project management that unlocks customer value",
|
"description": "Open-source project management that unlocks customer value",
|
||||||
"repository": "https://github.com/makeplane/plane.git",
|
"repository": "https://github.com/makeplane/plane.git",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/constants",
|
"name": "@plane/constants",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/editor",
|
"name": "@plane/editor",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"description": "Core Editor that powers Plane",
|
"description": "Core Editor that powers Plane",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/eslint-config",
|
"name": "@plane/eslint-config",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"files": [
|
"files": [
|
||||||
"library.js",
|
"library.js",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/hooks",
|
"name": "@plane/hooks",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"description": "React hooks that are shared across multiple apps internally",
|
"description": "React hooks that are shared across multiple apps internally",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/i18n",
|
"name": "@plane/i18n",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"description": "I18n shared across multiple apps internally",
|
"description": "I18n shared across multiple apps internally",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/logger",
|
"name": "@plane/logger",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"description": "Logger shared across multiple apps internally",
|
"description": "Logger shared across multiple apps internally",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/propel",
|
"name": "@plane/propel",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/services",
|
"name": "@plane/services",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/shared-state",
|
"name": "@plane/shared-state",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"description": "Shared state shared across multiple apps internally",
|
"description": "Shared state shared across multiple apps internally",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/tailwind-config",
|
"name": "@plane/tailwind-config",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"description": "common tailwind configuration across monorepo",
|
"description": "common tailwind configuration across monorepo",
|
||||||
"main": "tailwind.config.js",
|
"main": "tailwind.config.js",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/types",
|
"name": "@plane/types",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/typescript-config",
|
"name": "@plane/typescript-config",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"files": [
|
"files": [
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "@plane/ui",
|
"name": "@plane/ui",
|
||||||
"description": "UI components shared across multiple apps internally",
|
"description": "UI components shared across multiple apps internally",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@plane/utils",
|
"name": "@plane/utils",
|
||||||
"version": "0.27.0",
|
"version": "0.27.1",
|
||||||
"description": "Helper functions shared across multiple apps internally",
|
"description": "Helper functions shared across multiple apps internally",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
||||||
|
|
@ -318,3 +318,57 @@ export const copyTextToClipboard = async (text: string): Promise<void> => {
|
||||||
}
|
}
|
||||||
await navigator.clipboard.writeText(text);
|
await navigator.clipboard.writeText(text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Joins URL path segments properly, removing duplicate slashes using URL encoding
|
||||||
|
* @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 "";
|
||||||
|
|
||||||
|
// Process segments to normalize slashes
|
||||||
|
const processedSegments = validSegments.map((segment, index) => {
|
||||||
|
let processed = segment;
|
||||||
|
|
||||||
|
// Remove leading slashes from all segments except the first
|
||||||
|
if (index > 0) {
|
||||||
|
while (processed.startsWith("/")) {
|
||||||
|
processed = processed.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing slashes from all segments except the last
|
||||||
|
if (index < validSegments.length - 1) {
|
||||||
|
while (processed.endsWith("/")) {
|
||||||
|
processed = processed.substring(0, processed.length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return processed;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Join segments with single slash
|
||||||
|
const joined = processedSegments.join("/");
|
||||||
|
|
||||||
|
// Use URL constructor to normalize the path and handle double slashes
|
||||||
|
try {
|
||||||
|
// Create a dummy URL to leverage browser's URL normalization
|
||||||
|
const dummyUrl = new URL(`http://example.com/${joined}`);
|
||||||
|
return dummyUrl.pathname;
|
||||||
|
} catch {
|
||||||
|
// Fallback: manually handle double slashes by splitting and filtering
|
||||||
|
const pathParts = joined.split("/").filter((part) => part !== "");
|
||||||
|
return pathParts.length > 0 ? `/${pathParts.join("/")}` : "";
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue