@pacaf/wizard-ux 3.4.2 → 3.5.0
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/dist/assets/index-BL1yODjj.js +141 -0
- package/dist/index.html +1 -1
- package/package.json +2 -2
- package/server/routes/state.mjs +48 -0
- package/server/steps/09-verify-deploy.mjs +25 -0
- package/server/steps/10-add-to-solution.mjs +28 -0
- package/server/steps/index.mjs +2 -1
- package/dist/assets/index-CJnhmiwH.js +0 -141
package/dist/index.html
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
30
30
|
</style>
|
|
31
|
-
<script type="module" crossorigin src="/assets/index-
|
|
31
|
+
<script type="module" crossorigin src="/assets/index-BL1yODjj.js"></script>
|
|
32
32
|
</head>
|
|
33
33
|
<body>
|
|
34
34
|
<div id="root"><div id="boot"><div class="ring"></div></div></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pacaf/wizard-ux",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Browser-based setup wizard for Power Apps Code Apps (parallel to @pacaf/wizard CLI).",
|
|
@@ -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.
|
|
41
|
+
"@pacaf/wizard": "3.4.3"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/react": "^19.0.0",
|
package/server/routes/state.mjs
CHANGED
|
@@ -56,6 +56,52 @@ function readPowerAppInfo(rootDir, state) {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// Read the Power Platform environment GUID from power.config.json so we can
|
|
60
|
+
// build a Maker Portal deep link. The GUID is required by make.powerapps.com
|
|
61
|
+
// URLs (the org URL like https://contoso.crm.dynamics.com is NOT accepted).
|
|
62
|
+
function readEnvironmentId(rootDir, state) {
|
|
63
|
+
const projectDir = resolve(rootDir, String(state.PROJECT_DIR || '.'));
|
|
64
|
+
const powerConfigPath = join(projectDir, 'power.config.json');
|
|
65
|
+
if (!existsSync(powerConfigPath)) return '';
|
|
66
|
+
try {
|
|
67
|
+
const c = JSON.parse(readFileSync(powerConfigPath, 'utf-8'));
|
|
68
|
+
const direct = String(
|
|
69
|
+
c.environmentId || c.environment?.id || c.targetEnvironmentId || '',
|
|
70
|
+
).trim().toLowerCase();
|
|
71
|
+
if (direct) return direct;
|
|
72
|
+
const appUrl = String(c.localAppUrl || c.appUrl || c.playUrl || '').trim();
|
|
73
|
+
const m = appUrl.match(/\/play\/e\/([0-9a-f-]{36})\/app\//i);
|
|
74
|
+
return m ? m[1].toLowerCase() : '';
|
|
75
|
+
} catch {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Build the manual "add Code App to solution" guidance consumed by Step 10 in
|
|
81
|
+
// WizardUX. Returns a direct Maker Portal deep link to the user's solution
|
|
82
|
+
// (falling back to the environment's solutions list, then the portal root) so
|
|
83
|
+
// the user can add the deployed Code App by hand. Never exposes raw GUIDs to
|
|
84
|
+
// the UI — only the human-readable solution display name and app name.
|
|
85
|
+
function readSolutionInfo(rootDir, state) {
|
|
86
|
+
const environmentId = readEnvironmentId(rootDir, state);
|
|
87
|
+
const solutionId = String(state.SOLUTION_ID || '').trim().toLowerCase();
|
|
88
|
+
const displayName = String(state.SOLUTION_DISPLAY_NAME || '').trim();
|
|
89
|
+
const uniqueName = String(state.SOLUTION_UNIQUE_NAME || '').trim();
|
|
90
|
+
const appName = String(state.APP_NAME || '').trim();
|
|
91
|
+
|
|
92
|
+
let makerPortalUrl = 'https://make.powerapps.com/';
|
|
93
|
+
let linkTarget = 'portal'; // 'solution' | 'solutions' | 'portal'
|
|
94
|
+
if (environmentId && solutionId) {
|
|
95
|
+
makerPortalUrl = `https://make.powerapps.com/environments/${environmentId}/solutions/${solutionId}`;
|
|
96
|
+
linkTarget = 'solution';
|
|
97
|
+
} else if (environmentId) {
|
|
98
|
+
makerPortalUrl = `https://make.powerapps.com/environments/${environmentId}/solutions`;
|
|
99
|
+
linkTarget = 'solutions';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { displayName, uniqueName, appName, makerPortalUrl, linkTarget };
|
|
103
|
+
}
|
|
104
|
+
|
|
59
105
|
export default async function stateRoutes(app, opts) {
|
|
60
106
|
const { rootDir } = opts;
|
|
61
107
|
|
|
@@ -63,12 +109,14 @@ export default async function stateRoutes(app, opts) {
|
|
|
63
109
|
const state = readState(rootDir);
|
|
64
110
|
const completed = getCompletedStep(state);
|
|
65
111
|
const powerApp = readPowerAppInfo(rootDir, state);
|
|
112
|
+
const solution = readSolutionInfo(rootDir, state);
|
|
66
113
|
return {
|
|
67
114
|
state,
|
|
68
115
|
completed,
|
|
69
116
|
next: Math.min(completed + 1, TOTAL_STEPS),
|
|
70
117
|
totalSteps: TOTAL_STEPS,
|
|
71
118
|
powerApp,
|
|
119
|
+
solution,
|
|
72
120
|
};
|
|
73
121
|
});
|
|
74
122
|
|
|
@@ -118,6 +118,10 @@ export default {
|
|
|
118
118
|
title: 'Verify & Deploy',
|
|
119
119
|
description: 'Build the project, optionally push it to Power Platform, and surface the live app URL when available.',
|
|
120
120
|
canRunInBrowser: true,
|
|
121
|
+
// Do NOT auto-advance away from the deploy step: the user needs time to read
|
|
122
|
+
// the pac code push log (solution association, app URL, warnings) before
|
|
123
|
+
// moving on to the manual "add to solution" step.
|
|
124
|
+
noAutoAdvance: true,
|
|
121
125
|
},
|
|
122
126
|
|
|
123
127
|
questions() {
|
|
@@ -194,6 +198,27 @@ export default {
|
|
|
194
198
|
log.info(`Existing appId detected (${preInfo.appId}) — this push is an UPDATE (republish in place).`);
|
|
195
199
|
}
|
|
196
200
|
|
|
201
|
+
// PRECONDITION (issue #81 follow-up): `pac code push -s` only associates the
|
|
202
|
+
// app with its solution if that UNIQUE name already EXISTS in the target
|
|
203
|
+
// environment. If it does not, pac SILENTLY publishes into the Default
|
|
204
|
+
// solution. On the FIRST push, verify the solution exists FIRST and STOP if
|
|
205
|
+
// it is absent — never let the CREATE land the app outside its solution.
|
|
206
|
+
if (isFirstPush) {
|
|
207
|
+
log.info(`Verifying solution "${solutionUniqueName}" exists in the target environment...`);
|
|
208
|
+
const solCheck = PAC_TARGET.solutionExistsInSelectedEnv({ pac, uniqueName: solutionUniqueName, cwd: projectDir });
|
|
209
|
+
if (solCheck.status === 'absent') {
|
|
210
|
+
throw new Error(`Solution "${solutionUniqueName}" does not exist in the target environment. `
|
|
211
|
+
+ `Running "pac code push -s ${solutionUniqueName}" now would SILENTLY publish the app into the Default solution `
|
|
212
|
+
+ `(the recurring "app not in my solution" failure). Create the solution in this environment (Maker Portal → Solutions → New solution, or reuse an existing one), `
|
|
213
|
+
+ `then re-run this step. Tip: the -s value must be the solution UNIQUE name, not the display name.`);
|
|
214
|
+
}
|
|
215
|
+
if (solCheck.status === 'unknown') {
|
|
216
|
+
log.warn(`Could not confirm solution "${solutionUniqueName}" exists (${solCheck.reason}). Proceeding, but if the app lands in the Default solution, verify the unique name is correct.`);
|
|
217
|
+
} else {
|
|
218
|
+
log.ok(`Solution "${solutionUniqueName}" exists in the target environment — safe to push with -s`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
197
222
|
const pushResult = await runFileCapture(log, pac, pushArgs, { cwd: projectDir });
|
|
198
223
|
const pushOutput = `${pushResult.stdout}\n${pushResult.stderr}`;
|
|
199
224
|
if (!pushResult.ok || PAC_HTTP_ERROR_RE.test(pushOutput)) throw new Error('pac code push failed. Check the live output above, then retry.');
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Step 10 — Add the Code App to your Solution (manual).
|
|
2
|
+
//
|
|
3
|
+
// This is a MANUAL step, not a terminal/automation step. `pac code push -s`
|
|
4
|
+
// only associates the Code App with a solution when that solution already
|
|
5
|
+
// exists in the target environment, and even then the binding can silently
|
|
6
|
+
// fall back to the Default solution. Rather than pretend that automation is
|
|
7
|
+
// reliable, this step hands the user a direct Maker Portal deep link and the
|
|
8
|
+
// exact clicks needed to add the Code App to their target solution by hand.
|
|
9
|
+
//
|
|
10
|
+
// Because it is manual, it has no questions and no apply(): `canRunInBrowser`
|
|
11
|
+
// is false and `manual` is true so the WizardUX StepRunner renders a guided
|
|
12
|
+
// panel (deep link + "Outside Dataverse" guidance + illustration) instead of
|
|
13
|
+
// the question/run machinery. The deep link and solution display name are
|
|
14
|
+
// supplied to the frontend by GET /api/state (see routes/state.mjs).
|
|
15
|
+
export default {
|
|
16
|
+
meta: {
|
|
17
|
+
number: 10,
|
|
18
|
+
title: 'Add App to Solution',
|
|
19
|
+
description:
|
|
20
|
+
'Required manual step — open the Maker Portal and add your deployed Code App to your target solution.',
|
|
21
|
+
canRunInBrowser: false,
|
|
22
|
+
manual: true,
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
questions() {
|
|
26
|
+
return [];
|
|
27
|
+
},
|
|
28
|
+
};
|
package/server/steps/index.mjs
CHANGED
|
@@ -13,8 +13,9 @@ import step6 from './06-solution.mjs';
|
|
|
13
13
|
import step7 from './07-scaffold.mjs';
|
|
14
14
|
import step8 from './08-connectors.mjs';
|
|
15
15
|
import step9 from './09-verify-deploy.mjs';
|
|
16
|
+
import step10 from './10-add-to-solution.mjs';
|
|
16
17
|
|
|
17
|
-
export const STEPS = [step1, step2, step3, step4, step5, step6, step7, step8, step9];
|
|
18
|
+
export const STEPS = [step1, step2, step3, step4, step5, step6, step7, step8, step9, step10];
|
|
18
19
|
export const TOTAL_STEPS = STEPS.length;
|
|
19
20
|
|
|
20
21
|
export function getStep(n) {
|