Skip to content

Commit

Permalink
feat(web): Web containers Onboarding (novuhq#6172)
Browse files Browse the repository at this point in the history
Co-authored-by: Gosha <[email protected]>
Co-authored-by: Denis Kralj <[email protected]>
  • Loading branch information
3 people authored Aug 1, 2024
1 parent fec86d6 commit ffbe038
Show file tree
Hide file tree
Showing 109 changed files with 9,407 additions and 555 deletions.
8 changes: 6 additions & 2 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,10 @@
"xcodebuild",
"xkeysib",
"zulip",
"zwnj"
"zwnj",
"Embedder",
"credentialless",
"coep"
],
"flagWords": [],
"patterns": [
Expand Down Expand Up @@ -755,6 +758,7 @@
"pnpm-lock.yaml",
"apps/web/env.sh",
"packages/js/src/ui/index.directcss",
"unreadRead"
"unreadRead",
"apps/web/src/studio/components/workflows/step-editor/editor/files.ts"
]
}
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@
},
{
"type": "npm",
"script": "build",
"script": "setup",
"label": "NOVUI",
"path": "/libs/novui",
"problemMatcher": "$tsc"
Expand Down
1 change: 1 addition & 0 deletions apps/api/src/app/bridge/bridge.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export class BridgeController {
inputs: data.controls || data.inputs,
controls: data.controls || data.inputs,
data: data.payload,
bridgeUrl: data.bridgeUrl,
environmentId: user.environmentId,
organizationId: user.organizationId,
userId: user._id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class GetBridgeStatus {

return response.data;
} catch (err: any) {
throw new BadRequestException('Bridge URL is not accessible. ' + err.message);
throw new BadRequestException('Bridge is not accessible. ' + err.message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export class PreviewStepCommand extends EnvironmentWithUserCommand {
inputs: any;
controls: any;
data: any;
bridgeUrl?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ export class PreviewStep {

async execute(command: PreviewStepCommand) {
const environment = await this.environmentRepository.findOne({ _id: command.environmentId });
if (!environment?.echo.url) {
const bridgeUrl = command.bridgeUrl || environment?.echo.url;
if (!bridgeUrl) {
throw new BadRequestException('Bridge URL not found');
}

const axiosInstance = axios.create();
try {
const payload = this.mapPayload(command);
const novuSignatureHeader = this.buildNovuSignature(environment, payload);
const url = `${environment.echo.url}?action=preview&workflowId=${command.workflowId}&stepId=${command.stepId}`;
const url = `${bridgeUrl}?action=preview&workflowId=${command.workflowId}&stepId=${command.stepId}`;

const response = await axiosInstance.post(url, payload, {
headers: {
Expand All @@ -44,14 +45,14 @@ export class PreviewStep {
if (e?.response?.status === 404) {
throw new BadRequestException({
code: BridgeErrorCodeEnum.BRIDGE_ENDPOINT_NOT_FOUND,
message: 'Bridge Endpoint Was not found or not accessible. Endpoint: ' + environment.echo.url,
message: 'Bridge Endpoint Was not found or not accessible. Endpoint: ' + bridgeUrl,
});
}

if (e?.response?.status === 405) {
throw new BadRequestException({
code: BridgeErrorCodeEnum.BRIDGE_ENDPOINT_NOT_FOUND,
message: 'Bridge Endpoint is not properly configured. : ' + environment.echo.url,
message: 'Bridge Endpoint is not properly configured. : ' + bridgeUrl,
});
}

Expand Down
36 changes: 33 additions & 3 deletions apps/web/config-overrides.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { useBabelRc, override } = require('customize-cra');
const { useBabelRc, override, overrideDevServer } = require('customize-cra');
const { DefinePlugin } = require('webpack');
const { version } = require('./package.json');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
Expand All @@ -23,5 +23,35 @@ function overrideConfig(config, env) {
};
}

// eslint-disable-next-line react-hooks/rules-of-hooks
module.exports = override(useBabelRc(), overrideConfig);
const devServerConfig = () => (config) => {
return {
...config,
headers: (req, res, context) => {
const defaultHeaders = {
'Referrer-Policy': 'no-referrer',
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'Permissions-Policy':
'accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()',
};

const playgroundHeaders = {
...defaultHeaders,
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'credentialless',
'Cross-Origin-Resource-Policy': 'cross-origin',
'Referrer-Policy': 'no-referrer-when-downgrade',
};

const secureRoutes = ['/auth/application', '/playground'];

return secureRoutes.includes(req.baseUrl) ? playgroundHeaders : defaultHeaders;
},
};
};

module.exports = {
// eslint-disable-next-line react-hooks/rules-of-hooks
webpack: override(useBabelRc(), overrideConfig),
devServer: overrideDevServer(devServerConfig()),
};
32 changes: 31 additions & 1 deletion apps/web/netlify.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,41 @@
to = "/index.html"
status = 200

[[headers]]
for = "/auth/application"
[headers.values]
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "no-referrer-when-downgrade"
X-Content-Type-Options = "nosniff"
Cross-Origin-Opener-Policy = "same-origin"
Cross-Origin-Embedder-Policy = "credentialless"
Cross-Origin-Resource-Policy = "cross-origin"
Permissions-Policy = "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
Strict-Transport-Security = '''
max-age=63072000;
includeSubDomains;
preload'''

[[headers]]
for = "/playground"
[headers.values]
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "no-referrer-when-downgrade"
X-Content-Type-Options = "nosniff"
Cross-Origin-Opener-Policy = "same-origin"
Cross-Origin-Embedder-Policy = "credentialless"
Cross-Origin-Resource-Policy = "cross-origin"
Permissions-Policy = "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
Strict-Transport-Security = '''
max-age=63072000;
includeSubDomains;
preload'''

[[headers]]
for = "/*"
[headers.values]
X-XSS-Protection = "1; mode=block"
Referrer-Policy = "no-referrer"
Referrer-Policy = "no-referrer-when-downgrade"
X-Content-Type-Options = "nosniff"
Permissions-Policy = "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
Strict-Transport-Security = '''
Expand Down
10 changes: 9 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@
"@types/jest": "^29.5.0",
"@types/node": "^20.14.10",
"@types/react-table": "^7.7.12",
"@webcontainer/api": "^1.1.5",
"@xterm/xterm": "^5.5.0",
"ace-builds": "^1.4.12",
"allotment": "^1.20.2",
"antd": "^4.10.0",
"autoprefixer": "^9.8.6",
"axios": "^1.6.2",
Expand All @@ -90,6 +93,7 @@
"date-fns": "^2.29.2",
"dotenv": "^16.4.5",
"eslint-plugin-react-hooks": "^4.4.0",
"framer-motion": "^11.3.19",
"handlebars": "^4.7.7",
"highlight.js": "11.9.0",
"html-webpack-plugin": "5.5.3",
Expand All @@ -106,14 +110,15 @@
"lodash.set": "^4.3.2",
"mdx-bundler": "10.0.2",
"mixpanel-browser": "^2.52.0",
"monaco-editor": "^0.45.0",
"monaco-editor": "^0.39.0",
"polished": "^4.1.3",
"react": "^18.3.1",
"react-ace": "^9.4.3",
"react-chartjs-2": "^4.0.1",
"react-color": "^2.19.3",
"react-css-theme-switcher": "^0.3.0",
"react-custom-scrollbars": "^4.2.1",
"react-device-detect": "^2.2.3",
"react-dom": "^18.3.1",
"react-editor-js": "^1.9.0",
"react-error-boundary": "^3.1.4",
Expand All @@ -135,6 +140,8 @@
"uniqid": "^5.3.0",
"uuid": "8.3.2",
"web-vitals": "^1.0.1",
"xterm": "^5.1.0",
"xterm-addon-fit": "^0.7.0",
"zod": "^3.22.4"
},
"devDependencies": {
Expand All @@ -146,6 +153,7 @@
"@clerk/types": "^4.6.1",
"@faker-js/faker": "^6.0.0",
"@novu/dal": "workspace:*",
"@novu/framework": "workspace:*",
"@novu/testing": "workspace:*",
"@pandacss/dev": "^0.42.0",
"@pandacss/studio": "^0.42.0",
Expand Down
21 changes: 21 additions & 0 deletions apps/web/public/static/images/novu-gray.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/static/images/novu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 6 additions & 9 deletions apps/web/src/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,16 @@ import { OrganizationPage } from './pages/settings/organization';
import { LayoutsPage } from './pages/layouts/LayoutsPage';
import { StudioPageLayout } from './studio/StudioPageLayout';
import { LocalStudioAuthenticator } from './studio/LocalStudioAuthenticator';
import {
LocalStudioWorkflowLandingPage,
WorkflowsDetailPage,
WorkflowsStepEditorPage,
WorkflowsTestPage,
} from './studio/components/workflows';
import { LocalStudioWorkflowLandingPage, WorkflowsDetailPage, WorkflowsTestPage } from './studio/components/workflows';
import { WorkflowsStepEditorPageV2 } from './pages/templates/editor_v2/TemplateStepEditorV2';
import { IS_EE_AUTH_ENABLED } from './config/index';
import { EnterpriseAuthRoutes } from './ee/clerk/EnterpriseAuthRoutes';
import { novuOnboardedCookie } from './utils/cookies';
import { EnterprisePrivatePageLayout } from './ee/clerk/components/EnterprisePrivatePageLayout';
import { OnboardingPage } from './pages/auth/onboarding/Onboarding';
import { GetStartedPageV2 } from './studio/components/GetStartedPageV2/index';
import { PlaygroundPage } from './pages/auth/onboarding/PlaygroundPage';
import { BillingRoutes } from './pages/BillingPages';
import { StudioStepEditorPage } from './studio/pages/StudioStepEditorPage';

const AuthRoutes = () => {
const CommunityAuthRoutes = () => (
Expand All @@ -90,6 +86,7 @@ export const AppRoutes = () => {
<Routes>
{AuthRoutes()}
<Route path={ROUTES.DASHBOARD_ONBOARDING} element={<OnboardingPage />} />
<Route path={ROUTES.DASHBOARD_PLAYGROUND} element={<PlaygroundPage />} />
<Route element={!IS_EE_AUTH_ENABLED ? <PrivatePageLayout /> : <EnterprisePrivatePageLayout />}>
<Route
path={ROUTES.PARTNER_INTEGRATIONS_VERCEL_LINK_PROJECTS}
Expand Down Expand Up @@ -122,7 +119,7 @@ export const AppRoutes = () => {
<Route path=":identifier" element={<UpdateTenantPage />} />
</Route>
{isV2Enabled ? (
<Route path={ROUTES.GET_STARTED} element={<GetStartedPageV2 location="get-started" />} />
<Route path={ROUTES.GET_STARTED} element={<GetStartedPage />} />
) : (
<Route path={ROUTES.GET_STARTED} element={<GetStarted />} />
)}
Expand Down Expand Up @@ -178,7 +175,7 @@ export const AppRoutes = () => {
/>
<Route path={ROUTES.STUDIO_FLOWS} element={<LocalStudioWorkflowLandingPage />} />
<Route path={ROUTES.STUDIO_FLOWS_VIEW} element={<WorkflowsDetailPage />} />
<Route path={ROUTES.STUDIO_FLOWS_STEP_EDITOR} element={<WorkflowsStepEditorPage />} />
<Route path={ROUTES.STUDIO_FLOWS_STEP_EDITOR} element={<StudioStepEditorPage />} />
<Route path={ROUTES.STUDIO_FLOWS_TEST} element={<WorkflowsTestPage />} />
<Route path={ROUTES.STUDIO_ONBOARDING} element={<StudioOnboarding />} />
<Route path={ROUTES.STUDIO_ONBOARDING_PREVIEW} element={<StudioOnboardingPreview />} />
Expand Down
5 changes: 4 additions & 1 deletion apps/web/src/ApplicationReadyGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { type PropsWithChildren, useLayoutEffect } from 'react';
import { useAuth, useEnvironment, useMonitoring, useRouteScopes } from './hooks';
import { ROUTES } from './constants/routes';
import { IS_EE_AUTH_ENABLED } from './config/index';
import { navigateToAuthApplication } from './utils';

export function ApplicationReadyGuard({ children }: PropsWithChildren<{}>) {
useMonitoring();
Expand Down Expand Up @@ -64,7 +65,9 @@ export function ApplicationReadyGuard({ children }: PropsWithChildren<{}>) {
}

if (!isOnboardingComplete() && location.pathname !== ROUTES.AUTH_APPLICATION) {
return <Navigate to={ROUTES.AUTH_APPLICATION} replace />;
navigateToAuthApplication();

return null;
}

return <>{children}</>;
Expand Down
5 changes: 4 additions & 1 deletion apps/web/src/Providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ClerkProvider } from './ee/clerk/providers/ClerkProvider';
import { EnvironmentProvider } from './components/providers/EnvironmentProvider';
import { SegmentProvider } from './components/providers/SegmentProvider';
import { StudioStateProvider } from './studio/StudioStateProvider';
import { ContainerProvider } from './studio/components/workflows/step-editor/editor/useContainer';

const defaultQueryFn = async ({ queryKey }: { queryKey: string }) => {
const response = await api.get(`${queryKey[0]}`);
Expand Down Expand Up @@ -37,7 +38,9 @@ const Providers: React.FC<PropsWithChildren<{}>> = ({ children }) => {
<AuthProvider>
<EnvironmentProvider>
<HelmetProvider>
<StudioStateProvider>{children}</StudioStateProvider>
<StudioStateProvider>
<ContainerProvider>{children}</ContainerProvider>
</StudioStateProvider>
</HelmetProvider>
</EnvironmentProvider>
</AuthProvider>
Expand Down
7 changes: 3 additions & 4 deletions apps/web/src/bridgeApi/bridgeApi.client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import axios from 'axios';

import type { DiscoverWorkflowOutput } from '@novu/framework';

export type StepPreviewParams = {
workflowId: string;
stepId: string;
Expand Down Expand Up @@ -59,10 +61,7 @@ export function buildBridgeHTTPClient(baseURL: string) {
};

return {
/**
* TODO: Use framework shared types
*/
async discover(): Promise<{ workflows: any[] }> {
async discover(): Promise<{ workflows: DiscoverWorkflowOutput[] }> {
return get('', {
action: 'discover',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { Text } from '@novu/novui';
import { IconOutlineArrowBack } from '@novu/novui/icons';
import { hstack } from '@novu/novui/patterns';

type BackButtonProps = { onClick: () => void };
type BackButtonProps = { onClick: () => void; styles?: Record<string, any> };

export function BackButton({ onClick }: BackButtonProps) {
export function BackButton({ onClick, styles = {} }: BackButtonProps) {
return (
<button
className={hstack({
Expand All @@ -15,6 +15,7 @@ export function BackButton({ onClick }: BackButtonProps) {
borderRadius: '75',
textStyle: 'text.secondary !important',
_hover: { bg: 'badge.border', '& p, & svg': { color: 'typography.text.main !important' } },
...styles,
})}
onClick={onClick}
>
Expand Down
Loading

0 comments on commit ffbe038

Please sign in to comment.