1313 See the License for the specific language governing permissions and
1414 limitations under the License.
1515*/
16- import { ConfigurationChangeEvent , env , workspace } from "vscode" ;
16+ import { ConfigurationChangeEvent , env , workspace , Disposable } from "vscode" ;
1717import { getConfigurationValue , inspectConfiguration , updateConfigurationValue } from "../../configurations/handlers" ;
1818import { configKeys } from "../../configurations/configuration" ;
1919import { appendPrefixToCommand } from "../../utils" ;
20+ import { ExtensionContextInfo } from "../../extensionContextInfo" ;
21+ import { TelemetryPreference } from "../types" ;
22+ import { cacheService } from "./cacheServiceImpl" ;
23+ import { TELEMETRY_CONSENT_POPUP_TIME_KEY , TELEMETRY_CONSENT_VERSION_SCHEMA_KEY , TELEMETRY_SETTING_VALUE_KEY } from "../constants" ;
24+ import { TelemetryConfiguration } from "../config" ;
25+ import { LOGGER } from "../../logger" ;
2026
21- export class TelemetryPrefs {
22- public isExtTelemetryEnabled : boolean ;
27+ export class TelemetrySettings {
28+ private isTelemetryEnabled : boolean ;
29+ private extensionPrefs : ExtensionTelemetryPreference ;
30+ private vscodePrefs : VscodeTelemetryPreference ;
31+
32+ constructor (
33+ extensionContext : ExtensionContextInfo ,
34+ private onTelemetryEnableCallback : ( ) => void ,
35+ private onTelemetryDisableCallback : ( ) => void ,
36+ private triggerPopup : ( ) => void ) {
37+
38+ this . extensionPrefs = new ExtensionTelemetryPreference ( ) ;
39+ this . vscodePrefs = new VscodeTelemetryPreference ( ) ;
40+
41+ extensionContext . pushSubscription (
42+ this . extensionPrefs . onChangeTelemetrySetting ( this . onChangeTelemetrySettingCallback )
43+ ) ;
44+ extensionContext . pushSubscription (
45+ this . vscodePrefs . onChangeTelemetrySetting ( this . onChangeTelemetrySettingCallback )
46+ ) ;
47+
48+ this . isTelemetryEnabled = this . checkTelemetryStatus ( ) ;
49+ this . updateGlobalState ( ) ;
50+ this . checkConsentVersion ( ) ;
51+ }
52+
53+ private checkTelemetryStatus = ( ) : boolean => this . extensionPrefs . getIsTelemetryEnabled ( ) && this . vscodePrefs . getIsTelemetryEnabled ( ) ;
54+
55+ private onChangeTelemetrySettingCallback = ( ) => {
56+ const newTelemetryStatus = this . checkTelemetryStatus ( ) ;
57+ if ( newTelemetryStatus !== this . isTelemetryEnabled ) {
58+ this . isTelemetryEnabled = newTelemetryStatus ;
59+ cacheService . put ( TELEMETRY_SETTING_VALUE_KEY , newTelemetryStatus . toString ( ) ) ;
60+
61+ if ( newTelemetryStatus ) {
62+ this . onTelemetryEnableCallback ( ) ;
63+ } else {
64+ this . onTelemetryDisableCallback ( ) ;
65+ }
66+ } else if ( this . vscodePrefs . getIsTelemetryEnabled ( ) && ! this . extensionPrefs . isTelemetrySettingSet ( ) ) {
67+ this . triggerPopup ( ) ;
68+ }
69+ }
70+
71+ public getIsTelemetryEnabled = ( ) : boolean => this . isTelemetryEnabled ;
72+
73+ public isConsentPopupToBeTriggered = ( ) : boolean => {
74+ const isExtensionSettingSet = this . extensionPrefs . isTelemetrySettingSet ( ) ;
75+ const isVscodeSettingEnabled = this . vscodePrefs . getIsTelemetryEnabled ( ) ;
76+
77+ const showPopup = ! isExtensionSettingSet && isVscodeSettingEnabled ;
78+
79+ if ( showPopup ) {
80+ cacheService . put ( TELEMETRY_CONSENT_POPUP_TIME_KEY , Date . now ( ) . toString ( ) ) ;
81+ }
82+
83+ return showPopup ;
84+ }
85+
86+ public updateTelemetrySetting = ( value : boolean | undefined ) : void => {
87+ this . extensionPrefs . updateTelemetryConfig ( value ) ;
88+ }
89+
90+ private updateGlobalState ( ) : void {
91+ const cachedValue = cacheService . get ( TELEMETRY_SETTING_VALUE_KEY ) ;
92+
93+ if ( this . isTelemetryEnabled . toString ( ) !== cachedValue ) {
94+ cacheService . put ( TELEMETRY_SETTING_VALUE_KEY , this . isTelemetryEnabled . toString ( ) ) ;
95+ }
96+ }
97+
98+ private checkConsentVersion ( ) : void {
99+ const cachedVersion = cacheService . get ( TELEMETRY_CONSENT_VERSION_SCHEMA_KEY ) ;
100+ const currentVersion = TelemetryConfiguration . getInstance ( ) . getTelemetryConfigMetadata ( ) ?. consentSchemaVersion ;
101+
102+ if ( cachedVersion !== currentVersion ) {
103+ cacheService . put ( TELEMETRY_CONSENT_VERSION_SCHEMA_KEY , currentVersion ) ;
104+ LOGGER . debug ( "Removing telemetry config from user settings" ) ;
105+ if ( this . extensionPrefs . isTelemetrySettingSet ( ) ) {
106+ this . updateTelemetrySetting ( undefined ) ;
107+ }
108+ this . isTelemetryEnabled = false ;
109+ }
110+ }
111+ }
112+
113+ class ExtensionTelemetryPreference implements TelemetryPreference {
114+ private isTelemetryEnabled : boolean | undefined ;
115+ private readonly CONFIG = appendPrefixToCommand ( configKeys . telemetryEnabled ) ;
23116
24117 constructor ( ) {
25- this . isExtTelemetryEnabled = this . checkTelemetryStatus ( ) ;
118+ this . isTelemetryEnabled = getConfigurationValue ( configKeys . telemetryEnabled , false ) ;
26119 }
27120
28- private checkTelemetryStatus = ( ) : boolean => {
29- return getConfigurationValue ( configKeys . telemetryEnabled , false ) ;
121+ public getIsTelemetryEnabled = ( ) : boolean => this . isTelemetryEnabled === undefined ? false : this . isTelemetryEnabled ;
122+
123+ public onChangeTelemetrySetting = ( callback : ( ) => void ) : Disposable => workspace . onDidChangeConfiguration ( ( e : ConfigurationChangeEvent ) => {
124+ if ( e . affectsConfiguration ( this . CONFIG ) ) {
125+ this . isTelemetryEnabled = getConfigurationValue ( configKeys . telemetryEnabled , false ) ;
126+ callback ( ) ;
127+ }
128+ } ) ;
129+
130+ public updateTelemetryConfig = ( value : boolean | undefined ) : void => {
131+ this . isTelemetryEnabled = value ;
132+ updateConfigurationValue ( configKeys . telemetryEnabled , value , true ) ;
30133 }
31134
32- private configPref = ( configCommand : string ) : boolean => {
33- const config = inspectConfiguration ( configCommand ) ;
135+ public isTelemetrySettingSet = ( ) : boolean => {
136+ if ( this . isTelemetryEnabled === undefined ) return false ;
137+ const config = inspectConfiguration ( this . CONFIG ) ;
34138 return (
35- config ?. workspaceFolderValue !== undefined ||
36- config ?. workspaceFolderLanguageValue !== undefined ||
37- config ?. workspaceValue !== undefined ||
38- config ?. workspaceLanguageValue !== undefined ||
39139 config ?. globalValue !== undefined ||
40140 config ?. globalLanguageValue !== undefined
41141 ) ;
42142 }
143+ }
43144
44- public isExtTelemetryConfigured = ( ) : boolean => {
45- return this . configPref ( appendPrefixToCommand ( configKeys . telemetryEnabled ) ) ;
46- }
145+ class VscodeTelemetryPreference implements TelemetryPreference {
146+ private isTelemetryEnabled : boolean ;
47147
48- public updateTelemetryEnabledConfig = ( value : boolean ) : void => {
49- this . isExtTelemetryEnabled = value ;
50- updateConfigurationValue ( configKeys . telemetryEnabled , value , true ) ;
148+ constructor ( ) {
149+ this . isTelemetryEnabled = env . isTelemetryEnabled ;
51150 }
52151
53- public didUserDisableVscodeTelemetry = ( ) : boolean => {
54- return ! env . isTelemetryEnabled ;
55- }
152+ public getIsTelemetryEnabled = ( ) : boolean => this . isTelemetryEnabled ;
56153
57- public onDidChangeTelemetryEnabled = ( ) => workspace . onDidChangeConfiguration (
58- ( e : ConfigurationChangeEvent ) => {
59- if ( e . affectsConfiguration ( appendPrefixToCommand ( configKeys . telemetryEnabled ) ) ) {
60- this . isExtTelemetryEnabled = this . checkTelemetryStatus ( ) ;
61- }
62- }
63- ) ;
64- }
154+ public onChangeTelemetrySetting = ( callback : ( ) => void ) : Disposable => env . onDidChangeTelemetryEnabled ( ( newSetting : boolean ) => {
155+ this . isTelemetryEnabled = newSetting ;
156+ callback ( ) ;
157+ } ) ;
158+ }
159+
160+ // Question:
161+ // When consent version is changed, we have to show popup to all the users or only those who had accepted earlier?
162+
163+ // Test cases:
164+ // 1. User accepts consent and VSCode telemetry is set to 'all'. Output: enabled telemetry
165+ // 2. User accepts consent and VSCode telemetry is not set to 'all'. Output: disabled telemetry
166+ // 3. User rejects consent and VSCode telemetry is set to 'all'. Output: disabled telemetry
167+ // 4. User rejects consent and VSCode telemetry is not set to 'all'. Output: disabled telemetry
168+ // 5. User changes from accept to reject consent and VSCode telemetry is set to 'all'. Output: disabled telemetry
169+ // 6. User changes from accept to reject consent and VSCode telemetry is not set to 'all'. Output: disabled telemetry
170+ // 7. User changes from reject to accept consent and VSCode telemetry is set to 'all'. Output: enabled telemetry
171+ // 8. User changes from reject to accept consent and VSCode telemetry is not set to 'all'. Output: disabled telemetry
172+ // 9. User accepts consent and VSCode telemetry is changed from 'all' to 'error'. Output: disabled telemetry
173+ // 10. User accepts consent and VSCode telemetry is changed from 'error' to 'all'. Output: enabled telemetry
174+ // 11. When consent schema version updated, pop up should trigger again.
175+ // 12. When consent schema version updated, pop up should trigger again, if closed without selecting any value and again reloading the screen, it should pop-up again.: Disabled telemetry in settings
176+ // 13. When consent schema version updated, pop up should trigger again, if selected yes and again reloading the screen, it shouldn't pop-up again. Output: Enabled telemetry in settings
177+ // 14. When consent schema version updated, pop up should trigger again, if selected no and again reloading the screen, it shouldn't pop-up again. Output: Disabled telemetry in settings
178+ // 15. When VSCode setting is changed from reject to accept, our pop-up should come.
0 commit comments