Skip to content

Commit 4ff6aa5

Browse files
authored
docs[minor]: Swap gtag for supabase (langchain-ai#18937)
Added deps: - `@supabase/supabase-js` - for sending inserts - `supabase` - dev dep, for generating types via cli - `dotenv` for loading env vars Added script: - `yarn gen` - will auto generate the database schema types using the supabase CLI. Not necessary for development, but is useful. Requires authing with the supabase CLI (will error out w/ instructions if you're not authed). Added functionality: - pulls users IP address (using a free endpoint: `https://api.ipify.org` so we can filter out abuse down the line) TODO: - [x] add env vars to vercel
1 parent 5c2f7e6 commit 4ff6aa5

File tree

8 files changed

+274
-15840
lines changed

8 files changed

+274
-15840
lines changed

docs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/.quarto/
2+
src/supabase.d.ts

docs/docusaurus.config.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Note: type annotations allow type checking and IDEs autocompletion
55
// eslint-disable-next-line import/no-extraneous-dependencies
66
const { ProvidePlugin } = require("webpack");
7-
const path = require("path");
7+
require("dotenv").config();
88

99
const baseLightCodeBlockTheme = require("prism-react-renderer/themes/vsLight");
1010
const baseDarkCodeBlockTheme = require("prism-react-renderer/themes/vsDark");
@@ -335,12 +335,13 @@ const config = {
335335
src: "https://www.googletagmanager.com/gtag/js?id=G-9B66JQQH2F",
336336
async: true,
337337
},
338-
{
339-
src: "https://www.googletagmanager.com/gtag/js?id=G-WFT0J048RF",
340-
async: true,
341-
}
342338
],
343-
339+
340+
customFields: {
341+
NEXT_PUBLIC_SUPABASE_PUBLIC_KEY:
342+
process.env.NEXT_PUBLIC_SUPABASE_PUBLIC_KEY,
343+
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
344+
},
344345
};
345346

346347
module.exports = config;

docs/package-lock.json

Lines changed: 0 additions & 15800 deletions
This file was deleted.

docs/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@
1616
"lint:fix": "yarn lint --fix",
1717
"precommit": "lint-staged",
1818
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,md,mdx}\"",
19-
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,md,mdx}\""
19+
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,md,mdx}\"",
20+
"gen": "yarn gen:supabase",
21+
"gen:supabase": "npx supabase gen types typescript --project-id 'xsqpnijvmbodcxyapnyq' --schema public > ./src/supabase.d.ts"
2022
},
2123
"dependencies": {
2224
"@docusaurus/core": "2.4.3",
2325
"@docusaurus/preset-classic": "2.4.3",
2426
"@docusaurus/remark-plugin-npm2yarn": "^2.4.3",
2527
"@docusaurus/theme-mermaid": "2.4.3",
2628
"@mdx-js/react": "^1.6.22",
29+
"@supabase/supabase-js": "^2.39.7",
2730
"clsx": "^1.2.1",
2831
"cookie": "^0.6.0",
2932
"json-loader": "^0.5.7",
@@ -36,6 +39,7 @@
3639
"devDependencies": {
3740
"@babel/eslint-parser": "^7.18.2",
3841
"docusaurus-plugin-typedoc": "next",
42+
"dotenv": "^16.4.5",
3943
"eslint": "^8.19.0",
4044
"eslint-config-airbnb": "^19.0.4",
4145
"eslint-config-prettier": "^8.5.0",
@@ -45,6 +49,7 @@
4549
"eslint-plugin-react": "^7.30.1",
4650
"eslint-plugin-react-hooks": "^4.6.0",
4751
"prettier": "^2.7.1",
52+
"supabase": "^1.148.6",
4853
"typedoc": "^0.24.4",
4954
"typedoc-plugin-markdown": "next",
5055
"yaml-loader": "^0.8.0"

docs/src/analytics.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

docs/src/theme/Feedback.js

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable no-return-assign, react/jsx-props-no-spreading */
22
import React, { useState, useEffect } from "react";
3-
import gtag from "../analytics";
3+
import { createClient } from "@supabase/supabase-js";
44

55
const useCookie = () => {
66
/**
@@ -90,27 +90,69 @@ function SvgThumbsDown() {
9090
);
9191
}
9292

93+
/**
94+
* Generated type for the Supabase DB schema.
95+
* @typedef {import('../supabase').Database} Database
96+
*/
97+
9398
const FEEDBACK_COOKIE_PREFIX = "feedbackSent";
99+
/** @type {Database["public"]["Enums"]["project_type"]} */
100+
const LANGCHAIN_PROJECT_NAME = "langchain_py_docs";
101+
102+
/**
103+
* @returns {Promise<string>}
104+
*/
105+
const getIpAddress = async () => {
106+
const response = await fetch("https://api.ipify.org?format=json");
107+
return (await response.json()).ip;
108+
};
94109

95110
export default function Feedback() {
96111
const { setCookie, checkCookie } = useCookie();
97112
const [feedbackSent, setFeedbackSent] = useState(false);
98113

99-
/**
100-
* @param {"good" | "bad"} feedback
101-
*/
102-
const handleFeedback = (feedback) => {
114+
/** @param {"good" | "bad"} feedback */
115+
const handleFeedback = async (feedback) => {
116+
if (process.env.NODE_ENV !== "production") {
117+
console.log("Feedback (dev)");
118+
return;
119+
}
120+
103121
const cookieName = `${FEEDBACK_COOKIE_PREFIX}_${window.location.pathname}`;
104122
if (checkCookie(cookieName)) {
105123
return;
106124
}
107125

108-
const feedbackEnv =
109-
process.env.NODE_ENV === "production"
110-
? "page_feedback"
111-
: "page_feedback_dev";
126+
/** @type {Database} */
127+
const supabase = createClient(
128+
process.env.NEXT_PUBLIC_SUPABASE_URL,
129+
process.env.NEXT_PUBLIC_SUPABASE_PUBLIC_KEY
130+
);
131+
try {
132+
const ipAddress = await getIpAddress();
133+
134+
/**
135+
* "id" and "created_at" are automatically generated by Supabase
136+
* @type {Omit<Database["public"]["Tables"]["feedback"]["Row"], "id" | "created_at">}
137+
*/
138+
const data = {
139+
is_good: feedback === "good",
140+
url: window.location.pathname,
141+
user_ip: ipAddress,
142+
project: LANGCHAIN_PROJECT_NAME,
143+
};
144+
145+
const { error } = await supabase.from("feedback").insert(data);
146+
if (error) {
147+
throw error;
148+
}
149+
} catch (e) {
150+
console.error("Failed to send feedback", {
151+
e,
152+
});
153+
return;
154+
}
112155

113-
gtag("event", `${feedbackEnv}_${feedback}`, {});
114156
// Set a cookie to prevent feedback from being sent multiple times
115157
setCookie(cookieName, window.location.pathname, 1);
116158
setFeedbackSent(true);
@@ -161,16 +203,16 @@ export default function Feedback() {
161203
{...defaultFields}
162204
role="button" // Make it recognized as an interactive element
163205
tabIndex={0} // Make it focusable
164-
onKeyDown={(e) => {
206+
onKeyDown={async (e) => {
165207
// Handle keyboard interaction
166208
if (e.key === "Enter" || e.key === " ") {
167209
e.preventDefault();
168-
handleFeedback("good");
210+
await handleFeedback("good");
169211
}
170212
}}
171-
onClick={(e) => {
213+
onClick={async (e) => {
172214
e.preventDefault();
173-
handleFeedback("good");
215+
await handleFeedback("good");
174216
}}
175217
>
176218
<SvgThumbsUp />
@@ -179,16 +221,16 @@ export default function Feedback() {
179221
{...defaultFields}
180222
role="button" // Make it recognized as an interactive element
181223
tabIndex={0} // Make it focusable
182-
onKeyDown={(e) => {
224+
onKeyDown={async (e) => {
183225
// Handle keyboard interaction
184226
if (e.key === "Enter" || e.key === " ") {
185227
e.preventDefault();
186-
handleFeedback("bad");
228+
await handleFeedback("bad");
187229
}
188230
}}
189-
onClick={(e) => {
231+
onClick={async (e) => {
190232
e.preventDefault();
191-
handleFeedback("bad");
233+
await handleFeedback("bad");
192234
}}
193235
>
194236
<SvgThumbsDown />

docs/static/js/google_analytics.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,3 @@ function gtag(){dataLayer.push(arguments);}
33
gtag('js', new Date());
44

55
gtag('config', 'G-9B66JQQH2F');
6-
7-
// Only for feedback
8-
function gtagFeedback(){dataLayer.push(arguments);}
9-
gtagFeedback('js', new Date());
10-
11-
gtagFeedback('config', 'G-WFT0J048RF');

0 commit comments

Comments
 (0)