diff --git a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java index e9230185b..a8861fdd8 100644 --- a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java +++ b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java @@ -355,6 +355,8 @@ public class ApplicationProperties { private String tessdataDir; private Boolean enableAlphaFunctionality; private Boolean enableAnalytics; + private Boolean enablePosthog; + private Boolean enableScarf; private Datasource datasource; private Boolean disableSanitize; private int maxDPI; @@ -368,6 +370,18 @@ public class ApplicationProperties { public boolean isAnalyticsEnabled() { return this.getEnableAnalytics() != null && this.getEnableAnalytics(); } + + public boolean isPosthogEnabled() { + // Treat null as enabled when analytics is enabled + return this.isAnalyticsEnabled() + && (this.getEnablePosthog() == null || this.getEnablePosthog()); + } + + public boolean isScarfEnabled() { + // Treat null as enabled when analytics is enabled + return this.isAnalyticsEnabled() + && (this.getEnableScarf() == null || this.getEnableScarf()); + } } @Data diff --git a/app/common/src/main/java/stirling/software/common/service/PostHogService.java b/app/common/src/main/java/stirling/software/common/service/PostHogService.java index 2bc219832..0d6353b50 100644 --- a/app/common/src/main/java/stirling/software/common/service/PostHogService.java +++ b/app/common/src/main/java/stirling/software/common/service/PostHogService.java @@ -56,7 +56,7 @@ public class PostHogService { } private void captureSystemInfo() { - if (!applicationProperties.getSystem().isAnalyticsEnabled()) { + if (!applicationProperties.getSystem().isPosthogEnabled()) { return; } try { @@ -67,7 +67,7 @@ public class PostHogService { } public void captureEvent(String eventName, Map properties) { - if (!applicationProperties.getSystem().isAnalyticsEnabled()) { + if (!applicationProperties.getSystem().isPosthogEnabled()) { return; } @@ -325,6 +325,14 @@ public class PostHogService { properties, "system_enableAnalytics", applicationProperties.getSystem().isAnalyticsEnabled()); + addIfNotEmpty( + properties, + "system_enablePosthog", + applicationProperties.getSystem().isPosthogEnabled()); + addIfNotEmpty( + properties, + "system_enableScarf", + applicationProperties.getSystem().isScarfEnabled()); // Capture UI properties addIfNotEmpty(properties, "ui_appName", applicationProperties.getUi().getAppName()); diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/SettingsController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/SettingsController.java index 3c2e6f33a..48793a98b 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/SettingsController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/SettingsController.java @@ -6,7 +6,7 @@ import java.util.Map; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import io.swagger.v3.oas.annotations.Hidden; @@ -29,7 +29,7 @@ public class SettingsController { @AutoJobPostMapping("/update-enable-analytics") @Hidden - public ResponseEntity updateApiKey(@RequestBody Boolean enabled) throws IOException { + public ResponseEntity updateApiKey(@RequestParam Boolean enabled) throws IOException { if (applicationProperties.getSystem().getEnableAnalytics() != null) { return ResponseEntity.status(HttpStatus.ALREADY_REPORTED) .body( diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java index 072471e5c..9d94c3ad4 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java @@ -65,6 +65,8 @@ public class ConfigController { applicationProperties.getSystem().getEnableAlphaFunctionality()); configData.put( "enableAnalytics", applicationProperties.getSystem().getEnableAnalytics()); + configData.put("enablePosthog", applicationProperties.getSystem().getEnablePosthog()); + configData.put("enableScarf", applicationProperties.getSystem().getEnableScarf()); // Premium/Enterprise settings configData.put("premiumEnabled", applicationProperties.getPremium().isEnabled()); diff --git a/app/core/src/main/resources/settings.yml.template b/app/core/src/main/resources/settings.yml.template index 1e577a368..a9055833a 100644 --- a/app/core/src/main/resources/settings.yml.template +++ b/app/core/src/main/resources/settings.yml.template @@ -120,7 +120,9 @@ system: showUpdateOnlyAdmin: false # only admins can see when a new update is available, depending on showUpdate it must be set to 'true' customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template HTML files tessdataDir: /usr/share/tessdata # path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored. - enableAnalytics: null # set to 'true' to enable analytics, set to 'false' to disable analytics; for enterprise users, this is set to true + enableAnalytics: null # Master toggle for analytics: set to 'true' to enable all analytics, 'false' to disable all analytics, or leave as 'null' to prompt admin on first launch + enablePosthog: null # Enable PostHog analytics (open-source product analytics): set to 'true' to enable, 'false' to disable, or 'null' to enable by default when analytics is enabled + enableScarf: null # Enable Scarf tracking pixel: set to 'true' to enable, 'false' to disable, or 'null' to enable by default when analytics is enabled enableUrlToPDF: false # Set to 'true' to enable URL to PDF, INTERNAL ONLY, known security issues, should not be used externally disableSanitize: false # set to true to disable Sanitize HTML; (can lead to injections in HTML) maxDPI: 500 # Maximum allowed DPI for PDF to image conversion diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7dd9e15cd..6a769c90b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -436,7 +436,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -483,7 +482,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -507,7 +505,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.3.14.tgz", "integrity": "sha512-lE/vfhA53CxamaCfGWEibrEPr+JeZT42QCF+cOELUwv4+Zt6b+IE6+4wsznx/8wjjJYwllXJ3GJ/un1UzTqARw==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/engines": "1.3.14", "@embedpdf/models": "1.3.14" @@ -588,7 +585,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-1.3.14.tgz", "integrity": "sha512-77hnNLp0W0FHw8lT7SeqzCgp8bOClfeOAPZdcInu/jPDhVASUGYbtE/0fkLhiaqPH7kyMirNCLif4sF6n4b5vg==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.3.14" }, @@ -605,7 +601,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-1.3.14.tgz", "integrity": "sha512-nR0ZxNoTQtGqOHhweFh6QJ+nUJ4S4Ag1wWur6vAUAi8U95HUOfZhOEa0polZo0zR9WmmblGqRWjFM+mVSOoi1w==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.3.14" }, @@ -622,7 +617,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-loader/-/plugin-loader-1.3.14.tgz", "integrity": "sha512-KoJX1MacEWE2DrO1OeZeG/Ehz76//u+ida/xb4r9BfwqAp5TfYlksq09cOvcF8LMW5FY4pbAL+AHKI1Hjz+HNA==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.3.14" }, @@ -657,7 +651,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-1.3.14.tgz", "integrity": "sha512-IPj7GCQXJBsY++JaU+z7y+FwX5NaDBj4YYV6hsHNtSGf42Y1AdlwJzDYetivG2bA84xmk7KgD1X2Y3eIFBhjwA==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.3.14" }, @@ -690,7 +683,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-1.3.14.tgz", "integrity": "sha512-fQbt7OlRMLQJMuZj/Bzh0qpRxMw1ld5Qe/OTw8N54b/plljnFA52joE7cITl3H03huWWyHS3NKOScbw7f34dog==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.3.14" }, @@ -725,7 +717,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.3.14.tgz", "integrity": "sha512-EXENuaAsse3rT6cjA1nYzyrNvoy62ojJl28wblCng6zcs3HSlGPemIQZAvaYKPUxoY608M+6nKlcMQ5neRnk/A==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.3.14" }, @@ -797,7 +788,6 @@ "resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.3.14.tgz", "integrity": "sha512-mfJ7EbbU68eKk6oFvQ4ozGJNpxUxWbjQ5Gm3uuB+Gj5/tWgBocBOX36k/9LgivEEeX7g2S0tOgyErljApmH8Vg==", "license": "MIT", - "peer": true, "dependencies": { "@embedpdf/models": "1.3.14" }, @@ -951,7 +941,6 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -995,7 +984,6 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -2029,7 +2017,6 @@ "resolved": "https://registry.npmjs.org/@mantine/core/-/core-8.3.1.tgz", "integrity": "sha512-OYfxn9cTv+K6RZ8+Ozn/HDQXkB8Fmn+KJJt5lxyFDP9F09EHnC59Ldadv1LyUZVBGtNqz4sn6b3vBShbxwAmYw==", "license": "MIT", - "peer": true, "dependencies": { "@floating-ui/react": "^0.27.16", "clsx": "^2.1.1", @@ -2080,7 +2067,6 @@ "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-8.3.1.tgz", "integrity": "sha512-lQutBS+Q0iz/cNFvdrsYassPWo3RtWcmDGJeOtKfHigLzFOhxUuLOkQgepDbMf3WcVMB/tist6Px1PQOv57JTw==", "license": "MIT", - "peer": true, "peerDependencies": { "react": "^18.x || ^19.x" } @@ -2148,7 +2134,6 @@ "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.2.tgz", "integrity": "sha512-qXvbnawQhqUVfH1LMgMaiytP+ZpGoYhnGl7yYq2x57GYzcFL/iPzSZ3L30tlbwEjSVKNYcbiKO8tANR1tadjUg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.28.3", "@mui/core-downloads-tracker": "^7.3.2", @@ -3591,7 +3576,6 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -3915,7 +3899,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -3926,7 +3909,6 @@ "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -3987,7 +3969,6 @@ "integrity": "sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.44.1", "@typescript-eslint/types": "8.44.1", @@ -4701,6 +4682,7 @@ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz", "integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/shared": "3.5.21" } @@ -4710,6 +4692,7 @@ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz", "integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/reactivity": "3.5.21", "@vue/shared": "3.5.21" @@ -4720,6 +4703,7 @@ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz", "integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==", "license": "MIT", + "peer": true, "dependencies": { "@vue/reactivity": "3.5.21", "@vue/runtime-core": "3.5.21", @@ -4732,6 +4716,7 @@ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz", "integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-ssr": "3.5.21", "@vue/shared": "3.5.21" @@ -4759,7 +4744,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5434,7 +5418,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001741", @@ -6438,8 +6421,7 @@ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1508733.tgz", "integrity": "sha512-QJ1R5gtck6nDcdM+nlsaJXcelPEI7ZxSMw1ujHpO1c4+9l+Nue5qlebi9xO1Z2MGr92bFOQTW7/rrheh5hHxDg==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/dezalgo": { "version": "1.0.4", @@ -6834,7 +6816,6 @@ "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -7006,7 +6987,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -8280,7 +8260,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.27.6" }, @@ -9077,7 +9056,6 @@ "integrity": "sha512-lIHeR1qlIRrIN5VMccd8tI2Sgw6ieYXSVktcSHaNe3Z5nE/tcPQYQWOq00wxMvYOsz+73eAkNenVvmPC6bba9A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@asamuzakjp/dom-selector": "^6.5.4", "cssstyle": "^5.3.0", @@ -10866,7 +10844,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -11158,7 +11135,6 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.2.tgz", "integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -11531,7 +11507,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -11541,7 +11516,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -13179,7 +13153,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13462,7 +13435,6 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -13545,7 +13517,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "napi-postinstall": "^0.3.0" }, @@ -13765,7 +13736,6 @@ "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -13897,7 +13867,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13911,7 +13880,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 904817c75..973717879 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -250,6 +250,7 @@ "title": "Do you want make Stirling PDF better?", "paragraph1": "Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents.", "paragraph2": "Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better.", + "learnMore": "Learn more", "enable": "Enable analytics", "disable": "Disable analytics", "settings": "You can change the settings for analytics in the config/settings.yml file" @@ -3371,6 +3372,10 @@ "title": "Analytics", "description": "These cookies help us understand how our tools are being used, so we can focus on building the features our community values most. Rest assured—Stirling PDF cannot and will never track the content of the documents you work with." } + }, + "services": { + "posthog": "PostHog Analytics", + "scarf": "Scarf Pixel" } }, "removeMetadata": { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index fd4d466ad..ddadbc8c8 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -9,10 +9,12 @@ import { ToolWorkflowProvider } from "./contexts/ToolWorkflowContext"; import { HotkeyProvider } from "./contexts/HotkeyContext"; import { SidebarProvider } from "./contexts/SidebarContext"; import { PreferencesProvider } from "./contexts/PreferencesContext"; +import { AppConfigProvider } from "./contexts/AppConfigContext"; import { OnboardingProvider } from "./contexts/OnboardingContext"; import { TourOrchestrationProvider } from "./contexts/TourOrchestrationContext"; import ErrorBoundary from "./components/shared/ErrorBoundary"; import OnboardingTour from "./components/onboarding/OnboardingTour"; +import { useScarfTracking } from "./hooks/useScarfTracking"; // Import auth components import { AuthProvider } from "./auth/UseSession"; @@ -48,6 +50,12 @@ const LoadingFallback = () => ( ); +// Component to initialize scarf tracking (must be inside AppConfigProvider) +function ScarfTrackingInitializer() { + useScarfTracking(); + return null; +} + export default function App() { return ( }> @@ -66,30 +74,33 @@ export default function App() { path="/*" element={ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + } /> diff --git a/frontend/src/components/layout/Workbench.tsx b/frontend/src/components/layout/Workbench.tsx index 4ec7d8017..da4447a70 100644 --- a/frontend/src/components/layout/Workbench.tsx +++ b/frontend/src/components/layout/Workbench.tsx @@ -6,6 +6,7 @@ import { useFileState } from '../../contexts/FileContext'; import { useNavigationState, useNavigationActions } from '../../contexts/NavigationContext'; import { isBaseWorkbench } from '../../types/workbench'; import { useViewer } from '../../contexts/ViewerContext'; +import { useAppConfig } from '../../contexts/AppConfigContext'; import './Workbench.css'; import TopControls from '../shared/TopControls'; @@ -20,6 +21,7 @@ import DismissAllErrorsButton from '../shared/DismissAllErrorsButton'; // No props needed - component uses contexts directly export default function Workbench() { const { isRainbowMode } = useRainbowThemeContext(); + const { config } = useAppConfig(); // Use context-based hooks to eliminate all prop drilling const { selectors } = useFileState(); @@ -188,7 +190,7 @@ export default function Workbench() { {renderMainContent()} -