@@ -91,6 +91,7 @@ public static class SetupPages
9191 font-size: 0.85rem; color: #94a3b8; margin-top: 0.5rem;
9292 }
9393 .device-code-box a { color: #60a5fa; text-decoration: underline; }
94+ .disabled-section { opacity: 0.4; pointer-events: none; }
9495 </style>
9596</head>
9697<body>
@@ -100,9 +101,21 @@ public static class SetupPages
100101
101102 <div id="status-banner" class="info-banner hidden"></div>
102103
103- <!-- Option 1: Automated Setup (Device Code Flow) -->
104- <div class="card" id="auto-section">
105- <h2>Automated Setup</h2>
104+ <!-- Step 1: First User -->
105+ <div class="card" id="user-section">
106+ <h2>Step 1: First User</h2>
107+ <p>Add the first superadmin user before configuring authentication. This user will have full access to the application.</p>
108+ <label for="seed-upn">User Principal Name (email)</label>
109+ <input type="text" id="seed-upn" placeholder="admin@contoso.com">
110+ <button class="btn btn-primary" id="btn-seed" onclick="seedFirstUser()" disabled>Add Superadmin</button>
111+ <div id="seed-status" class="status"></div>
112+ </div>
113+
114+ <div class="divider" id="divider-user"></div>
115+
116+ <!-- Step 2: Automated Setup (Device Code Flow) -->
117+ <div class="card disabled-section" id="auto-section">
118+ <h2>Step 2a: Automated Setup</h2>
106119 <p>Sign in with a Global Administrator account to automatically create the EasyAuth app registration and configure this App Service.</p>
107120
108121 <label style="margin-bottom: 0.25rem;">Tenant Access</label>
@@ -131,11 +144,11 @@ public static class SetupPages
131144 <div id="auto-status" class="status"></div>
132145 </div>
133146
134- <div class="divider"></div>
147+ <div class="divider" id="divider-auth" ></div>
135148
136- <!-- Option 2 : Manual Setup -->
137- <div class="card" id="manual-section">
138- <h2>Manual Setup</h2>
149+ <!-- Step 2b : Manual Setup -->
150+ <div class="card disabled-section " id="manual-section">
151+ <h2>Step 2b: Manual Setup</h2>
139152 <p>If you already have an app registration, enter the details below.</p>
140153 <label style="margin-bottom: 0.25rem;">Tenant Access</label>
141154 <div class="toggle-group" id="manual-tenant-toggle">
@@ -205,15 +218,69 @@ function setTenantMode(section, isMulti) {
205218 if (setupState.isEasyAuthConfigured) {
206219 showBanner('Authentication is already configured. Redirecting...');
207220 setTimeout(() => window.location.href = '/', 2000);
221+ return;
208222 }
209223 if (!setupState.isRunningInAppService || !setupState.hasManagedIdentity) {
210224 showBanner('Warning: No managed identity detected. ARM self-configuration may fail. Use manual setup instead.');
211225 }
226+
227+ // Handle user table status
228+ const us = setupState.usersStatus;
229+ if (!us || !us.connected) {
230+ // Connection error — disable user section
231+ document.getElementById('btn-seed').disabled = true;
232+ showStatus('seed-status', 'Cannot connect to storage: ' + (us?.error || 'Unknown error'), 'error');
233+ } else if (us.hasUsers) {
234+ // Users already exist — skip to auth setup
235+ document.getElementById('user-section').classList.add('disabled-section');
236+ showStatus('seed-status', 'Users already exist in the table. Proceed to authentication setup below.', 'success');
237+ enableAuthSections();
238+ } else {
239+ // No users — enable the seed form, keep auth disabled
240+ document.getElementById('btn-seed').disabled = false;
241+ }
212242 } catch (e) {
213243 console.error('Failed to load status', e);
214244 }
215245 })();
216246
247+ function enableAuthSections() {
248+ document.getElementById('auto-section').classList.remove('disabled-section');
249+ document.getElementById('manual-section').classList.remove('disabled-section');
250+ }
251+
252+ async function seedFirstUser() {
253+ const upn = document.getElementById('seed-upn').value.trim();
254+ if (!upn) {
255+ showStatus('seed-status', 'Please enter a valid email address.', 'error');
256+ return;
257+ }
258+
259+ const btn = document.getElementById('btn-seed');
260+ btn.disabled = true;
261+ btn.textContent = 'Adding user...';
262+ showStatus('seed-status', 'Adding superadmin user...', 'info');
263+
264+ try {
265+ const res = await fetch('/api/setup/seed-user', {
266+ method: 'POST',
267+ headers: { 'Content-Type': 'application/json' },
268+ body: JSON.stringify({ upn })
269+ });
270+
271+ const data = await res.json();
272+ if (!res.ok || !data.success) throw new Error(data.message || 'Failed to add user');
273+
274+ showStatus('seed-status', data.message, 'success');
275+ document.getElementById('user-section').classList.add('disabled-section');
276+ enableAuthSections();
277+ } catch (e) {
278+ showStatus('seed-status', 'Error: ' + e.message, 'error');
279+ btn.disabled = false;
280+ btn.textContent = 'Add Superadmin';
281+ }
282+ }
283+
217284 function showBanner(msg) {
218285 const el = document.getElementById('status-banner');
219286 el.textContent = msg;
@@ -378,9 +445,11 @@ async function submitManual() {
378445 }
379446 function showRestartScreen() {
380447 // Hide setup sections, show restart polling UI
448+ document.getElementById('user-section').classList.add('hidden');
381449 document.getElementById('auto-section').classList.add('hidden');
382450 document.getElementById('manual-section').classList.add('hidden');
383- document.querySelector('.divider').classList.add('hidden');
451+ document.getElementById('divider-user').classList.add('hidden');
452+ document.getElementById('divider-auth').classList.add('hidden');
384453 document.querySelector('.subtitle').textContent = '';
385454 document.getElementById('page-title').textContent = 'Restarting...';
386455
0 commit comments