Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: OPTIC-1378: Track login / signup with GA client id #6829

Merged
merged 12 commits into from
Jan 15, 2025
36 changes: 36 additions & 0 deletions label_studio/core/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
"""This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
"""
import os

from core.feature_flags import all_flags
from core.utils.common import collect_versions
from django.conf import settings as django_settings
from django.utils import timezone

from label_studio.core.utils.io import get_config_dir


def sentry_fe(request):
Expand Down Expand Up @@ -33,3 +38,34 @@ def settings(request):
feature_flags = all_flags(request.user)

return {'settings': django_settings, 'versions': versions, 'feature_flags': feature_flags}


def frontend_events(request):
events = []
if should_send_install_event():
events.append(
{
'name': 'setup.install',
'with_iframe': True,
}
)
return {'frontend_events': events}


_INSTALL_EVENT_SENT = False


def should_send_install_event():
# Only fire install event once per instance
# Using global variable to avoid checking file on each request
global _INSTALL_EVENT_SENT
if django_settings.VERSION_EDITION == 'Community' and not _INSTALL_EVENT_SENT:
install_file = os.path.join(get_config_dir(), 'install.txt')
if not os.path.exists(install_file):
with open(install_file, 'w') as f:
f.write(timezone.now().isoformat())
_INSTALL_EVENT_SENT = True
return True
_INSTALL_EVENT_SENT = True

return False
1 change: 1 addition & 0 deletions label_studio/core/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'core.context_processors.settings',
'core.context_processors.frontend_events',
],
'builtins': ['django.templatetags.i18n'],
},
Expand Down
1 change: 1 addition & 0 deletions label_studio/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
feature_flags_default_value: {{ settings.FEATURE_FLAGS_DEFAULT_VALUE|json_dumps_ensure_ascii|safe }},
server_id: {{ request.server_id|json_dumps_ensure_ascii|safe }},
collect_analytics: {{ settings.COLLECT_ANALYTICS|yesno:"true,false" }},
frontend_events: {{ frontend_events|json_dumps_ensure_ascii|safe }},

{% block app_more_settings %}
flags: {
Expand Down
50 changes: 50 additions & 0 deletions label_studio/templates/simple.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% load static %}
{% load i18n %}
{% load filters %}

<!doctype html>
<html lang="en">
Expand Down Expand Up @@ -29,6 +30,55 @@
</head>

<body>
<script nonce="{{request.csp_nonce}}">
mcanu marked this conversation as resolved.
Show resolved Hide resolved
window.APP_SETTINGS = window.APP_SETTINGS ?? {};
window.APP_SETTINGS.collect_analytics = {{ settings.COLLECT_ANALYTICS|yesno:"true,false" }};

// Log event to the server, if analytics are enabled
// This is a fallback for when the __lsa global is not defined
// Normally this is a part of our main bundle but these pages do not use the main bundle
// and this allows us to log events from these pages
const logEvent = (eventName, metadata = {}) => {
if (!window.APP_SETTINGS?.collect_analytics) return;

const payload = {
...metadata,
event: eventName,
url: window.location.href,
};

window.requestIdleCallback(() => {
const params = new URLSearchParams({ __: JSON.stringify(payload) });
const url = `/__lsa/?${params}`;
try {
if (navigator.sendBeacon) {
navigator.sendBeacon(url);
} else {
const img = new Image();
img.src = url;
}
} catch {
// Ignore errors here
}
});
};
if (!window.__lsa) {
window.__lsa = logEvent;
}

mcanu marked this conversation as resolved.
Show resolved Hide resolved
const frontendEvents = {{ frontend_events|json_dumps_ensure_ascii|safe }};
frontendEvents.forEach((event) => {
if (window.APP_SETTINGS.collect_analytics && event.with_iframe) {
const iframe = document.createElement('iframe');
iframe.src = `https://www.labelstud.io/track/?event=${event.name}`;
iframe.style.display = 'none';
iframe.style.visibility = 'hidden';
document.body.appendChild(iframe);
}

__lsa(event.name);
});
</script>
{% block content %}
{% endblock %}

Expand Down
35 changes: 0 additions & 35 deletions label_studio/users/templates/users/new-ui/user_tips.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,6 @@

<script nonce="{{request.csp_nonce}}">

window.APP_SETTINGS = window.APP_SETTINGS ?? {};
window.APP_SETTINGS.collect_analytics = {{ settings.COLLECT_ANALYTICS|yesno:"true,false" }};

// Log event to the server, if analytics are enabled
// This is a fallback for when the __lsa global is not defined
// Normally this is a part of our main bundle but these pages do not use the main bundle
// and this allows us to log events from these pages
const logEvent = (eventName, metadata = {}) => {
if (!window.APP_SETTINGS?.collect_analytics) return;

const payload = {
...metadata,
event: eventName,
url: window.location.href,
};

window.requestIdleCallback(() => {
const params = new URLSearchParams({ __: JSON.stringify(payload) });
const url = `/__lsa/?${params}`;
try {
if (navigator.sendBeacon) {
navigator.sendBeacon(url);
} else {
const img = new Image();
img.src = url;
}
} catch {
// Ignore errors here
}
});
};
if (!window.__lsa) {
window.__lsa = logEvent;
}

const SERVER_ID = {{ request.server_id|json_dumps_ensure_ascii|safe }};
const EVENT_NAMESPACE_KEY = "heidi_tips";
const CACHE_KEY = "heidi_live_tips_collection";
Expand Down
18 changes: 18 additions & 0 deletions web/apps/labelstudio/src/app/RootPage.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { Menubar } from "../components/Menubar/Menubar";
import { ProjectRoutes } from "../routes/ProjectRoutes";
import { useOrgValidation } from "../hooks/useOrgValidation";
import { useEffect } from "react";

export const RootPage = ({ content }) => {
useOrgValidation();
const pinned = localStorage.getItem("sidebar-pinned") === "true";
const opened = pinned && localStorage.getItem("sidebar-opened") === "true";

useEffect(() => {
const frontendEvents = window.APP_SETTINGS.frontend_events;

frontendEvents.forEach((event) => {
if (window.APP_SETTINGS.collect_analytics && event.with_iframe) {
const iframe = document.createElement("iframe");
iframe.src = `https://www.labelstud.io/track/?event=${event.name}`;
iframe.style.display = "none";
iframe.style.visibility = "hidden";
document.body.appendChild(iframe);
}

// TODO: __lsa(event.name)
// I don't know why but __lsa isn't defined yet here
});
}, []);

return (
<Menubar
enabled={true}
Expand Down
Loading