@pacaf/wizard-ux 3.6.4 → 3.6.5

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
@@ -1,8 +1,8 @@
1
1
  # WizardUX — Browser-Based Setup
2
2
 
3
- A browser-based UX for the PAppsCAFoundations setup wizard. Runs alongside the CLI wizard, sharing the same `.wizard-state.json` so you can switch between them at any time.
3
+ The browser-based setup wizard for PAppsCAFoundations. This is the supported way to scaffold and configure a Code App run it with `npx @pacaf/wizard-ux@latest`.
4
4
 
5
- > Both the CLI wizard at [`../wizard/`](../wizard) and this browser wizard are fully supported entry points. WizardUX now keeps the full nine-step setup flow in the browser, using server-side runners and live logs for long-running commands.
5
+ > WizardUX keeps the full nine-step setup flow in the browser, using server-side runners and live logs for long-running commands.
6
6
 
7
7
  ## Quick start
8
8
 
@@ -36,7 +36,7 @@ This installs `wizard-ux` dependencies on first run, starts the Fastify server o
36
36
  | 8. Connectors | Native defer/notes step |
37
37
  | 9. Verify & deploy | Full form + live build/deploy output |
38
38
 
39
- All nine steps now stay inside WizardUX. App registration values are collected in browser forms, credentials can be read from or synced to 1Password, PAC auth output streams through the live log, scaffolding runs server-side, and verify/deploy can build and push without opening the old CLI wizard.
39
+ All nine steps now stay inside WizardUX. App registration values are collected in browser forms, credentials can be read from or synced to 1Password, PAC auth output streams through the live log, scaffolding runs server-side, and verify/deploy can build and push all in the browser.
40
40
 
41
41
  ## Architecture
42
42
 
@@ -59,14 +59,9 @@ wizard-ux/
59
59
  - Client secrets are held in memory on the server only — never sent back to the browser, never written to logs.
60
60
  - Auto-shutdown after 10 minutes of API inactivity.
61
61
 
62
- ## How it differs from the CLI
62
+ ## Architecture note shared internals
63
63
 
64
- The CLI ([`../wizard/`](../wizard)) is the authoritative pipeline. It calls the same `wizard/lib/*` helpers WizardUX does. You can:
65
- 1. Start in WizardUX, finish in the CLI.
66
- 2. Start in the CLI, finish in WizardUX.
67
- 3. Use WizardUX as a state inspector while the CLI runs in another terminal.
68
-
69
- `.wizard-state.json` is the single source of truth for both.
64
+ WizardUX is the user-facing entry point. Internally it reuses the same `wizard/lib/*` helpers from the [`@pacaf/wizard`](../wizard) package (a workspace dependency), so the setup pipeline logic lives in one place. `.wizard-state.json` is the single source of truth.
70
65
 
71
66
  ## Build for production
72
67
 
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@pacaf/wizard-ux",
3
- "version": "3.6.4",
3
+ "version": "3.6.5",
4
4
  "private": false,
5
5
  "type": "module",
6
- "description": "Browser-based setup wizard for Power Apps Code Apps (parallel to @pacaf/wizard CLI).",
6
+ "description": "Browser-based setup wizard for Power Apps Code Apps.",
7
7
  "license": "MIT",
8
8
  "repository": {
9
9
  "type": "git",
@@ -38,7 +38,7 @@
38
38
  "react-dom": "^19.0.0",
39
39
  "react-resizable-panels": "^2.1.7",
40
40
  "react-router-dom": "^7.1.0",
41
- "@pacaf/wizard": "3.4.7"
41
+ "@pacaf/wizard": "3.4.8"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/react": "^19.0.0",
@@ -8,7 +8,6 @@ import { parsePacTabularRows } from '../lib/pac-parse.mjs';
8
8
 
9
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
10
  const PACKAGE_DIR = resolve(__dirname, '..', '..', '..');
11
- const VALIDATE = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'validate.mjs')).href);
12
11
  const SHELL = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'shell.mjs')).href);
13
12
  const PAC_TARGET = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'pac-target.mjs')).href);
14
13
 
@@ -278,7 +277,10 @@ export default {
278
277
  options: [
279
278
  ...solutions,
280
279
  { value: PASTE_URL, label: 'Paste solution URL from Maker Portal' },
281
- { value: CREATE_NEW, label: '+ Create new solution' },
280
+ // "Create new solution" is only offered for service-principal auth, which
281
+ // can create solutions via the Dataverse API. User auth cannot, so they
282
+ // create the solution in the Maker Portal and paste its URL instead.
283
+ ...(!isUserAuth ? [{ value: CREATE_NEW, label: '+ Create new solution' }] : []),
282
284
  ],
283
285
  hideIf: { id: '__resume', equals: true },
284
286
  });
@@ -340,47 +342,10 @@ export default {
340
342
  }
341
343
  }
342
344
 
343
- // ── Create new user auth: link to Maker Portal + URL paste back ──
344
- if (isUserAuth) {
345
- questions.push({
346
- id: 'SOLUTION_CREATED_MANUALLY',
347
- type: 'confirm',
348
- label: 'I have created the solution in the Maker Portal',
349
- help: `Create the solution at ${makerLink}, then come back here. You can either paste the URL above (switch to "Paste solution URL") or toggle this and enter details manually.`,
350
- defaultValue: false,
351
- showIf: { id: 'SOLUTION_SELECTION', equals: CREATE_NEW },
352
- why: [
353
- 'Create your solution in the Maker Portal:',
354
- `1. Open ${makerLink}`,
355
- '2. Click + New Solution',
356
- '3. Enter the display name',
357
- '4. Select (or create) a publisher',
358
- '5. Save the solution',
359
- '',
360
- 'Then come back here and either:',
361
- '• Switch the dropdown to "Paste solution URL" and paste the URL (recommended)',
362
- '• OR toggle this confirmation and enter the details manually below',
363
- ].join('\n'),
364
- });
365
-
366
- questions.push({
367
- id: 'MANUAL_SOLUTION_UNIQUE_NAME',
368
- type: 'text',
369
- label: 'Solution unique name',
370
- help: 'The internal name (no spaces). Find this in the solution details in the Maker Portal.',
371
- defaultValue: '',
372
- showIf: { id: 'SOLUTION_CREATED_MANUALLY', equals: true },
373
- });
374
-
375
- questions.push({
376
- id: 'MANUAL_PUBLISHER_PREFIX',
377
- type: 'text',
378
- label: 'Publisher prefix',
379
- help: '2–8 lowercase letters. Find this in the Maker Portal under the publisher you selected.',
380
- defaultValue: state.PUBLISHER_PREFIX || '',
381
- showIf: { id: 'SOLUTION_CREATED_MANUALLY', equals: true },
382
- });
383
- }
345
+ // Note: "+ Create new solution" is only offered to service-principal auth
346
+ // (see SOLUTION_SELECTION options above). User auth creates the solution in
347
+ // the Maker Portal and pastes the URL back via the PASTE_URL path, so no
348
+ // manual create-and-enter-details questions are needed here.
384
349
 
385
350
  return questions;
386
351
  },
@@ -453,34 +418,15 @@ export default {
453
418
  return { stateUpdate: buildStateUpdate(sol), completedStep: 7 };
454
419
  }
455
420
 
456
- // ── Create new ──
421
+ // ── Create new (service-principal only) ──
457
422
  const solName = String(answers.NEW_SOLUTION_NAME || '').trim();
458
423
  if (!solName) throw new Error('Solution display name is required.');
459
424
  const solUnique = solName.replace(/[\s\-]+/g, '');
460
425
 
461
426
  if (isUserAuth) {
462
- if (answers.SOLUTION_CREATED_MANUALLY !== true) {
463
- throw new Error('Create the solution in the Maker Portal first, then confirm or switch to "Paste solution URL".');
464
- }
465
- const manualUnique = String(answers.MANUAL_SOLUTION_UNIQUE_NAME || '').trim();
466
- const manualPrefix = String(answers.MANUAL_PUBLISHER_PREFIX || '').trim();
467
- if (!manualUnique) throw new Error('Solution unique name is required.');
468
- if (!VALIDATE.isValidPrefix(manualPrefix)) throw new Error('Publisher prefix must be 2–8 lowercase letters.');
469
- log.ok(`Solution: "${solName}" (${manualUnique})`);
470
- log.ok(`Publisher prefix: ${manualPrefix}`);
471
- return {
472
- stateUpdate: {
473
- SOLUTION_ID: '',
474
- SOLUTION_UNIQUE_NAME: manualUnique,
475
- SOLUTION_DISPLAY_NAME: solName,
476
- PUBLISHER_ID: '',
477
- PUBLISHER_NAME: '',
478
- PUBLISHER_DISPLAY_NAME: '',
479
- PUBLISHER_PREFIX: manualPrefix,
480
- CHOICE_VALUE_PREFIX: '',
481
- },
482
- completedStep: 7,
483
- };
427
+ // "Create new solution" isn't offered for user auth — it can't create a
428
+ // solution via the API. Direct the user to the Maker Portal + paste flow.
429
+ throw new Error('Creating a new solution requires service-principal auth. Create the solution in the Maker Portal, then choose "Paste solution URL".');
484
430
  }
485
431
 
486
432
  // SPN: create via API