diff --git a/apps/desktop/vite.config.ts b/apps/desktop/vite.config.ts index f80274e06..99af0f343 100644 --- a/apps/desktop/vite.config.ts +++ b/apps/desktop/vite.config.ts @@ -37,6 +37,7 @@ export default defineConfig(({ mode }) => { plugins: [ devtoolsPlugin, process.env.SENTRY_AUTH_TOKEN && + // All this plugin does is give Sentry access to source maps and release data for errors that users *choose* to report sentryVitePlugin({ authToken: process.env.SENTRY_AUTH_TOKEN, org: 'spacedriveapp', diff --git a/apps/mobile/modules/sd-core/core/Cargo.toml b/apps/mobile/modules/sd-core/core/Cargo.toml index 75d627d32..2c8e8cf3b 100644 --- a/apps/mobile/modules/sd-core/core/Cargo.toml +++ b/apps/mobile/modules/sd-core/core/Cargo.toml @@ -7,9 +7,8 @@ license.workspace = true repository.workspace = true rust-version.workspace = true -[target.'cfg(target_os = "android")'.dependencies] -sd-core = { default-features = false, features = ["mobile"], path = "../../../../../core" } +# Spacedrive Sub-crates [target.'cfg(target_os = "ios")'.dependencies] sd-core = { default-features = false, features = [ "ffmpeg", @@ -17,6 +16,10 @@ sd-core = { default-features = false, features = [ "mobile" ], path = "../../../../../core" } +[target.'cfg(target_os = "android")'.dependencies] +sd-core = { path = "../../../../../core", features = ["mobile"], default-features = false } + +[dependencies] # Workspace dependencies futures = { workspace = true } rspc = { workspace = true } diff --git a/apps/mobile/src/App.tsx b/apps/mobile/src/App.tsx index 3ec7b8c44..f2e59d269 100644 --- a/apps/mobile/src/App.tsx +++ b/apps/mobile/src/App.tsx @@ -20,7 +20,7 @@ import { SafeAreaProvider } from 'react-native-safe-area-context'; import { useSnapshot } from 'valtio'; import { ClientContextProvider, - initPlausible, + configureAnalyticsProperties, LibraryContextProvider, P2PContextProvider, RspcProvider, @@ -63,7 +63,7 @@ function AppNavigation() { useEffect(() => { if (buildInfo?.data) { - initPlausible({ platformType: 'mobile', buildInfo: buildInfo.data }); + configureAnalyticsProperties({ platformType: 'mobile', buildInfo: buildInfo.data }); } }, [buildInfo]); diff --git a/apps/mobile/src/components/context/OnboardingContext.tsx b/apps/mobile/src/components/context/OnboardingContext.tsx index 31e6259b7..ff7816e14 100644 --- a/apps/mobile/src/components/context/OnboardingContext.tsx +++ b/apps/mobile/src/components/context/OnboardingContext.tsx @@ -37,8 +37,9 @@ export const useContextValue = () => { }; export const shareTelemetrySchema = z.union([ - z.literal('share-telemetry'), - z.literal('minimal-telemetry') + z.literal('full'), + z.literal('minimal'), + z.literal('none') ]); const schemas = { @@ -58,7 +59,7 @@ const useFormState = () => { defaultValues: { NewLibrary: obStore.data?.['new-library'] ?? undefined, Privacy: obStore.data?.privacy ?? { - shareTelemetry: 'share-telemetry' + shareTelemetry: 'full' } }, onData: (data) => (onboardingStore.data = data) @@ -81,7 +82,7 @@ const useFormState = () => { // opted to place this here as users could change their mind before library creation/onboarding finalization // it feels more fitting to configure it here (once) - telemetryState.shareFullTelemetry = data.Privacy.shareTelemetry === 'share-telemetry'; + telemetryState.telemetryLevelPreference = data.Privacy.shareTelemetry; try { // show creation screen for a bit for smoothness @@ -93,7 +94,7 @@ const useFormState = () => { new Promise((res) => setTimeout(res, 500)) ]); - if (telemetryState.shareFullTelemetry) { + if (telemetryState.telemetryLevelPreference === 'full') { submitPlausibleEvent({ event: { type: 'libraryCreate' } }); } diff --git a/apps/mobile/src/screens/onboarding/Privacy.tsx b/apps/mobile/src/screens/onboarding/Privacy.tsx index de6623d0b..a14beba5f 100644 --- a/apps/mobile/src/screens/onboarding/Privacy.tsx +++ b/apps/mobile/src/screens/onboarding/Privacy.tsx @@ -59,22 +59,26 @@ const PrivacyScreen = () => { control={form.control} render={({ field: { onChange, value } }) => ( <> - onChange('share-telemetry')}> + onChange('full')}> - onChange('minimal-telemetry')} - > + onChange('minimal')}> + + onChange('none')}> + diff --git a/apps/web/cypress/e2e/1-onboarding.spec.cy.ts b/apps/web/cypress/e2e/1-onboarding.spec.cy.ts index 2247a6e0f..df0407d5a 100644 --- a/apps/web/cypress/e2e/1-onboarding.spec.cy.ts +++ b/apps/web/cypress/e2e/1-onboarding.spec.cy.ts @@ -131,12 +131,18 @@ describe('Onboarding', () => { cy.get('h2').should('contain', 'Your Privacy'); // Check we have all privacy options + cy.get('label').contains("Don't share anything").click(); + cy.get('#radiofull').should('have.attr', 'data-state', 'unchecked'); + cy.get('#radiominimal').should('have.attr', 'data-state', 'unchecked'); + cy.get('#radionone').should('have.attr', 'data-state', 'checked'); cy.get('label').contains('Share the bare minimum').click(); - cy.get('#radiominimal-telemetry').should('have.attr', 'data-state', 'checked'); - cy.get('#radioshare-telemetry').should('have.attr', 'data-state', 'unchecked'); + cy.get('#radiofull').should('have.attr', 'data-state', 'unchecked'); + cy.get('#radiominimal').should('have.attr', 'data-state', 'checked'); + cy.get('#radionone').should('have.attr', 'data-state', 'unchecked'); cy.get('label').contains('Share anonymous usage').click(); - cy.get('#radioshare-telemetry').should('have.attr', 'data-state', 'checked'); - cy.get('#radiominimal-telemetry').should('have.attr', 'data-state', 'unchecked'); + cy.get('#radiofull').should('have.attr', 'data-state', 'checked'); + cy.get('#radiominimal').should('have.attr', 'data-state', 'unchecked'); + cy.get('#radionone').should('have.attr', 'data-state', 'unchecked'); // Check More info button exists and point to the valid pravacy policy cy.get('button').contains('More info').click(); diff --git a/interface/ErrorFallback.tsx b/interface/ErrorFallback.tsx index f0ba7f3e9..1dcaf0758 100644 --- a/interface/ErrorFallback.tsx +++ b/interface/ErrorFallback.tsx @@ -5,7 +5,7 @@ import { FallbackProps } from 'react-error-boundary'; import { useRouteError } from 'react-router'; -import { useDebugState } from '@sd/client'; +import { useDebugState, useTelemetryState } from '@sd/client'; import { Button, Dialogs } from '@sd/ui'; import { showAlertDialog } from './components'; @@ -68,6 +68,7 @@ export function ErrorPage({ }) { useTheme(); const debug = useDebugState(); + const { telemetryLevelPreference } = useTelemetryState(); const os = useOperatingSystem(); const platform = usePlatform(); const isMacOS = os === 'macOS'; @@ -134,19 +135,21 @@ export function ErrorPage({ {t('reload')} )} - + {telemetryLevelPreference !== 'none' && ( + + )} {platform.openLogsDir && (