diff --git a/admin/helpers/authentication.helper.tsx b/admin/helpers/authentication.helper.tsx index f34fd8758..6bfccd45e 100644 --- a/admin/helpers/authentication.helper.tsx +++ b/admin/helpers/authentication.helper.tsx @@ -1,10 +1,12 @@ import { ReactNode } from "react"; +import Link from "next/link"; export enum EPageTypes { - "PUBLIC" = "PUBLIC", - "NON_AUTHENTICATED" = "NON_AUTHENTICATED", - "ONBOARDING" = "ONBOARDING", - "AUTHENTICATED" = "AUTHENTICATED", + PUBLIC = "PUBLIC", + NON_AUTHENTICATED = "NON_AUTHENTICATED", + SET_PASSWORD = "SET_PASSWORD", + ONBOARDING = "ONBOARDING", + AUTHENTICATED = "AUTHENTICATED", } export enum EAuthModes { @@ -18,28 +20,26 @@ export enum EAuthSteps { UNIQUE_CODE = "UNIQUE_CODE", } -export enum EAuthenticationErrorCodes { - INSTANCE_NOT_CONFIGURED = "5000", - // Admin - ADMIN_ALREADY_EXIST = "5029", - REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME = "5030", - INVALID_ADMIN_EMAIL = "5031", - INVALID_ADMIN_PASSWORD = "5032", - REQUIRED_ADMIN_EMAIL_PASSWORD = "5033", - ADMIN_AUTHENTICATION_FAILED = "5034", - ADMIN_USER_ALREADY_EXIST = "5035", - ADMIN_USER_DOES_NOT_EXIST = "5036", -} - export enum EErrorAlertType { BANNER_ALERT = "BANNER_ALERT", - TOAST_ALERT = "TOAST_ALERT", INLINE_FIRST_NAME = "INLINE_FIRST_NAME", INLINE_EMAIL = "INLINE_EMAIL", INLINE_PASSWORD = "INLINE_PASSWORD", INLINE_EMAIL_CODE = "INLINE_EMAIL_CODE", } +export enum EAuthenticationErrorCodes { + // Admin + ADMIN_ALREADY_EXIST = "5150", + REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME = "5155", + INVALID_ADMIN_EMAIL = "5160", + INVALID_ADMIN_PASSWORD = "5165", + REQUIRED_ADMIN_EMAIL_PASSWORD = "5170", + ADMIN_AUTHENTICATION_FAILED = "5175", + ADMIN_USER_ALREADY_EXIST = "5180", + ADMIN_USER_DOES_NOT_EXIST = "5185", +} + export type TAuthErrorInfo = { type: EErrorAlertType; code: EAuthenticationErrorCodes; @@ -50,41 +50,54 @@ export type TAuthErrorInfo = { const errorCodeMessages: { [key in EAuthenticationErrorCodes]: { title: string; message: (email?: string | undefined) => ReactNode }; } = { - [EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED]: { - title: "Instance not configured", - message: () => "Please contact your administrator to configure the instance.", - }, + // admin [EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST]: { - title: "Admin already exists", - message: () => "Admin already exists. Please sign in.", + title: `Admin already exists`, + message: () => `Admin already exists. Please try again.`, }, [EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME]: { - title: "Required", - message: () => "Please enter email, password and first name.", + title: `Email, password and first name required`, + message: () => `Email, password and first name required. Please try again.`, }, [EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL]: { - title: "Invalid email", - message: () => "Please enter a valid email.", + title: `Invalid admin email`, + message: () => `Invalid admin email. Please try again.`, }, [EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD]: { - title: "Invalid password", - message: () => "Password must be at least 8 characters long.", + title: `Invalid admin password`, + message: () => `Invalid admin password. Please try again.`, }, [EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD]: { - title: "Required", - message: () => "Please enter email and password.", + title: `Email and password required`, + message: () => `Email and password required. Please try again.`, }, [EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED]: { - title: "Authentication failed", - message: () => "Please check your email and password and try again.", + title: `Authentication failed`, + message: () => `Authentication failed. Please try again.`, }, [EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST]: { - title: "User already exists", - message: () => "User already exists. Please sign in.", + title: `Admin user already exists`, + message: () => ( +
+ Admin user already exists.  + + Sign In + +  now. +
+ ), }, [EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST]: { - title: "User does not exist", - message: () => "User does not exist. Please sign up.", + title: `Admin user does not exist`, + message: () => ( +
+ Admin user does not exist.  + + Sign In + +  now. +
+ ), }, }; @@ -92,28 +105,16 @@ export const authErrorHandler = ( errorCode: EAuthenticationErrorCodes, email?: string | undefined ): TAuthErrorInfo | undefined => { - const toastAlertErrorCodes = [ - EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST, + const bannerAlertErrorCodes = [ + EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME, EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL, EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD, - EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED, - ]; - const bannerAlertErrorCodes = [ - EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED, - EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME, EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD, + EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED, EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST, EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST, ]; - if (toastAlertErrorCodes.includes(errorCode)) - return { - type: EErrorAlertType.TOAST_ALERT, - code: errorCode, - title: errorCodeMessages[errorCode]?.title || "Error", - message: errorCodeMessages[errorCode]?.message(email) || "Something went wrong. Please try again.", - }; - if (bannerAlertErrorCodes.includes(errorCode)) return { type: EErrorAlertType.BANNER_ALERT, diff --git a/apiserver/plane/api/serializers/issue.py b/apiserver/plane/api/serializers/issue.py index c40f56ccc..020917ee5 100644 --- a/apiserver/plane/api/serializers/issue.py +++ b/apiserver/plane/api/serializers/issue.py @@ -315,7 +315,7 @@ class IssueLinkSerializer(BaseSerializer): if IssueLink.objects.filter( url=validated_data.get("url"), issue_id=instance.issue_id, - ).exists(): + ).exclude(pk=instance.id).exists(): raise serializers.ValidationError( {"error": "URL already exists for this Issue"} ) diff --git a/apiserver/plane/app/serializers/issue.py b/apiserver/plane/app/serializers/issue.py index 748af96fb..e4a04fadf 100644 --- a/apiserver/plane/app/serializers/issue.py +++ b/apiserver/plane/app/serializers/issue.py @@ -462,7 +462,7 @@ class IssueLinkSerializer(BaseSerializer): if IssueLink.objects.filter( url=validated_data.get("url"), issue_id=instance.issue_id, - ).exists(): + ).exclude(pk=instance.id).exists(): raise serializers.ValidationError( {"error": "URL already exists for this Issue"} ) diff --git a/deploy/selfhost/README.md b/deploy/selfhost/README.md index 35d58f3d2..bb8a574d8 100644 --- a/deploy/selfhost/README.md +++ b/deploy/selfhost/README.md @@ -96,7 +96,7 @@ This will prompt you with the below options. ```bash Select a Action you want to perform: - 1) Install (arm64) + 1) Install (x86_64) 2) Start 3) Stop 4) Restart @@ -344,7 +344,7 @@ Similarly, you can view the logs of other services. There would a time when you might want to backup your data from docker volumes to external storage like S3 or drives. -Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `8` to view logs. +Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `7` to Backup the data. ```bash Select a Action you want to perform: diff --git a/deploy/selfhost/install.sh b/deploy/selfhost/install.sh index b36d3b6b2..48679a57a 100755 --- a/deploy/selfhost/install.sh +++ b/deploy/selfhost/install.sh @@ -390,7 +390,7 @@ fi # CPU ARCHITECHTURE BASED SETTINGS CPU_ARCH=$(uname -m) -if [[ $CPU_ARCH == "amd64" || $CPU_ARCH == "x86_64" || ( $BRANCH == "master" && ( $CPU_ARCH == "arm64" || $CPU_ARCH == "aarch64" ) ) ]]; +if [[ $FORCE_CPU == "amd64" || $CPU_ARCH == "amd64" || $CPU_ARCH == "x86_64" || ( $BRANCH == "master" && ( $CPU_ARCH == "arm64" || $CPU_ARCH == "aarch64" ) ) ]]; then USE_GLOBAL_IMAGES=1 DOCKERHUB_USER=makeplane diff --git a/nginx/nginx.conf.dev b/nginx/nginx.conf.dev index eb0d54d7d..869c2e807 100644 --- a/nginx/nginx.conf.dev +++ b/nginx/nginx.conf.dev @@ -16,7 +16,9 @@ http { add_header Permissions-Policy "interest-cohort=()" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Forwarded-Proto "${dollar}scheme"; - add_header Host "${dollar}host"; + add_header X-Forwarded-Host "${dollar}host"; + add_header X-Forwarded-For "${dollar}proxy_add_x_forwarded_for"; + add_header Host "${dollar}http_host"; location / { proxy_pass http://web:3000/; @@ -30,10 +32,14 @@ http { } location /api/ { + proxy_set_header X-Forwarded-For "${dollar}proxy_add_x_forwarded_for"; + proxy_set_header Host "${dollar}http_host"; proxy_pass http://api:8000/api/; } location /auth/ { + proxy_set_header X-Forwarded-For "${dollar}proxy_add_x_forwarded_for"; + proxy_set_header Host "${dollar}http_host"; proxy_pass http://api:8000/auth/; } diff --git a/nginx/nginx.conf.template b/nginx/nginx.conf.template index 35b021e81..a03e8ee5f 100644 --- a/nginx/nginx.conf.template +++ b/nginx/nginx.conf.template @@ -16,13 +16,17 @@ http { add_header Permissions-Policy "interest-cohort=()" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Forwarded-Proto "${dollar}scheme"; - add_header Host "${dollar}host"; + add_header X-Forwarded-Host "${dollar}host"; + add_header X-Forwarded-For "${dollar}proxy_add_x_forwarded_for"; + add_header Host "${dollar}http_host"; location / { proxy_pass http://web:3000/; } location /api/ { + proxy_set_header X-Forwarded-For "${dollar}proxy_add_x_forwarded_for"; + proxy_set_header Host "${dollar}http_host"; proxy_pass http://api:8000/api/; } @@ -35,6 +39,8 @@ http { } location /auth/ { + proxy_set_header X-Forwarded-For "${dollar}proxy_add_x_forwarded_for"; + proxy_set_header Host "${dollar}http_host"; proxy_pass http://api:8000/auth/; } diff --git a/packages/ui/src/dropdowns/custom-menu.tsx b/packages/ui/src/dropdowns/custom-menu.tsx index 549c83fe7..316cc6960 100644 --- a/packages/ui/src/dropdowns/custom-menu.tsx +++ b/packages/ui/src/dropdowns/custom-menu.tsx @@ -68,6 +68,13 @@ const CustomMenu = (props: ICustomMenuDropdownProps) => { if (closeOnSelect) closeDropdown(); }; + const handleMenuButtonClick = (e:React.MouseEvent)=>{ + e.stopPropagation(); + e.preventDefault() + isOpen ? closeDropdown() : openDropdown(); + if (menuButtonOnClick) menuButtonOnClick(); + } + useOutsideClickDetector(dropdownRef, closeDropdown); let menuItems = ( @@ -112,11 +119,7 @@ const CustomMenu = (props: ICustomMenuDropdownProps) => {