From 5045991d83a455e51bda8f5a6553d0c43ce06679 Mon Sep 17 00:00:00 2001 From: Sokratis Vidros Date: Thu, 27 Jun 2024 18:41:11 +0300 Subject: [PATCH 1/7] feat(web): New onboarding (#5855) * feat(web): New onboarding flow starting from npx novu@latest dev Flow ==== 1. Run npx novu@latest dev 2. Visit http://localhost:2022/studio 3. Redirect to https://web.novu.co/local-studio/auth 4. If signed in, redirect back to http://localhost:2022/studio?local_studio_url=... and load the studio iframe with src = local_studio_url 5. If not signed in, redirect to sign-in or sign-up (consult the nv_onboarding_step cookie) with redirect_url=https://web.novu.co/local-studio/auth 6. When authentication is complete the browser will redirect to step 3 and replay the following steps. * fix(web): Add a personal welcome message to studio onboarding * fix: imports and types * fix: pr comments --------- Co-authored-by: Dima Grossman --- apps/web/package.json | 2 + apps/web/src/AppRoutes.tsx | 6 +- .../components/EnsureOnboardingComplete.tsx | 11 +- .../components/v2/BridgeUpdateModal.tsx | 2 +- apps/web/src/hooks/index.ts | 1 + apps/web/src/hooks/useAuth.ts | 25 ++- apps/web/src/hooks/useRedirectURL.ts | 48 +++++ .../src/pages/auth/components/LoginForm.tsx | 10 +- .../src/pages/auth/components/SignUpForm.tsx | 7 +- .../components/SetupTimeline.tsx | 4 +- .../web/src/pages/studio-onboarding/index.tsx | 11 +- .../src/pages/studio-onboarding/success.tsx | 7 + .../src/studio/LocalStudioAuthenticator.tsx | 66 +++--- apps/web/src/studio/StudioPageLayout.tsx | 7 + apps/web/src/studio/StudioStateProvider.tsx | 20 +- apps/web/src/studio/types.ts | 2 + apps/web/src/utils/cookies.ts | 37 ++++ apps/web/src/utils/index.ts | 3 +- apps/web/src/utils/string.ts | 5 + apps/web/src/utils/url.ts | 16 ++ apps/web/tests/auth.spec.ts | 9 +- apps/web/tests/page-models/authLoginPage.ts | 18 +- apps/web/tests/page-models/signupPage.ts | 19 +- packages/cli/package.json | 8 +- packages/cli/src/dev-server/http-server.ts | 6 + pnpm-lock.yaml | 202 ++++++------------ 26 files changed, 348 insertions(+), 204 deletions(-) create mode 100644 apps/web/src/hooks/useRedirectURL.ts create mode 100644 apps/web/src/utils/cookies.ts create mode 100644 apps/web/src/utils/string.ts diff --git a/apps/web/package.json b/apps/web/package.json index f151e9928ca..a7705a7f701 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -88,6 +88,7 @@ "handlebars": "^4.7.7", "highlight.js": "11.9.0", "html-webpack-plugin": "5.5.3", + "js-cookie": "^3.0.5", "jwt-decode": "^3.1.2", "launchdarkly-react-client-sdk": "^3.3.2", "less": "^4.1.0", @@ -156,6 +157,7 @@ "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/testing-library__jest-dom": "^5.14.5", + "@types/js-cookie": "^3.0.6", "eslint-plugin-storybook": "^0.6.13", "http-server": "^0.13.0", "less-loader": "4.1.0", diff --git a/apps/web/src/AppRoutes.tsx b/apps/web/src/AppRoutes.tsx index d647939ecdb..a9a49fad7ba 100644 --- a/apps/web/src/AppRoutes.tsx +++ b/apps/web/src/AppRoutes.tsx @@ -64,6 +64,7 @@ import { useSegment } from './components/providers/SegmentProvider'; import * as mixpanel from 'mixpanel-browser'; import { useEffect } from 'react'; import { GetStartedPageV2 } from './studio/components/GetStartedPageV2'; +import { novuOnboardedCookie } from './utils/cookies'; export const AppRoutes = () => { const isImprovedOnboardingEnabled = useFeatureFlag(FeatureFlagsKeysEnum.IS_IMPROVED_ONBOARDING_ENABLED); @@ -171,7 +172,10 @@ export const AppRoutes = () => { } /> }> - } /> + } + /> } /> } /> } /> diff --git a/apps/web/src/components/layout/components/EnsureOnboardingComplete.tsx b/apps/web/src/components/layout/components/EnsureOnboardingComplete.tsx index 60a382e9cd6..b006950c4e6 100644 --- a/apps/web/src/components/layout/components/EnsureOnboardingComplete.tsx +++ b/apps/web/src/components/layout/components/EnsureOnboardingComplete.tsx @@ -1,16 +1,25 @@ import { Navigate, useLocation } from 'react-router-dom'; import { useAuth } from '../../../hooks/useAuth'; import { ROUTES } from '../../../constants/routes'; -import { useBlueprint } from '../../../hooks/index'; +import { useBlueprint, useRedirectURL } from '../../../hooks'; export function EnsureOnboardingComplete({ children }: any) { useBlueprint(); const location = useLocation(); + const { getRedirectURL } = useRedirectURL(); const { currentOrganization, environmentId } = useAuth(); if ((!currentOrganization || !environmentId) && location.pathname !== ROUTES.AUTH_APPLICATION) { return ; } + const redirectURL = getRedirectURL(); + if (redirectURL) { + // Note: Do not use react-router-dom. The version we have doesn't do instant cross origin redirects. + window.location.replace(redirectURL); + + return null; + } + return children; } diff --git a/apps/web/src/components/layout/components/v2/BridgeUpdateModal.tsx b/apps/web/src/components/layout/components/v2/BridgeUpdateModal.tsx index 7db5a976f3b..e43f11c247b 100644 --- a/apps/web/src/components/layout/components/v2/BridgeUpdateModal.tsx +++ b/apps/web/src/components/layout/components/v2/BridgeUpdateModal.tsx @@ -3,7 +3,7 @@ import { css } from '@novu/novui/css'; import { Button, Input, Title, Text } from '@novu/novui'; import { IconOutlineMenuBook } from '@novu/novui/icons'; import { HStack, Box } from '@novu/novui/jsx'; -import { FC, useMemo, useState } from 'react'; +import { FC, useState } from 'react'; import { validateBridgeUrl } from '../../../../api/bridge'; import { updateBridgeUrl } from '../../../../api/environment'; import { useEnvironment } from '../../../../hooks/useEnvironment'; diff --git a/apps/web/src/hooks/index.ts b/apps/web/src/hooks/index.ts index 29e918c444c..015bda37c9f 100644 --- a/apps/web/src/hooks/index.ts +++ b/apps/web/src/hooks/index.ts @@ -23,6 +23,7 @@ export * from './useNotificationGroup'; export * from './useNovu'; export * from './useProcessVariables'; export * from './usePrompt'; +export * from './useRedirectURL'; export * from './useSubscribers'; export * from './useTemplates'; export * from './useThemeChange'; diff --git a/apps/web/src/hooks/useAuth.ts b/apps/web/src/hooks/useAuth.ts index de2ed14444d..8991df981ce 100644 --- a/apps/web/src/hooks/useAuth.ts +++ b/apps/web/src/hooks/useAuth.ts @@ -107,9 +107,25 @@ export function useAuth() { navigate(ROUTES.AUTH_LOGIN); }, [navigate, queryClient, segment]); + const redirectTo = useCallback(({ url, redirectURL }: { url: string; redirectURL?: string }) => { + const finalURL = new URL(url, window.location.origin); + + if (redirectURL) { + finalURL.searchParams.append('redirect_url', redirectURL); + } + + // Note: Do not use react-router-dom. The version we have doesn't do instant cross origin redirects. + window.location.replace(finalURL.href); + }, []); + const redirectToLogin = useCallback( - (redirectUrl?: string) => navigate(`${ROUTES.AUTH_LOGIN}?redirect_url=${redirectUrl}`), - [navigate] + ({ redirectURL }: { redirectURL?: string } = {}) => redirectTo({ url: ROUTES.AUTH_LOGIN, redirectURL }), + [redirectTo] + ); + + const redirectToSignUp = useCallback( + ({ redirectURL }: { redirectURL?: string } = {}) => redirectTo({ url: ROUTES.AUTH_SIGNUP, redirectURL }), + [redirectTo] ); const { organizationId, environmentId } = getTokenClaims() || {}; @@ -161,9 +177,7 @@ export function useAuth() { return { inPublicRoute, inPrivateRoute, - isUserLoading, - isOrganizationLoading, - isLoading: inPrivateRoute && (isUserLoading || isOrganizationLoading), + isLoading: hasToken && (isUserLoading || isOrganizationLoading), currentUser: user, organizations, currentOrganization, @@ -172,5 +186,6 @@ export function useAuth() { environmentId, organizationId, redirectToLogin, + redirectToSignUp, }; } diff --git a/apps/web/src/hooks/useRedirectURL.ts b/apps/web/src/hooks/useRedirectURL.ts new file mode 100644 index 00000000000..0c91169ded5 --- /dev/null +++ b/apps/web/src/hooks/useRedirectURL.ts @@ -0,0 +1,48 @@ +import { useCallback } from 'react'; +import { createCookieHandler } from '../utils/cookies'; +import { assertProtocol } from '../utils/url'; + +const novuRedirectURLCookie = createCookieHandler('nv_redirect_url'); + +const REDIRECT_URL_SEARCH_PARAM = 'redirect_url'; + +const REDIRECT_COOKIE_EXPIRY_DAYS = 7; + +export function useRedirectURL() { + const setRedirectURL = useCallback(() => { + const redirectURLFromParams = new URL(window.location.href).searchParams.get(REDIRECT_URL_SEARCH_PARAM) || ''; + + // If there is a redirect URL in the URL, set it in the cookie. + if (redirectURLFromParams) { + // Protect against XSS attacks via the javascript: pseudo protocol. + assertProtocol(redirectURLFromParams); + // Expires in 7 days. + novuRedirectURLCookie.set(redirectURLFromParams, { expires: REDIRECT_COOKIE_EXPIRY_DAYS }); + + // Clean the URL so that the redirect URL doesn't get used again. + const url = new URL(window.location.href); + url.searchParams.delete(REDIRECT_URL_SEARCH_PARAM); + history.replaceState({}, '', url.href); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const getRedirectURL = useCallback(() => { + const redirectURLFromCookie = novuRedirectURLCookie.get(); + + // If there is a cookie in the URL, redirect to that URL. Otherwise, its a noop. + if (redirectURLFromCookie) { + // Clean the cookie first, so that it doesn't get used again. + novuRedirectURLCookie.remove(); + + return redirectURLFromCookie; + } + + return ''; + }, []); + + return { + setRedirectURL, + getRedirectURL, + }; +} diff --git a/apps/web/src/pages/auth/components/LoginForm.tsx b/apps/web/src/pages/auth/components/LoginForm.tsx index 47252dd68a0..eebcd5cc17e 100644 --- a/apps/web/src/pages/auth/components/LoginForm.tsx +++ b/apps/web/src/pages/auth/components/LoginForm.tsx @@ -5,9 +5,8 @@ import { useForm } from 'react-hook-form'; import * as Sentry from '@sentry/react'; import { Center } from '@mantine/core'; import { PasswordInput, Button, colors, Input, Text } from '@novu/design-system'; -import { useAuth } from '../../../hooks/useAuth'; import type { IResponseError } from '@novu/shared'; -import { useVercelIntegration, useVercelParams } from '../../../hooks'; +import { useAuth, useRedirectURL, useVercelIntegration, useVercelParams } from '../../../hooks'; import { useSegment } from '../../../components/providers/SegmentProvider'; import { api } from '../../../api/api.client'; import { useAcceptInvite } from './useAcceptInvite'; @@ -28,6 +27,11 @@ export interface LocationState { export function LoginForm({ email, invitationToken }: LoginFormProps) { const segment = useSegment(); + + const { setRedirectURL } = useRedirectURL(); + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => setRedirectURL(), []); + const { login, currentUser, organizations } = useAuth(); const { startVercelSetup } = useVercelIntegration(); const { isFromVercel, params: vercelParams } = useVercelParams(); @@ -38,8 +42,6 @@ export function LoginForm({ email, invitationToken }: LoginFormProps) { // TODO: Deprecate the legacy cameCased format in search param const invitationTokenFromGithub = params.get('invitationToken') || params.get('invitation_token') || ''; const isRedirectedFromLoginPage = params.get('isLoginPage') || params.get('is_login_page') || ''; - // TODO: Use redirectUrl if available and redirect post login to the URL. This should be used during the Local studio authentication flow - const redirectUrl = params.get('redirect_url') || ''; const { isLoading: isLoadingAcceptInvite, acceptInvite } = useAcceptInvite(); const navigate = useNavigate(); diff --git a/apps/web/src/pages/auth/components/SignUpForm.tsx b/apps/web/src/pages/auth/components/SignUpForm.tsx index d4aabd018e2..2571b01f865 100644 --- a/apps/web/src/pages/auth/components/SignUpForm.tsx +++ b/apps/web/src/pages/auth/components/SignUpForm.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { useMutation } from '@tanstack/react-query'; import { useForm } from 'react-hook-form'; @@ -9,7 +9,7 @@ import { PasswordInput, Button, colors, Input, Text, Checkbox } from '@novu/desi import { useAuth } from '../../../hooks/useAuth'; import { api } from '../../../api/api.client'; -import { useVercelParams } from '../../../hooks'; +import { useRedirectURL, useVercelParams } from '../../../hooks'; import { useAcceptInvite } from './useAcceptInvite'; import { PasswordRequirementPopover } from './PasswordRequirementPopover'; import { ROUTES } from '../../../constants/routes'; @@ -28,6 +28,9 @@ export type SignUpFormInputType = { export function SignUpForm({ invitationToken, email }: SignUpFormProps) { const navigate = useNavigate(); + const { setRedirectURL } = useRedirectURL(); + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => setRedirectURL(), []); const { login } = useAuth(); const { isLoading: isAcceptInviteLoading, acceptInvite } = useAcceptInvite(); diff --git a/apps/web/src/pages/studio-onboarding/components/SetupTimeline.tsx b/apps/web/src/pages/studio-onboarding/components/SetupTimeline.tsx index c2c281fa38b..f9caea64643 100644 --- a/apps/web/src/pages/studio-onboarding/components/SetupTimeline.tsx +++ b/apps/web/src/pages/studio-onboarding/components/SetupTimeline.tsx @@ -77,11 +77,11 @@ export const SetupTimeline = ({ testResponse }: { testResponse: { isLoading: boo } lineVariant="dashed" - title="Connect to the endpoint" + title="Connect to the Novu Bridge Endpoint" active={active >= 3} > - {active < 3 ? 'Waiting for you to start the application' : 'Succefully connected to the Novu Endpoint'} + {active < 3 ? 'Waiting for you to start the application' : 'Succefully connected to the Novu Bridge Endpoint'} diff --git a/apps/web/src/pages/studio-onboarding/index.tsx b/apps/web/src/pages/studio-onboarding/index.tsx index 589ea8b08d4..d9e73317346 100644 --- a/apps/web/src/pages/studio-onboarding/index.tsx +++ b/apps/web/src/pages/studio-onboarding/index.tsx @@ -11,10 +11,13 @@ import { ROUTES } from '../../constants/routes'; import { useNavigate } from 'react-router-dom'; import { useHealthCheck } from '../../studio/hooks/useBridgeAPI'; import { BridgeStatus } from '../../bridgeApi/bridgeApi.client'; +import { useStudioState } from '../../studio/StudioStateProvider'; +import { capitalizeFirstLetter } from '../../utils/string'; export const StudioOnboarding = () => { const segment = useSegment(); const navigate = useNavigate(); + const { testUser } = useStudioState(); const { data, isLoading } = useHealthCheck(); useEffect(() => { @@ -22,6 +25,8 @@ export const StudioOnboarding = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const welcomeMessage = `Welcome ${capitalizeFirstLetter(testUser?.firstName || '')}`.trim() + `. Let's get started!`; + return (
@@ -31,7 +36,7 @@ export const StudioOnboarding = () => { width: 'onboarding', })} > - Create an Novu endpoint + {welcomeMessage} { marginTop: '50', })} > - To start sending your first workflows, you first need to connect Novu to your Bridge Endpoint. This setup - will create a sample Next.js project and pre-configured the @novu/framework client for you. + Send your first email notification, by connecting to your Novu Bridge Endpoint. This setup will create a + sample Next.js project with a pre-configured @novu/framework. diff --git a/apps/web/src/pages/studio-onboarding/success.tsx b/apps/web/src/pages/studio-onboarding/success.tsx index f596b358e0e..e9ce3802366 100644 --- a/apps/web/src/pages/studio-onboarding/success.tsx +++ b/apps/web/src/pages/studio-onboarding/success.tsx @@ -14,6 +14,9 @@ import { ROUTES } from '../../constants/routes'; import { Footer } from './components/Footer'; import { Header } from './components/Header'; import { Wrapper } from './components/Wrapper'; +import { novuOnboardedCookie } from '../../utils/cookies'; + +const ONBOARDING_COOKIE_EXPIRY_DAYS = 10 * 365; export const StudioOnboardingSuccess = () => { const [searchParams] = useSearchParams(); @@ -65,6 +68,10 @@ export const StudioOnboardingSuccess = () => { useEffect(() => { segment.track('Test workflow step completed - [Onboarding - Signup]'); + + // Never expires! Well it does, in 10 years but you will change device or browser by then :) + novuOnboardedCookie.set('1', { expires: ONBOARDING_COOKIE_EXPIRY_DAYS }); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/apps/web/src/studio/LocalStudioAuthenticator.tsx b/apps/web/src/studio/LocalStudioAuthenticator.tsx index a5a01c6e51d..1e6a0deeed6 100644 --- a/apps/web/src/studio/LocalStudioAuthenticator.tsx +++ b/apps/web/src/studio/LocalStudioAuthenticator.tsx @@ -5,11 +5,11 @@ import { colors } from '@novu/design-system'; import { css } from '@novu/novui/css'; import { useAuth } from '../hooks/useAuth'; import { ROUTES } from '../constants/routes'; +import { assertProtocol } from '../utils/url'; import { encodeBase64 } from './utils/base64'; import { StudioState } from './types'; import { useLocation } from 'react-router-dom'; - -const ALLOWED_PROTOCOLS = ['http:', 'https:']; +import { novuOnboardedCookie } from '../utils/cookies'; function buildBridgeURL(origin: string | null, tunnelPath: string) { if (!origin) { @@ -19,31 +19,18 @@ function buildBridgeURL(origin: string | null, tunnelPath: string) { return new URL(tunnelPath, origin).href; } -function buildStudioURL(state: StudioState) { - const url = new URL(ROUTES.STUDIO, window.location.origin); +function buildStudioURL(state: StudioState, defaultPath?: string | null) { + const url = new URL(defaultPath || ROUTES.STUDIO, window.location.origin); url.searchParams.append('state', encodeBase64(state)); return url.href; } -function assertProtocol(url: URL | string | null) { - if (!url) { - return; - } - - if (typeof url === 'string') { - url = new URL(url); - } - - if (!ALLOWED_PROTOCOLS.includes(url.protocol)) { - throw new Error(`Novu: "${url.protocol}" protocol from "${url}" is not allowed.`); - } -} - export function LocalStudioAuthenticator() { - const { currentUser, isUserLoading, redirectToLogin, currentOrganization } = useAuth(); + const { currentUser, isLoading, redirectToLogin, redirectToSignUp, currentOrganization } = useAuth(); const location = useLocation(); + // TODO: Refactor this to a smaller size function useEffect(() => { const parsedSearchParams = new URLSearchParams(location.search); @@ -60,6 +47,34 @@ export function LocalStudioAuthenticator() { // Protect against XSS attacks via the javascript: pseudo protocol assertProtocol(parsedRedirectURL); + // Parse the current URL, we will need it later + const currentURL = new URL(window.location.href); + + // If the user is not logged in, redirect to the login or signup page + if (!currentUser) { + // If user is loading, wait for user to be loaded + if (!isLoading) { + /* + * If the user has logged in before, redirect to the login page. + * After authentication, redirect back to the this /local-studio/auth path. + */ + if (novuOnboardedCookie.get()) { + return redirectToLogin({ redirectURL: window.location.href }); + } + + /* + * If the user hasn't logged in before, redirect to the login page. + * After authentication, redirect back to the this /local-studio/auth path and + * remember that studio needs to be in onboarding mode. + */ + // currentURL.searchParams.append('studio_path_hint', ROUTES.STUDIO_ONBOARDING); + + return redirectToSignUp({ redirectURL: currentURL.href }); + } + + return; + } + // Get the local application origin parameter const applicationOrigin = parsedSearchParams.get('application_origin'); @@ -87,14 +102,6 @@ export function LocalStudioAuthenticator() { const localBridgeURL = buildBridgeURL(parsedApplicationOrigin.origin, tunnelPath); const tunnelBridgeURL = buildBridgeURL(tunnelOrigin, tunnelPath); - if (!currentUser) { - if (!isUserLoading) { - return redirectToLogin(window.location.href); - } - - return; - } - const state: StudioState = { local: true, testUser: { @@ -111,7 +118,10 @@ export function LocalStudioAuthenticator() { * the iframe src URL as a search param. */ const finalRedirectURL = new URL(redirectURL); - finalRedirectURL.searchParams.append('local_studio_url', buildStudioURL(state)); + finalRedirectURL.searchParams.append( + 'local_studio_url', + buildStudioURL(state, currentURL.searchParams.get('studio_path_hint')) + ); // Redirect to Local Studio server window.location.href = finalRedirectURL.href; diff --git a/apps/web/src/studio/StudioPageLayout.tsx b/apps/web/src/studio/StudioPageLayout.tsx index c1cb8f47e69..d0c3060404a 100644 --- a/apps/web/src/studio/StudioPageLayout.tsx +++ b/apps/web/src/studio/StudioPageLayout.tsx @@ -1,9 +1,16 @@ import { useStudioState } from './StudioStateProvider'; import { PrivatePageLayout } from '../components/layout/components/PrivatePageLayout'; import { LocalStudioPageLayout } from '../components/layout/components/LocalStudioPageLayout'; +import { ROUTES } from '../constants/routes'; +import { Outlet, useLocation } from 'react-router-dom'; export function StudioPageLayout() { const state = useStudioState(); + const { pathname } = useLocation(); + + if (pathname.startsWith(ROUTES.STUDIO_ONBOARDING)) { + return ; + } if (state?.local) { return ; diff --git a/apps/web/src/studio/StudioStateProvider.tsx b/apps/web/src/studio/StudioStateProvider.tsx index 4468438f35f..a7995486040 100644 --- a/apps/web/src/studio/StudioStateProvider.tsx +++ b/apps/web/src/studio/StudioStateProvider.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; +import type { IUserEntity } from '@novu/shared'; import { useAuth } from '../hooks/useAuth'; import { useEnvironment } from '../hooks/useEnvironment'; import type { StudioState } from './types'; @@ -13,6 +14,15 @@ function computeBridgeURL(state: StudioState) { return state.local ? state.localBridgeURL || state.tunnelBridgeURL : state.storedBridgeURL; } +function convertToTestUser(currentUser?: IUserEntity) { + return { + id: currentUser?._id || '', + emailAddress: currentUser?.email || '', + firstName: currentUser?.firstName || '', + lastName: currentUser?.lastName || '', + }; +} + export const StudioStateProvider = ({ children }: { children: React.ReactNode }) => { const location = useLocation(); const { currentUser, currentOrganization } = useAuth(); @@ -28,10 +38,7 @@ export const StudioStateProvider = ({ children }: { children: React.ReactNode }) return { local: false, storedBridgeURL: environment?.echo?.url || '', - testUser: { - id: currentUser?._id || '', - emailAddress: currentUser?.email || '', - }, + testUser: convertToTestUser(currentUser), organizationName: currentOrganization?.name || '', }; }); @@ -43,10 +50,7 @@ export const StudioStateProvider = ({ children }: { children: React.ReactNode }) setState({ local: false, storedBridgeURL: environment?.echo?.url || '', - testUser: { - id: currentUser?._id || '', - emailAddress: currentUser?.email || '', - }, + testUser: convertToTestUser(currentUser), organizationName: currentOrganization?.name || '', }); } diff --git a/apps/web/src/studio/types.ts b/apps/web/src/studio/types.ts index 22e22fb27b5..1d19a604603 100644 --- a/apps/web/src/studio/types.ts +++ b/apps/web/src/studio/types.ts @@ -23,6 +23,8 @@ export interface IBridgeWorkflow { type BaseStudioState = { testUser: { id: string; + firstName?: string; + lastName?: string; emailAddress: string; }; organizationName?: string; diff --git a/apps/web/src/utils/cookies.ts b/apps/web/src/utils/cookies.ts new file mode 100644 index 00000000000..cd34a0b84c3 --- /dev/null +++ b/apps/web/src/utils/cookies.ts @@ -0,0 +1,37 @@ +import Cookies from 'js-cookie'; + +type LocationAttributes = { + path?: string; + domain?: string; +}; + +export function createCookieHandler(cookieName: string) { + return { + get() { + return Cookies.get(cookieName); + }, + + set(newValue: string, options: Cookies.CookieAttributes = {}): void { + Cookies.set(cookieName, newValue, options); + }, + + remove(locationAttributes?: LocationAttributes) { + Cookies.remove(cookieName, locationAttributes); + }, + + getOnce(locationAttributes?: LocationAttributes) { + const value = Cookies.get(cookieName); + this.remove(locationAttributes); + + return value; + }, + }; +} + +export const novuRedirectURLCookie = createCookieHandler('nv_redirect_url'); + +/* + * TODO: Store the onboarding step in the cookie and resume the flow from that step on page reload. + * For now we just store 1. + */ +export const novuOnboardedCookie = createCookieHandler('nv_onboarding_step'); diff --git a/apps/web/src/utils/index.ts b/apps/web/src/utils/index.ts index 132073b78a9..ee8b6c4bd98 100644 --- a/apps/web/src/utils/index.ts +++ b/apps/web/src/utils/index.ts @@ -1,4 +1,5 @@ -export * from './utils'; +export * from './cookies'; export * from './pluralize'; export * from './templates'; export * from './url'; +export * from './utils'; diff --git a/apps/web/src/utils/string.ts b/apps/web/src/utils/string.ts new file mode 100644 index 00000000000..52c855e3b2f --- /dev/null +++ b/apps/web/src/utils/string.ts @@ -0,0 +1,5 @@ +export function capitalizeFirstLetter(string) { + if (!string) return ''; + + return string.charAt(0).toUpperCase() + string.slice(1); +} diff --git a/apps/web/src/utils/url.ts b/apps/web/src/utils/url.ts index ac3b88dbc81..2bfdaa4e736 100644 --- a/apps/web/src/utils/url.ts +++ b/apps/web/src/utils/url.ts @@ -9,3 +9,19 @@ export function validateURL(url: string, msg = 'The provided URL is invalid'): a throw new Error(msg); } } + +const ALLOWED_PROTOCOLS = ['http:', 'https:']; + +export function assertProtocol(url: URL | string | null) { + if (!url) { + return; + } + + if (typeof url === 'string') { + url = new URL(url); + } + + if (!ALLOWED_PROTOCOLS.includes(url.protocol)) { + throw new Error(`Novu: "${url.protocol}" protocol from "${url}" is not allowed.`); + } +} diff --git a/apps/web/tests/auth.spec.ts b/apps/web/tests/auth.spec.ts index 0db2d90e2e3..46feedd57c6 100644 --- a/apps/web/tests/auth.spec.ts +++ b/apps/web/tests/auth.spec.ts @@ -47,7 +47,7 @@ test('should show password reset link sent message on any email input', async ({ test('should redirect to the dashboard page when a token exists in query', async ({ page }) => { const { session } = await initializeSession(page); - const authLoginPage = await AuthLoginPage.goTo(page, session.token); + const authLoginPage = await AuthLoginPage.goTo(page, { token: session.token }); await authLoginPage.assertNavigationPath('/workflows**'); }); @@ -96,3 +96,10 @@ test('should logout user when auth token is expired', async ({ page }) => { await page.goto('/subscribers'); await page.waitForURL('/auth/login'); }); + +test('redirect_url is respected post authentication', async ({ page }) => { + const authLoginPage = await AuthLoginPage.goTo(page, { redirectURL: 'https://novu.co' }); + await authLoginPage.fillLoginForm({ email: testUser.email, password: testPassword() }); + await authLoginPage.clickSignInButton(); + await authLoginPage.assertNavigationPath('https://novu.co'); +}); diff --git a/apps/web/tests/page-models/authLoginPage.ts b/apps/web/tests/page-models/authLoginPage.ts index 8d0c1c40c72..567a5a2b6fa 100644 --- a/apps/web/tests/page-models/authLoginPage.ts +++ b/apps/web/tests/page-models/authLoginPage.ts @@ -22,13 +22,23 @@ export class AuthLoginPage { public async assertNavigationPath(path: string) { await this.page.waitForURL(path); } - static async goTo(page: Page, token?: string): Promise { + + static async goTo( + page: Page, + { token, redirectURL }: { token?: string; redirectURL?: string } = {} + ): Promise { + const searchParams = new URLSearchParams(); + + if (redirectURL) { + searchParams.append('redirect_url', redirectURL); + } + if (token) { - await page.goto(`auth/login?token=${token}`); - } else { - await page.goto(`auth/login`); + searchParams.append('token', token); } + await page.goto(`/auth/login?${searchParams.toString()}`); + return new AuthLoginPage(page); } diff --git a/apps/web/tests/page-models/signupPage.ts b/apps/web/tests/page-models/signupPage.ts index e0741252091..c17f59cd0ed 100644 --- a/apps/web/tests/page-models/signupPage.ts +++ b/apps/web/tests/page-models/signupPage.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-restricted-imports import { UserEntity } from '@novu/dal'; import { Page, selectors } from '@playwright/test'; import { faker } from '@faker-js/faker'; @@ -8,8 +9,22 @@ export interface SignUpTestData extends Partial { } export class SignUpPage { - static async goTo(page: Page): Promise { - await page.goto('/auth/signup'); + static async goTo( + page: Page, + { token, redirectURL }: { token?: string; redirectURL?: string } = {} + ): Promise { + const searchParams = new URLSearchParams(); + + if (redirectURL) { + searchParams.append('redirect_url', redirectURL); + } + + if (token) { + searchParams.append('token', token); + } + + await page.goto(`/auth/signup?${searchParams.toString()}`); + return new SignUpPage(page); } diff --git a/packages/cli/package.json b/packages/cli/package.json index 2d55527d709..f756cf68d63 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -25,19 +25,18 @@ "devDependencies": { "@types/configstore": "^5.0.1", "@types/inquirer": "^8.2.0", - "@types/ws": "^8.5.3", "@types/mocha": "10.0.2", + "@types/ws": "^8.5.3", "ncp": "^2.0.0", "nodemon": "^3.0.1", "typescript": "4.9.5" }, "dependencies": { + "@novu/ntfr-client": "^0.0.3", "@novu/shared": "workspace:*", "@segment/analytics-node": "^1.1.4", "axios": "^1.6.2", - "ws": "^8.11.0", "chalk": "4.1.2", - "@novu/ntfr-client": "^0.0.3", "commander": "^9.0.0", "configstore": "^5.0.0", "dotenv": "^8.2.0", @@ -49,6 +48,7 @@ "open": "^8.4.0", "ora": "^5.4.1", "ts-node": "~10.9.1", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "ws": "^8.11.0" } } diff --git a/packages/cli/src/dev-server/http-server.ts b/packages/cli/src/dev-server/http-server.ts index 5510e756b74..22efe561598 100644 --- a/packages/cli/src/dev-server/http-server.ts +++ b/packages/cli/src/dev-server/http-server.ts @@ -28,6 +28,12 @@ export class DevServer { this.serveWellKnownPath(req, res); } else if (req.url.startsWith(STUDIO_PATH)) { this.serveStudio(req, res); + } else { + res + .writeHead(301, { + Location: STUDIO_PATH, + }) + .end(); } } catch (e) { // eslint-disable-next-line no-console diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c5825d78dc2..cfeead820c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -877,6 +877,9 @@ importers: html-webpack-plugin: specifier: 5.5.3 version: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) + js-cookie: + specifier: ^3.0.5 + version: 3.0.5 jwt-decode: specifier: ^3.1.2 version: 3.1.2 @@ -1064,6 +1067,9 @@ importers: '@testing-library/jest-dom': specifier: ^4.2.4 version: 4.2.4 + '@types/js-cookie': + specifier: ^3.0.6 + version: 3.0.6 '@types/mixpanel-browser': specifier: ^2.49.0 version: 2.49.0 @@ -3272,7 +3278,7 @@ importers: version: link:../../libs/shared '@novu/studio': specifier: ^0.0.1-alpha.87 - version: 0.0.1-alpha.90(@ant-design/icons@4.8.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@babel/core@7.24.4)(@chakra-ui/icons@2.1.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/react@1.8.9(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@emotion/is-prop-valid@1.2.0)(@opentelemetry/api@1.7.0)(@types/react@17.0.62)(antd@4.24.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(babel-plugin-macros@3.1.0)(chakra-react-select@4.7.6(@chakra-ui/form-control@2.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/layout@2.3.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(dayjs@1.11.10)(encoding@0.1.13)(immer@9.0.21)(sass@1.64.1)(webpack@5.88.2(@swc/core@1.3.107)) + version: 0.0.1-alpha.90(fe7j6aun3zofsv6bp43tnzybva) '@segment/analytics-node': specifier: ^1.1.4 version: 1.1.4(encoding@0.1.13) @@ -3616,10 +3622,10 @@ importers: version: 5.3.0 compression-webpack-plugin: specifier: ^10.0.0 - version: 10.0.0(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)) + version: 10.0.0(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)) esbuild-plugin-compress: specifier: ^1.0.1 - version: 1.0.1(esbuild@0.19.12) + version: 1.0.1(esbuild@0.20.1) jest: specifier: ^29.3.1 version: 29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5)) @@ -3640,28 +3646,28 @@ importers: version: 3.4.4(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5)) terser-webpack-plugin: specifier: ^5.3.9 - version: 5.3.9(@swc/core@1.3.107)(esbuild@0.19.12)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)) + version: 5.3.9(@swc/core@1.3.107)(esbuild@0.20.1)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)) tiny-glob: specifier: ^0.2.9 version: 0.2.9 ts-jest: specifier: ^29.0.3 - version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.19.12)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5)))(typescript@4.9.5) + version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.20.1)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5)))(typescript@4.9.5) ts-loader: specifier: ~9.4.0 - version: 9.4.2(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)) + version: 9.4.2(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)) tsup: specifier: ^8.0.2 version: 8.0.2(@microsoft/api-extractor@7.38.0(@types/node@18.16.9))(@swc/core@1.3.107)(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5))(typescript@4.9.5) tsup-preset-solid: specifier: ^2.2.0 - version: 2.2.0(esbuild@0.19.12)(solid-js@1.8.17)(tsup@8.0.2(@microsoft/api-extractor@7.38.0(@types/node@18.16.9))(@swc/core@1.3.107)(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5))(typescript@4.9.5)) + version: 2.2.0(esbuild@0.20.1)(solid-js@1.8.17)(tsup@8.0.2(@microsoft/api-extractor@7.38.0(@types/node@18.16.9))(@swc/core@1.3.107)(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5))(typescript@4.9.5)) typescript: specifier: 4.9.5 version: 4.9.5 webpack: specifier: ^5.74.0 - version: 5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4) + version: 5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4) webpack-bundle-analyzer: specifier: ^4.9.0 version: 4.10.1 @@ -15170,6 +15176,9 @@ packages: '@types/jest@29.5.2': resolution: {integrity: sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==} + '@types/js-cookie@3.0.6': + resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} + '@types/jsdom@20.0.1': resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} @@ -22904,6 +22913,10 @@ packages: resolution: {integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==} engines: {node: '>=12'} + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-sdsl@4.4.0: resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==} @@ -32668,7 +32681,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.575.0 - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-bucket-endpoint': 3.575.0 @@ -32898,7 +32911,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -33231,58 +33244,13 @@ snapshots: - aws-crt optional: true - '@aws-sdk/client-sts@3.575.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0 - '@aws-sdk/core': 3.575.0 - '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) - '@aws-sdk/middleware-host-header': 3.575.0 - '@aws-sdk/middleware-logger': 3.575.0 - '@aws-sdk/middleware-recursion-detection': 3.575.0 - '@aws-sdk/middleware-user-agent': 3.575.0 - '@aws-sdk/region-config-resolver': 3.575.0 - '@aws-sdk/types': 3.575.0 - '@aws-sdk/util-endpoints': 3.575.0 - '@aws-sdk/util-user-agent-browser': 3.575.0 - '@aws-sdk/util-user-agent-node': 3.575.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.0 - '@smithy/fetch-http-handler': 3.0.0 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.0 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.0 - '@smithy/util-defaults-mode-node': 3.0.0 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/core': 3.575.0 - '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)) + '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 '@aws-sdk/middleware-logger': 3.575.0 '@aws-sdk/middleware-recursion-detection': 3.575.0 @@ -33455,26 +33423,9 @@ snapshots: - aws-crt optional: true - '@aws-sdk/credential-provider-ini@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0))': - dependencies: - '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) - '@aws-sdk/credential-provider-env': 3.575.0 - '@aws-sdk/credential-provider-process': 3.575.0 - '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) - '@aws-sdk/credential-provider-web-identity': 3.575.0(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)) - '@aws-sdk/types': 3.575.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/credential-provider-ini@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/credential-provider-env': 3.575.0 '@aws-sdk/credential-provider-process': 3.575.0 '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) @@ -33539,25 +33490,6 @@ snapshots: - aws-crt optional: true - '@aws-sdk/credential-provider-node@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.575.0 - '@aws-sdk/credential-provider-http': 3.575.0 - '@aws-sdk/credential-provider-ini': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)) - '@aws-sdk/credential-provider-process': 3.575.0 - '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) - '@aws-sdk/credential-provider-web-identity': 3.575.0(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)) - '@aws-sdk/types': 3.575.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - '@aws-sdk/credential-provider-node@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0)': dependencies: '@aws-sdk/credential-provider-env': 3.575.0 @@ -33687,17 +33619,9 @@ snapshots: - aws-crt optional: true - '@aws-sdk/credential-provider-web-identity@3.575.0(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0))': - dependencies: - '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) - '@aws-sdk/types': 3.575.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.575.0(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/types': 3.575.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -42195,8 +42119,8 @@ snapshots: transitivePeerDependencies: - debug - ? '@novu/studio@0.0.1-alpha.90(@ant-design/icons@4.8.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@babel/core@7.24.4)(@chakra-ui/icons@2.1.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/react@1.8.9(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@emotion/is-prop-valid@1.2.0)(@opentelemetry/api@1.7.0)(@types/react@17.0.62)(antd@4.24.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(babel-plugin-macros@3.1.0)(chakra-react-select@4.7.6(@chakra-ui/form-control@2.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/layout@2.3.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(dayjs@1.11.10)(encoding@0.1.13)(immer@9.0.21)(sass@1.64.1)(webpack@5.88.2(@swc/core@1.3.107))' - : dependencies: + '@novu/studio@0.0.1-alpha.90(fe7j6aun3zofsv6bp43tnzybva)': + dependencies: '@mantine/code-highlight': 7.6.2(@mantine/core@7.6.2(@mantine/hooks@7.6.2(react@18.2.0))(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.6.2(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/core': 7.6.2(@mantine/hooks@7.6.2(react@18.2.0))(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/hooks': 7.6.2(react@18.2.0) @@ -42206,7 +42130,7 @@ snapshots: '@microlink/react-json-view': 1.23.0(@types/react@17.0.62)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@next/bundle-analyzer': 14.2.3 '@rjsf/antd': 5.18.3(@ant-design/icons@4.8.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@rjsf/core@5.17.1(@rjsf/utils@5.17.1(react@18.2.0))(react@18.2.0))(@rjsf/utils@5.17.1(react@18.2.0))(antd@4.24.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(dayjs@1.11.10)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@rjsf/chakra-ui': 5.17.1(@chakra-ui/icons@2.1.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/react@1.8.9(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@rjsf/core@5.17.1(@rjsf/utils@5.17.1(react@18.2.0))(react@18.2.0))(@rjsf/utils@5.17.1(react@18.2.0))(@types/react@17.0.62)(chakra-react-select@4.7.6(@chakra-ui/form-control@2.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/layout@2.3.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rjsf/chakra-ui': 5.17.1(l2tcgzxxdbhlpil4iohtcrd2ju) '@rjsf/core': 5.17.1(@rjsf/utils@5.17.1(react@18.2.0))(react@18.2.0) '@rjsf/utils': 5.17.1(react@18.2.0) '@rjsf/validator-ajv8': 5.17.1(@rjsf/utils@5.17.1(react@18.2.0)) @@ -45565,14 +45489,14 @@ snapshots: transitivePeerDependencies: - react-dom - ? '@rjsf/chakra-ui@5.17.1(@chakra-ui/icons@2.1.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/react@1.8.9(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@rjsf/core@5.17.1(@rjsf/utils@5.17.1(react@18.2.0))(react@18.2.0))(@rjsf/utils@5.17.1(react@18.2.0))(@types/react@17.0.62)(chakra-react-select@4.7.6(@chakra-ui/form-control@2.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/layout@2.3.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)' - : dependencies: + '@rjsf/chakra-ui@5.17.1(l2tcgzxxdbhlpil4iohtcrd2ju)': + dependencies: '@chakra-ui/icons': 2.1.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0) '@chakra-ui/react': 1.8.9(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@chakra-ui/system': 2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0) '@rjsf/core': 5.17.1(@rjsf/utils@5.17.1(react@18.2.0))(react@18.2.0) '@rjsf/utils': 5.17.1(react@18.2.0) - chakra-react-select: 4.7.6(@chakra-ui/form-control@2.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/layout@2.3.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + chakra-react-select: 4.7.6(srrelquo2op6lcdtdecobgquaq) framer-motion: 11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-select: 5.8.0(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -50923,6 +50847,8 @@ snapshots: expect: 29.7.0 pretty-format: 29.7.0 + '@types/js-cookie@3.0.6': {} + '@types/jsdom@20.0.1': dependencies: '@types/node': 14.18.42 @@ -52617,9 +52543,9 @@ snapshots: '@webassemblyjs/ast': 1.11.5 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))(webpack@5.82.1(@swc/core@1.3.107)(webpack-cli@5.1.4))': @@ -52627,9 +52553,9 @@ snapshots: webpack: 5.82.1(@swc/core@1.3.107)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))(webpack@5.82.1(@swc/core@1.3.107)(webpack-cli@5.1.4))': @@ -52637,9 +52563,9 @@ snapshots: webpack: 5.82.1(@swc/core@1.3.107)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))(webpack@5.82.1(@swc/core@1.3.107)(webpack-cli@5.1.4))': @@ -54670,8 +54596,8 @@ snapshots: pathval: 1.1.1 type-detect: 4.0.8 - ? chakra-react-select@4.7.6(@chakra-ui/form-control@2.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/layout@2.3.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(framer-motion@11.1.9(@emotion/is-prop-valid@1.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0))(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - : dependencies: + chakra-react-select@4.7.6(srrelquo2op6lcdtdecobgquaq): + dependencies: '@chakra-ui/form-control': 2.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0) '@chakra-ui/icon': 3.2.0(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0) '@chakra-ui/layout': 2.3.1(@chakra-ui/system@2.6.2(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@emotion/styled@11.10.6(@emotion/react@11.11.4(@types/react@17.0.62)(react@18.2.0))(@types/react@17.0.62)(react@18.2.0))(react@18.2.0))(react@18.2.0) @@ -55186,11 +55112,11 @@ snapshots: dependencies: mime-db: 1.52.0 - compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)): + compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)): dependencies: schema-utils: 4.0.0 serialize-javascript: 6.0.1 - webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4) compression-webpack-plugin@10.0.0(webpack@5.82.1(@swc/core@1.3.107)(webpack-cli@5.1.4)): dependencies: @@ -57128,19 +57054,19 @@ snapshots: esbuild-plugin-alias@0.2.1: {} - esbuild-plugin-compress@1.0.1(esbuild@0.19.12): + esbuild-plugin-compress@1.0.1(esbuild@0.20.1): dependencies: chalk: 4.1.2 - esbuild: 0.19.12 + esbuild: 0.20.1 fs-extra: 10.1.0 micromatch: 4.0.5 - esbuild-plugin-solid@0.5.0(esbuild@0.19.12)(solid-js@1.8.17): + esbuild-plugin-solid@0.5.0(esbuild@0.20.1)(solid-js@1.8.17): dependencies: '@babel/core': 7.24.4 '@babel/preset-typescript': 7.23.2(@babel/core@7.24.4) babel-preset-solid: 1.8.17(@babel/core@7.24.4) - esbuild: 0.19.12 + esbuild: 0.20.1 solid-js: 1.8.17 transitivePeerDependencies: - supports-color @@ -63055,6 +62981,8 @@ snapshots: js-cookie@3.0.1: {} + js-cookie@3.0.5: {} + js-sdsl@4.4.0: {} js-tokens@4.0.0: {} @@ -72920,17 +72848,17 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.2) esbuild: 0.18.17 - terser-webpack-plugin@5.3.9(@swc/core@1.3.107)(esbuild@0.19.12)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.9(@swc/core@1.3.107)(esbuild@0.20.1)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.1 terser: 5.22.0 - webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.2) - esbuild: 0.19.12 + esbuild: 0.20.1 terser-webpack-plugin@5.3.9(@swc/core@1.3.107)(webpack@5.78.0(@swc/core@1.3.107)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))): dependencies: @@ -73385,7 +73313,7 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.24.4) - ts-jest@29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.19.12)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5)))(typescript@4.9.5): + ts-jest@29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.20.1)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5)))(typescript@4.9.5): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -73401,7 +73329,7 @@ snapshots: '@babel/core': 7.24.4 '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.24.4) - esbuild: 0.19.12 + esbuild: 0.20.1 ts-jest@29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(jest@29.7.0(@types/node@14.18.42)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@14.18.42)(typescript@4.9.5)))(typescript@4.9.5): dependencies: @@ -73454,14 +73382,14 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.24.4) - ts-loader@9.4.2(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)): + ts-loader@9.4.2(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)): dependencies: chalk: 4.1.2 enhanced-resolve: 5.15.0 micromatch: 4.0.5 semver: 7.5.2 typescript: 4.9.5 - webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4) ts-loader@9.4.2(typescript@4.9.5)(webpack@5.82.1(@swc/core@1.3.107)(webpack-cli@5.1.4)): dependencies: @@ -73871,9 +73799,9 @@ snapshots: tslib@2.6.2: {} - tsup-preset-solid@2.2.0(esbuild@0.19.12)(solid-js@1.8.17)(tsup@8.0.2(@microsoft/api-extractor@7.38.0(@types/node@18.16.9))(@swc/core@1.3.107)(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5))(typescript@4.9.5)): + tsup-preset-solid@2.2.0(esbuild@0.20.1)(solid-js@1.8.17)(tsup@8.0.2(@microsoft/api-extractor@7.38.0(@types/node@18.16.9))(@swc/core@1.3.107)(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5))(typescript@4.9.5)): dependencies: - esbuild-plugin-solid: 0.5.0(esbuild@0.19.12)(solid-js@1.8.17) + esbuild-plugin-solid: 0.5.0(esbuild@0.20.1)(solid-js@1.8.17) tsup: 8.0.2(@microsoft/api-extractor@7.38.0(@types/node@18.16.9))(@swc/core@1.3.107)(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107)(@types/node@18.16.9)(typescript@4.9.5))(typescript@4.9.5) transitivePeerDependencies: - esbuild @@ -75210,9 +75138,9 @@ snapshots: webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -75221,7 +75149,7 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4) webpack-merge: 5.9.0 optionalDependencies: webpack-bundle-analyzer: 4.10.1 @@ -75600,7 +75528,7 @@ snapshots: - esbuild - uglify-js - webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4): + webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 0.0.51 @@ -75623,7 +75551,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.9(@swc/core@1.3.107)(esbuild@0.19.12)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.19.12)(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.9(@swc/core@1.3.107)(esbuild@0.20.1)(webpack@5.78.0(@swc/core@1.3.107)(esbuild@0.20.1)(webpack-cli@5.1.4)) watchpack: 2.4.0 webpack-sources: 3.2.3 optionalDependencies: From 94973c39b53ab5856bf5c31e03d3b91ca4c39006 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Thu, 27 Jun 2024 18:41:35 +0300 Subject: [PATCH 2/7] fix: headers in netlify --- apps/web/netlify.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/web/netlify.toml b/apps/web/netlify.toml index fd7f22df7bc..6cf4b086a46 100644 --- a/apps/web/netlify.toml +++ b/apps/web/netlify.toml @@ -15,7 +15,6 @@ [[headers]] for = "/*" [headers.values] - X-Frame-Options = "DENY" X-XSS-Protection = "1; mode=block" Referrer-Policy = "no-referrer" X-Content-Type-Options = "nosniff" From 6d8a095a9b3256d8a7d89a0536f13302238f04c0 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Thu, 27 Jun 2024 19:39:30 +0300 Subject: [PATCH 3/7] fix: change cli tab name --- apps/web/src/components/layout/components/v2/SyncInfoModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/layout/components/v2/SyncInfoModal.tsx b/apps/web/src/components/layout/components/v2/SyncInfoModal.tsx index 9736d546f86..9f70588fd45 100644 --- a/apps/web/src/components/layout/components/v2/SyncInfoModal.tsx +++ b/apps/web/src/components/layout/components/v2/SyncInfoModal.tsx @@ -30,7 +30,7 @@ export const SyncInfoModal: FC = ({ isOpen, toggleOpen }) => }, { value: 'other', - label: 'Other CI', + label: 'CLI', content: ( {getOtherCodeContent({ apiKey, bridgeUrl })} From 907eb2b85869ecad8d57e35c388dd9f8b5c15f23 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Thu, 27 Jun 2024 20:39:03 +0300 Subject: [PATCH 4/7] fix: iframe redirect --- apps/web/src/hooks/useAuth.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/web/src/hooks/useAuth.ts b/apps/web/src/hooks/useAuth.ts index 8991df981ce..d6933f9b66e 100644 --- a/apps/web/src/hooks/useAuth.ts +++ b/apps/web/src/hooks/useAuth.ts @@ -44,6 +44,14 @@ export function getTokenClaims(): IJwtClaims | null { return token ? jwtDecode(token) : null; } +function inIframe() { + try { + return window.self !== window.top; + } catch (e) { + return true; + } +} + export function useAuth() { const ldClient = useLDClient(); const segment = useSegment(); @@ -57,7 +65,7 @@ export function useAuth() { const hasToken = !!getToken(); useEffect(() => { - if (!getToken() && inPrivateRoute) { + if (!getToken() && inPrivateRoute && !inIframe()) { navigate(ROUTES.AUTH_LOGIN, { state: { redirectTo: location } }); } }, [navigate, inPrivateRoute, location]); From d28a83dd1230bcca6458cb423cf6464625c74c31 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Thu, 27 Jun 2024 20:56:07 +0300 Subject: [PATCH 5/7] fix: onboarding cookie --- apps/web/src/pages/studio-onboarding/success.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/web/src/pages/studio-onboarding/success.tsx b/apps/web/src/pages/studio-onboarding/success.tsx index e9ce3802366..7490914ad15 100644 --- a/apps/web/src/pages/studio-onboarding/success.tsx +++ b/apps/web/src/pages/studio-onboarding/success.tsx @@ -70,7 +70,11 @@ export const StudioOnboardingSuccess = () => { segment.track('Test workflow step completed - [Onboarding - Signup]'); // Never expires! Well it does, in 10 years but you will change device or browser by then :) - novuOnboardedCookie.set('1', { expires: ONBOARDING_COOKIE_EXPIRY_DAYS }); + novuOnboardedCookie.set('1', { + expires: ONBOARDING_COOKIE_EXPIRY_DAYS, + sameSite: 'none', + secure: window.location.protocol === 'https', + }); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); From 2568813c9f78beea375ef907b14c863f853392e4 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Thu, 27 Jun 2024 22:43:31 +0300 Subject: [PATCH 6/7] fix: test --- .../src/pages/studio-onboarding/preview.tsx | 2 +- .../components/GetStartedPageV2/index.tsx | 33 +++++++++++-------- .../test-workflow/WorkflowsTestPage.tsx | 4 ++- apps/web/src/studio/hooks/useBridgeAPI.ts | 2 +- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/web/src/pages/studio-onboarding/preview.tsx b/apps/web/src/pages/studio-onboarding/preview.tsx index 837102c47f6..c9566814ce7 100644 --- a/apps/web/src/pages/studio-onboarding/preview.tsx +++ b/apps/web/src/pages/studio-onboarding/preview.tsx @@ -64,7 +64,7 @@ export const StudioOnboardingPreview = () => { navigate({ pathname: ROUTES.STUDIO_ONBOARDING_SUCCESS, search: createSearchParams({ - transactionId: response.transactionId, + transactionId: response.data.transactionId, }).toString(), }); }; diff --git a/apps/web/src/studio/components/GetStartedPageV2/index.tsx b/apps/web/src/studio/components/GetStartedPageV2/index.tsx index 15e6ee8d9f2..7cddfed2b3e 100644 --- a/apps/web/src/studio/components/GetStartedPageV2/index.tsx +++ b/apps/web/src/studio/components/GetStartedPageV2/index.tsx @@ -94,21 +94,28 @@ export const GetStartedPageV2 = () => { gap="50" > Run this in your terminal to get started - { +
{ segment.track('Command copied - [Get Started - V2]'); }} - /> + > + { + segment.track('Command copied - [Get Started - V2]'); + }} + /> +
{ let response; if (local) { - response = await trigger({ + const bridgeResponse = await trigger({ workflowId: workflowId, to, payload, }); + + response = bridgeResponse.data; } else { response = await triggerCloudTestEvent({ name: workflowId, diff --git a/apps/web/src/studio/hooks/useBridgeAPI.ts b/apps/web/src/studio/hooks/useBridgeAPI.ts index 52fcbdb3738..0805c4d0c73 100644 --- a/apps/web/src/studio/hooks/useBridgeAPI.ts +++ b/apps/web/src/studio/hooks/useBridgeAPI.ts @@ -91,7 +91,7 @@ export const useWorkflowTrigger = () => { const bridgeUrl = state.local ? state.tunnelBridgeURL : state.storedBridgeURL; - async function trigger(params: TriggerParams) { + async function trigger(params: TriggerParams): Promise<{ data: { transactionId: string } }> { return mutateAsync({ ...params, bridgeUrl }); } From 85507a87ed60865c2cef7d788885084137c632d2 Mon Sep 17 00:00:00 2001 From: Dima Grossman <dima@grossman.io> Date: Thu, 27 Jun 2024 23:00:48 +0300 Subject: [PATCH 7/7] fix: copy --- apps/web/src/pages/studio-onboarding/components/Header.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/studio-onboarding/components/Header.tsx b/apps/web/src/pages/studio-onboarding/components/Header.tsx index c5b7ca83887..111efb19eb5 100644 --- a/apps/web/src/pages/studio-onboarding/components/Header.tsx +++ b/apps/web/src/pages/studio-onboarding/components/Header.tsx @@ -74,8 +74,8 @@ export const Header = ({ activeStepIndex = 0 }: { activeStepIndex?: number }) => active={activeStepIndex} > <Stepper.Step label="Add the endpoint"></Stepper.Step> - <Stepper.Step label="Create workflow"></Stepper.Step> - <Stepper.Step label="Test workflow"></Stepper.Step> + <Stepper.Step label="Test the workflow"></Stepper.Step> + <Stepper.Step label="Check your Inbox"></Stepper.Step> </Stepper> </div> </VStack>