diff --git a/packages/server/src/IdentityManager.ts b/packages/server/src/IdentityManager.ts index 57ccdac1775..bf18b42b981 100644 --- a/packages/server/src/IdentityManager.ts +++ b/packages/server/src/IdentityManager.ts @@ -289,6 +289,16 @@ export class IdentityManager { } } + public static disableForCloud(message: string) { + return (_req: Request, res: Response, next: NextFunction) => { + const identityManager = getRunningExpressApp().identityManager + if (identityManager.isCloud()) { + return res.status(403).json({ message }) + } + return next() + } + } + public async createStripeCustomerPortalSession(req: Request) { if (!this.stripeManager) { throw new Error('Stripe manager is not initialized') diff --git a/packages/server/src/StripeManager.ts b/packages/server/src/StripeManager.ts index d0cfc86b7b5..05da3863b66 100644 --- a/packages/server/src/StripeManager.ts +++ b/packages/server/src/StripeManager.ts @@ -3,6 +3,8 @@ import Stripe from 'stripe' import { UserPlan } from './Interface' import { UsageCacheManager } from './UsageCacheManager' import { LICENSE_QUOTAS } from './utils/constants' +import { InternalFlowiseError } from './errors/internalFlowiseError' +import { StatusCodes } from 'http-status-codes' export class StripeManager { private static instance: StripeManager @@ -53,6 +55,7 @@ export class StripeManager { try { const subscription = await this.stripe.subscriptions.retrieve(subscriptionId) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') const items = subscription.items.data if (items.length === 0) { return '' @@ -85,6 +88,7 @@ export class StripeManager { const subscription = await this.stripe.subscriptions.retrieve(subscriptionId, { timeout: 5000 }) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') const items = subscription.items.data if (items.length === 0) { return {} @@ -241,6 +245,7 @@ export class StripeManager { try { const subscription = await this.stripe.subscriptions.retrieve(subscriptionId) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') const additionalSeatsItem = subscription.items.data.find( (item) => (item.price.product as string) === process.env.ADDITIONAL_SEAT_ID ) @@ -282,6 +287,7 @@ export class StripeManager { try { const subscription = await this.stripe.subscriptions.retrieve(subscriptionId) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') // Get customer's credit balance const customer = await this.stripe.customers.retrieve(subscription.customer as string) @@ -374,6 +380,7 @@ export class StripeManager { try { const subscription = await this.stripe.subscriptions.retrieve(subscriptionId) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') const additionalSeatsItem = subscription.items.data.find( (item) => (item.price.product as string) === process.env.ADDITIONAL_SEAT_ID ) @@ -438,6 +445,7 @@ export class StripeManager { try { const subscription = await this.stripe.subscriptions.retrieve(subscriptionId) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') const customerId = subscription.customer as string // Get customer's credit balance and metadata @@ -510,6 +518,7 @@ export class StripeManager { try { const subscription = await this.stripe.subscriptions.retrieve(subscriptionId) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') const customerId = subscription.customer as string // Get customer details and metadata diff --git a/packages/server/src/UsageCacheManager.ts b/packages/server/src/UsageCacheManager.ts index 420daa64161..35a4057697d 100644 --- a/packages/server/src/UsageCacheManager.ts +++ b/packages/server/src/UsageCacheManager.ts @@ -4,6 +4,8 @@ import { Cache, createCache } from 'cache-manager' import { MODE } from './Interface' import { LICENSE_QUOTAS } from './utils/constants' import { StripeManager } from './StripeManager' +import { InternalFlowiseError } from './errors/internalFlowiseError' +import { StatusCodes } from 'http-status-codes' const DISABLED_QUOTAS = { [LICENSE_QUOTAS.PREDICTIONS_LIMIT]: 0, @@ -100,6 +102,7 @@ export class UsageCacheManager { // If not in cache, retrieve from Stripe const subscription = await stripeManager.getStripe().subscriptions.retrieve(subscriptionId) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') // Update subscription data cache await this.updateSubscriptionDataToCache(subscriptionId, { subsriptionDetails: stripeManager.getSubscriptionObject(subscription) }) @@ -123,6 +126,7 @@ export class UsageCacheManager { // If not in cache, retrieve from Stripe const subscription = await stripeManager.getStripe().subscriptions.retrieve(subscriptionId) + if (subscription.status === 'canceled') throw new InternalFlowiseError(StatusCodes.UNAUTHORIZED, 'Subscription is canceled') const items = subscription.items.data if (items.length === 0) { return DISABLED_QUOTAS diff --git a/packages/server/src/enterprise/routes/organization.route.ts b/packages/server/src/enterprise/routes/organization.route.ts index 52dc17c2646..ee3d7de9637 100644 --- a/packages/server/src/enterprise/routes/organization.route.ts +++ b/packages/server/src/enterprise/routes/organization.route.ts @@ -1,4 +1,5 @@ import express from 'express' +import { IdentityManager } from '../../IdentityManager' import { OrganizationController } from '../controllers/organization.controller' const router = express.Router() @@ -16,11 +17,19 @@ router.get('/customer-default-source', organizationController.getCustomerWithDef router.get('/additional-seats-proration', organizationController.getAdditionalSeatsProration) -router.post('/update-additional-seats', organizationController.updateAdditionalSeats) +router.post( + '/update-additional-seats', + IdentityManager.disableForCloud('Plan changes are currently disabled.'), + organizationController.updateAdditionalSeats +) router.get('/plan-proration', organizationController.getPlanProration) -router.post('/update-subscription-plan', organizationController.updateSubscriptionPlan) +router.post( + '/update-subscription-plan', + IdentityManager.disableForCloud('Plan changes are currently disabled.'), + organizationController.updateSubscriptionPlan +) router.get('/get-current-usage', organizationController.getCurrentUsage) diff --git a/packages/server/src/enterprise/services/account.service.ts b/packages/server/src/enterprise/services/account.service.ts index e364370b625..55f147e8e0d 100644 --- a/packages/server/src/enterprise/services/account.service.ts +++ b/packages/server/src/enterprise/services/account.service.ts @@ -197,7 +197,8 @@ export class AccountService { break case Platform.CLOUD: { const user = await this.userService.readUserByEmail(data.user.email, queryRunner) - if (user && (user.status === UserStatus.ACTIVE || user.status === UserStatus.UNVERIFIED)) + if (!user) throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.') + if (user.status === UserStatus.ACTIVE || user.status === UserStatus.UNVERIFIED) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, UserErrorMessage.USER_EMAIL_ALREADY_EXISTS) if (!data.user.email) throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, UserErrorMessage.INVALID_USER_EMAIL) @@ -364,6 +365,8 @@ export class AccountService { data.role = role const user = await this.userService.readUserByEmail(data.user.email, queryRunner) if (!user) { + if (this.identityManager.isCloud()) + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.') await checkUsageLimit('users', subscriptionId, getRunningExpressApp().usageCacheManager, totalOrgUsers + 1) // generate a temporary token @@ -413,6 +416,8 @@ export class AccountService { return data } + if (user.status !== UserStatus.ACTIVE && this.identityManager.isCloud()) + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.') const { organizationUser } = await this.organizationUserService.readOrganizationUserByOrganizationIdUserId( data.workspace.organizationId, user.id, diff --git a/packages/server/src/enterprise/services/organization-user.service.ts b/packages/server/src/enterprise/services/organization-user.service.ts index 07873613363..04ac573b18c 100644 --- a/packages/server/src/enterprise/services/organization-user.service.ts +++ b/packages/server/src/enterprise/services/organization-user.service.ts @@ -7,7 +7,7 @@ import { sanitizeUser } from '../../utils/sanitize.util' import { OrganizationUser, OrganizationUserStatus } from '../database/entities/organization-user.entity' import { Organization } from '../database/entities/organization.entity' import { GeneralRole } from '../database/entities/role.entity' -import { User } from '../database/entities/user.entity' +import { User, UserStatus } from '../database/entities/user.entity' import { WorkspaceUser } from '../database/entities/workspace-user.entity' import { Workspace } from '../database/entities/workspace.entity' import { OrganizationErrorMessage, OrganizationService } from './organization.service' @@ -215,6 +215,11 @@ export class OrganizationUserService { const queryRunner = this.dataSource.createQueryRunner() await queryRunner.connect() + const user = await this.userService.readUserById(data.userId, queryRunner) + if (!user) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, UserErrorMessage.USER_NOT_FOUND) + if (user.status !== UserStatus.ACTIVE && getRunningExpressApp().identityManager.isCloud()) + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.') + const { organization, organizationUser } = await this.readOrganizationUserByOrganizationIdUserId( data.organizationId, data.userId, diff --git a/packages/server/src/enterprise/services/user.service.ts b/packages/server/src/enterprise/services/user.service.ts index 6d54de53349..9006100e25f 100644 --- a/packages/server/src/enterprise/services/user.service.ts +++ b/packages/server/src/enterprise/services/user.service.ts @@ -82,6 +82,8 @@ export class UserService { public async createNewUser(data: Partial, queryRunner: QueryRunner) { const user = await this.readUserByEmail(data.email, queryRunner) + if (!user && getRunningExpressApp().identityManager.isCloud()) + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.') if (user) throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, UserErrorMessage.USER_EMAIL_ALREADY_EXISTS) if (data.credential) data.credential = this.encryptUserCredential(data.credential) if (!data.name) data.name = data.email diff --git a/packages/server/src/enterprise/services/workspace-user.service.ts b/packages/server/src/enterprise/services/workspace-user.service.ts index f6a4c85fc8b..52301ab9131 100644 --- a/packages/server/src/enterprise/services/workspace-user.service.ts +++ b/packages/server/src/enterprise/services/workspace-user.service.ts @@ -13,6 +13,7 @@ import { OrganizationErrorMessage, OrganizationService } from './organization.se import { RoleErrorMessage, RoleService } from './role.service' import { UserErrorMessage, UserService } from './user.service' import { WorkspaceErrorMessage, WorkspaceService } from './workspace.service' +import { UserStatus } from '../database/entities/user.entity' export const enum WorkspaceUserErrorMessage { INVALID_WORKSPACE_USER_SATUS = 'Invalid Workspace User Status', @@ -226,6 +227,11 @@ export class WorkspaceUserService { const queryRunner = this.dataSource.createQueryRunner() await queryRunner.connect() + const user = await this.userService.readUserById(data.userId, queryRunner) + if (!user) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, UserErrorMessage.USER_NOT_FOUND) + if (user.status !== UserStatus.ACTIVE && getRunningExpressApp().identityManager.isCloud()) + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.') + const { workspace, workspaceUser } = await this.readWorkspaceUserByWorkspaceIdUserId(data.workspaceId, data.userId, queryRunner) if (workspace.organizationId !== activeOrganizationId) throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, WorkspaceErrorMessage.WORKSPACE_NOT_FOUND) diff --git a/packages/server/src/enterprise/sso/SSOBase.ts b/packages/server/src/enterprise/sso/SSOBase.ts index c58f33a0d37..7ca87ea6980 100644 --- a/packages/server/src/enterprise/sso/SSOBase.ts +++ b/packages/server/src/enterprise/sso/SSOBase.ts @@ -61,23 +61,11 @@ abstract class SSOBase { if (getRunningExpressApp().identityManager.getPlatformType() === Platform.ENTERPRISE) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, UserErrorMessage.USER_NOT_FOUND) } - // no user found, register the user - const data: any = { - user: { - email: email, - name: profile.displayName || email, - status: UserStatus.ACTIVE, - credential: undefined - } - } - if (getRunningExpressApp().identityManager.getPlatformType() === Platform.CLOUD) { - const accountService = new AccountService() - const newAccount = await accountService.register(data) - wu = newAccount.workspaceUser - wu.workspace = newAccount.workspace - user = newAccount.user - } + if (getRunningExpressApp().identityManager.getPlatformType() === Platform.CLOUD) + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.') } else { + if (user.status !== UserStatus.ACTIVE && getRunningExpressApp().identityManager.getPlatformType() === Platform.CLOUD) + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, 'New registrations are currently closed.') if (user.status === UserStatus.INVITED) { const data: any = { user: { diff --git a/packages/ui/src/layout/MainLayout/AnnouncementBanner.jsx b/packages/ui/src/layout/MainLayout/AnnouncementBanner.jsx new file mode 100644 index 00000000000..fa35bcebcb4 --- /dev/null +++ b/packages/ui/src/layout/MainLayout/AnnouncementBanner.jsx @@ -0,0 +1,35 @@ +import PropTypes from 'prop-types' +import { Alert, Link } from '@mui/material' + +const AnnouncementBanner = ({ onClose }) => ( + + We're sunsetting Flowise.{' '} + + Learn more + + +) + +AnnouncementBanner.propTypes = { + onClose: PropTypes.func +} + +export default AnnouncementBanner diff --git a/packages/ui/src/layout/MainLayout/Header/index.jsx b/packages/ui/src/layout/MainLayout/Header/index.jsx index ae95c1eefef..4244951a65e 100644 --- a/packages/ui/src/layout/MainLayout/Header/index.jsx +++ b/packages/ui/src/layout/MainLayout/Header/index.jsx @@ -1,7 +1,6 @@ import PropTypes from 'prop-types' import { useSelector, useDispatch } from 'react-redux' import { useEffect, useState } from 'react' -import { useNavigate } from 'react-router-dom' // material-ui import { Button, Avatar, Box, ButtonBase, Switch, Typography, Link } from '@mui/material' @@ -12,10 +11,9 @@ import LogoSection from '../LogoSection' import ProfileSection from './ProfileSection' import WorkspaceSwitcher from '@/layout/MainLayout/Header/WorkspaceSwitcher' import OrgWorkspaceBreadcrumbs from '@/layout/MainLayout/Header/OrgWorkspaceBreadcrumbs' -import PricingDialog from '@/ui-component/subscription/PricingDialog' // assets -import { IconMenu2, IconX, IconSparkles } from '@tabler/icons-react' +import { IconMenu2, IconX } from '@tabler/icons-react' // store import { store } from '@/store' @@ -144,7 +142,6 @@ GitHubStarButton.propTypes = { const Header = ({ handleLeftDrawerToggle }) => { const theme = useTheme() - const navigate = useNavigate() const customization = useSelector((state) => state.customization) const logoutApi = useApi(accountApi.logout) @@ -152,9 +149,7 @@ const Header = ({ handleLeftDrawerToggle }) => { const [isDark, setIsDark] = useState(customization.isDarkMode) const dispatch = useDispatch() const { isEnterpriseLicensed, isCloud, isOpenSource } = useConfig() - const currentUser = useSelector((state) => state.auth.user) const isAuthenticated = useSelector((state) => state.auth.isAuthenticated) - const [isPricingOpen, setIsPricingOpen] = useState(false) const [starCount, setStarCount] = useState(0) useNotifier() @@ -270,45 +265,6 @@ const Header = ({ handleLeftDrawerToggle }) => { )} {isEnterpriseLicensed && isAuthenticated && } {isCloud && isAuthenticated && } - {isCloud && currentUser?.isOrganizationAdmin && ( - - )} - {isPricingOpen && isCloud && ( - { - setIsPricingOpen(false) - if (planUpdated) { - navigate('/') - navigate(0) - } - }} - /> - )} diff --git a/packages/ui/src/layout/MainLayout/Sidebar/index.jsx b/packages/ui/src/layout/MainLayout/Sidebar/index.jsx index b05d6669ee8..76ad71d7aa7 100644 --- a/packages/ui/src/layout/MainLayout/Sidebar/index.jsx +++ b/packages/ui/src/layout/MainLayout/Sidebar/index.jsx @@ -19,7 +19,7 @@ import { drawerWidth, headerHeight } from '@/store/constant' // ==============================|| SIDEBAR DRAWER ||============================== // -const Sidebar = ({ drawerOpen, drawerToggle, window }) => { +const Sidebar = ({ drawerOpen, drawerToggle, window, bannerOffset = 0 }) => { const theme = useTheme() const matchUpMd = useMediaQuery(theme.breakpoints.up('md')) const isAuthenticated = useSelector((state) => state.auth.isAuthenticated) @@ -40,7 +40,7 @@ const Sidebar = ({ drawerOpen, drawerToggle, window }) => { { background: theme.palette.background.default, color: theme.palette.text.primary, [theme.breakpoints.up('md')]: { - top: `${headerHeight}px` + top: `${headerHeight + bannerOffset}px` }, borderRight: drawerOpen ? '1px solid' : 'none', borderColor: drawerOpen ? theme.palette.grey[900] + 25 : 'transparent' @@ -101,7 +101,8 @@ const Sidebar = ({ drawerOpen, drawerToggle, window }) => { Sidebar.propTypes = { drawerOpen: PropTypes.bool, drawerToggle: PropTypes.func, - window: PropTypes.object + window: PropTypes.object, + bannerOffset: PropTypes.number } export default Sidebar diff --git a/packages/ui/src/layout/MainLayout/index.jsx b/packages/ui/src/layout/MainLayout/index.jsx index cab73c15a83..a73c4ef7df4 100644 --- a/packages/ui/src/layout/MainLayout/index.jsx +++ b/packages/ui/src/layout/MainLayout/index.jsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { Outlet } from 'react-router-dom' @@ -9,50 +9,57 @@ import { AppBar, Box, CssBaseline, Toolbar, useMediaQuery } from '@mui/material' // project imports import Header from './Header' import Sidebar from './Sidebar' +import AnnouncementBanner from './AnnouncementBanner' import { drawerWidth, headerHeight } from '@/store/constant' import { SET_MENU } from '@/store/actions' +const BANNER_HEIGHT = 45 +const BANNER_DISMISSED_KEY = 'flowise.announcementDismissed' + // styles -const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({ - ...theme.typography.mainContent, - ...(!open && { - backgroundColor: 'transparent', - borderBottomLeftRadius: 0, - borderBottomRightRadius: 0, - transition: theme.transitions.create('all', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.leavingScreen +const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' && prop !== 'bannerOffset' })( + ({ theme, open, bannerOffset }) => ({ + ...theme.typography.mainContent, + marginTop: `${75 + bannerOffset}px`, + ...(!open && { + backgroundColor: 'transparent', + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0, + transition: theme.transitions.create('all', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen + }), + marginRight: 0, + [theme.breakpoints.up('md')]: { + marginLeft: -drawerWidth, + width: `calc(100% - ${drawerWidth}px)` + }, + [theme.breakpoints.down('md')]: { + marginLeft: '20px', + width: `calc(100% - ${drawerWidth}px)`, + padding: '16px' + }, + [theme.breakpoints.down('sm')]: { + marginLeft: '10px', + width: `calc(100% - ${drawerWidth}px)`, + padding: '16px', + marginRight: '10px' + } }), - marginRight: 0, - [theme.breakpoints.up('md')]: { - marginLeft: -drawerWidth, + ...(open && { + backgroundColor: 'transparent', + transition: theme.transitions.create('all', { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen + }), + marginLeft: 0, + marginRight: 0, + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0, width: `calc(100% - ${drawerWidth}px)` - }, - [theme.breakpoints.down('md')]: { - marginLeft: '20px', - width: `calc(100% - ${drawerWidth}px)`, - padding: '16px' - }, - [theme.breakpoints.down('sm')]: { - marginLeft: '10px', - width: `calc(100% - ${drawerWidth}px)`, - padding: '16px', - marginRight: '10px' - } - }), - ...(open && { - backgroundColor: 'transparent', - transition: theme.transitions.create('all', { - easing: theme.transitions.easing.easeOut, - duration: theme.transitions.duration.enteringScreen - }), - marginLeft: 0, - marginRight: 0, - borderBottomLeftRadius: 0, - borderBottomRightRadius: 0, - width: `calc(100% - ${drawerWidth}px)` + }) }) -})) +) // ==============================|| MAIN LAYOUT ||============================== // @@ -72,6 +79,13 @@ const MainLayout = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [matchDownMd]) + const [bannerDismissed, setBannerDismissed] = useState(() => localStorage.getItem(BANNER_DISMISSED_KEY) === 'true') + const handleDismissBanner = () => { + localStorage.setItem(BANNER_DISMISSED_KEY, 'true') + setBannerDismissed(true) + } + const bannerOffset = bannerDismissed ? 0 : BANNER_HEIGHT + return ( @@ -86,16 +100,17 @@ const MainLayout = () => { transition: leftDrawerOpened ? theme.transitions.create('width') : 'none' }} > + {!bannerDismissed && }
{/* drawer */} - + {/* main content */} -
+
diff --git a/packages/ui/src/views/account/index.jsx b/packages/ui/src/views/account/index.jsx index ae5bc501d18..1c3b0775880 100644 --- a/packages/ui/src/views/account/index.jsx +++ b/packages/ui/src/views/account/index.jsx @@ -22,7 +22,7 @@ import { TextField, Typography } from '@mui/material' -import { darken, useTheme } from '@mui/material/styles' +import { useTheme } from '@mui/material/styles' // project imports import ViewHeader from '@/layout/MainLayout/ViewHeader' @@ -32,7 +32,7 @@ import SettingsSection from '@/ui-component/form/settings' import PricingDialog from '@/ui-component/subscription/PricingDialog' // Icons -import { IconAlertCircle, IconCreditCard, IconExternalLink, IconSparkles, IconX } from '@tabler/icons-react' +import { IconAlertCircle, IconCreditCard, IconExternalLink, IconX } from '@tabler/icons-react' // API import accountApi from '@/api/account.api' @@ -533,34 +533,6 @@ const AccountSettings = () => { 'Billing' )} - @@ -611,49 +583,6 @@ const AccountSettings = () => { - - {getAdditionalSeatsQuantityApi.data?.quantity > 0 && - currentPlanTitle.toUpperCase() === 'PRO' && ( - - )} - { - if (currentPlanTitle.toUpperCase() === 'PRO') { - setOpenAddSeatsDialog(true) - } else { - setOpenPricingDialog(true) - } - }} - title='Add Seats is available only for PRO plan' - sx={{ borderRadius: 2, height: 40 }} - > - Add Seats - - diff --git a/packages/ui/src/views/auth/register.jsx b/packages/ui/src/views/auth/register.jsx index 40311e0cb9e..50db113a898 100644 --- a/packages/ui/src/views/auth/register.jsx +++ b/packages/ui/src/views/auth/register.jsx @@ -188,7 +188,7 @@ const RegisterPage = () => { `Error in registering user. Please contact your administrator. (${registerApi.error?.response?.data?.message})` ) } else if (isCloud) { - setAuthError(`Error in registering user. Please try again.`) + setAuthError(registerApi.error?.response?.data?.message || 'Error in registering user. Please try again.') } setLoading(false) } diff --git a/packages/ui/src/views/auth/signIn.jsx b/packages/ui/src/views/auth/signIn.jsx index 6328ef8ebe3..a3091dfc3c9 100644 --- a/packages/ui/src/views/auth/signIn.jsx +++ b/packages/ui/src/views/auth/signIn.jsx @@ -206,11 +206,7 @@ const SignInPage = () => { Sign In {isCloud && ( - Don't have an account?{' '} - - Sign up for free - - . + New sign-ups are currently closed. )} {isEnterpriseLicensed && (