diff --git a/apps/circuit-compiler/src/app/actions/index.ts b/apps/circuit-compiler/src/app/actions/index.ts index 30c7342b6d3..db39692597d 100644 --- a/apps/circuit-compiler/src/app/actions/index.ts +++ b/apps/circuit-compiler/src/app/actions/index.ts @@ -33,7 +33,7 @@ export const computeWitness = async (plugin: CircomPluginClient, appState: AppSt const writePath = extractParentFromKey(appState.filePath) + `/.bin/${fileName.replace('.circom', '_js')}/${fileName.replace('.circom', '.wtn.json')}` await plugin.call('fileManager', 'writeFile', writePath, JSON.stringify(wtnsJson, null, 2)) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'computeWitness', name: 'wtns.exportJson', value: writePath, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'compiler.generate_witness', name: 'wtns.exportJson', value: writePath, isClick: true }) } } else { console.log('Existing witness computation in progress') @@ -62,38 +62,38 @@ export const runSetupAndExport = async (plugin: CircomPluginClient, appState: Ap const zkey_final = { type: "mem" } if (appState.provingScheme === 'groth16') { - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'runSetupAndExport', name: 'provingScheme', value: 'groth16', isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'runSetupAndExport', name: 'provingScheme', value: 'groth16', isClick: true }) await snarkjs.zKey.newZKey(r1cs, ptau_final, zkey_final, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK')) const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK')) if (appState.exportVerificationKey) { await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/keys/verification_key.json`, JSON.stringify(vKey, null, 2)) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'runSetupAndExport', name: 'zKey.exportVerificationKey', value: `${extractParentFromKey(appState.filePath)}/groth16/zk/keys/verification_key.json`, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'runSetupAndExport', name: 'zKey.exportVerificationKey', value: `${extractParentFromKey(appState.filePath)}/groth16/zk/keys/verification_key.json`, isClick: true }) } if (appState.exportVerificationContract) { const templates = { groth16: GROTH16_VERIFIER } const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK')) await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/zk_verifier.sol`, solidityContract) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'runSetupAndExport', name: 'zKey.exportSolidityVerifier', value: `${extractParentFromKey(appState.filePath)}/groth16/zk/build/zk_verifier.sol`, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'runSetupAndExport', name: 'zKey.exportSolidityVerifier', value: `${extractParentFromKey(appState.filePath)}/groth16/zk/build/zk_verifier.sol`, isClick: true }) } dispatch({ type: 'SET_ZKEY', payload: zkey_final }) dispatch({ type: 'SET_VERIFICATION_KEY', payload: vKey }) } else if (appState.provingScheme === 'plonk') { - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'runSetupAndExport', name: 'provingScheme', value: 'plonk', isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'runSetupAndExport', name: 'provingScheme', value: 'plonk', isClick: true }) await snarkjs.plonk.setup(r1cs, ptau_final, zkey_final, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK')) const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK')) if (appState.exportVerificationKey) { await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/keys/verification_key.json`, JSON.stringify(vKey, null, 2)) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'runSetupAndExport', name: 'zKey.exportVerificationKey', value: `${extractParentFromKey(appState.filePath)}/plonk/zk/keys/verification_key.json`, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'runSetupAndExport', name: 'zKey.exportVerificationKey', value: `${extractParentFromKey(appState.filePath)}/plonk/zk/keys/verification_key.json`, isClick: true }) } if (appState.exportVerificationContract) { const templates = { plonk: PLONK_VERIFIER } const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK')) await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/zk_verifier.sol`, solidityContract) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'runSetupAndExport', name: 'zKey.exportSolidityVerifier', value: `${extractParentFromKey(appState.filePath)}/plonk/zk/build/zk_verifier.sol`, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'runSetupAndExport', name: 'zKey.exportSolidityVerifier', value: `${extractParentFromKey(appState.filePath)}/plonk/zk/build/zk_verifier.sol`, isClick: true }) } dispatch({ type: 'SET_ZKEY', payload: zkey_final }) dispatch({ type: 'SET_VERIFICATION_KEY', payload: vKey }) @@ -101,7 +101,7 @@ export const runSetupAndExport = async (plugin: CircomPluginClient, appState: Ap dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' }) dispatch({ type: 'SET_SETUP_EXPORT_STATUS', payload: 'done' }) } catch (e) { - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'runSetupAndExport', name: 'error', value: e.message, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'runSetupAndExport', name: 'error', value: e.message, isClick: true }) dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' }) console.error(e) } @@ -133,12 +133,12 @@ export const generateProof = async (plugin: CircomPluginClient, appState: AppSta plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/proof.json`, JSON.stringify(proof, null, 2)) plugin.call('terminal', 'log', { type: 'log', value: 'zk proof validity ' + verified }) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'generateProof', name: 'groth16.prove', value: verified, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'generateProof', name: 'groth16.prove', value: verified, isClick: true }) if (appState.exportVerifierCalldata) { const calldata = await snarkjs.groth16.exportSolidityCallData(proof, publicSignals) plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/verifierCalldata.json`, calldata) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'generateProof', name: 'groth16.exportSolidityCallData', value: `${extractParentFromKey(appState.filePath)}/groth16/zk/build/verifierCalldata.json`, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'generateProof', name: 'groth16.exportSolidityCallData', value: `${extractParentFromKey(appState.filePath)}/groth16/zk/build/verifierCalldata.json`, isClick: true }) } } else if (appState.provingScheme === 'plonk') { const { proof, publicSignals } = await snarkjs.plonk.prove(zkey_final, wtns, zkLogger(plugin, dispatch, 'SET_PROOF_FEEDBACK')) @@ -146,12 +146,12 @@ export const generateProof = async (plugin: CircomPluginClient, appState: AppSta plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/proof.json`, JSON.stringify(proof, null, 2)) plugin.call('terminal', 'log', { type: 'log', value: 'zk proof validity ' + verified }) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'generateProof', name: 'plonk.prove', value: verified, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'generateProof', name: 'plonk.prove', value: verified, isClick: true }) if (appState.exportVerifierCalldata) { const calldata = await snarkjs.plonk.exportSolidityCallData(proof, publicSignals) plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/verifierCalldata.json`, calldata) - trackMatomoEvent(plugin, { category: 'circuitCompiler', action: 'generateProof', name: 'plonk.exportSolidityCallData', value: `${extractParentFromKey(appState.filePath)}/plonk/zk/build/verifierCalldata.json`, isClick: true }) + trackMatomoEvent(plugin, { category: 'circuit-compiler', action: 'generateProof', name: 'plonk.exportSolidityCallData', value: `${extractParentFromKey(appState.filePath)}/plonk/zk/build/verifierCalldata.json`, isClick: true }) } } dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' }) diff --git a/apps/circuit-compiler/src/app/services/circomPluginClient.ts b/apps/circuit-compiler/src/app/services/circomPluginClient.ts index 256871f78c1..4aa95499709 100644 --- a/apps/circuit-compiler/src/app/services/circomPluginClient.ts +++ b/apps/circuit-compiler/src/app/services/circomPluginClient.ts @@ -171,7 +171,7 @@ export class CircomPluginClient extends PluginClient { const circuitErrors = circuitApi.report() this.logCompilerReport(circuitErrors) - trackMatomoEvent(this, { category: 'circuitCompiler', action: 'compile', name: 'Compilation failed', isClick: true }) + trackMatomoEvent(this, { category: 'circuit-compiler', action: 'compile', name: 'Compilation failed', isClick: true }) throw new Error(circuitErrors) } else { this.lastCompiledFile = path @@ -200,7 +200,7 @@ export class CircomPluginClient extends PluginClient { this.internalEvents.emit('circuit_parsing_done', parseErrors, filePathToId) this.emit('statusChanged', { key: 'succeed', title: 'circuit compiled successfully', type: 'success' }) } - trackMatomoEvent(this, { category: 'circuitCompiler', action: 'compile', name: 'Compilation successful', isClick: true }) + trackMatomoEvent(this, { category: 'circuit-compiler', action: 'compile', name: 'Compilation successful', isClick: true }) circuitApi.log().map(log => { log && this.call('terminal', 'log', { type: 'log', value: log }) }) @@ -282,7 +282,7 @@ export class CircomPluginClient extends PluginClient { const r1csErrors = r1csApi.report() this.logCompilerReport(r1csErrors) - trackMatomoEvent(this, { category: 'circuitCompiler', action: 'generateR1cs', name: 'R1CS Generation failed', isClick: true }) + trackMatomoEvent(this, { category: 'circuit-compiler', action: 'generateR1cs', name: 'R1CS Generation failed', isClick: true }) throw new Error(r1csErrors) } else { const fileName = extractNameFromKey(path) @@ -290,7 +290,7 @@ export class CircomPluginClient extends PluginClient { // @ts-ignore await this.call('fileManager', 'writeFile', writePath, r1csProgram, true) - trackMatomoEvent(this, { category: 'circuitCompiler', action: 'generateR1cs', name: 'R1CS Generation successful', isClick: true }) + trackMatomoEvent(this, { category: 'circuit-compiler', action: 'generateR1cs', name: 'R1CS Generation successful', isClick: true }) r1csApi.log().map(log => { log && this.call('terminal', 'log', { type: 'log', value: log }) }) @@ -338,7 +338,7 @@ export class CircomPluginClient extends PluginClient { const witness = this.compiler ? await this.compiler.generate_witness(dataRead, input) : await generate_witness(dataRead, input) // @ts-ignore await this.call('fileManager', 'writeFile', wasmPath.replace('.wasm', '.wtn'), witness, { encoding: null }) - trackMatomoEvent(this, { category: 'circuitCompiler', action: 'computeWitness', name: wasmPath.replace('.wasm', '.wtn'), isClick: true }) + trackMatomoEvent(this, { category: 'circuit-compiler', action: 'compiler.generate_witness', name: wasmPath.replace('.wasm', '.wtn'), isClick: true }) this.internalEvents.emit('circuit_computing_witness_done') this.emit('statusChanged', { key: 'succeed', title: 'witness computed successfully', type: 'success' }) return witness diff --git a/apps/learneth/src/redux/models/remixide.ts b/apps/learneth/src/redux/models/remixide.ts index b538ff33435..4736996065e 100644 --- a/apps/learneth/src/redux/models/remixide.ts +++ b/apps/learneth/src/redux/models/remixide.ts @@ -69,7 +69,7 @@ const Model: ModelType = { return } - trackMatomoEvent(remixClient, { category: 'learneth', action: 'displayFile', name: `${(step && step.name)}/${path}`, isClick: true }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'display_file', name: `${(step && step.name)}/${path}`, isClick: true }) toast.info(`loading ${path} into IDE`) yield put({ @@ -96,7 +96,7 @@ const Model: ModelType = { }) toast.dismiss() } catch (error) { - trackMatomoEvent(remixClient, { category: 'learneth', action: 'displayFileError', name: error.message, isClick: false }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'display_file_error', name: error.message, isClick: false }) toast.dismiss() toast.error('File could not be loaded. Please try again.') yield put({ @@ -146,7 +146,7 @@ const Model: ModelType = { type: 'remixide/save', payload: { errors: ['Compiler failed to test this file']}, }); - trackMatomoEvent(remixClient, { category: 'learneth', action: 'testStepError', name: 'Compiler failed to test this file', isClick: false }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'test_step_error', name: 'Compiler failed to test this file', isClick: false }) } else { const success = result.totalFailing === 0; if (success) { @@ -162,14 +162,14 @@ const Model: ModelType = { }, }) } - trackMatomoEvent(remixClient, { category: 'learneth', action: 'testStep', name: String(success), isClick: true }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'test_step', name: String(success), isClick: true }) } } catch (err) { yield put({ type: 'remixide/save', payload: { errors: [String(err)]}, }); - trackMatomoEvent(remixClient, { category: 'learneth', action: 'testStepError', name: String(err), isClick: false }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'test_step_error', name: String(err), isClick: false }) } yield put({ type: 'loading/save', @@ -199,13 +199,13 @@ const Model: ModelType = { yield remixClient.call('fileManager', 'setFile', path, content) yield remixClient.call('fileManager', 'switchFile', `${path}`); - trackMatomoEvent(remixClient, { category: 'learneth', action: 'showAnswer', name: path, isClick: true }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'show_answer', name: path, isClick: true }) } catch (err) { yield put({ type: 'remixide/save', payload: { errors: [String(err)]}, }); - trackMatomoEvent(remixClient, { category: 'learneth', action: 'showAnswerError', name: err.message, isClick: false }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'show_answer_error', name: err.message, isClick: false }) } toast.dismiss() @@ -219,7 +219,7 @@ const Model: ModelType = { *testSolidityCompiler(_, { put, select }) { try { yield remixClient.call('solidity', 'getCompilationResult'); - trackMatomoEvent(remixClient, { category: 'learneth', action: 'testSolidityCompiler', isClick: true }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'test_solidity_compiler', isClick: true }) } catch (err) { const errors = yield select((state) => state.remixide.errors) yield put({ @@ -228,7 +228,7 @@ const Model: ModelType = { errors: [...errors, "The `Solidity Compiler` is not yet activated.
Please activate it using the `SOLIDITY` button in the `Featured Plugins` section of the homepage."], }, }); - trackMatomoEvent(remixClient, { category: 'learneth', action: 'testSolidityCompilerError', name: err.message, isClick: false }) + trackMatomoEvent(remixClient, { category: 'learneth', action: 'test_solidity_compiler_error', name: err.message, isClick: false }) } } }, diff --git a/apps/remix-ide/src/app.ts b/apps/remix-ide/src/app.ts index 07505624656..d66f03aa334 100644 --- a/apps/remix-ide/src/app.ts +++ b/apps/remix-ide/src/app.ts @@ -685,7 +685,7 @@ class AppComponent { if (callDetails.length > 1) { this.appManager.call('notification', 'toast', `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...`) // @todo(remove the timeout when activatePlugin is on 0.3.0) - this.track({ category: 'App', action: 'queryParamsCalls', name: this.params.call, isClick: false }) + this.track({ category: 'App', action: 'queryParams-calls', name: this.params.call, isClick: false }) //@ts-ignore await this.appManager.call(...callDetails).catch(console.error) } @@ -696,7 +696,7 @@ class AppComponent { // call all functions in the list, one after the other for (const call of calls) { - this.track({ category: 'App', action: 'queryParamsCalls', name: call, isClick: false }) + this.track({ category: 'App', action: 'queryParams-calls', name: call, isClick: false }) const callDetails = call.split('//') if (callDetails.length > 1) { this.appManager.call('notification', 'toast', `initiating ${callDetails[0]} and calling "${callDetails[1]}" ...`) diff --git a/apps/remix-ide/src/app/components/preload.tsx b/apps/remix-ide/src/app/components/preload.tsx index bd2db8cff8e..3b430413f86 100644 --- a/apps/remix-ide/src/app/components/preload.tsx +++ b/apps/remix-ide/src/app/components/preload.tsx @@ -69,7 +69,7 @@ export const Preload = (props: PreloadProps) => { setShowDownloader(false) const fsUtility = new fileSystemUtility() const migrationResult = await fsUtility.migrate(localStorageFileSystem.current, remixIndexedDB.current) - trackMatomoEvent?.({ category: 'migrate', action: 'result', name: migrationResult ? 'success' : 'fail', isClick: false }) + trackMatomoEvent?.({ category: 'Migrate', action: 'result', name: migrationResult ? 'success' : 'fail', isClick: false }) await setFileSystems() } diff --git a/apps/remix-ide/src/app/files/filesystems/fileSystemUtility.ts b/apps/remix-ide/src/app/files/filesystems/fileSystemUtility.ts index b3d8fd9e196..71186d7fb36 100644 --- a/apps/remix-ide/src/app/files/filesystems/fileSystemUtility.ts +++ b/apps/remix-ide/src/app/files/filesystems/fileSystemUtility.ts @@ -39,14 +39,14 @@ export class fileSystemUtility { console.log('file migration successful') return true } else { - track({ category: 'migrate', action: 'error', name: 'hash mismatch', isClick: false }) + track({ category: 'Migrate', action: 'error', name: 'hash mismatch', isClick: false }) console.log('file migration failed falling back to ' + fsFrom.name) fsTo.loaded = false return false } } catch (err) { console.log(err) - track({ category: 'migrate', action: 'error', name: err && err.message, isClick: false }) + track({ category: 'Migrate', action: 'error', name: err && err.message, isClick: false }) console.log('file migration failed falling back to ' + fsFrom.name) fsTo.loaded = false return false diff --git a/apps/remix-ide/src/app/plugins/remix-ai-assistant.tsx b/apps/remix-ide/src/app/plugins/remix-ai-assistant.tsx index 7f4d7bb11aa..23e57a8e4aa 100644 --- a/apps/remix-ide/src/app/plugins/remix-ai-assistant.tsx +++ b/apps/remix-ide/src/app/plugins/remix-ai-assistant.tsx @@ -102,8 +102,9 @@ export class RemixAIAssistant extends ViewPlugin { } async handleActivity(type: string, payload: any) { - // Use the proper type-safe tracking helper with RemixAI events - trackMatomoEvent(this, { category: 'ai', action: 'remixAI', name: `${type}-${payload}`, isClick: true }) + // Never log user prompts - only track the activity type + const eventName = type === 'promptSend' ? 'remixai-assistant-promptSend' : `remixai-assistant-${type}-${payload}`; + trackMatomoEvent(this, { category: 'ai', action: 'remixAI', name: eventName as any, isClick: true }) } updateComponent(state: { diff --git a/apps/remix-ide/src/app/plugins/solidity-script.tsx b/apps/remix-ide/src/app/plugins/solidity-script.tsx index 93fae6dbe92..d73bd925f62 100644 --- a/apps/remix-ide/src/app/plugins/solidity-script.tsx +++ b/apps/remix-ide/src/app/plugins/solidity-script.tsx @@ -18,7 +18,7 @@ export class SolidityScript extends Plugin { } async execute(path: string, functionName: string = 'run') { - trackMatomoEvent(this, { category: 'solidityScript', action: 'execute', name: 'script', isClick: true }) + trackMatomoEvent(this, { category: 'SolidityScript', action: 'execute', name: 'script', isClick: true }) this.call('terminal', 'log', `Running free function '${functionName}' from ${path}...`) let content = await this.call('fileManager', 'readFile', path) const params = await this.call('solidity', 'getCompilerQueryParameters') diff --git a/apps/remix-ide/src/app/plugins/solidity-umlgen.tsx b/apps/remix-ide/src/app/plugins/solidity-umlgen.tsx index 81d69676235..3bc11403a0a 100644 --- a/apps/remix-ide/src/app/plugins/solidity-umlgen.tsx +++ b/apps/remix-ide/src/app/plugins/solidity-umlgen.tsx @@ -88,7 +88,7 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { }) const payload = vizRenderStringSync(umlDot) this.updatedSvg = payload - trackMatomoEvent(this, { category: 'solidityUMLGen', action: 'umlgenerated', isClick: false }) + trackMatomoEvent(this, { category: 'solidityumlgen', action: 'umlgenerated', isClick: false }) this.renderComponent() await this.call('tabs', 'focus', 'solidityumlgen') } catch (error) { @@ -125,7 +125,7 @@ export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen { generateCustomAction = async (action: customAction) => { this.triggerGenerateUml = true this.updatedSvg = this.updatedSvg.startsWith(' { this.opts = {} - trackMatomoEvent(this, { category: 'templateSelection', action: 'addToCurrentWorkspace', name: item.value, isClick: true }) + trackMatomoEvent(this, { category: 'template-selection', action: 'addToCurrentWorkspace', name: item.value, isClick: true }) if (templateGroup.hasOptions) { const modal: AppModal = { id: 'TemplatesSelection', diff --git a/apps/remix-ide/src/app/tabs/compile-and-run.ts b/apps/remix-ide/src/app/tabs/compile-and-run.ts index 46256db8da9..35bb68a335b 100644 --- a/apps/remix-ide/src/app/tabs/compile-and-run.ts +++ b/apps/remix-ide/src/app/tabs/compile-and-run.ts @@ -29,11 +29,11 @@ export class CompileAndRun extends Plugin { e.preventDefault() this.targetFileName = file await this.call('solidity', 'compile', file) - trackMatomoEvent(this, { category: 'scriptExecutor', action: 'compileAndRun', name: 'compile_solidity', isClick: true }) + trackMatomoEvent(this, { category: 'ScriptExecutor', action: 'CompileAndRun', name: 'compile_solidity', isClick: true }) } else if (file.endsWith('.js') || file.endsWith('.ts')) { e.preventDefault() this.runScript(file, false) - trackMatomoEvent(this, { category: 'scriptExecutor', action: 'compileAndRun', name: 'run_script', isClick: true }) + trackMatomoEvent(this, { category: 'ScriptExecutor', action: 'CompileAndRun', name: 'run_script', isClick: true }) } } } @@ -42,7 +42,7 @@ export class CompileAndRun extends Plugin { runScriptAfterCompilation (fileName: string) { this.targetFileName = fileName - trackMatomoEvent(this, { category: 'scriptExecutor', action: 'compileAndRun', name: 'request_run_script', isClick: true }) + trackMatomoEvent(this, { category: 'ScriptExecutor', action: 'CompileAndRun', name: 'request_run_script', isClick: true }) } async runScript (fileName, clearAllInstances) { @@ -73,7 +73,7 @@ export class CompileAndRun extends Plugin { const file = contract.object.devdoc['custom:dev-run-script'] if (file) { this.runScript(file, true) - trackMatomoEvent(this, { category: 'scriptExecutor', action: 'compileAndRun', name: 'run_script_after_compile', isClick: true }) + trackMatomoEvent(this, { category: 'ScriptExecutor', action: 'CompileAndRun', name: 'run_script_after_compile', isClick: true }) } else { this.call('notification', 'toast', 'You have not set a script to run. Set it with @custom:dev-run-script NatSpec tag.') } diff --git a/apps/remix-ide/src/assets/list.json b/apps/remix-ide/src/assets/list.json index 1e99f780891..e136bac177b 100644 --- a/apps/remix-ide/src/assets/list.json +++ b/apps/remix-ide/src/assets/list.json @@ -1066,6 +1066,18 @@ "urls": [ "dweb:/ipfs/QmXFsguaaxZj2FZmf2pGLTPDDkDD8nHX4grC4jDVugnMxv" ] + }, + { + "path": "soljson-v0.8.31-pre.1+commit.b59566f6.js", + "version": "0.8.31", + "prerelease": "pre.1", + "build": "commit.b59566f6", + "longVersion": "0.8.31-pre.1+commit.b59566f6", + "keccak256": "0x5cbab72123ec1f65e72592375e568788d88c96ffd90a1a3e9107fcd5a3b9cf87", + "sha256": "0xaf2b74e3c674c09ce89189edfaa81a0d01f1a0dce9100968e0d442de8a93b926", + "urls": [ + "dweb:/ipfs/QmafWKo2uVeEPMi1GbY2DVPreWtbA6aqXjynnn4wViA6a4" + ] } ], "releases": { diff --git a/libs/remix-api/src/lib/plugins/matomo/core/categories.ts b/libs/remix-api/src/lib/plugins/matomo/core/categories.ts index f66573fd2b9..910556a7510 100644 --- a/libs/remix-api/src/lib/plugins/matomo/core/categories.ts +++ b/libs/remix-api/src/lib/plugins/matomo/core/categories.ts @@ -28,7 +28,8 @@ export const MatomoCategories = { SOLIDITY_SCRIPT: 'SolidityScript' as const, SCRIPT_EXECUTOR: 'ScriptExecutor' as const, LOCALE_MODULE: 'localeModule' as const, - THEME_MODULE: 'themeModule' as const + THEME_MODULE: 'themeModule' as const, + STATUS_BAR: 'statusBar' as const } // Common action constants used across multiple categories diff --git a/libs/remix-api/src/lib/plugins/matomo/events/ai-events.ts b/libs/remix-api/src/lib/plugins/matomo/events/ai-events.ts index 8606baaf034..110209a2bad 100644 --- a/libs/remix-api/src/lib/plugins/matomo/events/ai-events.ts +++ b/libs/remix-api/src/lib/plugins/matomo/events/ai-events.ts @@ -3,23 +3,47 @@ * * This file contains all AI-related Matomo events including RemixAI interactions, * Ollama local AI, and code completion features. + * + * STANDARDIZED PATTERN: + * - category: 'ai' (always) + * - action: 'remixAI' (always) + * - name: specific event identifier (type-safe) */ import { MatomoEventBase } from '../core/base-types'; export interface AIEvent extends MatomoEventBase { category: 'ai'; - action: - | 'remixAI' - | 'error_explaining_SolidityError' - | 'vulnerability_check_pasted_code' - | 'generateDocumentation' - | 'explainFunction' + action: 'remixAI'; + name: + // Code completion & generation | 'Copilot_Completion_Accepted' | 'code_generation' | 'code_insertion' | 'code_completion' + | 'code_generation_did_show' + | 'code_insertion_did_show' + | 'code_completion_did_show' + | 'code_generation_partial_accept' + | 'code_insertion_partial_accept' + | 'code_completion_partial_accept' + | 'vulnerability_check_pasted_code' + | 'generateDocumentation' + | 'explainFunction' + | 'error_explaining_SolidityError' + // AI Context | 'AddingAIContext' + // RemixAI workspace & chat + | 'GenerateNewAIWorkspace' + | 'WorkspaceAgentEdit' + | 'remixAI_chat' + | 'GenerateNewAIWorkspaceFromEditMode' + | 'GenerateNewAIWorkspaceFromModal' + // AI Provider selection + | 'SetAIProvider' + | 'SetOllamaModel' + | 'ModeSwitch' + // Ollama host discovery | 'ollama_host_cache_hit' | 'ollama_port_check' | 'ollama_host_discovered_success' @@ -27,47 +51,54 @@ export interface AIEvent extends MatomoEventBase { | 'ollama_host_discovery_failed' | 'ollama_availability_check' | 'ollama_availability_result' + | 'ollama_reset_host' + // Ollama models | 'ollama_list_models_start' | 'ollama_list_models_failed' - | 'ollama_reset_host' | 'ollama_pull_model_start' | 'ollama_pull_model_failed' | 'ollama_pull_model_success' | 'ollama_pull_model_error' | 'ollama_get_best' | 'ollama_get_best_model_error' - | 'ollama_initialize_failed' - | 'ollama_host_discovered' | 'ollama_models_found' | 'ollama_model_auto_selected' + | 'ollama_model_selected' + | 'ollama_model_set_backend_success' + | 'ollama_model_set_backend_failed' + | 'ollama_default_model_selected' + // Ollama initialization + | 'ollama_initialize_failed' + | 'ollama_host_discovered' | 'ollama_initialize_success' | 'ollama_model_selection_error' + // Ollama code operations | 'ollama_fim_native' | 'ollama_fim_token_based' | 'ollama_completion_no_fim' | 'ollama_suffix_overlap_removed' | 'ollama_code_completion_complete' | 'ollama_code_insertion' + | 'ollama_code_generation' | 'ollama_generate_contract' | 'ollama_generate_workspace' | 'ollama_chat_answer' | 'ollama_code_explaining' | 'ollama_error_explaining' | 'ollama_vulnerability_check' + // Ollama provider | 'ollama_provider_selected' | 'ollama_fallback_to_provider' - | 'ollama_default_model_selected' | 'ollama_unavailable' | 'ollama_connection_error' - | 'ollama_model_selected' - | 'ollama_model_set_backend_success' - | 'ollama_model_set_backend_failed'; + // Assistant feedback (kebab-case to match original) + | 'like-response' + | 'dislike-response'; } - - /** - * RemixAI Events - Specific to RemixAI interactions + * @deprecated Use AIEvent with category: 'ai', action: 'remixAI' instead + * This interface is kept for backward compatibility during migration */ export interface RemixAIEvent extends MatomoEventBase { category: 'remixAI'; @@ -79,15 +110,14 @@ export interface RemixAIEvent extends MatomoEventBase { | 'GenerateNewAIWorkspaceFromModal'; } - - /** - * RemixAI Assistant Events - Specific to assistant interactions + * @deprecated Use AIEvent with name: 'like-response' | 'dislike-response' instead + * This interface is kept for backward compatibility during migration */ export interface RemixAIAssistantEvent extends MatomoEventBase { - category: 'remixAIAssistant'; + category: 'remixai-assistant'; action: - | 'likeResponse' - | 'dislikeResponse'; + | 'like-response' + | 'dislike-response'; } diff --git a/libs/remix-api/src/lib/plugins/matomo/events/file-events.ts b/libs/remix-api/src/lib/plugins/matomo/events/file-events.ts index 2c8436240ae..0035c0fdaa1 100644 --- a/libs/remix-api/src/lib/plugins/matomo/events/file-events.ts +++ b/libs/remix-api/src/lib/plugins/matomo/events/file-events.ts @@ -21,7 +21,7 @@ export interface FileExplorerEvent extends MatomoEventBase { } export interface WorkspaceEvent extends MatomoEventBase { - category: 'Workspace'; + category: 'workspace'; action: | 'switchWorkspace' | 'template' diff --git a/libs/remix-api/src/lib/plugins/matomo/events/plugin-events.ts b/libs/remix-api/src/lib/plugins/matomo/events/plugin-events.ts index 4dcece9970a..00c47344a19 100644 --- a/libs/remix-api/src/lib/plugins/matomo/events/plugin-events.ts +++ b/libs/remix-api/src/lib/plugins/matomo/events/plugin-events.ts @@ -49,11 +49,11 @@ export interface AppEvent extends MatomoEventBase { | 'loaded' | 'error' | 'PreloadError' - | 'queryParamsCalls'; + | 'queryParams-calls'; } export interface MigrateEvent extends MatomoEventBase { - category: 'migrate'; + category: 'Migrate'; action: | 'start' | 'complete' diff --git a/libs/remix-api/src/lib/plugins/matomo/events/tools-events.ts b/libs/remix-api/src/lib/plugins/matomo/events/tools-events.ts index c884d70cee6..f5eea9bb9ee 100644 --- a/libs/remix-api/src/lib/plugins/matomo/events/tools-events.ts +++ b/libs/remix-api/src/lib/plugins/matomo/events/tools-events.ts @@ -70,7 +70,7 @@ export interface XTERMEvent extends MatomoEventBase { } export interface SolidityScriptEvent extends MatomoEventBase { - category: 'solidityScript'; + category: 'SolidityScript'; action: | 'execute' | 'deploy' @@ -90,7 +90,7 @@ export interface RemixGuideEvent extends MatomoEventBase { } export interface TemplateSelectionEvent extends MatomoEventBase { - category: 'templateSelection'; + category: 'template-selection'; action: | 'selectTemplate' | 'createWorkspace' @@ -99,13 +99,13 @@ export interface TemplateSelectionEvent extends MatomoEventBase { } export interface ScriptExecutorEvent extends MatomoEventBase { - category: 'scriptExecutor'; + category: 'ScriptExecutor'; action: | 'execute' | 'deploy' | 'run' | 'compile' - | 'compileAndRun'; + | 'CompileAndRun'; } @@ -154,7 +154,7 @@ export interface ScriptExecutorEvent extends MatomoEventBase { * Solidity UML Generation Events - Type-safe builders */ export interface SolidityUMLGenEvent extends MatomoEventBase { - category: 'solidityUMLGen'; + category: 'solidityumlgen'; action: | 'umlpngdownload' | 'umlpdfdownload' @@ -171,17 +171,30 @@ export interface SolidityUMLGenEvent extends MatomoEventBase { * Circuit Compiler Events - Type-safe builders */ export interface CircuitCompilerEvent extends MatomoEventBase { - category: 'circuitCompiler'; + category: 'circuit-compiler'; action: | 'compile' | 'generateProof' | 'error' | 'generateR1cs' - | 'computeWitness' + | 'compiler.generate_witness' + | 'template' | 'runSetupAndExport'; } +/** + * Noir Compiler Events - Type-safe builders + */ +export interface NoirCompilerEvent extends MatomoEventBase { + category: 'noir-compiler'; + action: + | 'compile' + | 'template' + | 'error'; +} + + /** * Contract Verification Events - Type-safe builders */ @@ -204,14 +217,14 @@ export interface LearnethEvent extends MatomoEventBase { | 'lesson' | 'tutorial' | 'error' - | 'displayFile' - | 'displayFileError' - | 'testStep' - | 'testStepError' - | 'showAnswer' - | 'showAnswerError' - | 'testSolidityCompiler' - | 'testSolidityCompilerError' + | 'display_file' + | 'display_file_error' + | 'test_step' + | 'test_step_error' + | 'show_answer' + | 'show_answer_error' + | 'test_solidity_compiler' + | 'test_solidity_compiler_error' | 'start_workshop' | 'select_repo' | 'import_repo' diff --git a/libs/remix-api/src/lib/plugins/matomo/events/ui-events.ts b/libs/remix-api/src/lib/plugins/matomo/events/ui-events.ts index 62997813cd6..17913944a7f 100644 --- a/libs/remix-api/src/lib/plugins/matomo/events/ui-events.ts +++ b/libs/remix-api/src/lib/plugins/matomo/events/ui-events.ts @@ -66,6 +66,27 @@ export interface LandingPageEvent extends MatomoEventBase { | 'MatomoAIModal'; } +export interface StatusBarEvent extends MatomoEventBase { + category: 'statusBar'; + action: + | 'initNewRepo'; +} + + + + + + + + + + + + + + + + diff --git a/libs/remix-api/src/lib/plugins/matomo/index.ts b/libs/remix-api/src/lib/plugins/matomo/index.ts index 31a790a2d08..c05afd48a51 100644 --- a/libs/remix-api/src/lib/plugins/matomo/index.ts +++ b/libs/remix-api/src/lib/plugins/matomo/index.ts @@ -30,11 +30,11 @@ export * from './events/tools-events'; import type { AIEvent, RemixAIEvent, RemixAIAssistantEvent } from './events/ai-events'; import type { CompilerEvent, SolidityCompilerEvent, CompilerContainerEvent } from './events/compiler-events'; import type { GitEvent } from './events/git-events'; -import type { HomeTabEvent, TopbarEvent, LayoutEvent, SettingsEvent, ThemeEvent, LocaleEvent, LandingPageEvent } from './events/ui-events'; +import type { HomeTabEvent, TopbarEvent, LayoutEvent, SettingsEvent, ThemeEvent, LocaleEvent, LandingPageEvent, StatusBarEvent } from './events/ui-events'; import type { FileExplorerEvent, WorkspaceEvent, StorageEvent, BackupEvent } from './events/file-events'; import type { BlockchainEvent, UdappEvent, RunEvent } from './events/blockchain-events'; import type { PluginEvent, ManagerEvent, PluginManagerEvent, AppEvent, MatomoManagerEvent, PluginPanelEvent, MigrateEvent } from './events/plugin-events'; -import type { DebuggerEvent, EditorEvent, SolidityUnitTestingEvent, SolidityStaticAnalyzerEvent, DesktopDownloadEvent, XTERMEvent, SolidityScriptEvent, RemixGuideEvent, TemplateSelectionEvent, ScriptExecutorEvent, GridViewEvent, SolidityUMLGenEvent, ScriptRunnerPluginEvent, CircuitCompilerEvent, ContractVerificationEvent, LearnethEvent } from './events/tools-events'; +import type { DebuggerEvent, EditorEvent, SolidityUnitTestingEvent, SolidityStaticAnalyzerEvent, DesktopDownloadEvent, XTERMEvent, SolidityScriptEvent, RemixGuideEvent, TemplateSelectionEvent, ScriptExecutorEvent, GridViewEvent, SolidityUMLGenEvent, ScriptRunnerPluginEvent, CircuitCompilerEvent, NoirCompilerEvent, ContractVerificationEvent, LearnethEvent } from './events/tools-events'; // Union type of all Matomo events - includes base properties for compatibility export type MatomoEvent = ( @@ -59,6 +59,7 @@ export type MatomoEvent = ( | ThemeEvent | LocaleEvent | LandingPageEvent + | StatusBarEvent // File Management events | FileExplorerEvent @@ -95,6 +96,7 @@ export type MatomoEvent = ( | SolidityUMLGenEvent | ScriptRunnerPluginEvent | CircuitCompilerEvent + | NoirCompilerEvent | ContractVerificationEvent | LearnethEvent diff --git a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts index 87ecba34f35..927463a6768 100644 --- a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts +++ b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts @@ -202,7 +202,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli }) const data = await this.props.plugin.call('remixAI', 'code_insertion', word, word_after) - this.trackMatomoEvent?.({ category: 'ai', action: 'code_generation', isClick: false }) + this.trackMatomoEvent?.({ category: 'ai', action: 'remixAI', name: 'code_generation', isClick: false }) this.task = 'code_generation' const parsedData = data.trimStart() @@ -228,7 +228,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli try { CompletionParams.stop = ['\n\n', '```'] const output = await this.props.plugin.call('remixAI', 'code_insertion', word, word_after, CompletionParams) - this.trackMatomoEvent?.({ category: 'ai', action: 'code_insertion', isClick: false }) + this.trackMatomoEvent?.({ category: 'ai', action: 'remixAI', name: 'code_insertion', isClick: false }) const generatedText = output this.task = 'code_insertion' @@ -259,7 +259,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli CompletionParams.stop = ['\n', '```'] this.task = 'code_completion' const output = await this.props.plugin.call('remixAI', 'code_completion', word, word_after, CompletionParams) - this.trackMatomoEvent?.({ category: 'ai', action: 'code_completion', isClick: false }) + this.trackMatomoEvent?.({ category: 'ai', action: 'remixAI', name: 'code_completion', isClick: false }) const generatedText = output let clean = generatedText @@ -307,7 +307,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli this.currentCompletion.task = this.task this.rateLimiter.trackCompletionShown() - this.trackMatomoEvent?.({ category: 'ai', action: 'remixAI', name: this.task + '_did_show', isClick: true }) + this.trackMatomoEvent?.({ category: 'ai', action: 'remixAI', name: `${this.task}_did_show` as any, isClick: true }) } handlePartialAccept?( @@ -319,7 +319,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli this.currentCompletion.task = this.task this.rateLimiter.trackCompletionAccepted() - this.trackMatomoEvent?.({ category: 'ai', action: 'remixAI', name: this.task + '_partial_accept', isClick: true }) + this.trackMatomoEvent?.({ category: 'ai', action: 'remixAI', name: `${this.task}_partial_accept` as any, isClick: true }) } freeInlineCompletions( diff --git a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx index 1751ee8cfb3..cd80fcab4aa 100644 --- a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx +++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx @@ -794,7 +794,7 @@ export const EditorUI = (props: EditorUIProps) => { setTimeout(async () => { props.plugin.call('remixAI', 'chatPipe', 'vulnerability_check', pastedCodePrompt) }, 500) - trackMatomoEvent({ category: 'ai', action: 'vulnerability_check_pasted_code', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'vulnerability_check_pasted_code', isClick: true }) })(); } }; @@ -862,7 +862,7 @@ export const EditorUI = (props: EditorUIProps) => { if (changes.some(change => change.text === inlineCompletionProvider.currentCompletion.item.insertText)) { inlineCompletionProvider.currentCompletion.onAccepted() inlineCompletionProvider.currentCompletion.accepted = true - trackMatomoEvent({ category: 'ai', action: 'Copilot_Completion_Accepted', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'Copilot_Completion_Accepted', isClick: true }) } } }); @@ -998,7 +998,7 @@ export const EditorUI = (props: EditorUIProps) => { }, 150) } } - trackMatomoEvent({ category: 'ai', action: 'generateDocumentation', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'generateDocumentation', isClick: true }) }, } } @@ -1017,7 +1017,7 @@ export const EditorUI = (props: EditorUIProps) => { setTimeout(async () => { await props.plugin.call('remixAI' as any, 'chatPipe', 'code_explaining', message, context) }, 500) - trackMatomoEvent({ category: 'ai', action: 'explainFunction', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'explainFunction', isClick: true }) }, } @@ -1041,7 +1041,7 @@ export const EditorUI = (props: EditorUIProps) => { setTimeout(async () => { await props.plugin.call('remixAI' as any, 'chatPipe', 'code_explaining', selectedCode, content, pipeMessage) }, 500) - trackMatomoEvent({ category: 'ai', action: 'explainFunction', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'explainFunction', isClick: true }) }, } diff --git a/libs/remix-ui/home-tab/src/lib/components/homeTabTitle.tsx b/libs/remix-ui/home-tab/src/lib/components/homeTabTitle.tsx index bd41ebf5ef7..2c6770c858e 100644 --- a/libs/remix-ui/home-tab/src/lib/components/homeTabTitle.tsx +++ b/libs/remix-ui/home-tab/src/lib/components/homeTabTitle.tsx @@ -119,7 +119,7 @@ function HomeTabTitle() { trackMatomoEvent({ category: 'hometab', action: 'titleCard', - name: button.matomoTrackingEntry[3], + name: button.matomoTrackingEntry[index], isClick: true }) }} diff --git a/libs/remix-ui/remix-ai-assistant/src/components/prompt.tsx b/libs/remix-ui/remix-ai-assistant/src/components/prompt.tsx index 608dbed0f48..53a640edc4a 100644 --- a/libs/remix-ui/remix-ai-assistant/src/components/prompt.tsx +++ b/libs/remix-ui/remix-ai-assistant/src/components/prompt.tsx @@ -129,7 +129,7 @@ export const PromptArea: React.FC = ({ className={`btn btn-sm ${aiMode === 'ask' ? 'btn-primary' : 'btn-outline-secondary'} px-2`} onClick={() => { setAiMode('ask') - trackMatomoEvent({ category: 'remixAI', action: 'ModeSwitch', name: 'ask', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ModeSwitch', value: 'ask', isClick: true }) }} title="Ask mode - Chat with AI" > @@ -140,7 +140,7 @@ export const PromptArea: React.FC = ({ className={`btn btn-sm ${aiMode === 'edit' ? 'btn-primary' : 'btn-outline-secondary'} px-2`} onClick={() => { setAiMode('edit') - trackMatomoEvent({ category: 'remixAI', action: 'ModeSwitch', name: 'edit', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ModeSwitch', value: 'edit', isClick: true }) }} title="Edit mode - Edit workspace code" > diff --git a/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx b/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx index 71e37d7cc52..c90de548599 100644 --- a/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx +++ b/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx @@ -158,7 +158,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< break case 'current': { - trackMatomoEvent({ category: 'ai', action: 'AddingAIContext', name: choice, isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'AddingAIContext', value: choice, isClick: true }) const f = await props.plugin.call('fileManager', 'getCurrentFile') if (f) files = [f] await props.plugin.call('remixAI', 'setContextFiles', { context: 'currentFile' }) @@ -166,7 +166,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< break case 'opened': { - trackMatomoEvent({ category: 'ai', action: 'AddingAIContext', name: choice, isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'AddingAIContext', value: choice, isClick: true }) const res = await props.plugin.call('fileManager', 'getOpenedFiles') if (Array.isArray(res)) { files = res @@ -178,7 +178,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< break case 'workspace': { - trackMatomoEvent({ category: 'ai', action: 'AddingAIContext', name: choice, isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'AddingAIContext', value: choice, isClick: true }) await props.plugin.call('remixAI', 'setContextFiles', { context: 'workspace' }) files = ['@workspace'] } @@ -251,9 +251,9 @@ export const RemixUiRemixAiAssistant = React.forwardRef< prev.map(m => (m.id === msgId ? { ...m, sentiment: next } : m)) ) if (next === 'like') { - trackMatomoEvent({ category: 'remixAIAssistant', action: 'likeResponse', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'like-response', isClick: true }) } else if (next === 'dislike') { - trackMatomoEvent({ category: 'remixAIAssistant', action: 'dislikeResponse', isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'dislike-response', isClick: true }) } } @@ -435,7 +435,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< dispatchActivity('button', 'generateWorkspace') if (prompt && prompt.trim()) { await sendPrompt(`/workspace ${prompt.trim()}`) - trackMatomoEvent({ category: 'remixAI', action: 'GenerateNewAIWorkspaceFromEditMode', name: prompt, isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'GenerateNewAIWorkspaceFromEditMode', value: prompt, isClick: true }) } }, [sendPrompt]) @@ -472,14 +472,14 @@ export const RemixUiRemixAiAssistant = React.forwardRef< dispatchActivity('button', 'setAssistant') setMessages([]) sendPrompt(`/setAssistant ${assistantChoice}`) - trackMatomoEvent({ category: 'remixAI', action: 'SetAIProvider', name: assistantChoice, isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'SetAIProvider', value: assistantChoice, isClick: true }) // Log specific Ollama selection if (assistantChoice === 'ollama') { - trackMatomoEvent({ category: 'ai', action: 'ollama_provider_selected', name: `from:${choiceSetting || 'unknown'}`, isClick: false }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ollama_provider_selected', value: `from:${choiceSetting || 'unknown'}`, isClick: false }) } } else { // This is a fallback, just update the backend silently - trackMatomoEvent({ category: 'ai', action: 'ollama_fallback_to_provider', name: `${assistantChoice}|from:${choiceSetting}`, isClick: false }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ollama_fallback_to_provider', value: `${assistantChoice}|from:${choiceSetting}`, isClick: false }) await props.plugin.call('remixAI', 'setAssistantProvider', assistantChoice) } setAssistantChoice(assistantChoice || 'mistralai') @@ -515,7 +515,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< if (!selectedModel && models.length > 0) { const defaultModel = models.find(m => m.includes('codestral')) || models[0] setSelectedModel(defaultModel) - trackMatomoEvent({ category: 'ai', action: 'ollama_default_model_selected', name: `${defaultModel}|codestral|total:${models.length}`, isClick: false }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ollama_default_model_selected', value: `${defaultModel}|codestral|total:${models.length}`, isClick: false }) // Sync the default model with the backend try { await props.plugin.call('remixAI', 'setModel', defaultModel) @@ -542,7 +542,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< sentiment: 'none' }]) // Log Ollama unavailable event - trackMatomoEvent({ category: 'ai', action: 'ollama_unavailable', name: 'switching_to_mistralai', isClick: false }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ollama_unavailable', value: 'switching_to_mistralai', isClick: false }) // Set failure flag before switching back to prevent success message setIsOllamaFailureFallback(true) // Automatically switch back to mistralai @@ -559,7 +559,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< sentiment: 'none' }]) // Log Ollama connection error - trackMatomoEvent({ category: 'ai', action: 'ollama_connection_error', name: `${error.message || 'unknown'}|switching_to_mistralai`, isClick: false }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ollama_connection_error', value: `${error.message || 'unknown'}|switching_to_mistralai`, isClick: false }) // Set failure flag before switching back to prevent success message setIsOllamaFailureFallback(true) // Switch back to mistralai on error @@ -582,16 +582,16 @@ export const RemixUiRemixAiAssistant = React.forwardRef< const previousModel = selectedModel setSelectedModel(modelName) setShowModelOptions(false) - trackMatomoEvent({ category: 'ai', action: 'ollama_model_selected', name: `${modelName}|from:${previousModel || 'none'}`, isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ollama_model_selected', value: `${modelName}|from:${previousModel || 'none'}`, isClick: true }) // Update the model in the backend try { await props.plugin.call('remixAI', 'setModel', modelName) - trackMatomoEvent({ category: 'ai', action: 'ollama_model_set_backend_success', name: modelName, isClick: false }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ollama_model_set_backend_success', value: modelName, isClick: false }) } catch (error) { console.warn('Failed to set model:', error) - trackMatomoEvent({ category: 'ai', action: 'ollama_model_set_backend_failed', name: `${modelName}|${error.message || 'unknown'}`, isClick: false }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'ollama_model_set_backend_failed', value: `${modelName}|${error.message || 'unknown'}`, isClick: false }) } - trackMatomoEvent({ category: 'remixAI', action: 'SetOllamaModel', name: modelName, isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'SetOllamaModel', value: modelName, isClick: true }) }, [props.plugin, selectedModel]) // refresh context whenever selection changes (even if selector is closed) @@ -640,7 +640,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< if (description && description.trim()) { sendPrompt(`/generate ${description.trim()}`) - trackMatomoEvent({ category: 'remixAI', action: 'GenerateNewAIWorkspaceFromModal', name: description, isClick: true }) + trackMatomoEvent({ category: 'ai', action: 'remixAI', name: 'GenerateNewAIWorkspaceFromModal', value: description, isClick: true }) } } catch { /* user cancelled */ diff --git a/libs/remix-ui/renderer/src/lib/renderer.tsx b/libs/remix-ui/renderer/src/lib/renderer.tsx index 23451de3749..5a5889064cf 100644 --- a/libs/remix-ui/renderer/src/lib/renderer.tsx +++ b/libs/remix-ui/renderer/src/lib/renderer.tsx @@ -102,7 +102,7 @@ export const Renderer = ({ message, opt, plugin, context }: RendererProps) => { setTimeout(async () => { await plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message) }, 500) - trackMatomoEvent?.({ category: 'ai', action: 'error_explaining_SolidityError' }) + trackMatomoEvent?.({ category: 'ai', action: 'remixAI', name: 'error_explaining_SolidityError', isClick: true }) } catch (err) { console.error('unable to ask RemixAI') console.error(err) diff --git a/libs/remix-ui/solidity-uml-gen/src/lib/components/UmlDownload.tsx b/libs/remix-ui/solidity-uml-gen/src/lib/components/UmlDownload.tsx index d3c990b369a..a0d5cb5afd1 100644 --- a/libs/remix-ui/solidity-uml-gen/src/lib/components/UmlDownload.tsx +++ b/libs/remix-ui/solidity-uml-gen/src/lib/components/UmlDownload.tsx @@ -81,7 +81,7 @@ export default function UmlDownload(props: UmlDownloadProps) { { - trackMatomoEvent({ category: 'solidityUMLGen', action: 'umlpngdownload', name: 'downloadAsPng', isClick: true }) + trackMatomoEvent({ category: 'solidityumlgen', action: 'umlpngdownload', name: 'downloadAsPng', isClick: true }) props.download('png') }} data-id="umlPngDownload" @@ -103,7 +103,7 @@ export default function UmlDownload(props: UmlDownloadProps) { { - trackMatomoEvent({ category: 'solidityUMLGen', action: 'umlpdfdownload', name: 'downloadAsPdf', isClick: true }) + trackMatomoEvent({ category: 'solidityumlgen', action: 'umlpdfdownload', name: 'downloadAsPdf', isClick: true }) props.download('pdf') }} data-id="umlPdfDownload" diff --git a/libs/remix-ui/statusbar/src/lib/components/gitStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/gitStatus.tsx index c2282abb4b2..b61a790a5ea 100644 --- a/libs/remix-ui/statusbar/src/lib/components/gitStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/gitStatus.tsx @@ -21,7 +21,7 @@ export default function GitStatus({ plugin, gitBranchName, setGitBranchName }: G const initializeNewGitRepo = async () => { await plugin.call('dgit', 'init') - trackMatomoEvent(plugin, { category: 'git', action: 'INIT', name: 'initNewRepo', isClick: false }); + trackMatomoEvent(plugin, { category: 'statusBar', action: 'initNewRepo', isClick: true }); } if (!appContext.appState.canUseGit) return null diff --git a/libs/remix-ui/terminal/src/lib/components/RenderUnknownTransactions.tsx b/libs/remix-ui/terminal/src/lib/components/RenderUnknownTransactions.tsx index 2f6b62806f9..94951d1c6b2 100644 --- a/libs/remix-ui/terminal/src/lib/components/RenderUnknownTransactions.tsx +++ b/libs/remix-ui/terminal/src/lib/components/RenderUnknownTransactions.tsx @@ -32,7 +32,7 @@ const RenderUnKnownTransactions = ({ tx, receipt, index, plugin, showTableHash, let to = tx.to if (tx.isUserOp) { - trackMatomoEvent({ category: 'udapp', action: 'safeSmartAccount', name: 'txExecuted', value: 'successfully', isClick: false }) + trackMatomoEvent({ category: 'udapp', action: 'safeSmartAccount', name: 'txExecutedSuccessfully', isClick: true }) // Track event with signature: ExecutionFromModuleSuccess (index_topic_1 address module) // to get sender smart account address const fromAddrLog = receipt.logs.find(e => e.topics[0] === "0x6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb8") diff --git a/libs/remix-ui/top-bar/src/lib/remix-ui-topbar.tsx b/libs/remix-ui/top-bar/src/lib/remix-ui-topbar.tsx index ed820421a81..14b2f1b95be 100644 --- a/libs/remix-ui/top-bar/src/lib/remix-ui-topbar.tsx +++ b/libs/remix-ui/top-bar/src/lib/remix-ui-topbar.tsx @@ -390,7 +390,7 @@ export function RemixUiTopbar() { try { await switchToWorkspace(name) handleExpandPath([]) - trackMatomoEvent({ category: 'Workspace', action: 'switchWorkspace', name: name, isClick: true }) + trackMatomoEvent({ category: 'workspace', action: 'switchWorkspace', name: name, isClick: true }) } catch (e) { global.modal( intl.formatMessage({ id: 'filePanel.workspace.switch' }), diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index 8e0a9d00a9a..ab02edb84dc 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -239,10 +239,12 @@ export const populateWorkspace = async ( if (workspaceTemplateName === 'semaphore' || workspaceTemplateName === 'hashchecker' || workspaceTemplateName === 'rln') { const isCircomActive = await plugin.call('manager', 'isActive', 'circuit-compiler') if (!isCircomActive) await plugin.call('manager', 'activatePlugin', 'circuit-compiler') + await trackMatomoEventAsync(plugin, { category: 'circuit-compiler', action: 'template', name: 'create', value: workspaceTemplateName, isClick: false }) } if (workspaceTemplateName === 'multNr' || workspaceTemplateName === 'stealthDropNr') { const isNoirActive = await plugin.call('manager', 'isActive', 'noir-compiler') if (!isNoirActive) await plugin.call('manager', 'activatePlugin', 'noir-compiler') + await trackMatomoEventAsync(plugin, { category: 'noir-compiler', action: 'template', name: 'create', value: workspaceTemplateName, isClick: false }) } } @@ -299,7 +301,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe let content if (params.code) { - await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'code-template-code-param', isClick: false }) + await trackMatomoEventAsync(plugin, { category: 'workspace', action: 'template', name: 'code-template-code-param', isClick: false }) const hashed = bytesToHex(hash.keccakFromString(params.code)) path = 'contract-' + hashed.replace('0x', '').substring(0, 10) + (params.language && params.language.toLowerCase() === 'yul' ? '.yul' : '.sol') @@ -307,7 +309,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe await workspaceProvider.set(path, content) } if (params.shareCode) { - await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'code-template-shareCode-param', isClick: false }) + await trackMatomoEventAsync(plugin, { category: 'workspace', action: 'template', name: 'code-template-shareCode-param', isClick: false }) const host = '127.0.0.1' const port = 5001 const protocol = 'http' @@ -332,7 +334,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe await workspaceProvider.set(path, content) } if (params.url) { - await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'code-template-url-param', isClick: false }) + await trackMatomoEventAsync(plugin, { category: 'workspace', action: 'template', name: 'code-template-url-param', isClick: false }) const data = await plugin.call('contentImport', 'resolve', params.url) path = data.cleanUrl content = data.content @@ -356,7 +358,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe } if (params.ghfolder) { try { - await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'code-template-ghfolder-param', isClick: false }) + await trackMatomoEventAsync(plugin, { category: 'workspace', action: 'template', name: 'code-template-ghfolder-param', isClick: false }) const files = await plugin.call('contentImport', 'resolveGithubFolder', params.ghfolder) for (const [path, content] of Object.entries(files)) { await workspaceProvider.set(path, content) @@ -375,7 +377,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe case 'gist-template': // creates a new workspace gist-sample and get the file from gist try { - await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'gist-template', isClick: false }) + await trackMatomoEventAsync(plugin, { category: 'workspace', action: 'template', name: 'gist-template', isClick: false }) const gistId = params.gist const response: AxiosResponse = await axios.get(`https://api.github.com/gists/${gistId}`) const data = response.data as { files: any } @@ -438,7 +440,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe const templateList = Object.keys(templateWithContent) if (!templateList.includes(template)) break - await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: template, isClick: false }) + await trackMatomoEventAsync(plugin, { category: 'workspace', action: 'template', name: template, isClick: false }) // @ts-ignore const files = await templateWithContent[template](opts, plugin) for (const file in files) { diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 8594e9460c6..f5140f6143a 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -525,7 +525,7 @@ export function Workspace() { try { await global.dispatchSwitchToWorkspace(name) global.dispatchHandleExpandPath([]) - trackMatomoEvent({ category: 'Workspace', action: 'switchWorkspace', name: name, isClick: true }) + trackMatomoEvent({ category: 'workspace', action: 'switchWorkspace', name: name, isClick: true }) } catch (e) { global.modal( intl.formatMessage({ id: 'filePanel.workspace.switch' }), @@ -863,10 +863,10 @@ export function Workspace() { try { if (branch.remote) { await global.dispatchCheckoutRemoteBranch(branch) - trackMatomoEvent({ category: 'Workspace', action: 'GIT', name: 'checkout_remote_branch', isClick: true }) + trackMatomoEvent({ category: 'workspace', action: 'GIT', name: 'checkout_remote_branch', isClick: true }) } else { await global.dispatchSwitchToBranch(branch) - trackMatomoEvent({ category: 'Workspace', action: 'GIT', name: 'switch_to_existing_branch', isClick: true }) + trackMatomoEvent({ category: 'workspace', action: 'GIT', name: 'switch_to_existing_branch', isClick: true }) } } catch (e) { console.error(e) @@ -883,7 +883,7 @@ export function Workspace() { const switchToNewBranch = async () => { try { await global.dispatchCreateNewBranch(branchFilter) - trackMatomoEvent({ category: 'Workspace', action: 'GIT', name: 'switch_to_new_branch', isClick: true }) + trackMatomoEvent({ category: 'workspace', action: 'GIT', name: 'switch_to_new_branch', isClick: true }) } catch (e) { global.modal( intl.formatMessage({ id: 'filePanel.checkoutGitBranch' }), @@ -927,7 +927,7 @@ export function Workspace() { const logInGithub = async () => { await global.plugin.call('menuicons', 'select', 'dgit'); await global.plugin.call('dgit', 'open', gitUIPanels.GITHUB) - trackMatomoEvent({ category: 'Workspace', action: 'GIT', name: 'login', isClick: true }) + trackMatomoEvent({ category: 'workspace', action: 'GIT', name: 'login', isClick: true }) } const IsGitRepoDropDownMenuItem = (props: { isGitRepo: boolean, mName: string}) => {