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

Implement Sentry error logging for GUI #1153

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
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
10 changes: 7 additions & 3 deletions .github/workflows/build-gui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,15 @@ jobs:
node-version-file: '.node-version'
cache: 'pnpm'

- name: Install dependencies
shell: bash
run: pnpm i

- name: Build
shell: bash
run: |
pnpm i
pnpm run skipbundler --config $( ./gui/scripts/gitversion.mjs )
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: pnpm run skipbundler --config $( ./gui/scripts/gitversion.mjs )

- if: matrix.os == 'windows-latest'
name: Upload a Build Artifact (Windows)
Expand Down
38 changes: 26 additions & 12 deletions .github/workflows/gradle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,13 @@ jobs:
node-version-file: '.node-version'
cache: 'pnpm'

- name: Build GUI
run: |
pnpm i
cd gui && pnpm run build
- name: Install dependencies
run: pnpm i

- name: Build
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: cd gui && pnpm run build

- name: Build with Gradle
run: ./gradlew :server:android:assembleDebug
Expand Down Expand Up @@ -191,10 +194,13 @@ jobs:
node-version-file: '.node-version'
cache: 'pnpm'

- name: Install dependencies
run: pnpm i

- name: Build
run: |
pnpm i
pnpm run tauri build --config $( ./gui/scripts/gitversion.mjs )
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: pnpm run tauri build --config $( ./gui/scripts/gitversion.mjs )

- name: Make GUI tarball
run: |
Expand Down Expand Up @@ -266,11 +272,15 @@ jobs:
node-version-file: '.node-version'
cache: 'pnpm'

- name: Build
- name: Install dependencies
run: |
rustup target add x86_64-apple-darwin
pnpm i
pnpm run tauri build --target universal-apple-darwin --config $( ./gui/scripts/gitversion.mjs )

- name: Build
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: pnpm run tauri build --target universal-apple-darwin --config $( ./gui/scripts/gitversion.mjs )

- name: Modify Application
run: |
Expand Down Expand Up @@ -338,11 +348,15 @@ jobs:
node-version-file: '.node-version'
cache: 'pnpm'

- name: Install dependencies
shell: bash
run: pnpm i

- name: Build
shell: bash
run: |
pnpm i
pnpm run skipbundler --config $( ./gui/scripts/gitversion.mjs )
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: pnpm run skipbundler --config $( ./gui/scripts/gitversion.mjs )

- name: Bundle to zips
shell: bash
Expand Down
3 changes: 3 additions & 0 deletions gui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ yarn-error.log*

# eslint
.eslintcache

# Sentry Config File
.env.sentry-build-plugin
4 changes: 3 additions & 1 deletion gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"@hookform/resolvers": "^3.6.0",
"@react-three/drei": "^9.114.3",
"@react-three/fiber": "^8.17.10",
"@sentry/react": "^8.44.0",
"@sentry/vite-plugin": "^2.22.7",
"@tailwindcss/typography": "^0.5.15",
"@tanstack/react-query": "^5.48.0",
"@tauri-apps/api": "^2.0.2",
Expand Down Expand Up @@ -93,4 +95,4 @@
"vite": "^5.4.8",
"typescript-eslint": "^8.8.0"
}
}
}
24 changes: 21 additions & 3 deletions gui/public/i18n/en/translation.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ settings-sidebar-utils = Utilities
settings-sidebar-serial = Serial console
settings-sidebar-appearance = Appearance
settings-sidebar-notifications = Notifications
settings-sidebar-behavior = Behavior
settings-sidebar-firmware-tool = DIY Firmware Tool
settings-sidebar-advanced = Advanced

Expand Down Expand Up @@ -514,9 +515,6 @@ settings-general-gesture_control-numberTrackersOverThreshold-description = Incre

## Appearance settings
settings-interface-appearance = Appearance
settings-general-interface-dev_mode = Developer Mode
settings-general-interface-dev_mode-description = This mode can be useful if you need in-depth data or to interact with connected trackers on a more advanced level.
settings-general-interface-dev_mode-label = Developer Mode
settings-general-interface-theme = Color theme
settings-general-interface-show-navbar-onboarding = Show "{ navbar-onboarding }" on navigation bar
settings-general-interface-show-navbar-onboarding-description = This changes if the "{ navbar-onboarding }" button shows on the navigation bar.
Expand Down Expand Up @@ -548,6 +546,12 @@ settings-general-interface-feedback_sound-volume = Feedback sound volume
settings-general-interface-connected_trackers_warning = Connected trackers warning
settings-general-interface-connected_trackers_warning-description = This option will show a pop-up every time you try exiting SlimeVR while having one or more connected trackers. It reminds you to turn off your trackers when you are done to preserve battery life.
settings-general-interface-connected_trackers_warning-label = Connected trackers warning on exit

## Behavior settings
settings-interface-behavior = Behavior
settings-general-interface-dev_mode = Developer Mode
settings-general-interface-dev_mode-description = This mode can be useful if you need in-depth data or to interact with connected trackers on a more advanced level.
settings-general-interface-dev_mode-label = Developer Mode
settings-general-interface-use_tray = Minimize to system tray
settings-general-interface-use_tray-description = Lets you close the window without closing the SlimeVR Server so you can continue using it without having the GUI bothering you.
settings-general-interface-use_tray-label = Minimize to system tray
Expand All @@ -559,6 +563,12 @@ settings-general-interface-discord_presence-message = { $amount ->
[one] Using 1 tracker
*[other] Using { $amount } trackers
}
settings-interface-behavior-error_tracking = Error collection via Sentry.io
settings-interface-behavior-error_tracking-description =
We send errors, load times and operating system information to be able to fix issues found on SlimeVR, we collect these via Sentry.io.

We don't collect any of your personal information (not even your IP address), but we do care that you want to give your consent for it.
settings-interface-behavior-error_tracking-label = Send errors to developers

## Serial settings
settings-serial = Serial Console
Expand Down Expand Up @@ -1244,3 +1254,11 @@ unknown_device-modal-description = There is a new tracker with MAC address <b>{$
Do you want to connect it to SlimeVR?
unknown_device-modal-confirm = Sure!
unknown_device-modal-forget = Ignore it

## Error collection consent modal
error_collection_modal-title = Can we collect errors?
error_collection_modal-description = { settings-interface-behavior-error_tracking-description }

You can later change this on the interface section of settings
error_collection_modal-confirm = I agree
error_collection_modal-cancel = I don't want to
7 changes: 5 additions & 2 deletions gui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { AppLayout } from './AppLayout';
import { Preload } from './components/Preload';
import { UnknownDeviceModal } from './components/UnknownDeviceModal';
import { useDiscordPresence } from './hooks/discord-presence';
import { withSentryReactRouterV6Routing } from '@sentry/react';
import { EmptyLayout } from './components/EmptyLayout';
import { AdvancedSettings } from './components/settings/pages/AdvancedSettings';
import { FirmwareUpdate } from './components/firmware-update/FirmwareUpdate';
Expand All @@ -65,6 +66,8 @@ export const VersionContext = createContext('');
export const DOCS_SITE = 'https://docs.slimevr.dev';
export const SLIMEVR_DISCORD = 'https://discord.gg/slimevr';

const SentryRoutes = withSentryReactRouterV6Routing(Routes);

function Layout() {
const { isMobile } = useBreakpoint('mobile');
useDiscordPresence();
Expand All @@ -74,7 +77,7 @@ function Layout() {
<SerialDetectionModal></SerialDetectionModal>
<VersionUpdateModal></VersionUpdateModal>
<UnknownDeviceModal></UnknownDeviceModal>
<Routes>
<SentryRoutes>
<Route element={<AppLayout />}>
<Route
path="/"
Expand Down Expand Up @@ -166,7 +169,7 @@ function Layout() {
</Route>
<Route path="*" element={<TopBar></TopBar>}></Route>
</Route>
</Routes>
</SentryRoutes>
</>
);
}
Expand Down
9 changes: 8 additions & 1 deletion gui/src/AppLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useLayoutEffect } from 'react';
import { useEffect, useLayoutEffect } from 'react';
import { useConfig } from './hooks/config';
import { Outlet, useNavigate } from 'react-router-dom';
import { getSentryOrCompute } from './utils/sentry';

export function AppLayout() {
const { loading, config } = useConfig();
Expand Down Expand Up @@ -33,6 +34,12 @@ export function AppLayout() {
}
}, [config?.doneOnboarding]);

useEffect(() => {
if (config?.errorTracking !== undefined) {
getSentryOrCompute(config.errorTracking ?? false);
}
}, [config?.errorTracking]);

// const location = useLocation();
// const navigationType = useNavigationType();
// useEffect(() => {
Expand Down
54 changes: 54 additions & 0 deletions gui/src/components/ErrorConsentModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useLocalization } from '@fluent/react';
import { BaseModal } from './commons/BaseModal';
import { Button } from './commons/Button';
import { Typography } from './commons/Typography';

export function ErrorConsentModal({
isOpen = true,
cancel,
accept,
}: {
/**
* Is the parent/sibling component opened?
*/
isOpen: boolean;
/**
* Function to trigger when you still want to close the app
*/
accept: () => void;
/**
* Function to trigger when cancelling app close
*/
cancel?: () => void;
}) {
const { l10n } = useLocalization();

return (
<BaseModal isOpen={isOpen} onRequestClose={cancel} closeable={false}>
<div className="flex flex-col gap-3">
<>
<div className="flex flex-col items-center gap-3 fill-accent-background-20">
<div className="flex flex-col items-center gap-2 max-w-[512px]">
<Typography variant="main-title">
{l10n.getString('error_collection_modal-title')}
</Typography>
<Typography
variant="vr-accessible"
whitespace="whitespace-pre-line"
>
{l10n.getString('error_collection_modal-description')}
</Typography>
</div>
</div>

<Button variant="primary" onClick={accept}>
{l10n.getString('error_collection_modal-confirm')}
</Button>
<Button variant="tertiary" onClick={cancel}>
{l10n.getString('error_collection_modal-cancel')}
</Button>
</>
</div>
</BaseModal>
);
}
2 changes: 1 addition & 1 deletion gui/src/components/SerialDetectionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export function SerialDetectionModal() {
{l10n.getString('serial_detection-new_device-p1')}
</Typography>
</div>
<div className="flex flex-col gap-3 rounded-xl max-w-sm">
<div className="flex flex-col gap-3 rounded-xl max-w-sm sentry-mask">
<Localized
id="onboarding-wifi_creds-ssid"
attrs={{ placeholder: true, label: true }}
Expand Down
6 changes: 6 additions & 0 deletions gui/src/components/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { TrayOrExitModal } from './TrayOrExitModal';
import { error } from '@/utils/logging';
import { useDoubleTap } from 'use-double-tap';
import { isTrayAvailable } from '@/utils/tauri';
import { ErrorConsentModal } from './ErrorConsentModal';

export function VersionTag() {
return (
Expand Down Expand Up @@ -304,6 +305,11 @@ export function TopBar({
accept={() => closeApp()}
cancel={() => setConnectedTrackerWarning(false)}
></TrackersStillOnModal>
<ErrorConsentModal
isOpen={config?.errorTracking === null}
accept={() => setConfig({ errorTracking: true })}
cancel={() => setConfig({ errorTracking: false })}
/>
</>
);
}
6 changes: 4 additions & 2 deletions gui/src/components/commons/BaseModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@ import ReactModal from 'react-modal';
export function BaseModal({
children,
important = false,
closeable = true,
...props
}: {
isOpen: boolean;
children: ReactNode;
important?: boolean;
closeable?: boolean;
} & ReactModal.Props) {
return (
<ReactModal
{...props}
shouldCloseOnOverlayClick
shouldCloseOnEsc
shouldCloseOnOverlayClick={closeable}
shouldCloseOnEsc={closeable}
overlayClassName={
props.overlayClassName ||
classNames(
Expand Down
4 changes: 3 additions & 1 deletion gui/src/components/commons/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ export const InputInside = forwardRef<
<div className="relative w-full">
<input
type={forceText ? 'text' : type}
className={classNames(classes, { 'pr-10': type === 'password' })}
className={classNames(classes, {
'pr-10 sentry-mask': type === 'password',
})}
placeholder={placeholder || undefined}
autoComplete={autocomplete ? 'off' : 'on'}
onChange={onChange}
Expand Down
3 changes: 3 additions & 0 deletions gui/src/components/commons/Typography.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export function Typography({
italic = false,
truncate = false,
textAlign,
sentryMask = false,
}: {
variant?:
| 'main-title'
Expand All @@ -37,6 +38,7 @@ export function Typography({
| 'text-start'
| 'text-end';
children?: ReactNode;
sentryMask?: boolean;
}) {
const tag = useMemo(() => {
const tags = {
Expand Down Expand Up @@ -72,6 +74,7 @@ export function Typography({
truncate && 'leading-3 text-ellipsis',
truncate && (config?.textSize ?? 12) > 12 && 'line-clamp-1',
truncate && (config?.textSize ?? 12) <= 12 && 'line-clamp-2',
sentryMask && 'sentry-mask',
]),
},
children || []
Expand Down
19 changes: 19 additions & 0 deletions gui/src/components/commons/icon/ArrowIcons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,22 @@ export function ArrowRightIcon() {
</svg>
);
}

export function ArrowRightLeftIcon() {
return (
<svg
width="24"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2}
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M7.5 21 3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5"
/>
</svg>
);
}
2 changes: 1 addition & 1 deletion gui/src/components/onboarding/pages/WifiCreds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function WifiCredsPage() {
</div>
<div
className={classNames(
'flex flex-col gap-3 p-10 rounded-xl max-w-sm',
'flex flex-col gap-3 p-10 rounded-xl max-w-sm sentry-mask',
!state.alonePage && 'bg-background-70',
state.alonePage && 'bg-background-60'
)}
Expand Down
Loading
Loading