Skip to content

Commit

Permalink
[OPIK-63] [New feature] Add segment to Opik Cloud (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
andriidudar authored Sep 10, 2024
1 parent d979e15 commit 4fd6400
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 1 deletion.
1 change: 1 addition & 0 deletions apps/opik-frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Comet Opik</title>
<script type='text/javascript' src='../../config.js?version=1725550071774'></script>
</head>
<body class="size-full">
<div class="size-full" id="root"></div>
Expand Down
6 changes: 6 additions & 0 deletions apps/opik-frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apps/opik-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@tanstack/react-router": "^1.36.3",
"@tanstack/react-table": "^8.17.3",
"@types/md5": "^2.3.5",
"@types/segment-analytics": "^0.0.38",
"@uiw/react-codemirror": "^4.23.0",
"axios": "^1.7.2",
"class-variance-authority": "^0.7.0",
Expand Down
1 change: 1 addition & 0 deletions apps/opik-frontend/public/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
window.environmentVariablesOverwrite = {};
3 changes: 3 additions & 0 deletions apps/opik-frontend/src/plugins/comet/WorkspacePreloader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { MoveLeft } from "lucide-react";
import useUser from "./useUser";
import { buildUrl } from "./utils";
import imageLogoUrl from "/images/logo_and_text.png";
import useSegment from "@/plugins/comet/analytics/useSegment";

type WorkspacePreloaderProps = {
children: React.ReactNode;
Expand All @@ -29,6 +30,8 @@ const WorkspacePreloader: React.FunctionComponent<WorkspacePreloaderProps> = ({
});
const isRootPath = matchRoute({ to: "/" });

useSegment(user?.userName);

if (isLoading) {
return <Loader />;
}
Expand Down
16 changes: 16 additions & 0 deletions apps/opik-frontend/src/plugins/comet/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import initSnippet from "./snippet";

export const initAnalytics = (writeKey?: string) => {
if (writeKey) {
initSnippet(writeKey);
}
};

export const trackEvent = (
name: string,
properties: Record<string, unknown>,
) => {
if (window.analytics) {
window.analytics.track(name, properties);
}
};
83 changes: 83 additions & 0 deletions apps/opik-frontend/src/plugins/comet/analytics/snippet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
export default function initSnippet(writeKey) {
var i = "analytics",
analytics = (window[i] = window[i] || []);
if (!analytics.initialize)
if (analytics.invoked)
window.console &&
console.error &&
console.error("Segment snippet included twice.");
else {
analytics.invoked = !0;
analytics.methods = [
"trackSubmit",
"trackClick",
"trackLink",
"trackForm",
"pageview",
"identify",
"reset",
"group",
"track",
"ready",
"alias",
"debug",
"page",
"screen",
"once",
"off",
"on",
"addSourceMiddleware",
"addIntegrationMiddleware",
"setAnonymousId",
"addDestinationMiddleware",
"register",
];
analytics.factory = function (e) {
return function () {
if (window[i].initialized)
return window[i][e].apply(window[i], arguments);
var n = Array.prototype.slice.call(arguments);
if (
["track", "screen", "alias", "group", "page", "identify"].indexOf(
e,
) > -1
) {
var c = document.querySelector("link[rel='canonical']");
n.push({
__t: "bpc",
c: (c && c.getAttribute("href")) || void 0,
p: location.pathname,
u: location.href,
s: location.search,
t: document.title,
r: document.referrer,
});
}
n.unshift(e);
analytics.push(n);
return analytics;
};
};
for (var n = 0; n < analytics.methods.length; n++) {
var key = analytics.methods[n];
analytics[key] = analytics.factory(key);
}
analytics.load = function (key, n) {
var t = document.createElement("script");
t.type = "text/javascript";
t.async = !0;
t.setAttribute("data-global-segment-analytics-key", i);
t.src =
"https://cdn.segment.com/analytics.js/v1/" +
key +
"/analytics.min.js";
var r = document.getElementsByTagName("script")[0];
r.parentNode.insertBefore(t, r);
analytics._loadOptions = n;
};
analytics._writeKey = writeKey;
analytics.SNIPPET_VERSION = "5.2.0";
analytics.load(writeKey);
analytics.page();
}
}
11 changes: 11 additions & 0 deletions apps/opik-frontend/src/plugins/comet/analytics/useSegment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useEffect } from "react";

const useSegment = (username?: string) => {
useEffect(() => {
if (window.analytics && username) {
window.analytics.identify(username);
}
}, [username]);
};

export default useSegment;
16 changes: 16 additions & 0 deletions apps/opik-frontend/src/plugins/comet/init.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// <reference types="@types/segment-analytics" />

import { initAnalytics } from "./analytics";

type EnvironmentVariablesOverwrite = {
OPIK_SEGMENT_ID?: string;
};

declare global {
interface Window {
analytics: SegmentAnalytics.AnalyticsJS;
environmentVariablesOverwrite: EnvironmentVariablesOverwrite;
}
}

initAnalytics(window.environmentVariablesOverwrite.OPIK_SEGMENT_ID);
9 changes: 8 additions & 1 deletion apps/opik-frontend/src/store/PluginsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@ type PluginStore = {
GetStartedPage: React.ComponentType | null;
UserMenu: React.ComponentType | null;
WorkspacePreloader: React.ComponentType<{ children: React.ReactNode }> | null;
init: unknown;
setupPlugins: (folderName: string) => Promise<void>;
};

const VALID_PLUGIN_FOLDER_NAMES = ["comet"];
const PLUGIN_NAMES = ["GetStartedPage", "UserMenu", "WorkspacePreloader"];
const PLUGIN_NAMES = [
"GetStartedPage",
"UserMenu",
"WorkspacePreloader",
"init",
];

const usePluginsStore = create<PluginStore>((set) => ({
GetStartedPage: null,
UserMenu: null,
WorkspacePreloader: null,
init: null,
setupPlugins: async (folderName: string) => {
if (!VALID_PLUGIN_FOLDER_NAMES.includes(folderName)) {
return set({ WorkspacePreloader });
Expand Down

0 comments on commit 4fd6400

Please sign in to comment.