Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/admin/react-router.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Config } from "@react-router/dev/config";
import { joinUrlPath } from "@plane/utils";
import { normalizeBasePath } from "@plane/utils";

const basePath = joinUrlPath(process.env.VITE_ADMIN_BASE_PATH ?? "", "/") ?? "/";
const basePath = normalizeBasePath(process.env.VITE_ADMIN_BASE_PATH ?? "");

export default {
appDirectory: "app",
Expand Down
4 changes: 2 additions & 2 deletions apps/admin/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as dotenv from "dotenv";
import { reactRouter } from "@react-router/dev/vite";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import { joinUrlPath } from "@plane/utils";
import { normalizeBasePath } from "@plane/utils";

dotenv.config({ path: path.resolve(__dirname, ".env") });

Expand All @@ -15,7 +15,7 @@ const viteEnv = Object.keys(process.env)
return a;
}, {});

const basePath = joinUrlPath(process.env.VITE_ADMIN_BASE_PATH ?? "", "/") ?? "/";
const basePath = normalizeBasePath(process.env.VITE_ADMIN_BASE_PATH ?? "");

export default defineConfig(() => ({
base: basePath,
Expand Down
24 changes: 21 additions & 3 deletions packages/utils/src/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const truncateText = (str: string, length: number) => {
export const createSimilarString = (str: string) => {
const shuffled = str
.split("")
.sort(() => Math.random() - 0.5)
.toSorted(() => Math.random() - 0.5)
.join("");

return shuffled;
Expand Down Expand Up @@ -153,7 +153,7 @@ export const checkEmailValidity = (email: string): boolean => {
if (!email) return false;

const isEmailValid =
/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
email
);

Expand Down Expand Up @@ -236,7 +236,7 @@ export const isCommentEmpty = (comment: Content | undefined): boolean => {

// Handle JSONContent[] (array)
if (Array.isArray(comment)) {
return comment.length === 0 || comment.every(isJSONContentEmpty);
return comment.every(isJSONContentEmpty);
}

// Handle JSONContent (object)
Expand Down Expand Up @@ -431,3 +431,21 @@ export const joinUrlPath = (...segments: string[]): string => {
return pathParts.length > 0 ? `/${pathParts.join("/")}` : "";
}
};

export const normalizeBasePath = (rawBasePath: string): string => {
const trimmed = rawBasePath.trim();

// Empty or slash-only paths become root
if (trimmed === "" || /^\/+$/.test(trimmed)) {
return "/";
}

// Collapse multiple slashes
const normalized = trimmed.replace(/\/{2,}/g, "/");

// Remove trailing slashes except root
const withoutTrailingSlashes = normalized.replace(/\/+$/, "");

// Ensure leading slash
return withoutTrailingSlashes.startsWith("/") ? withoutTrailingSlashes : `/${withoutTrailingSlashes}`;
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.