@@ -106,26 +106,48 @@ const bulkAssign = async (type, folderId, items) => {
106106 return response . result ;
107107} ;
108108
109- const getDiagnostics = async ( ) => {
110- const response = await apiGetJson ( ' /plugins/folderview.plus/server/diagnostics.php?action=report' ) ;
109+ const getDiagnostics = async ( privacy = 'sanitized' ) => {
110+ const response = await apiGetJson ( ` /plugins/folderview.plus/server/diagnostics.php?action=report&privacy= ${ encodeURIComponent ( privacy || 'sanitized' ) } ` ) ;
111111 if ( ! response . ok ) {
112112 throw new Error ( response . error || 'Diagnostics failed.' ) ;
113113 }
114114 return response . diagnostics || { } ;
115115} ;
116116
117- const runDiagnosticAction = async ( action , type ) => {
117+ const runDiagnosticAction = async ( action , type , privacy = 'sanitized' ) => {
118118 const payload = { action } ;
119119 if ( type ) {
120120 payload . type = type ;
121121 }
122+ payload . privacy = privacy || 'sanitized' ;
122123 const response = parseJsonResponse ( await $ . post ( '/plugins/folderview.plus/server/diagnostics.php' , payload ) . promise ( ) ) ;
123124 if ( ! response . ok ) {
124125 throw new Error ( response . error || 'Diagnostics action failed.' ) ;
125126 }
126127 return response . diagnostics || { } ;
127128} ;
128129
130+ const trackDiagnosticsEvent = async ( { eventType, type = null , status = 'ok' , source = 'ui' , details = { } } ) => {
131+ if ( ! eventType ) {
132+ return ;
133+ }
134+ const payload = {
135+ action : 'track_event' ,
136+ eventType : String ( eventType ) ,
137+ status : String ( status || 'ok' ) ,
138+ source : String ( source || 'ui' ) ,
139+ details : JSON . stringify ( details || { } )
140+ } ;
141+ if ( type ) {
142+ payload . type = type ;
143+ }
144+ try {
145+ await $ . post ( '/plugins/folderview.plus/server/diagnostics.php' , payload ) . promise ( ) ;
146+ } catch ( error ) {
147+ // Event tracking is best-effort and should never block UI actions.
148+ }
149+ } ;
150+
129151const fetchPrefs = async ( type ) => {
130152 try {
131153 const response = await apiGetJson ( `/plugins/folderview.plus/server/prefs.php?type=${ type } ` ) ;
@@ -690,6 +712,15 @@ const downloadType = (type, id) => {
690712 pluginVersion
691713 } ) ;
692714 downloadFile ( `${ folder . name } .json` , toPrettyJson ( payload ) ) ;
715+ trackDiagnosticsEvent ( {
716+ eventType : 'export' ,
717+ type,
718+ details : {
719+ mode : 'single' ,
720+ folderCount : 1 ,
721+ schemaVersion : utils . EXPORT_SCHEMA_VERSION
722+ }
723+ } ) ;
693724 return ;
694725 }
695726
@@ -701,6 +732,15 @@ const downloadType = (type, id) => {
701732
702733 const name = type === 'docker' ? `${ EXPORT_BASENAME } .json` : `${ EXPORT_BASENAME } VM.json` ;
703734 downloadFile ( name , toPrettyJson ( payload ) ) ;
735+ trackDiagnosticsEvent ( {
736+ eventType : 'export' ,
737+ type,
738+ details : {
739+ mode : 'full' ,
740+ folderCount : Object . keys ( folders ) . length ,
741+ schemaVersion : utils . EXPORT_SCHEMA_VERSION
742+ }
743+ } ) ;
704744} ;
705745const importType = async ( type ) => {
706746 let selected ;
@@ -756,6 +796,16 @@ const importType = async (type) => {
756796 const backup = await createBackup ( type , `before-import-${ dialogResult . mode } ` ) ;
757797 await applyImportOperations ( type , operations ) ;
758798 await Promise . all ( [ refreshType ( type ) , refreshBackups ( type ) ] ) ;
799+ await trackDiagnosticsEvent ( {
800+ eventType : 'import' ,
801+ type,
802+ details : {
803+ mode : dialogResult . mode ,
804+ creates : operations . creates . length ,
805+ updates : operations . upserts . length ,
806+ deletes : operations . deletes . length
807+ }
808+ } ) ;
759809 await offerUndoAction ( type , backup , 'Import' ) ;
760810 } catch ( error ) {
761811 showError ( 'Import failed' , error ) ;
@@ -797,6 +847,14 @@ const clearType = (type, id) => {
797847 }
798848
799849 await Promise . all ( [ refreshType ( type ) , refreshBackups ( type ) ] ) ;
850+ await trackDiagnosticsEvent ( {
851+ eventType : id ? 'delete_folder' : 'clear_folders' ,
852+ type,
853+ details : {
854+ deletedCount : id ? 1 : Object . keys ( folders ) . length ,
855+ singleFolder : Boolean ( id )
856+ }
857+ } ) ;
800858 await offerUndoAction ( type , backup , id ? 'Delete folder' : 'Clear folders' ) ;
801859 } catch ( error ) {
802860 showError ( 'Delete failed' , error ) ;
@@ -1035,6 +1093,14 @@ const assignSelectedItems = async (type) => {
10351093 const backup = await createBackup ( type , 'before-bulk-assign' ) ;
10361094 await bulkAssign ( type , folderId , selected ) ;
10371095 await Promise . all ( [ refreshType ( type ) , refreshBackups ( type ) ] ) ;
1096+ await trackDiagnosticsEvent ( {
1097+ eventType : 'bulk_assign' ,
1098+ type,
1099+ details : {
1100+ folderId,
1101+ itemCount : selected . length
1102+ }
1103+ } ) ;
10381104 await offerUndoAction ( type , backup , 'Bulk assignment' ) ;
10391105 } catch ( error ) {
10401106 showError ( 'Bulk assignment failed' , error ) ;
@@ -1171,15 +1237,30 @@ const repairDiagnostics = async (action) => {
11711237} ;
11721238
11731239const exportDiagnostics = async ( ) => {
1174- try {
1175- if ( ! lastDiagnostics ) {
1176- const diagnostics = await getDiagnostics ( ) ;
1240+ swal ( {
1241+ title : 'Export diagnostics' ,
1242+ text : 'Include full details (paths, names, and request metadata)?\nChoose Cancel for sanitized export.' ,
1243+ type : 'warning' ,
1244+ showCancelButton : true ,
1245+ confirmButtonText : 'Full export' ,
1246+ cancelButtonText : 'Sanitized export'
1247+ } , async ( useFull ) => {
1248+ const privacy = useFull ? 'full' : 'sanitized' ;
1249+ try {
1250+ const diagnostics = await getDiagnostics ( privacy ) ;
11771251 renderDiagnostics ( diagnostics ) ;
1252+ downloadFile ( 'FolderView Plus Diagnostics.json' , toPrettyJson ( diagnostics || { } ) ) ;
1253+ await trackDiagnosticsEvent ( {
1254+ eventType : 'diagnostics_export' ,
1255+ details : {
1256+ privacyMode : privacy ,
1257+ schemaVersion : diagnostics ?. schemaVersion || null
1258+ }
1259+ } ) ;
1260+ } catch ( error ) {
1261+ showError ( 'Diagnostics export failed' , error ) ;
11781262 }
1179- downloadFile ( 'FolderView Plus Diagnostics.json' , toPrettyJson ( lastDiagnostics || { } ) ) ;
1180- } catch ( error ) {
1181- showError ( 'Diagnostics export failed' , error ) ;
1182- }
1263+ } ) ;
11831264} ;
11841265
11851266const checkForUpdatesNow = async ( ) => {
0 commit comments