From 847c037debc6d15c987b69690c4f88353088ca70 Mon Sep 17 00:00:00 2001 From: sriramveeraghanta Date: Mon, 24 Nov 2025 21:16:01 +0530 Subject: [PATCH 1/5] feat: add in common py --- apps/api/plane/settings/common.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/api/plane/settings/common.py b/apps/api/plane/settings/common.py index 41780521668..4d926a13d5e 100644 --- a/apps/api/plane/settings/common.py +++ b/apps/api/plane/settings/common.py @@ -25,6 +25,9 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = int(os.environ.get("DEBUG", "0")) +# Self-hosted mode +IS_SELF_HOSTED = int(os.environ.get("IS_SELF_HOSTED", "1")) == 1 + # Allowed Hosts ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "*").split(",") @@ -69,9 +72,7 @@ # Rest Framework settings REST_FRAMEWORK = { - "DEFAULT_AUTHENTICATION_CLASSES": ( - "rest_framework.authentication.SessionAuthentication", - ), + "DEFAULT_AUTHENTICATION_CLASSES": ("rest_framework.authentication.SessionAuthentication",), "DEFAULT_THROTTLE_CLASSES": ("rest_framework.throttling.AnonRateThrottle",), "DEFAULT_THROTTLE_RATES": { "anon": "30/minute", From 19d1dde4c135717fe122f44bc740a3c56881cba8 Mon Sep 17 00:00:00 2001 From: sriramveeraghanta Date: Thu, 27 Nov 2025 21:16:13 +0530 Subject: [PATCH 2/5] fix: update marketing consent screen based on is self managed flag --- apps/api/plane/license/api/views/instance.py | 1 + apps/api/plane/settings/common.py | 2 +- .../components/onboarding/steps/profile/root.tsx | 16 ++++++++++------ packages/types/src/instance/base.ts | 1 + 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/api/plane/license/api/views/instance.py b/apps/api/plane/license/api/views/instance.py index 23eeebec1c1..fed0c5e17e6 100644 --- a/apps/api/plane/license/api/views/instance.py +++ b/apps/api/plane/license/api/views/instance.py @@ -175,6 +175,7 @@ def get(self, request): data["app_base_url"] = settings.APP_BASE_URL data["instance_changelog_url"] = settings.INSTANCE_CHANGELOG_URL + data["is_self_managed"] = settings.IS_SELF_MANAGED instance_data = serializer.data instance_data["workspaces_exist"] = Workspace.objects.count() >= 1 diff --git a/apps/api/plane/settings/common.py b/apps/api/plane/settings/common.py index 4d926a13d5e..a9e9925c28c 100644 --- a/apps/api/plane/settings/common.py +++ b/apps/api/plane/settings/common.py @@ -26,7 +26,7 @@ DEBUG = int(os.environ.get("DEBUG", "0")) # Self-hosted mode -IS_SELF_HOSTED = int(os.environ.get("IS_SELF_HOSTED", "1")) == 1 +IS_SELF_MANAGED = True # Allowed Hosts ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "*").split(",") diff --git a/apps/web/core/components/onboarding/steps/profile/root.tsx b/apps/web/core/components/onboarding/steps/profile/root.tsx index c74daa8361a..3e352c1c6d1 100644 --- a/apps/web/core/components/onboarding/steps/profile/root.tsx +++ b/apps/web/core/components/onboarding/steps/profile/root.tsx @@ -22,6 +22,7 @@ import { AuthService } from "@/services/auth.service"; import { CommonOnboardingHeader } from "../common"; import { MarketingConsent } from "./consent"; import { SetPasswordRoot } from "./set-password"; +import { useInstance } from "@/hooks/store/use-instance"; type Props = { handleStepChange: (step: EOnboardingSteps, skipInvites?: boolean) => void; @@ -55,6 +56,7 @@ export const ProfileSetupStep = observer(function ProfileSetupStep({ handleStepC // store hooks const { data: user, updateCurrentUser } = useUser(); const { updateUserProfile } = useUserProfile(); + const { config: instanceConfig } = useInstance(); // form info const { getValues, @@ -253,12 +255,14 @@ export const ProfileSetupStep = observer(function ProfileSetupStep({ handleStepC {/* Marketing Consent */} - - setValue("has_marketing_email_consent", has_marketing_email_consent) - } - /> + {!instanceConfig.is_self_managed && ( + + setValue("has_marketing_email_consent", has_marketing_email_consent) + } + /> + )} ); }); diff --git a/packages/types/src/instance/base.ts b/packages/types/src/instance/base.ts index 742698f5631..975e1238609 100644 --- a/packages/types/src/instance/base.ts +++ b/packages/types/src/instance/base.ts @@ -56,6 +56,7 @@ export interface IInstanceConfig { app_base_url: string | undefined; space_base_url: string | undefined; admin_base_url: string | undefined; + is_self_managed: boolean; // intercom is_intercom_enabled: boolean; intercom_app_id: string | undefined; From c09c64dcab6e21a457e5d3266252b12abfd7785a Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Fri, 28 Nov 2025 15:59:21 +0530 Subject: [PATCH 3/5] improvement: enhance ImagePickerPopover with dynamic tab options based on Unsplash configuration --- .../components/core/image-picker-popover.tsx | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/apps/web/core/components/core/image-picker-popover.tsx b/apps/web/core/components/core/image-picker-popover.tsx index 7eefa0d3ab0..d3313040587 100644 --- a/apps/web/core/components/core/image-picker-popover.tsx +++ b/apps/web/core/components/core/image-picker-popover.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useCallback } from "react"; +import React, { useState, useRef, useCallback, useMemo } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import { useDropzone } from "react-dropzone"; @@ -16,24 +16,16 @@ import { Input, Loader } from "@plane/ui"; // helpers import { getFileURL } from "@plane/utils"; // hooks +import { useInstance } from "@/hooks/store/use-instance"; import { useDropdownKeyDown } from "@/hooks/use-dropdown-key-down"; // services import { FileService } from "@/services/file.service"; -const tabOptions = [ - { - key: "unsplash", - title: "Unsplash", - }, - { - key: "images", - title: "Images", - }, - { - key: "upload", - title: "Upload", - }, -]; +type TTabOption = { + key: string; + title: string; + isEnabled: boolean; +}; type Props = { label: string | React.ReactNode; @@ -63,6 +55,30 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr const ref = useRef(null); // router params const { workspaceSlug } = useParams(); + // store hooks + const { config } = useInstance(); + // derived values + const hasUnsplashConfigured = config?.has_unsplash_configured || false; + const tabOptions: TTabOption[] = useMemo( + () => [ + { + key: "unsplash", + title: "Unsplash", + isEnabled: hasUnsplashConfigured, + }, + { + key: "images", + title: "Images", + isEnabled: true, + }, + { + key: "upload", + title: "Upload", + isEnabled: true, + }, + ], + [hasUnsplashConfigured] + ); const { data: unsplashImages, error: unsplashError } = useSWR( `UNSPLASH_IMAGES_${searchParams}`, From ffb806f8c05f705d18442c40cc36819b2ea852ec Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Tue, 2 Dec 2025 20:27:42 +0530 Subject: [PATCH 4/5] refactor: product updates modal to include changelog --- apps/web/ce/components/global/index.ts | 1 - .../global/product-updates/changelog.tsx | 37 +++++++++++++++++++ .../header.tsx} | 7 +--- .../global/product-updates/modal.tsx | 29 ++------------- 4 files changed, 41 insertions(+), 33 deletions(-) create mode 100644 apps/web/ce/components/global/product-updates/changelog.tsx rename apps/web/ce/components/global/{product-updates-header.tsx => product-updates/header.tsx} (79%) diff --git a/apps/web/ce/components/global/index.ts b/apps/web/ce/components/global/index.ts index c87c8ae0273..08b85c764c0 100644 --- a/apps/web/ce/components/global/index.ts +++ b/apps/web/ce/components/global/index.ts @@ -1,2 +1 @@ export * from "./version-number"; -export * from "./product-updates-header"; diff --git a/apps/web/ce/components/global/product-updates/changelog.tsx b/apps/web/ce/components/global/product-updates/changelog.tsx new file mode 100644 index 00000000000..e2c1e1af70c --- /dev/null +++ b/apps/web/ce/components/global/product-updates/changelog.tsx @@ -0,0 +1,37 @@ +import { observer } from "mobx-react"; +// plane imports +import { USER_TRACKER_ELEMENTS } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; +// hooks +import { useInstance } from "@/hooks/store/use-instance"; + +export const ProductUpdatesChangelog = observer(function ProductUpdatesChangelog() { + // plane hooks + const { t } = useTranslation(); + // store hooks + const { config } = useInstance(); + // derived values + const changeLogUrl = config?.instance_changelog_url; + + if (changeLogUrl && changeLogUrl !== "") { + return