Skip to content

Commit 2011420

Browse files
committed
First cut at analytics
Signed-off-by: Heiko W. Rupp <[email protected]>
1 parent fc3eac0 commit 2011420

File tree

13 files changed

+179
-0
lines changed

13 files changed

+179
-0
lines changed

.env.github.example

+8
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,11 @@ IL_ENABLE_DEV_MODE=true #Enable this option if you want to enable UI features th
2323
NEXT_PUBLIC_EXPERIMENTAL_FEATURES=false
2424

2525
SLACK_WEBHOOK_URL=
26+
27+
# Analtyics setup
28+
# UMAMI_KEY: 'umami-key'
29+
# UMAMI_HOST_URL: 'http://umami-host:3000'
30+
# SEGMENT_KEY: 'segment-key'
31+
# Next needs to be in one line
32+
# SEGMENT_INTEGRATIONS: '{"Segment.io": {"apiHost": "some.host.com/connections/api/v1","protocol": "https"}}'
33+
# SEGMENT_CDN: 'https://some.host.com/connections/cdn'

.env.native.example

+9
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,12 @@ NEXT_PUBLIC_EXPERIMENTAL_FEATURES=false
1414
# IL_FILE_CONVERSION_SERVICE=http://localhost:5001 # Uncomment and fill in the http://host:port if the docling conversion service is running.
1515
# NEXT_PUBLIC_API_SERVER=http://localhost:8080 # Uncomment and point to the URL the api-server is running on. Native mode only and needs to be running on the same host as the UI.
1616
# NEXT_PUBLIC_MODEL_SERVER_URL=http://x.x.x.x # Used for model chat evaluation vLLM instances. Currently, server side rendering is not supported so the client must have access to this address for model chat evaluation to function in the UI. Currently ports, 8000 & 8001 are hardcoded and why it is not an option to set.
17+
18+
19+
# Analtyics setup
20+
# UMAMI_KEY: 'umami-key'
21+
# UMAMI_HOST_URL: 'http://umami-host:3000'
22+
# SEGMENT_KEY: 'segment-key'
23+
# Next needs to be in one line
24+
# SEGMENT_INTEGRATIONS: '{"Segment.io": {"apiHost": "some.host.com/connections/api/v1","protocol": "https"}}'
25+
# SEGMENT_CDN: 'https://some.host.com/connections/cdn'

package-lock.json

+68
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/api/analyticsConfig/route.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { NextResponse } from 'next/server';
2+
3+
export const dynamic = 'force-dynamic';
4+
5+
export async function GET() {
6+
const uiConfig = {
7+
umamiKey: process.env.UMAMI_KEY || '',
8+
umamiHostUrl: process.env.UMAMI_HOST_URL || '',
9+
segmentKey: process.env.SEGMENT_KEY || '',
10+
segmentCdn: process.env.SEGMENT_CDN || '',
11+
segmentIntegrations: {}
12+
} ;
13+
14+
const tmp = process.env.SEGMENT_INTEGRATIONS;
15+
if (tmp) {
16+
uiConfig.segmentIntegrations = JSON.parse(tmp);
17+
}
18+
19+
return NextResponse.json(uiConfig);
20+
}

src/app/playground/chat/page.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const ChatPage: React.FC = () => {
3636
variant="link"
3737
isInline
3838
onClick={(e) => {
39+
window.analytics.trackSingleItem('Chat Cleared', {});
3940
e.preventDefault();
4041
router.push('/playground/endpoints');
4142
}}

src/app/playground/endpoints/page.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ const EndpointsPage: React.FC = () => {
6666
};
6767

6868
const handleSaveEndpoint = () => {
69+
window.analytics.trackSingleItem(currentEndpoint ? 'Model Endpoint edited' : 'Model Endpoint added', {})
6970
const updatedUrl = removeTrailingSlash(url);
7071
if (currentEndpoint) {
7172
const updatedEndpoint: ExtendedEndpoint = {

src/components/AppLayout.tsx

+23
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
import { BarsIcon } from '@patternfly/react-icons';
3333
import ThemePreference from '@/components/ThemePreference/ThemePreference';
3434
import '../styles/globals.scss';
35+
import { initAnalytics } from '@/components/analytics/initAnalytics';
3536

3637
interface IAppLayout {
3738
children: React.ReactNode;
@@ -61,6 +62,28 @@ const AppLayout: React.FunctionComponent<IAppLayout> = ({ children, className })
6162
fetchExperimentalFeature();
6263
}, []);
6364

65+
React.useEffect(() => {
66+
console.log("Get analytics effect " + window.analytics);
67+
if (!window.analytics) {
68+
initAnalytics();
69+
}
70+
}, []);
71+
72+
React.useEffect(() => {
73+
if (window.analytics) {
74+
window.analytics.trackPageView(pathname);
75+
}
76+
77+
}, [pathname]);
78+
79+
React.useEffect(() => {
80+
console.log(("Identify effect " + session?.user) )
81+
if (window.analytics) {
82+
// TODO we may potentially want to hash this. Also different code per target install?
83+
window.analytics.identify(session?.user?.name ? session.user.name : '-unknown-user-name ');
84+
}
85+
},[session?.user?.name,session?.user]);
86+
6487
React.useEffect(() => {
6588
if (status === 'loading') return; // Do nothing while loading
6689
if (!session && pathname !== '/login') {

src/components/Contribute/ContributionWizard/ContributionWizard.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,11 @@ export const ContributionWizard: React.FunctionComponent<Props> = ({
139139

140140
const autoFillForm = (): void => {
141141
setFormData(isSkillContribution ? { ...autoFillSkillsFields } : { ...autoFillKnowledgeFields });
142+
window.analytics.trackSingleItem('AutoFill Clicked', {isSkillContribution});
142143
};
143144

144145
const handleCancel = () => {
146+
window.analytics.trackSingleItem('Contribution Cancelled', {isSkillContribution});
145147
router.push('/dashboard');
146148
};
147149

src/components/Contribute/Knowledge/KnowledgeSeedExamples/KnowledgeSeedExamples.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,12 @@ const KnowledgeSeedExamples: React.FC<Props> = ({ isGithubMode, seedExamples, on
110110
seedExample.immutable = false;
111111
seedExample.isExpanded = true;
112112
onUpdateSeedExamples([...seedExamples, seedExample]);
113+
window.analytics.trackSingleItem("Added Seed", {isSkillContribution: false});
113114
};
114115

115116
const deleteSeedExample = (seedExampleIndex: number): void => {
116117
onUpdateSeedExamples(seedExamples.filter((_, index: number) => index !== seedExampleIndex));
118+
window.analytics.trackSingleItem("Deleted Seed", {isSkillContribution: false});
117119
};
118120

119121
return (

src/components/Contribute/Knowledge/KnowledgeWizard/KnowledgeWizard.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ export const KnowledgeWizard: React.FunctionComponent<KnowledgeFormProps> = ({ k
340340
};
341341

342342
const handleSubmit = async (githubUsername: string): Promise<boolean> => {
343+
window.analytics.trackSingleItem("Knowledge Contribution Submitted", {}); // TODO add data
343344
if (knowledgeEditFormData) {
344345
const result = isGithubMode
345346
? await updateGithubKnowledgeData(session, knowledgeFormData, knowledgeEditFormData, updateActionGroupAlertContent)
@@ -363,6 +364,7 @@ export const KnowledgeWizard: React.FunctionComponent<KnowledgeFormProps> = ({ k
363364

364365
const onYamlUploadKnowledgeFillForm = (data: KnowledgeYamlData): void => {
365366
setKnowledgeFormData(addYamlUploadKnowledge(knowledgeFormData, data));
367+
window.analytics.trackSingleItem('Knowledge Yaml uploaded', {});
366368
updateActionGroupAlertContent({
367369
title: 'YAML Uploaded Successfully',
368370
message: 'Your knowledge form has been populated based on the uploaded YAML file.',

src/components/Contribute/Skill/SkillSeedExamples/SkillSeedExamples.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ const SkillSeedExamples: React.FC<Props> = ({ seedExamples, onSelectContext, onU
4949
seedExample.immutable = false;
5050
seedExample.isExpanded = true;
5151
onUpdateSeedExamples([...seedExamples, seedExample]);
52+
window.analytics.trackSingleItem("Added Seed", {isSkillContribution: true});
5253
};
5354

5455
const deleteSeedExample = (seedExampleIndex: number): void => {
5556
onUpdateSeedExamples(seedExamples.filter((_, index: number) => index !== seedExampleIndex));
57+
window.analytics.trackSingleItem("Deleted Seed", {isSkillContribution: true});
5658
};
5759

5860
return (

src/components/Contribute/Skill/SkillWizard/SkillWizard.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ export const SkillWizard: React.FunctionComponent<Props> = ({ skillEditFormData,
187187
};
188188

189189
const handleSubmit = async (githubUsername: string): Promise<boolean> => {
190+
window.analytics.trackSingleItem("Knowledge Contribution Submitted", {}); // TODO better place, add data
190191
if (skillEditFormData) {
191192
const result = isGithubMode
192193
? await updateGithubSkillData(session, skillFormData, skillEditFormData, updateActionGroupAlertContent)
@@ -211,6 +212,7 @@ export const SkillWizard: React.FunctionComponent<Props> = ({ skillEditFormData,
211212

212213
const onYamlUploadSkillFillForm = (data: SkillYamlData): void => {
213214
setSkillFormData(addYamlUploadSkill(skillFormData, data));
215+
window.analytics.trackSingleItem('Skill Yaml uploaded', {});
214216
updateActionGroupAlertContent({
215217
title: 'YAML Uploaded Successfully',
216218
message: 'Your skill form has been populated based on the uploaded YAML file.',
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use client'
2+
3+
import { TrackingApi } from '@patternfly/chatbot/src/tracking/tracking_api';
4+
import { getTrackingProviders } from '@patternfly/chatbot';
5+
6+
declare global {
7+
interface Window {
8+
analytics: TrackingApi;
9+
}
10+
}
11+
12+
export const initAnalytics = () : TrackingApi => {
13+
console.log('initAnalytics');
14+
15+
if (window.analytics) {
16+
return window.analytics;
17+
}
18+
19+
let api: TrackingApi ;
20+
fetch('/api/analyticsConfig', {
21+
method: 'GET'
22+
})
23+
.then((response) => response.json())
24+
.then((data) => {
25+
console.log(data);
26+
api = getTrackingProviders(data);
27+
window.analytics = api;
28+
return api;
29+
})
30+
.catch((error) => {
31+
console.error(error);
32+
api = getTrackingProviders({ console: true })
33+
window.analytics = api;
34+
return api;
35+
});
36+
37+
// Should not be reached, but lint complains otherwise
38+
return getTrackingProviders({ console: true });
39+
};

0 commit comments

Comments
 (0)