@@ -5,6 +5,7 @@ import * as packageJson from '../../../../../package.json'
55import { RemixUiSettings } from '@remix-ui/settings' //eslint-disable-line
66import { Registry } from '@remix-project/remix-lib'
77import { PluginViewWrapper } from '@remix-ui/helper'
8+
89declare global {
910 interface Window {
1011 _paq : any
@@ -15,7 +16,8 @@ const _paq = (window._paq = window._paq || [])
1516const profile = {
1617 name : 'settings' ,
1718 displayName : 'Settings' ,
18- methods : [ 'get' , 'updateCopilotChoice' , 'getCopilotSetting' , 'updateMatomoPerfAnalyticsChoice' ] ,
19+ // updateMatomoAnalyticsMode deprecated: tracking mode now derived purely from perf toggle (Option B)
20+ methods : [ 'get' , 'updateCopilotChoice' , 'getCopilotSetting' , 'updateMatomoPerfAnalyticsChoice' , 'updateMatomoAnalyticsMode' ] ,
1921 events : [ ] ,
2022 icon : 'assets/img/settings.webp' ,
2123 description : 'Remix-IDE settings' ,
@@ -104,38 +106,114 @@ export default class SettingsTab extends ViewPlugin {
104106 return this . get ( 'settings/copilot/suggest/activate' )
105107 }
106108
107- updateMatomoAnalyticsChoice ( isChecked ) {
108- this . config . set ( 'settings/matomo-analytics' , isChecked )
109- // set timestamp to local storage to track when the user has given consent
110- localStorage . setItem ( 'matomo-analytics-consent' , Date . now ( ) . toString ( ) )
111- this . useMatomoAnalytics = isChecked
112- if ( ! isChecked ) {
113- // revoke tracking consent
114- _paq . push ( [ 'forgetConsentGiven' ] ) ;
115- } else {
116- // user has given consent to process their data
117- _paq . push ( [ 'setConsentGiven' ] ) ;
109+ updateMatomoAnalyticsChoice ( _isChecked ) {
110+ // Deprecated legacy toggle (disabled in UI). Mode now derives from performance analytics only.
111+ // Intentionally no-op to avoid user confusion; kept for backward compat if invoked programmatically.
112+ }
113+
114+ // Deprecated public method: retained for backward compatibility (external plugins or old code calling it).
115+ // It now simply forwards to performance-based derivation by toggling perf flag if needed.
116+ updateMatomoAnalyticsMode ( _mode : 'cookie' | 'anon' ) {
117+ if ( window . localStorage . getItem ( 'matomo-debug' ) === 'true' ) {
118+ console . debug ( '[Matomo][settings] DEPRECATED updateMatomoAnalyticsMode call ignored; mode derived from perf toggle' )
118119 }
119- this . dispatch ( {
120- ...this
121- } )
122120 }
123121
124122 updateMatomoPerfAnalyticsChoice ( isChecked ) {
123+ console . log ( '[Matomo][settings] updateMatomoPerfAnalyticsChoice called with' , isChecked )
125124 this . config . set ( 'settings/matomo-perf-analytics' , isChecked )
126- // set timestamp to local storage to track when the user has given consent
125+ // Timestamp consent indicator (we treat enabling perf as granting cookie consent; disabling as revoking)
127126 localStorage . setItem ( 'matomo-analytics-consent' , Date . now ( ) . toString ( ) )
128127 this . useMatomoPerfAnalytics = isChecked
129- this . emit ( 'matomoPerfAnalyticsChoiceUpdated' , isChecked )
130- if ( ! isChecked ) {
131- // revoke tracking consent for performance data
132- _paq . push ( [ 'disableCookies' ] )
128+
129+ const MATOMO_TRACKING_MODE_DIMENSION_ID = 1 // only remaining custom dimension (tracking mode)
130+ const mode = isChecked ? 'cookie' : 'anon'
131+
132+ // Always re-assert cookie consent boundary so runtime flip is clean
133+ _paq . push ( [ 'requireCookieConsent' ] )
134+
135+ if ( mode === 'cookie' ) {
136+ // Cookie mode: give cookie consent and remember it
137+ _paq . push ( [ 'rememberConsentGiven' ] ) ;
138+ _paq . push ( [ 'enableBrowserFeatureDetection' ] ) ;
139+ _paq . push ( [ 'setCustomDimension' , MATOMO_TRACKING_MODE_DIMENSION_ID , 'cookie' ] ) ;
140+ _paq . push ( [ 'trackEvent' , 'tracking_mode_change' , 'cookie' ] ) ;
141+ console . log ( 'Granting cookie consent for Matomo (switching to cookie mode)' ) ;
142+ ( window as any ) . __initMatomoTracking ( 'cookie' ) ;
133143 } else {
134- // user has given consent to process their performance data
135- _paq . push ( [ 'setCookieConsentGiven' ] )
144+ // Anonymous mode: revoke cookie consent completely
145+ //_paq.push(['setConsentGiven']);
146+ console . log ( 'Revoking cookie consent for Matomo (switching to anon mode)' )
147+ //_paq.push(['forgetCookieConsentGiven']) // This removes cookie consent and deletes cookies
148+ //_paq.push(['disableCookies']) // Extra safety - prevent any new cookies
149+
150+ // Manual cookie deletion as backup (Matomo cookies typically start with _pk_)
151+ this . deleteMatomoCookies ( )
152+
153+ _paq . push ( [ 'setCustomDimension' , MATOMO_TRACKING_MODE_DIMENSION_ID , 'anon' ] )
154+ _paq . push ( [ 'trackEvent' , 'tracking_mode_change' , 'anon' ] )
155+ if ( window . localStorage . getItem ( 'matomo-debug' ) === 'true' ) {
156+ _paq . push ( [ 'trackEvent' , 'debug' , 'anon_mode_active_toggle' ] )
157+ }
158+ ( window as any ) . __initMatomoTracking ( 'anon' ) ;
159+ }
160+
161+ // Performance dimension removed: mode alone now encodes cookie vs anon. Keep event for analytics toggle if useful.
162+ _paq . push ( [ 'trackEvent' , 'perf_analytics_toggle' , isChecked ? 'on' : 'off' ] )
163+ if ( window . localStorage . getItem ( 'matomo-debug' ) === 'true' ) {
164+ console . debug ( '[Matomo][settings] perf toggle -> mode derived' , { perf : isChecked , mode } )
165+ }
166+
167+ // If running inside Electron, propagate mode to desktop tracker & emit desktop-specific event.
168+ if ( ( window as any ) . electronAPI ) {
169+ try {
170+ ( window as any ) . electronAPI . setTrackingMode ( mode )
171+ // Also send an explicit desktop event (uses new API if available)
172+ if ( ( window as any ) . electronAPI . trackDesktopEvent ) {
173+ ( window as any ) . electronAPI . trackDesktopEvent ( 'tracking_mode_change' , mode , isChecked ? 'on' : 'off' )
174+ }
175+ } catch ( e ) {
176+ console . warn ( '[Matomo][desktop-sync] failed to set tracking mode in electron layer' , e )
177+ }
178+ }
179+ // Persist deprecated mode key for backward compatibility (other code might read it)
180+ this . config . set ( 'settings/matomo-analytics-mode' , mode )
181+ this . config . set ( 'settings/matomo-analytics' , mode === 'cookie' ) // legacy boolean
182+ this . useMatomoAnalytics = true
183+
184+ this . emit ( 'matomoPerfAnalyticsChoiceUpdated' , isChecked ) ;
185+
186+ const buffer = ( window as any ) . __drainMatomoQueue ( ) ;
187+ ( window as any ) . __loadMatomoScript ( ) ;
188+ ( window as any ) . __restoreMatomoQueue ( buffer ) ;
189+
190+ this . dispatch ( { ...this } )
191+ }
192+
193+ // Helper method to manually delete Matomo cookies
194+ private deleteMatomoCookies ( ) {
195+ try {
196+ // Get all cookies
197+ const cookies = document . cookie . split ( ';' )
198+
199+ for ( let cookie of cookies ) {
200+ const eqPos = cookie . indexOf ( '=' )
201+ const name = eqPos > - 1 ? cookie . substr ( 0 , eqPos ) . trim ( ) : cookie . trim ( )
202+
203+ // Delete Matomo cookies (typically start with _pk_)
204+ if ( name . startsWith ( '_pk_' ) ) {
205+ // Delete for current domain and path
206+ document . cookie = `${ name } =; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`
207+ document . cookie = `${ name } =; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${ window . location . hostname } `
208+ document . cookie = `${ name } =; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${ window . location . hostname } `
209+
210+ if ( window . localStorage . getItem ( 'matomo-debug' ) === 'true' ) {
211+ console . debug ( '[Matomo][cookie-cleanup] Deleted cookie:' , name )
212+ }
213+ }
214+ }
215+ } catch ( e ) {
216+ console . warn ( '[Matomo][cookie-cleanup] Failed to delete cookies:' , e )
136217 }
137- this . dispatch ( {
138- ...this
139- } )
140218 }
141219}
0 commit comments