Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions projects/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
41 changes: 41 additions & 0 deletions projects/ui/schematics/ng-add/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
Comment on lines +69 to +108
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These telemetry tests are added under an xdescribe(...) suite, so they will be skipped by Jasmine and won’t run in CI (including via npm run test:ui:schematics). If these tests are meant to validate the new behavior, switch to describe(...) so the suite executes.

Copilot uses AI. Check for mistakes.

describe('Theme configuration:', () => {
const defaultThemePath = './node_modules/@po-ui/style/css/po-theme-default.min.css';

Expand Down
18 changes: 17 additions & 1 deletion projects/ui/schematics/ng-add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
]);
}

Expand All @@ -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));

Comment on lines +32 to +41
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configureTelemetry() is always creating .po-ui-telemetry.json and always writing a consentDate, even when enableTelemetry is false/undefined. For an opt-in flow this records a consent timestamp without consent and also leaves a new file in the consumer project even when telemetry is disabled. Consider only creating the file (and setting consentDate) when options.enableTelemetry === true, and otherwise skipping the rule (or writing only { enabled: false } without a timestamp).

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +41
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tree.create('.po-ui-telemetry.json', ...) will throw if the file already exists (e.g. running ng add twice or if the user already has a config). This would break the schematic execution. Consider checking tree.exists() and using tree.overwrite() (or skipping) as a fallback.

Suggested change
tree.create('.po-ui-telemetry.json', JSON.stringify(telemetryConfig, null, 2));
const telemetryConfigContent = JSON.stringify(telemetryConfig, null, 2);
if (tree.exists('.po-ui-telemetry.json')) {
tree.overwrite('.po-ui-telemetry.json', telemetryConfigContent);
} else {
tree.create('.po-ui-telemetry.json', telemetryConfigContent);
}

Copilot uses AI. Check for mistakes.
return tree;
};
}
18 changes: 11 additions & 7 deletions projects/ui/schematics/ng-add/schema.json
Original file line number Diff line number Diff line change
@@ -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
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configSideMenu changed from default true with x-prompt/x-user-analytics to default false without any prompt/analytics. This is a behavioral change for all ng add users (the side menu option will no longer be offered and will default off). If this wasn’t intentional for this telemetry feature, consider restoring the previous default and prompt/analytics fields.

Suggested change
"default": false
"default": true,
"x-prompt": "Deseja configurar o layout de menu lateral?",
"x-user-analytics": {
"featureName": "configSideMenu"
}

Copilot uses AI. Check for mistakes.
},
"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?"
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new enableTelemetry prompt text is in PT-BR, but existing schematic x-prompt messages in this repo are in English (e.g. projects/ui/schematics/ng-generate/po-page-*/schema.json). To keep CLI prompts consistent, consider using English here as well (or standardize prompts repo-wide if PT-BR is the new desired convention).

Suggested change
"x-prompt": "Deseja habilitar telemetria anônima para ajudar a equipe do PO UI a melhorar os componentes?"
"x-prompt": "Enable anonymous telemetry to help the PO UI team improve components?"

Copilot uses AI. Check for mistakes.
}
},
"required": []
Expand Down
35 changes: 35 additions & 0 deletions projects/ui/schematics/postinstall/telemetry-notice.js
Original file line number Diff line number Diff line change
@@ -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) {
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says the notice should not be shown in CI or when stdin is non-interactive, but the code only checks CI env vars. Either add a process.stdin.isTTY (and/or process.env.npm_config_yes) guard, or update the comment so it matches the actual behavior.

Suggested change
if (isCI) {
const isNonInteractive = !process.stdin.isTTY || process.env.npm_config_yes;
if (isCI || isNonInteractive) {

Copilot uses AI. Check for mistakes.
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);
64 changes: 64 additions & 0 deletions projects/ui/schematics/postinstall/telemetry-prompt.js
Original file line number Diff line number Diff line change
@@ -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');
Comment on lines +30 to +35
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fs.writeFileSync(...) in a postinstall script can throw (permissions, read-only FS, etc.) and would fail the installation. Consider wrapping the file write (and JSON stringify) in a try/catch and exiting gracefully (status 0) if writing the config isn’t possible.

Suggested change
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');
try {
const configJson = JSON.stringify(config, null, 2);
fs.writeFileSync(configPath, configJson);
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');
}
} catch (err) {
// Falha ao gravar o arquivo de configuração não deve quebrar a instalação
console.warn('Aviso: não foi possível salvar a preferência de telemetria.', err && err.message ? `Detalhes: ${err.message}` : '');

Copilot uses AI. Check for mistakes.
}
}

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);
Comment on lines +42 to +47
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 30s setTimeout is never cleared when the user answers the question. This keeps the process alive for 30 seconds even after input, and will later print the timeout message / call process.exit(0) after the prompt already completed. Store the timeout handle and clearTimeout(...) before closing the readline interface.

Copilot uses AI. Check for mistakes.

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;
}
Loading