Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/webapp/app/hooks/useOrganizations.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useCallback, useEffect, useRef, useState } from "react";
import type { UseDataFunctionReturn } from "remix-typedjson";
import type { loader as appLoader } from "~/routes/__app";
import type { loader as orgLoader } from "~/routes/__app/orgs/$organizationSlug";
Expand Down
83 changes: 83 additions & 0 deletions apps/webapp/app/hooks/usePostHog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { useLocation } from "@remix-run/react";
import posthog from "posthog-js";
import { useEffect, useRef } from "react";
import { useCurrentEnvironment } from "./useEnvironments";
import { useCurrentOrganization } from "./useOrganizations";
import { useOptionalUser } from "./useUser";
import { useCurrentWorkflow } from "./useWorkflows";

export const usePostHog = (apiKey?: string, logging = false): void => {
const postHogInitialized = useRef(false);
const location = useLocation();
const user = useOptionalUser();
const currentOrganization = useCurrentOrganization();
const currentOrganizationId = currentOrganization?.id;
const currentWorkflow = useCurrentWorkflow();
const currentWorkflowId = currentWorkflow?.id;
const currentEnvironment = useCurrentEnvironment();
const currentEnvironmentId = currentEnvironment?.id;

//start PostHog once
useEffect(() => {
if (apiKey === undefined) return;
if (postHogInitialized.current === true) return;
if (logging) console.log("posthog.init", apiKey);
postHogInitialized.current = true;
posthog.init(apiKey, {
api_host: "https://app.posthog.com",
loaded: function (posthog) {
if (logging) console.log("posthog.loaded", apiKey);
if (user !== undefined) {
if (logging) console.log("posthog.identify", user.id, user.email);
posthog.identify(user.id, { email: user.email });
}
},
});
}, [apiKey, logging, user]);

//identify the user, and unidentify on log out
useEffect(() => {
if (postHogInitialized.current === false) return;
if (user === undefined) {
if (logging) console.log("posthog.reset");
posthog.reset();
} else {
if (logging) console.log("posthog.identify", user.id, user.email);
posthog.identify(user.id, { email: user.email });
}
}, [logging, user]);

//identify the organization
useEffect(() => {
if (postHogInitialized.current === false) return;
if (currentOrganizationId !== undefined) {
if (logging) console.log("posthog.organization", currentOrganizationId);
posthog.group("organization", currentOrganizationId);
}
}, [currentOrganizationId, logging]);

//identify the workflow
useEffect(() => {
if (postHogInitialized.current === false) return;
if (currentWorkflowId !== undefined) {
if (logging) console.log("posthog.workflow", currentWorkflowId);
posthog.group("workflow", currentWorkflowId);
}
}, [currentWorkflowId, logging]);

//identify the environment
useEffect(() => {
if (postHogInitialized.current === false) return;
if (currentEnvironmentId !== undefined) {
if (logging) console.log("posthog.environment", currentEnvironmentId);
posthog.group("environment", currentEnvironmentId);
}
}, [currentEnvironmentId, logging]);

//page view
useEffect(() => {
if (postHogInitialized.current === false) return;
if (logging) console.log("posthog.capture", "$pageview", location.pathname);
posthog.capture("$pageview");
}, [location, logging]);
};
13 changes: 6 additions & 7 deletions apps/webapp/app/models/organization.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { prisma } from "~/db.server";
import slug from "slug";
import { customAlphabet } from "nanoid";
import { generateTwoRandomWords } from "~/utils/randomWords";
import { taskQueue } from "~/services/messageBroker.server";

export type { Organization } from ".prisma/client";

Expand Down Expand Up @@ -34,13 +35,7 @@ export function getOrganizationFromSlug({
{ title: "asc" },
],
},
environments: {
select: {
id: true,
slug: true,
apiKey: true,
},
},
environments: true,
},
where: { slug, users: { some: { id: userId } } },
});
Expand Down Expand Up @@ -130,6 +125,10 @@ export async function createOrganization({
await createEnvironment(organization, "development");
await createEnvironment(organization, "live");

await taskQueue.publish("ORGANIZATION_CREATED", {
id: organization.id,
});

return organization;
}

Expand Down
35 changes: 5 additions & 30 deletions apps/webapp/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
ScrollRestoration,
useCatch,
} from "@remix-run/react";

import tailwindStylesheetUrl from "./styles/tailwind.css";
import prismStylesheetUrl from "./styles/prism.css";
import prismThemeStylesheetUrl from "./styles/prism-trigger-theme.css";
Expand All @@ -17,12 +16,12 @@ import { Toaster, toast } from "react-hot-toast";
import type { ToastMessage } from "~/models/message.server";
import { commitSession, getSession } from "~/models/message.server";
import { useEffect, useRef } from "react";
import posthog from "posthog-js";
import { withSentry } from "@sentry/remix";
import { env } from "./env.server";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { PrimaryLink } from "./components/primitives/Buttons";
import { Body } from "./components/primitives/text/Body";
import { usePostHog } from "./hooks/usePostHog";

export const links: LinksFunction = () => {
return [
Expand Down Expand Up @@ -63,7 +62,7 @@ export function CatchBoundary() {
<Links />
</head>
<body className="bg-slate-850">
<div className="flex items-center justify-center h-screen w-screen">
<div className="flex h-screen w-screen items-center justify-center">
<div className="flex flex-col items-center justify-center space-y-4">
<h1>
{caught.status} {caught.statusText}
Expand All @@ -89,7 +88,7 @@ export function ErrorBoundary({ error }: { error: any }) {
<Links />
</head>
<body className="bg-slate-850">
<div className="flex items-center justify-center h-screen w-screen">
<div className="flex h-screen w-screen items-center justify-center">
<div className="flex flex-col items-center justify-center space-y-4">
<h1>Oh no!</h1>
<Body size="small">{JSON.stringify(error)}</Body>
Expand All @@ -105,9 +104,9 @@ export function ErrorBoundary({ error }: { error: any }) {
}

function App() {
const { toastMessage, posthogProjectKey, user } =
const { toastMessage, posthogProjectKey } =
useTypedLoaderData<typeof loader>();
const postHogInitialised = useRef<boolean>(false);
usePostHog(posthogProjectKey);

useEffect(() => {
if (!toastMessage) {
Expand All @@ -127,30 +126,6 @@ function App() {
}
}, [toastMessage]);

useEffect(() => {
if (posthogProjectKey !== undefined) {
posthog.init(posthogProjectKey, {
api_host: "https://app.posthog.com",
loaded: function (posthog) {
if (user !== null) {
posthog.identify(user.id, { email: user.email });
}
},
});
postHogInitialised.current = true;
}
});

useEffect(() => {
if (postHogInitialised.current) {
if (user === null) {
posthog.reset();
} else {
posthog.identify(user.id, { email: user.email });
}
}
}, [user]);

return (
<html lang="en" className="h-full">
<head>
Expand Down
18 changes: 17 additions & 1 deletion apps/webapp/app/routes/__app/orgs/$organizationSlug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Outlet } from "@remix-run/react";
import { getOrganizationFromSlug } from "~/models/organization.server";
import { typedjson } from "remix-typedjson";
import { getRuntimeEnvironmentFromRequest } from "~/models/runtimeEnvironment.server";
import { analytics } from "~/services/analytics.server";

export const loader = async ({ request, params }: LoaderArgs) => {
const userId = await requireUserId(request);
Expand All @@ -20,11 +21,26 @@ export const loader = async ({ request, params }: LoaderArgs) => {
throw new Response("Not Found", { status: 404 });
}

analytics.organization.identify({ organization });

const currentEnvironmentSlug = await getRuntimeEnvironmentFromRequest(
request
);
const currentEnvironment = organization.environments?.find(
(e) => e.slug === currentEnvironmentSlug
);

return typedjson({ organization, currentEnvironmentSlug });
if (currentEnvironment == null) {
throw new Response("Not Found", { status: 404 });
}

analytics.environment.identify({ environment: currentEnvironment });

return typedjson({
organization,
currentEnvironment,
currentEnvironmentSlug,
});
};

export default function Organization() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { buildExternalSourceUrl } from "~/models/externalSource.server";
import { getIntegrations } from "~/models/integrations.server";
import { getRuntimeEnvironmentFromRequest } from "~/models/runtimeEnvironment.server";
import { getWorkflowFromSlugs } from "~/models/workflow.server";
import { analytics } from "~/services/analytics.server";
import { requireUser } from "~/services/session.server";

type ExternalSourceConfig =
Expand Down Expand Up @@ -59,17 +60,15 @@ export const loader = async ({ request, params }: LoaderArgs) => {
throw new Response("Not Found", { status: 404 });
}

analytics.workflow.identify({ workflow });

const integrations = getIntegrations(user.admin);

const rules = workflow.rules.map((r) => ({
...r,
trigger: TriggerMetadataSchema.parse(r.trigger),
}));

const currentEnvironmentSlug = await getRuntimeEnvironmentFromRequest(
request
);

const allConnections = await getConnectedApiConnectionsForOrganizationSlug({
slug: organizationSlug,
});
Expand Down
12 changes: 6 additions & 6 deletions apps/webapp/app/routes/__app/orgs/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export default function NewOrganizationPage() {
}, [actionData]);

return (
<main className="w-full h-full flex items-center justify-center">
<div className="flex flex-col gap-y-3.5 min-w-[400px] bg-slate-800 border border-slate-800 rounded-md p-10 shadow-md">
<main className="flex h-full w-full items-center justify-center">
<div className="flex min-w-[400px] flex-col gap-y-3.5 rounded-md border border-slate-800 bg-slate-800 p-10 shadow-md">
<Header1 size="large" className="">
Create a new Organization
</Header1>
Expand All @@ -63,21 +63,21 @@ export default function NewOrganizationPage() {
width: "100%",
}}
>
<div className="flex flex-col gap-4 mb-3">
<div className="mb-3 flex flex-col gap-4">
<div className="flex w-full flex-col gap-1">
<label className="text-slate-500 text-sm">
<label className="text-sm text-slate-500">
Name your Organization
</label>
<div className="group flex">
<div className="flex justify-end pointer-events-none z-10 -mr-8 items-center w-8">
<div className="pointer-events-none z-10 -mr-8 flex w-8 items-center justify-end">
<BookmarkIcon className="h-5 w-5 text-slate-600" />
</div>
<input
ref={titleRef}
name="title"
autoFocus
placeholder="e.g. Company name"
className="relative w-full pl-10 pr-3 py-2 rounded bg-slate-850 group-focus:border-indigo-500 placeholder:text-slate-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500"
className="relative w-full rounded bg-slate-850 py-2 pl-10 pr-3 placeholder:text-slate-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 group-focus:border-indigo-500"
aria-invalid={actionData?.errors?.title ? true : undefined}
aria-errormessage={
actionData?.errors?.title ? "title-error" : undefined
Expand Down
Loading