generate-ui-cli 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -105,7 +105,7 @@ If your project uses custom routing, standalone components, or advanced layouts,
105
105
 
106
106
  Defaults:
107
107
  - `--schemas` defaults to the last generated path (stored in `~/.generateui/config.json`), otherwise `./src/generate-ui` (or `./frontend/src/generate-ui` / `./generate-ui`)
108
- - `--features` defaults to `./src/app/features` when it exists, otherwise `./frontend/src/app/features` or `./features`
108
+ - `--features` defaults to `./src/app/features` when `./src/app` exists; otherwise it errors and asks for `--features`
109
109
 
110
110
  Optional paths:
111
111
 
@@ -56,17 +56,19 @@ function resolveSchemasRoot(value, featuresRoot) {
56
56
  }
57
57
  function resolveFeaturesRoot(value) {
58
58
  if (value) {
59
- return path_1.default.resolve(process.cwd(), value);
60
- }
61
- const defaultApp = path_1.default.resolve(process.cwd(), 'src', 'app', 'features');
62
- if (fs_1.default.existsSync(defaultApp)) {
63
- return defaultApp;
59
+ const resolved = path_1.default.resolve(process.cwd(), value);
60
+ const isSrcApp = path_1.default.basename(resolved) === 'app' &&
61
+ path_1.default.basename(path_1.default.dirname(resolved)) === 'src';
62
+ if (isSrcApp) {
63
+ return path_1.default.join(resolved, 'features');
64
+ }
65
+ return resolved;
64
66
  }
65
- const defaultFrontend = path_1.default.resolve(process.cwd(), 'frontend', 'src', 'app', 'features');
66
- if (fs_1.default.existsSync(defaultFrontend)) {
67
- return defaultFrontend;
67
+ const srcAppRoot = path_1.default.resolve(process.cwd(), 'src', 'app');
68
+ if (!fs_1.default.existsSync(srcAppRoot)) {
69
+ throw new Error('Default features path not found: ./src/app. Provide --features /path/to/src/app (or /path/to/src/app/features)');
68
70
  }
69
- return path_1.default.resolve(process.cwd(), 'features');
71
+ return path_1.default.join(srcAppRoot, 'features');
70
72
  }
71
73
  function inferSchemasRootFromFeatures(featuresRoot) {
72
74
  const candidate = path_1.default.resolve(featuresRoot, '../../..', 'generate-ui');
@@ -8,6 +8,7 @@ const http_1 = __importDefault(require("http"));
8
8
  const url_1 = require("url");
9
9
  const promises_1 = require("readline/promises");
10
10
  const config_1 = require("../runtime/config");
11
+ const user_config_1 = require("../runtime/user-config");
11
12
  const open_browser_1 = require("../runtime/open-browser");
12
13
  const token_1 = require("../license/token");
13
14
  const permissions_1 = require("../license/permissions");
@@ -24,6 +25,12 @@ async function login(options) {
24
25
  // Cached permissions will be refreshed on next online command.
25
26
  }
26
27
  const email = await promptEmail();
28
+ if (email) {
29
+ (0, user_config_1.updateUserConfig)((config) => ({
30
+ ...config,
31
+ lastLoginEmail: email
32
+ }));
33
+ }
27
34
  await (0, telemetry_1.trackLogin)(email, options.telemetryEnabled);
28
35
  console.log('✔ Login completo');
29
36
  }
@@ -45,6 +52,7 @@ async function promptEmail() {
45
52
  }
46
53
  async function waitForLogin() {
47
54
  return new Promise((resolve, reject) => {
55
+ let loginUrl = '';
48
56
  const server = http_1.default.createServer((req, res) => {
49
57
  const requestUrl = req.url || '/';
50
58
  if (!requestUrl.startsWith('/callback')) {
@@ -132,7 +140,10 @@ async function waitForLogin() {
132
140
  });
133
141
  const timeout = setTimeout(() => {
134
142
  server.close();
135
- reject(new Error('Login timed out'));
143
+ const help = loginUrl
144
+ ? ` Ensure the login page is reachable and try again: ${loginUrl}`
145
+ : ` Ensure ${(0, config_1.getWebAuthUrl)()} and ${(0, config_1.getApiBaseUrl)()} are reachable.`;
146
+ reject(new Error(`Login timed out.${help}`));
136
147
  }, LOGIN_TIMEOUT_MS);
137
148
  server.listen(0, () => {
138
149
  const address = server.address();
@@ -145,7 +156,9 @@ async function waitForLogin() {
145
156
  const url = new url_1.URL((0, config_1.getWebAuthUrl)());
146
157
  url.searchParams.set('redirect_uri', redirectUri);
147
158
  url.searchParams.set('api_base', (0, config_1.getApiBaseUrl)());
148
- (0, open_browser_1.openBrowser)(url.toString());
159
+ loginUrl = url.toString();
160
+ console.log(`Open this URL to finish login: ${loginUrl}`);
161
+ (0, open_browser_1.openBrowser)(loginUrl);
149
162
  });
150
163
  });
151
164
  }
@@ -473,8 +473,11 @@ export class ${name}Service {
473
473
 
474
474
  .form-grid {
475
475
  display: grid;
476
- grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
477
- gap: 18px;
476
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
477
+ gap: 16px;
478
+ width: 100%;
479
+ max-width: 960px;
480
+ margin: 0 auto;
478
481
  }
479
482
 
480
483
  .actions {
@@ -482,6 +485,7 @@ export class ${name}Service {
482
485
  justify-content: flex-end;
483
486
  gap: 14px;
484
487
  margin-top: 20px;
488
+ flex-wrap: wrap;
485
489
  }
486
490
 
487
491
  .result {
@@ -583,6 +587,21 @@ export class ${name}Service {
583
587
  border-radius: 6px;
584
588
  box-shadow: 0 6px 12px rgba(15, 23, 42, 0.16);
585
589
  }
590
+
591
+ @media (max-width: 720px) {
592
+ :host {
593
+ padding: 18px;
594
+ }
595
+
596
+ .form-grid {
597
+ grid-template-columns: 1fr;
598
+ max-width: 100%;
599
+ }
600
+
601
+ .actions {
602
+ justify-content: stretch;
603
+ }
604
+ }
586
605
  `);
587
606
  return {
588
607
  path: toRouteSegment(name),
@@ -750,7 +769,7 @@ function buildComponentHtml(options) {
750
769
 
751
770
  <textarea
752
771
  *ngIf="isTextarea(field)"
753
- rows="4"
772
+ rows="3"
754
773
  [formControlName]="field.name"
755
774
  [placeholder]="field.placeholder || field.label || field.name"
756
775
  [class.invalid]="isInvalid(field)"
@@ -978,8 +997,8 @@ export class UiFieldComponent {
978
997
 
979
998
  .ui-field {
980
999
  display: grid;
981
- gap: 10px;
982
- font-size: 13px;
1000
+ gap: 6px;
1001
+ font-size: 12px;
983
1002
  color: #374151;
984
1003
  }
985
1004
 
@@ -1029,12 +1048,12 @@ export class UiFieldComponent {
1029
1048
  :host ::ng-deep textarea,
1030
1049
  :host ::ng-deep select {
1031
1050
  width: 100%;
1032
- min-height: 3.4rem;
1033
- border-radius: 10px;
1051
+ min-height: 2.6rem;
1052
+ border-radius: 8px;
1034
1053
  border: 1px solid #e5e7eb;
1035
1054
  background: #ffffff;
1036
- padding: 0.9rem 1.1rem;
1037
- font-size: 15px;
1055
+ padding: 0.6rem 0.8rem;
1056
+ font-size: 14px;
1038
1057
  font-weight: 500;
1039
1058
  box-shadow: none;
1040
1059
  outline: none;
@@ -1061,14 +1080,19 @@ export class UiFieldComponent {
1061
1080
  }
1062
1081
 
1063
1082
  :host ::ng-deep select {
1064
- padding-right: 2.6rem;
1083
+ padding-right: 2.2rem;
1065
1084
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='8' viewBox='0 0 14 8' fill='none'><path d='M1 1.5L7 6.5L13 1.5' stroke='%236b7280' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
1066
1085
  background-repeat: no-repeat;
1067
- background-position: right 0.9rem center;
1086
+ background-position: right 0.7rem center;
1068
1087
  background-size: 14px 8px;
1069
1088
  appearance: none;
1070
1089
  }
1071
1090
 
1091
+ :host ::ng-deep textarea {
1092
+ min-height: 5.5rem;
1093
+ resize: vertical;
1094
+ }
1095
+
1072
1096
  :host ::ng-deep input[type='checkbox'] {
1073
1097
  width: 20px;
1074
1098
  height: 20px;
@@ -12,9 +12,9 @@ function getCliVersion() {
12
12
  }
13
13
  function getApiBaseUrl() {
14
14
  return (process.env.GENERATEUI_API_BASE_URL?.trim() ||
15
- 'http://localhost:3000');
15
+ 'https://generateuibackend-production.up.railway.app');
16
16
  }
17
17
  function getWebAuthUrl() {
18
18
  return (process.env.GENERATEUI_WEB_AUTH_URL?.trim() ||
19
- 'http://localhost:3001');
19
+ 'https://generateuibackend-production.up.railway.app');
20
20
  }
package/dist/telemetry.js CHANGED
@@ -6,8 +6,9 @@ const crypto_1 = require("crypto");
6
6
  const config_1 = require("./runtime/config");
7
7
  const user_config_1 = require("./runtime/user-config");
8
8
  const device_1 = require("./license/device");
9
+ const token_1 = require("./license/token");
9
10
  const TELEMETRY_URL = process.env.GENERATEUI_TELEMETRY_URL?.trim() ||
10
- 'https://api.generateui.dev/events';
11
+ 'https://api.generateui.dev/telemetry';
11
12
  const TELEMETRY_TIMEOUT_MS = 1000;
12
13
  function getOsName() {
13
14
  return process.platform;
@@ -50,7 +51,8 @@ function loadOrCreateConfig() {
50
51
  return {
51
52
  config: {
52
53
  installationId,
53
- telemetry: config.telemetry
54
+ telemetry: config.telemetry,
55
+ lastLoginEmail: config.lastLoginEmail
54
56
  },
55
57
  isNew
56
58
  };
@@ -61,13 +63,17 @@ function isTelemetryEnabled(cliEnabled, config) {
61
63
  return config.telemetry !== false;
62
64
  }
63
65
  async function sendEvent(payload) {
66
+ const token = (0, token_1.loadToken)();
64
67
  const controller = new AbortController();
65
68
  const timeout = setTimeout(() => controller.abort(), TELEMETRY_TIMEOUT_MS);
66
69
  try {
67
70
  await fetch(TELEMETRY_URL, {
68
71
  method: 'POST',
69
72
  headers: {
70
- 'Content-Type': 'application/json'
73
+ 'Content-Type': 'application/json',
74
+ ...(token
75
+ ? { Authorization: `Bearer ${token.accessToken}` }
76
+ : {})
71
77
  },
72
78
  body: JSON.stringify(payload),
73
79
  signal: controller.signal
@@ -91,6 +97,7 @@ async function trackCommand(command, cliEnabled) {
91
97
  event: 'first_run',
92
98
  installationId: config.installationId,
93
99
  deviceId: device.deviceId,
100
+ deviceCreatedAt: device.createdAt,
94
101
  os: getOsName(),
95
102
  arch: process.arch,
96
103
  cliVersion: (0, config_1.getCliVersion)()
@@ -99,7 +106,9 @@ async function trackCommand(command, cliEnabled) {
99
106
  await sendEvent({
100
107
  event: 'command_run',
101
108
  installationId: config.installationId,
109
+ deviceId: device.deviceId,
102
110
  command,
111
+ email: config.lastLoginEmail ?? '',
103
112
  cliVersion: (0, config_1.getCliVersion)()
104
113
  });
105
114
  }
@@ -108,9 +117,11 @@ async function trackLogin(email, cliEnabled) {
108
117
  const enabled = isTelemetryEnabled(cliEnabled, config);
109
118
  if (!enabled)
110
119
  return;
120
+ const device = (0, device_1.loadDeviceIdentity)();
111
121
  await sendEvent({
112
122
  event: 'login',
113
123
  installationId: config.installationId,
124
+ deviceId: device.deviceId,
114
125
  email: email ?? '',
115
126
  cliVersion: (0, config_1.getCliVersion)()
116
127
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generate-ui-cli",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Generate UI from OpenAPI",
5
5
  "license": "MIT",
6
6
  "repository": {