diff --git a/projects/ui/package.json b/projects/ui/package.json index c8a66dac4..0adc053bd 100644 --- a/projects/ui/package.json +++ b/projects/ui/package.json @@ -2,6 +2,9 @@ "name": "@po-ui/ng-components", "version": "0.0.0-PLACEHOLDER", "description": "PO UI - Components", + "scripts": { + "postinstall": "node ./schematics/postinstall/telemetry-notice.js" + }, "author": "PO UI", "license": "MIT", "homepage": "https://po-ui.io", diff --git a/projects/ui/schematics/ng-add/index.spec.ts b/projects/ui/schematics/ng-add/index.spec.ts index adcd6b13d..64d6b9d2c 100644 --- a/projects/ui/schematics/ng-add/index.spec.ts +++ b/projects/ui/schematics/ng-add/index.spec.ts @@ -66,6 +66,47 @@ xdescribe('Schematic: ng-add', () => { }); }); + describe('Telemetry configuration:', () => { + it('should create .po-ui-telemetry.json with enabled true when enableTelemetry is true', async () => { + const tree = await runner.runSchematic('ng-add', { ...componentOptions, enableTelemetry: true }, appTree); + + const telemetryConfig = JSON.parse(getFileContent(tree, '.po-ui-telemetry.json')); + expect(telemetryConfig.enabled).toBe(true); + expect(telemetryConfig.consentDate).toBeDefined(); + expect(telemetryConfig.version).toBe('0.0.0-PLACEHOLDER'); + }); + + it('should create .po-ui-telemetry.json with enabled false when enableTelemetry is false', async () => { + const tree = await runner.runSchematic('ng-add', { ...componentOptions, enableTelemetry: false }, appTree); + + const telemetryConfig = JSON.parse(getFileContent(tree, '.po-ui-telemetry.json')); + expect(telemetryConfig.enabled).toBe(false); + expect(telemetryConfig.consentDate).toBeDefined(); + expect(telemetryConfig.version).toBe('0.0.0-PLACEHOLDER'); + }); + + it('should create .po-ui-telemetry.json with enabled false when enableTelemetry is not provided', async () => { + const tree = await runner.runSchematic('ng-add', componentOptions, appTree); + + const telemetryConfig = JSON.parse(getFileContent(tree, '.po-ui-telemetry.json')); + expect(telemetryConfig.enabled).toBe(false); + expect(telemetryConfig.consentDate).toBeDefined(); + expect(telemetryConfig.version).toBe('0.0.0-PLACEHOLDER'); + }); + + it('should have correct JSON structure in .po-ui-telemetry.json', async () => { + const tree = await runner.runSchematic('ng-add', { ...componentOptions, enableTelemetry: true }, appTree); + + const telemetryConfig = JSON.parse(getFileContent(tree, '.po-ui-telemetry.json')); + + const keys = Object.keys(telemetryConfig); + expect(keys).toContain('enabled'); + expect(keys).toContain('consentDate'); + expect(keys).toContain('version'); + expect(keys.length).toBe(3); + }); + }); + describe('Theme configuration:', () => { const defaultThemePath = './node_modules/@po-ui/style/css/po-theme-default.min.css'; diff --git a/projects/ui/schematics/ng-add/index.ts b/projects/ui/schematics/ng-add/index.ts index a030b5f48..e2482a872 100644 --- a/projects/ui/schematics/ng-add/index.ts +++ b/projects/ui/schematics/ng-add/index.ts @@ -8,13 +8,15 @@ import { addPackageToPackageJson } from '@po-ui/ng-schematics/package-config'; * - Imports PoModule to app root module; * - Install dependencies; * - Configure theme style in project workspace; + * - Configure telemetry if enabled; */ export default function (options: any): Rule { return chain([ addPoPackageAndInstall(), schematic('ng-add-setup-project', { ...options - }) + }), + configureTelemetry(options) ]); } @@ -26,3 +28,17 @@ function addPoPackageAndInstall(): Rule { context.addTask(new NodePackageInstallTask()); }; } + +function configureTelemetry(options: any): Rule { + return (tree: Tree) => { + const telemetryConfig = { + enabled: options.enableTelemetry === true, + consentDate: new Date().toISOString(), + version: '0.0.0-PLACEHOLDER' + }; + + tree.create('.po-ui-telemetry.json', JSON.stringify(telemetryConfig, null, 2)); + + return tree; + }; +} diff --git a/projects/ui/schematics/ng-add/schema.json b/projects/ui/schematics/ng-add/schema.json index 1e53c97c3..5846a17b6 100644 --- a/projects/ui/schematics/ng-add/schema.json +++ b/projects/ui/schematics/ng-add/schema.json @@ -1,22 +1,26 @@ { "$schema": "http://json-schema.org/schema", - "$id": "SchematicsNgAdd", - "title": "Ng Add Options Schema", + "$id": "SchematicsPONgAdd", + "title": "PO UI ng-add Options Schema", "type": "object", "properties": { "project": { "type": "string", - "description": "Name of the project.", + "description": "The name of the project.", "$default": { "$source": "projectName" } }, "configSideMenu": { "type": "boolean", - "description": "When true create a app.component with po-toolbar and po-menu configured.", - "default": true, - "x-prompt": "Would you like to configure Sidemenu?", - "x-user-analytics": 17 + "description": "Configure side menu layout", + "default": false + }, + "enableTelemetry": { + "type": "boolean", + "description": "Enable anonymous telemetry to help the PO UI team improve components", + "default": false, + "x-prompt": "Deseja habilitar telemetria anônima para ajudar a equipe do PO UI a melhorar os componentes?" } }, "required": [] diff --git a/projects/ui/schematics/postinstall/telemetry-notice.js b/projects/ui/schematics/postinstall/telemetry-notice.js new file mode 100644 index 000000000..bc4561ec0 --- /dev/null +++ b/projects/ui/schematics/postinstall/telemetry-notice.js @@ -0,0 +1,35 @@ +#!/usr/bin/env node +'use strict'; + +// Não exibir mensagem em CI ou quando stdin não é interativo +const isCI = + process.env.CI || + process.env.CONTINUOUS_INTEGRATION || + process.env.BUILD_NUMBER || + process.env.GITHUB_ACTIONS || + process.env.TRAVIS || + process.env.CIRCLECI || + process.env.JENKINS_URL; + +if (isCI) { + process.exit(0); +} + +const message = ` +╔══════════════════════════════════════════════════════════════════╗ +║ ║ +║ Obrigado por instalar @po-ui/ng-components! ║ +║ ║ +║ Ajude-nos a melhorar o PO UI habilitando telemetria anônima. ║ +║ Para ativar, execute: ║ +║ ║ +║ ng add @po-ui/ng-components ║ +║ ║ +║ Durante o ng add, você poderá escolher habilitar telemetria. ║ +║ ║ +║ Saiba mais: https://po-ui.io/guides/telemetry ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +`; + +console.log(message); diff --git a/projects/ui/schematics/postinstall/telemetry-prompt.js b/projects/ui/schematics/postinstall/telemetry-prompt.js new file mode 100644 index 000000000..3c4851925 --- /dev/null +++ b/projects/ui/schematics/postinstall/telemetry-prompt.js @@ -0,0 +1,64 @@ +#!/usr/bin/env node +'use strict'; + +const readline = require('readline'); +const fs = require('fs'); +const path = require('path'); + +const isCI = process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.GITHUB_ACTIONS || process.env.TRAVIS; + +if (isCI || !process.stdin.isTTY) { + process.exit(0); +} + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +rl.question('\n\uD83D\uDD0D Deseja habilitar telemetria anônima para ajudar a equipe do PO UI? (s/N): ', answer => { + const enabled = answer.trim().toLowerCase() === 's' || answer.trim().toLowerCase() === 'y'; + + // Tenta gravar na raiz do projeto do consumidor + const projectRoot = findProjectRoot(); + if (projectRoot) { + const configPath = path.join(projectRoot, '.po-ui-telemetry.json'); + const config = { + enabled, + consentDate: new Date().toISOString() + }; + fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); + + if (enabled) { + console.log('\u2705 Telemetria habilitada. Obrigado por ajudar!'); + } else { + console.log('Telemetria não habilitada. Você pode habilitar depois com: ng add @po-ui/ng-components'); + } + } + + rl.close(); +}); + +// Timeout de 30 segundos para não travar a instalação +setTimeout(() => { + console.log('\nTimeout atingido. Telemetria não habilitada.'); + rl.close(); + process.exit(0); +}, 30000); + +function findProjectRoot() { + let dir = process.cwd(); + while (dir !== path.dirname(dir)) { + if ( + fs.existsSync(path.join(dir, 'package.json')) && + !fs.existsSync(path.join(dir, 'node_modules', '.package-lock.json')) + ) { + // Verificar se não é o próprio node_modules + if (!dir.includes('node_modules')) { + return dir; + } + } + dir = path.dirname(dir); + } + return null; +}