Skip to content

Commit

Permalink
Merge branch 'next' into fix/plain_suport_key_env_enterprise_only
Browse files Browse the repository at this point in the history
  • Loading branch information
jainpawan21 authored Nov 7, 2024
2 parents 7f3c70b + c1f3f4a commit c56e77a
Show file tree
Hide file tree
Showing 48 changed files with 2,070 additions and 1,517 deletions.
2 changes: 1 addition & 1 deletion .source
2 changes: 1 addition & 1 deletion apps/dashboard/src/components/workflow-editor/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const workflowSchema = z.object({
type: z.nativeEnum(StepTypeEnum),
_id: z.string(),
stepId: z.string(),
slug: z.literal<StepResponseDto['slug']>('_stp_'),
slug: z.literal<StepResponseDto['slug']>('_st_'),
})
.passthrough()
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Card } from '@mantine/core';
import { css } from '@novu/novui/css';
import { Text, Title, Button, IconButton } from '@novu/novui';
import { IconOutlineClose } from '@novu/novui/icons';
import { useUser } from '@clerk/clerk-react';
import { FeatureFlagsKeysEnum, NewDashboardOptInStatusEnum } from '@novu/shared';
import { IS_SELF_HOSTED } from '../../../../config';
import { useFeatureFlag } from '../../../../hooks';

export function NewDashboardOptInWidget() {
const { user } = useUser();
const isNewDashboardEnabled = useFeatureFlag(FeatureFlagsKeysEnum.IS_NEW_DASHBOARD_ENABLED);

const isDismissed = user?.unsafeMetadata?.newDashboardOptInStatus === NewDashboardOptInStatusEnum.DISMISSED;

if (IS_SELF_HOSTED || isDismissed || !isNewDashboardEnabled) {
return null;
}

const updateUserOptInStatus = (status: NewDashboardOptInStatusEnum) => {
if (!user) return;

user.update({
unsafeMetadata: {
...user.unsafeMetadata,
newDashboardOptInStatus: status,
},
});
};

function handleOptIn() {
const newDashboardUrl = process.env.NEW_DASHBOARD_URL;
if (!newDashboardUrl || !user) return;

updateUserOptInStatus(NewDashboardOptInStatusEnum.OPTED_IN);
window.location.href = newDashboardUrl;
}

function handleDismiss() {
updateUserOptInStatus(NewDashboardOptInStatusEnum.DISMISSED);
}

return (
<Card shadow="sm" className={styles.card}>
<div className={styles.content}>
<div className={styles.header}>
<Title className={styles.title}>
<span style={{ marginRight: '4px' }}>🎉</span> You're invited!
</Title>
<IconButton onClick={handleDismiss} Icon={IconOutlineClose} size="xs" />
</div>
<Text className={styles.text}>
We’d love to extend you the access for the new workflows dashboard that we’re building.
</Text>
</div>
<div className={styles.buttonContainer}>
<Button size="sm" variant="transparent" onClick={handleOptIn}>
Take me there
</Button>
</div>
</Card>
);
}

const styles = {
card: css({
padding: '9px 16px !important',
backgroundColor: 'surface.popover !important',
_before: {
content: '""',
position: 'absolute',
width: '50',
top: '0',
right: '0',
bottom: '0',
left: '0',
borderTopLeftRadius: '100',
borderBottomLeftRadius: '100',
bgGradient: `to-b`,
gradientFrom: 'colorPalette.start',
gradientTo: 'colorPalette.end',
},
}),
content: css({
display: 'flex',
flexDirection: 'column',
gap: '4px',
alignSelf: 'stretch',
}),
header: css({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
gap: '8px',
}),
title: css({
fontSize: '12px',
fontWeight: '700 ',
lineHeight: '20px',
}),
text: css({
fontSize: '12px',
lineHeight: '16px',
fontWeight: '500',
fontStyle: 'normal',
}),
buttonContainer: css({
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
}),
};
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const SyncInfoModal: FC<SyncInfoModalProps> = ({ isOpen, toggleOpen, refe
href="https://docs.novu.co/deployment/syncing"
target={'_blank'}
className={css({
textDecoration: 'underline !important',
textDecoration: '!important underline',
})}
>
our docs.
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/components/nav/RootNavMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { SidebarFooter } from '../layout/components/LocalStudioSidebar/SidebarFo
import { useNavigateToLocalStudio } from '../../studio/hooks/useNavigateToLocalStudio';
import { OpenLocalStudioModal } from '../../studio/components/OpenLocalStudioModal';
import { OutlineButton } from '../../studio/components/OutlineButton';
import { NewDashboardOptInWidget } from '../layout/components/v2/NewDashboardOptInWidget';

const getEnvPageRoute = (route: ROUTES, env: BaseEnvironmentEnum) => parseUrl(route, { env });

Expand Down Expand Up @@ -161,6 +162,7 @@ export const RootNavMenu: React.FC = () => {
{isV2Enabled ? (
<>
<SidebarFooter>
<NewDashboardOptInWidget />
<FreeTrialSidebarWidget />
<OutlineButton fullWidth onClick={navigateToLocalStudio} Icon={IconLaptop}>
Open Local Studio
Expand Down
4 changes: 2 additions & 2 deletions packages/novu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "novu",
"version": "2.1.0",
"version": "2.2.0-rc.2",
"description": "Novu CLI. Run Novu Studio and sync workflows with Novu Cloud",
"main": "src/index.js",
"publishConfig": {
Expand Down Expand Up @@ -68,7 +68,7 @@
},
"dependencies": {
"@novu/ntfr-client": "^0.0.4",
"@novu/shared": "workspace:*",
"@novu/shared": "2.1.1",
"@segment/analytics-node": "^1.1.4",
"axios": "^1.6.8",
"chalk": "4.1.2",
Expand Down
6 changes: 6 additions & 0 deletions packages/novu/src/commands/init/create-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export async function createApp({
srcDir,
importAlias,
secretKey,
applicationId,
userId,
}: {
appPath: string;
packageManager: PackageManager;
Expand All @@ -29,6 +31,8 @@ export async function createApp({
srcDir: boolean;
importAlias: string;
secretKey: string;
applicationId: string;
userId: string;
}): Promise<void> {
let repoInfo: RepoInfo | undefined;
const mode: TemplateMode = typescript ? 'ts' : 'js';
Expand Down Expand Up @@ -73,6 +77,8 @@ export async function createApp({
srcDir,
importAlias,
secretKey,
applicationId,
userId,
});

if (tryGitInit(root)) {
Expand Down
12 changes: 12 additions & 0 deletions packages/novu/src/commands/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export async function init(program: IInitCommandOptions, anonymousId?: string):
process.exit(1);
}

let applicationId: string;
let userId: string;
// if no secret key is supplied set to empty string
if (!program.secretKey) {
Expand All @@ -114,6 +115,15 @@ export async function init(program: IInitCommandOptions, anonymousId?: string):

userId = user.data?._id;

const integrationsResponse = await fetch(`${program.apiUrl}/v1/environments/me`, {
headers: {
Authorization: `ApiKey ${program.secretKey}`,
},
});

const environment = await integrationsResponse.json();
applicationId = environment.data.identifier;

analytics.alias({
previousId: anonymousId,
userId,
Expand Down Expand Up @@ -172,6 +182,8 @@ export async function init(program: IInitCommandOptions, anonymousId?: string):
srcDir: defaults.srcDir as boolean,
importAlias: defaults.importAlias as string,
secretKey: program.secretKey,
applicationId,
userId,
});

if (userId || anonymousId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export async function GET() {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);

const response = await fetch("http://localhost:2022/.well-known/novu", {
signal: controller.signal,
headers: {
Accept: "application/json",
},
});

clearTimeout(timeoutId);

if (response.ok) {
const data = await response.json();
if (data.port && data.route) {
return Response.json({ connected: true, data });
}
}

return Response.json({
connected: false,
error: await response.text(),
});
} catch (error) {
return Response.json({
connected: false,
error: error instanceof Error ? error.message : "Unknown error",
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export async function POST(request: Request) {
try {
const body = await request.json();

const response = await fetch("https://api.novu.co/v1/telemetry/measure", {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `ApiKey ${process.env.NOVU_SECRET_KEY}`,
},
method: "POST",
body: JSON.stringify({
event: body.event,
data: body.data,
}),
});

if (response.ok) {
return Response.json({ success: true });
}

return Response.json({
connected: false,
error: await response.text(),
});
} catch (error) {
return Response.json({
connected: false,
error: error instanceof Error ? error.message : "Unknown error",
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NextResponse } from "next/server";
import { welcomeOnboardingEmail } from "../../novu/workflows";

export async function POST() {
try {
await welcomeOnboardingEmail.trigger({
to: process.env.NEXT_PUBLIC_NOVU_SUBSCRIBER_ID || "",
payload: {},
});

return NextResponse.json({
message: "Notification triggered successfully",
});
} catch (error: unknown) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error occurred";
console.error("Error triggering notification:", errorMessage);

return NextResponse.json(
{ message: "Error triggering notification", error: errorMessage },
{ status: 500 },
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
.toast {
position: fixed;
background: linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%);
border-radius: 16px;
padding: 18px 24px;
box-shadow:
0 10px 25px rgba(0, 0, 0, 0.1),
0 6px 12px rgba(0, 0, 0, 0.08),
0 0 0 1px rgba(255, 255, 255, 0.5) inset;
z-index: 1000;
width: 90%;
max-width: 400px;
right: 24px;
top: 24px;
border: 1px solid rgba(0, 0, 0, 0.06);
animation: slideIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
backdrop-filter: blur(10px);
transform-origin: top right;
}

.toastContent {
display: flex;
flex-direction: column;
gap: 10px;
position: relative;
overflow: hidden;
font-weight: 600;
background: linear-gradient(90deg, #1a1a1a 0%, #404040 100%);
-webkit-background-clip: text;
color: transparent;
font-size: 1rem;
letter-spacing: -0.02em;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}

.toastContent::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(45deg,
transparent 0%,
rgba(255, 255, 255, 0.1) 50%,
transparent 100%);
animation: shimmer 2s infinite;
}

@keyframes slideIn {
0% {
transform: translateY(-120%) scale(0.9);
opacity: 0;
}

100% {
transform: translateY(0) scale(1);
opacity: 1;
}
}

@keyframes shimmer {
0% {
transform: translateX(-100%) rotate(45deg);
}

100% {
transform: translateX(100%) rotate(45deg);
}
}

@media (prefers-reduced-motion: reduce) {
.toast {
animation: none;
}

.toastContent::before {
animation: none;
}
}
Loading

0 comments on commit c56e77a

Please sign in to comment.