imcp 0.0.16 → 0.0.17
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/cli/commands/install.js +2 -2
- package/dist/cli/commands/list.js +2 -2
- package/dist/cli/commands/serve.js +1 -1
- package/dist/core/RequirementService.d.ts +0 -12
- package/dist/core/RequirementService.js +0 -24
- package/dist/core/installers/clients/BaseClientInstaller.d.ts +1 -1
- package/dist/core/installers/clients/ClientInstaller.d.ts +1 -1
- package/dist/core/installers/clients/ClientInstaller.js +1 -1
- package/dist/core/installers/clients/ClientInstallerFactory.js +1 -1
- package/dist/core/installers/clients/ClineInstaller.d.ts +1 -1
- package/dist/core/installers/clients/ClineInstaller.js +1 -1
- package/dist/core/installers/clients/ExtensionInstaller.js +1 -1
- package/dist/core/installers/clients/GithubCopilotInstaller.d.ts +1 -1
- package/dist/core/installers/clients/GithubCopilotInstaller.js +1 -1
- package/dist/core/installers/clients/MSRooCodeInstaller.d.ts +1 -1
- package/dist/core/installers/clients/MSRooCodeInstaller.js +1 -1
- package/dist/core/installers/requirements/BaseInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/BaseInstaller.js +1 -1
- package/dist/core/installers/requirements/CommandInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/CommandInstaller.js +1 -1
- package/dist/core/installers/requirements/GeneralInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/InstallerFactory.d.ts +1 -1
- package/dist/core/installers/requirements/NpmInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/NpmInstaller.js +1 -1
- package/dist/core/installers/requirements/PipInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/RequirementInstaller.d.ts +1 -1
- package/dist/core/loaders/ConfigurationLoader.d.ts +32 -0
- package/dist/core/loaders/ConfigurationLoader.js +236 -0
- package/dist/core/loaders/ConfigurationProvider.d.ts +35 -0
- package/dist/core/loaders/ConfigurationProvider.js +375 -0
- package/dist/core/loaders/ServerSchemaLoader.d.ts +11 -0
- package/{src/core/ServerSchemaLoader.ts → dist/core/loaders/ServerSchemaLoader.js} +43 -48
- package/dist/core/loaders/ServerSchemaProvider.d.ts +17 -0
- package/{src/core/ServerSchemaProvider.ts → dist/core/loaders/ServerSchemaProvider.js} +120 -137
- package/dist/core/metadatas/constants.d.ts +47 -0
- package/dist/core/metadatas/constants.js +94 -0
- package/dist/core/metadatas/types.d.ts +166 -0
- package/dist/core/metadatas/types.js +16 -0
- package/dist/core/onboard/FeedOnboardService.d.ts +1 -1
- package/dist/core/onboard/FeedOnboardService.js +1 -1
- package/dist/core/onboard/OnboardProcessor.d.ts +1 -1
- package/dist/core/onboard/OnboardProcessor.js +1 -1
- package/dist/core/onboard/OnboardStatus.d.ts +1 -1
- package/dist/core/onboard/OnboardStatusManager.d.ts +1 -1
- package/dist/core/onboard/OnboardStatusManager.js +1 -1
- package/dist/core/validators/FeedValidator.d.ts +1 -1
- package/dist/core/validators/IServerValidator.d.ts +1 -1
- package/dist/core/validators/SSEServerValidator.d.ts +1 -1
- package/dist/core/validators/ServerValidatorFactory.d.ts +1 -1
- package/dist/core/validators/StdioServerValidator.d.ts +1 -1
- package/dist/core/validators/StdioServerValidator.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/services/InstallationService.d.ts +50 -0
- package/dist/services/InstallationService.js +350 -0
- package/dist/services/MCPManager.d.ts +28 -0
- package/dist/services/MCPManager.js +188 -0
- package/dist/services/RequirementService.d.ts +40 -0
- package/dist/services/RequirementService.js +110 -0
- package/dist/services/ServerService.d.ts +2 -2
- package/dist/services/ServerService.js +5 -5
- package/dist/utils/adoUtils.d.ts +2 -2
- package/dist/utils/adoUtils.js +1 -1
- package/dist/utils/feedUtils.js +1 -1
- package/dist/utils/githubUtils.d.ts +1 -1
- package/dist/utils/githubUtils.js +1 -1
- package/dist/utils/logger.js +1 -1
- package/dist/utils/macroExpressionUtils.d.ts +1 -1
- package/dist/utils/osUtils.d.ts +1 -1
- package/dist/utils/osUtils.js +1 -1
- package/dist/web/contract/serverContract.d.ts +1 -1
- package/dist/web/public/index.html +1 -3
- package/dist/web/public/js/api.js +2 -80
- package/dist/web/server.js +2 -2
- package/package.json +1 -1
- package/src/cli/commands/install.ts +3 -3
- package/src/cli/commands/list.ts +2 -2
- package/src/cli/commands/serve.ts +3 -2
- package/src/cli/index.ts +1 -1
- package/src/core/installers/clients/BaseClientInstaller.ts +134 -3
- package/src/core/installers/clients/ClientInstaller.ts +3 -3
- package/src/core/installers/clients/ClientInstallerFactory.ts +1 -1
- package/src/core/installers/clients/ClineInstaller.ts +1 -101
- package/src/core/installers/clients/ExtensionInstaller.ts +1 -1
- package/src/core/installers/clients/GithubCopilotInstaller.ts +1 -101
- package/src/core/installers/clients/MSRooCodeInstaller.ts +1 -102
- package/src/core/installers/requirements/BaseInstaller.ts +2 -2
- package/src/core/installers/requirements/CommandInstaller.ts +1 -1
- package/src/core/installers/requirements/GeneralInstaller.ts +1 -1
- package/src/core/installers/requirements/InstallerFactory.ts +1 -1
- package/src/core/installers/requirements/NpmInstaller.ts +12 -12
- package/src/core/installers/requirements/PipInstaller.ts +1 -1
- package/src/core/installers/requirements/RequirementInstaller.ts +1 -1
- package/src/core/{ConfigurationLoader.ts → loaders/ConfigurationLoader.ts} +31 -7
- package/src/core/{ConfigurationProvider.ts → loaders/ConfigurationProvider.ts} +18 -10
- package/src/core/loaders/ServerSchemaLoader.ts +117 -0
- package/src/core/loaders/ServerSchemaProvider.ts +99 -0
- package/src/core/{types.ts → metadatas/types.ts} +3 -2
- package/src/core/onboard/FeedOnboardService.ts +270 -146
- package/src/core/onboard/OnboardProcessor.ts +60 -11
- package/src/core/onboard/OnboardStatus.ts +7 -2
- package/src/core/onboard/OnboardStatusManager.ts +270 -43
- package/src/core/validators/FeedValidator.ts +65 -9
- package/src/core/validators/IServerValidator.ts +1 -1
- package/src/core/validators/SSEServerValidator.ts +2 -2
- package/src/core/validators/ServerValidatorFactory.ts +1 -1
- package/src/core/validators/StdioServerValidator.ts +86 -34
- package/src/index.ts +3 -3
- package/src/{core → services}/InstallationService.ts +5 -5
- package/src/{core → services}/MCPManager.ts +10 -5
- package/src/{core → services}/RequirementService.ts +2 -31
- package/src/services/ServerService.ts +7 -7
- package/src/utils/adoUtils.ts +3 -3
- package/src/utils/feedUtils.ts +2 -2
- package/src/utils/githubUtils.ts +2 -2
- package/src/utils/logger.ts +13 -1
- package/src/utils/macroExpressionUtils.ts +1 -1
- package/src/utils/osUtils.ts +4 -4
- package/src/web/contract/serverContract.ts +2 -2
- package/src/web/public/index.html +1 -3
- package/src/web/public/js/api.js +2 -80
- package/src/web/public/js/modal/installation.js +1 -1
- package/src/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +41 -9
- package/src/web/public/js/onboard/formProcessor.js +200 -34
- package/src/web/public/js/onboard/index.js +2 -2
- package/src/web/public/js/onboard/publishHandler.js +30 -22
- package/src/web/public/js/onboard/templates.js +34 -40
- package/src/web/public/js/onboard/uiHandlers.js +175 -84
- package/src/web/public/js/onboard/validationHandlers.js +147 -64
- package/src/web/public/js/serverCategoryDetails.js +19 -4
- package/src/web/public/js/serverCategoryList.js +13 -1
- package/src/web/public/onboard.html +1 -1
- package/src/web/server.ts +30 -14
- package/src/services/InstallRequestValidator.ts +0 -112
- /package/src/core/{constants.ts → metadatas/constants.ts} +0 -0
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
|
|
168
168
|
<!-- Module scripts -->
|
|
169
169
|
<script type="module">
|
|
170
|
-
import { fetchServerCategories, handleInstallServer,
|
|
170
|
+
import { fetchServerCategories, handleInstallServer, uninstallTool } from './js/api.js';
|
|
171
171
|
import { setupSearch } from './js/serverCategoryList.js';
|
|
172
172
|
import { showServerDetails } from './js/serverCategoryDetails.js';
|
|
173
173
|
import { showInstallModal, closeModal, setupModalOutsideClick } from './js/modal.js';
|
|
@@ -182,8 +182,6 @@
|
|
|
182
182
|
// If other parts of the app call window.showOnboardModal, they'll need updating too.
|
|
183
183
|
window.closeModal = closeModal;
|
|
184
184
|
window.handleInstallServer = handleInstallServer;
|
|
185
|
-
window.installRequirement = installRequirement;
|
|
186
|
-
window.upgradeRequirement = upgradeRequirement;
|
|
187
185
|
window.uninstallTool = uninstallTool;
|
|
188
186
|
|
|
189
187
|
// Initialize
|
package/src/web/public/js/api.js
CHANGED
|
@@ -42,7 +42,7 @@ async function fetchServerCategories() {
|
|
|
42
42
|
async function handleInstallServer(event, categoryName, serverName, callback, options = {}) {
|
|
43
43
|
event.preventDefault(); // Prevent page reload
|
|
44
44
|
console.log("Handling install for:", categoryName, serverName);
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
// Get selected targets from the form if not provided in options
|
|
47
47
|
const selectedTargets = options.targets || [...document.querySelectorAll('input[name="targets"]:checked')]
|
|
48
48
|
.map(cb => cb.value);
|
|
@@ -71,7 +71,7 @@ async function handleInstallServer(event, categoryName, serverName, callback, op
|
|
|
71
71
|
const response = await fetch(`/api/categories/${categoryName}/install`, {
|
|
72
72
|
method: 'POST',
|
|
73
73
|
headers: { 'Content-Type': 'application/json' },
|
|
74
|
-
body: JSON.stringify({serverList: serverList})
|
|
74
|
+
body: JSON.stringify({ serverList: serverList })
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
if (!response.ok) {
|
|
@@ -90,82 +90,6 @@ async function handleInstallServer(event, categoryName, serverName, callback, op
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
// Install requirement handler
|
|
94
|
-
async function installRequirement(reqName) {
|
|
95
|
-
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
96
|
-
const serverTitle = detailsDiv.querySelector('h3');
|
|
97
|
-
if (!serverTitle) {
|
|
98
|
-
showToast('No server selected.', 'error');
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
let serverName = serverTitle.textContent;
|
|
102
|
-
if (serverName.includes(' for ')) {
|
|
103
|
-
serverName = serverName.split(' for ')[0];
|
|
104
|
-
}
|
|
105
|
-
const confirmed = await showConfirm(`Do you want to install requirement '${reqName}' for ${serverName}?`);
|
|
106
|
-
if (!confirmed) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const btn = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Install' && b.onclick?.toString().includes(reqName));
|
|
111
|
-
if (btn) btn.disabled = true;
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
const response = await fetch(`/api/categories/${serverName}/install-requirement`, {
|
|
115
|
-
method: 'POST',
|
|
116
|
-
headers: { 'Content-Type': 'application/json' },
|
|
117
|
-
body: JSON.stringify({ requirementName: reqName })
|
|
118
|
-
});
|
|
119
|
-
if (!response.ok) {
|
|
120
|
-
const errorData = await response.text();
|
|
121
|
-
throw new Error(`Installation failed: ${errorData || response.statusText}`);
|
|
122
|
-
}
|
|
123
|
-
showToast(`Requirement '${reqName}' installation initiated successfully!`, 'success');
|
|
124
|
-
setTimeout(() => {
|
|
125
|
-
fetchServerCategories();
|
|
126
|
-
window.showServerDetails(serverName);
|
|
127
|
-
}, 1000);
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.error('Error installing requirement:', error);
|
|
130
|
-
showToast(`Error installing requirement: ${error.message}. Please check console.`, 'error');
|
|
131
|
-
} finally {
|
|
132
|
-
if (btn) btn.disabled = false;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Handle upgrade/uninstall actions
|
|
137
|
-
async function upgradeRequirement(name) {
|
|
138
|
-
const serverTitle = document.querySelector('#serverCategoryDetails h3')?.textContent;
|
|
139
|
-
if (!serverTitle) {
|
|
140
|
-
showToast('No server selected.', 'error');
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const upgradeConfirmed = await showConfirm(`Do you want to upgrade requirement '${name}' for ${serverTitle}?`);
|
|
145
|
-
if (!upgradeConfirmed) {
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
const response = await fetch(`/api/categories/${serverTitle}/upgrade-requirement`, {
|
|
151
|
-
method: 'POST',
|
|
152
|
-
headers: { 'Content-Type': 'application/json' },
|
|
153
|
-
body: JSON.stringify({ requirementName: name })
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
if (!response.ok) {
|
|
157
|
-
const errorData = await response.text();
|
|
158
|
-
throw new Error(`Upgrade failed: ${errorData || response.statusText}`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
showToast(`Requirement '${name}' upgrade initiated successfully!`, 'success');
|
|
162
|
-
fetchServerCategories();
|
|
163
|
-
window.showServerDetails(serverTitle);
|
|
164
|
-
} catch (error) {
|
|
165
|
-
console.error('Error upgrading requirement:', error);
|
|
166
|
-
showToast(`Error upgrading requirement: ${error.message}`, 'error');
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
93
|
|
|
170
94
|
async function uninstallTool(name) {
|
|
171
95
|
const serverTitle = document.querySelector('#serverCategoryDetails h3')?.textContent;
|
|
@@ -204,7 +128,5 @@ export {
|
|
|
204
128
|
allServerCategoriesData,
|
|
205
129
|
fetchServerCategories,
|
|
206
130
|
handleInstallServer,
|
|
207
|
-
installRequirement,
|
|
208
|
-
upgradeRequirement,
|
|
209
131
|
uninstallTool
|
|
210
132
|
};
|
|
@@ -175,7 +175,7 @@ async function pollInstallStatus(categoryName, serverName, targets, interval = 2
|
|
|
175
175
|
delayedAppendInstallLoadingMessage(`${target}: ${msg}`);
|
|
176
176
|
lastMessages[target] = msg;
|
|
177
177
|
}
|
|
178
|
-
if (status !== "completed") {
|
|
178
|
+
if (status !== "completed" && status !== "failed") {
|
|
179
179
|
allTargetsCompleted = false;
|
|
180
180
|
}
|
|
181
181
|
}
|
|
@@ -168,9 +168,9 @@ A toggle switch allows users to switch between the standard form view and a raw
|
|
|
168
168
|
- Calls `getFormData()` (from `formProcessor.js`) to get the current form data as `FeedConfiguration`.
|
|
169
169
|
- Sends an initial POST request to `/api/categories/onboard` with the `FeedConfiguration` object and an `isUpdate` flag.
|
|
170
170
|
- The "Publish" button shows a spinning loader icon and its text changes to "Publishing...". Both "Validate" and "Publish" buttons are disabled.
|
|
171
|
-
- **Polling for Status**: If the initial publish request is successful and the operation is not immediately completed or failed, `handlePublish` initiates polling
|
|
172
|
-
- **Displaying Results**: The shared `updateOperationDisplay` function (from `validationHandlers.js`) formats and displays
|
|
173
|
-
- **Completion/Failure**: Polling stops
|
|
171
|
+
- **Polling for Status**: If the initial publish request is successful and the operation is not immediately completed or failed, `handlePublish` initiates polling. The shared `pollOperationStatus` function (from `validationHandlers.js`) is called, which periodically queries `GET /api/categories/:categoryName/onboard/status?operationType=FULL_ONBOARDING`. `pollOperationStatus` now returns a boolean to manage polling continuation.
|
|
172
|
+
- **Displaying Results**: The shared `updateOperationDisplay` function (from `validationHandlers.js`) formats and displays detailed progress, including individual steps, from both the initial publish call and subsequent status polls.
|
|
173
|
+
- **Completion/Failure**: Polling stops based on the status returned by `pollOperationStatus`. Upon completion or failure, buttons are reset, and `showToast()` displays messages. For detailed information on recent changes to polling and status display, see Section 9: "Enhanced Operation Status Polling and Display".
|
|
174
174
|
- **Validation (`handleValidation` in `validationHandlers.js`)**:
|
|
175
175
|
- **Validation (`handleValidation` in `validationHandlers.js`)**:
|
|
176
176
|
- The `validationStatusPanel` (unique per tab) is located under the "MCP Servers" section (or equivalent) and above the main action buttons ("Validate", "Publish"). It is a foldable panel.
|
|
@@ -179,14 +179,14 @@ A toggle switch allows users to switch between the standard form view and a raw
|
|
|
179
179
|
- Sends an initial POST request to `/api/categories/onboard/validate`.
|
|
180
180
|
- The "Validate" button shows a spinning loader icon and its text changes to "Validating...". Both "Validate" and "Publish" buttons are disabled.
|
|
181
181
|
- **Polling for Status**:
|
|
182
|
-
- If the initial validation request is successful and the operation is not immediately completed or failed, `handleValidation` initiates polling
|
|
183
|
-
-
|
|
182
|
+
- If the initial validation request is successful and the operation is not immediately completed or failed, `handleValidation` initiates polling.
|
|
183
|
+
- The shared `pollOperationStatus` function (from `validationHandlers.js`) is called, which periodically queries `GET /api/categories/:categoryName/onboard/status?operationType=VALIDATION_ONLY` (using the category name from the form). `pollOperationStatus` now returns a boolean to manage polling continuation.
|
|
184
184
|
- **Displaying Results**:
|
|
185
|
-
- The shared `updateOperationDisplay` function (from `validationHandlers.js`) formats and displays
|
|
186
|
-
- It handles different structures of the `validationStatus` object
|
|
185
|
+
- The shared `updateOperationDisplay` function (from `validationHandlers.js`) formats and displays detailed progress, including individual steps, from both the initial validation call and subsequent status polls.
|
|
186
|
+
- It handles different structures of the `validationStatus` object and overall operation status.
|
|
187
187
|
- **Completion/Failure**:
|
|
188
|
-
- Polling stops
|
|
189
|
-
- Upon completion or failure,
|
|
188
|
+
- Polling stops based on the status returned by `pollOperationStatus`.
|
|
189
|
+
- Upon completion or failure, buttons are reset. For detailed information on recent changes to polling and status display, see Section 9: "Enhanced Operation Status Polling and Display".
|
|
190
190
|
- **Copy JSON (`copyJsonToClipboard` in `uiHandlers.js`)**: Copies the content of `jsonEditorTextarea` to the clipboard. Uses `showToast()` for feedback.
|
|
191
191
|
- **Global Function Exposure**: Necessary UI handler functions (like `addServer`, `removeServer`, `toggleSectionContent`, etc.) are attached to the `window` object so they can be called from `onclick` attributes in the HTML templates.
|
|
192
192
|
- **Custom Notifications**: Standard browser `alert()` calls have been replaced with a custom toast notification system (`showToast()` from `../notifications.js`). This system requires an `.alert-container` div in the host HTML (`onboard.html`) and uses CSS from `css/notifications.css` for styling. The `notifications.js` module handles the creation, display, and dismissal (manual and automatic) of these toasts without relying on Bootstrap's JavaScript.
|
|
@@ -290,6 +290,38 @@ This section documents significant fixes and behavior changes implemented recent
|
|
|
290
290
|
- **Outcome:** The "Publish" and "Validate" buttons now reliably revert to their default active states when an operation (validation or publish) concludes with a failure, regardless of the casing of the status string from the backend or whether the failure occurs immediately or during polling.
|
|
291
291
|
- **Overall Outcome:** These changes improve the reliability of data submission and provide more accurate UI feedback for asynchronous operations on the "Create Server in Existing Category" tab.
|
|
292
292
|
|
|
293
|
+
- **Enhanced Operation Status Polling and Display (May 2025 - Current Session):**
|
|
294
|
+
- **Context:** Significant improvements were made to the handling of asynchronous operations (validation and publishing), including more detailed progress display, robust polling, and clearer API interactions.
|
|
295
|
+
- **Issues Addressed & Solutions:**
|
|
296
|
+
1. **Server-Side API (`server.ts` - `/api/categories/:categoryName/onboard/status`):**
|
|
297
|
+
- The endpoint now requires an `operationType` query parameter (e.g., `VALIDATION_ONLY`, `FULL_ONBOARDING`).
|
|
298
|
+
- The response payload (`OperationStatus`) was enhanced to include:
|
|
299
|
+
- `steps`: An array of objects detailing each step of the operation (name, serverName, timestamp, status, errorMessage).
|
|
300
|
+
- `operationType`: Reflects the type of operation being tracked, taken from the status object.
|
|
301
|
+
- `feedConfiguration`: Conditionally included for successful `VALIDATION_ONLY` operations if present in the result.
|
|
302
|
+
- The `onboardingId` in the response is `categoryName_operationType`.
|
|
303
|
+
- The `message` field in the response now prioritizes the last step's name or an overall error message.
|
|
304
|
+
2. **Client-Side Polling Logic (`validationHandlers.js` - `pollOperationStatus`):**
|
|
305
|
+
- The function now accepts an `operationType` parameter, which is passed to the API.
|
|
306
|
+
- It returns a boolean promise (`Promise<boolean>`) indicating whether polling should continue, allowing the caller (`handleValidation` or `handlePublish`) to manage `clearInterval`.
|
|
307
|
+
- Calls `ensureProgressToggleListener` to ensure the UI for displaying progress steps is interactive.
|
|
308
|
+
- Status comparisons (`COMPLETED`, `FAILED`, `SUCCEEDED`) are now case-insensitive.
|
|
309
|
+
3. **Operation Initiation (`publishHandler.js` - `handlePublish`, `validationHandlers.js` - `handleValidation`):**
|
|
310
|
+
- When initiating polling, these functions now pass the correct `operationType` (`FULL_ONBOARDING` for publish, `VALIDATION_ONLY` for validate) and use the original `finalFeedConfiguration.name` as the `categoryName` for the polling request.
|
|
311
|
+
- They now manage `clearInterval` based on the boolean returned by `pollOperationStatus`.
|
|
312
|
+
- Both handlers call `ensureProgressToggleListener` at the beginning to prepare the UI for status updates.
|
|
313
|
+
- `handlePublish` includes improved error handling for the initial publish request, ensuring UI elements are correctly updated even if the initial call fails or returns a terminal status.
|
|
314
|
+
4. **UI Display (`validationHandlers.js` - `updateOperationDisplay`):**
|
|
315
|
+
- A new collapsible "Progress" section is displayed, showing detailed `steps` from the API response. Each step includes:
|
|
316
|
+
- A status icon (error, in-progress spinner, success).
|
|
317
|
+
- The step name, server name (if applicable), and timestamp.
|
|
318
|
+
- An error message for the step, if any.
|
|
319
|
+
- The visibility of the "Progress" section is managed by `ensureProgressToggleListener` (which attaches a click handler to the section header) and the `toggleSectionContent` utility.
|
|
320
|
+
- The `operationType` is now displayed.
|
|
321
|
+
- The logic for displaying the overall status spinner has been updated to cover more in-progress states (e.g., `PENDING`, `VALIDATING`, `PRCREATING`, `PUBLISHING`) and uses case-insensitive comparisons.
|
|
322
|
+
5. **Progress Section Toggling (`validationHandlers.js` - `ensureProgressToggleListener`):**
|
|
323
|
+
- A new exported utility function, `ensureProgressToggleListener`, was added. It attaches a click event listener to the status content element. This listener delegates to `toggleSectionContent` (from `uiHandlers.js`) when the progress section header is clicked, allowing users to expand or collapse the detailed list of progress steps. The listener is attached only once per status content element.
|
|
324
|
+
- **Outcome:** These changes provide users with more granular and interactive feedback on long-running operations, improve the robustness and accuracy of status polling, and align client-server communication for tracking asynchronous onboarding tasks.
|
|
293
325
|
---
|
|
294
326
|
|
|
295
327
|
## 10. Server Validation System
|
|
@@ -172,14 +172,26 @@ export async function submitForm(event, activeTab, currentSelectedCategoryData =
|
|
|
172
172
|
showToast('No existing category selected or category data is missing.', 'error');
|
|
173
173
|
return;
|
|
174
174
|
}
|
|
175
|
-
const newServersData = formDataToFeedConfiguration(formElement, true, currentSelectedCategoryData);
|
|
176
175
|
|
|
177
|
-
|
|
176
|
+
// Get the complete state of servers and their requirements from the current form.
|
|
177
|
+
// The `true` flag for `forExistingCategoryTab` tells formDataToFeedConfiguration
|
|
178
|
+
// to only process server data and not category-level fields from this form.
|
|
179
|
+
// It should return ALL servers currently in this form, including modified adhoc and new ones.
|
|
180
|
+
const formDerivedData = formDataToFeedConfiguration(formElement, true, currentSelectedCategoryData);
|
|
178
181
|
|
|
179
|
-
|
|
182
|
+
// Start with a deep clone of the original category data (for name, description, etc.)
|
|
183
|
+
feedConfiguration = JSON.parse(JSON.stringify(currentSelectedCategoryData));
|
|
180
184
|
|
|
185
|
+
// Replace the mcpServers list entirely with what was parsed from the form.
|
|
186
|
+
// This ensures that the list reflects the current state of the form (original read-only, modified adhoc, new).
|
|
187
|
+
feedConfiguration.mcpServers = formDerivedData.mcpServers || [];
|
|
188
|
+
|
|
189
|
+
// Merge requirements: start with original requirements, then add any new ones from the form.
|
|
190
|
+
// `formDerivedData.requirements` should ideally only contain requirements introduced by
|
|
191
|
+
// servers in the current form that are not already in `currentSelectedCategoryData.requirements`.
|
|
192
|
+
// The existing logic for merging requirements seems okay if `formDerivedData.requirements` is correctly populated.
|
|
181
193
|
const existingReqKeys = new Set((feedConfiguration.requirements || []).map(r => `${r.type}|${r.name}|${r.version}`));
|
|
182
|
-
(
|
|
194
|
+
(formDerivedData.requirements || []).forEach(newReq => {
|
|
183
195
|
const reqKey = `${newReq.type}|${newReq.name}|${newReq.version}`;
|
|
184
196
|
if (!existingReqKeys.has(reqKey)) {
|
|
185
197
|
feedConfiguration.requirements.push(newReq);
|
|
@@ -193,7 +205,7 @@ export async function submitForm(event, activeTab, currentSelectedCategoryData =
|
|
|
193
205
|
}
|
|
194
206
|
|
|
195
207
|
try {
|
|
196
|
-
|
|
208
|
+
const response = await fetch('/api/categories/onboard', {
|
|
197
209
|
method: 'POST',
|
|
198
210
|
headers: { 'Content-Type': 'application/json' },
|
|
199
211
|
body: JSON.stringify({
|
|
@@ -208,7 +220,7 @@ export async function submitForm(event, activeTab, currentSelectedCategoryData =
|
|
|
208
220
|
}
|
|
209
221
|
|
|
210
222
|
const result = await response.json();
|
|
211
|
-
console.log('Form submitted successfully:', result);
|
|
223
|
+
// console.log('Form submitted successfully:', result);
|
|
212
224
|
showToast('Form submitted successfully! See console for operation details.', 'success');
|
|
213
225
|
} catch (error) {
|
|
214
226
|
console.error('Error submitting form:', error);
|
|
@@ -327,6 +339,15 @@ export function formDataToFeedConfiguration(formElement, forExistingCategoryTab
|
|
|
327
339
|
mcpServers: []
|
|
328
340
|
};
|
|
329
341
|
|
|
342
|
+
let serversListId;
|
|
343
|
+
if (formElement.id === 'onboardForm') {
|
|
344
|
+
serversListId = 'serversList';
|
|
345
|
+
} else if (formElement.id === 'onboardServerForm') {
|
|
346
|
+
serversListId = 'existingCategoryServersList';
|
|
347
|
+
} else {
|
|
348
|
+
console.warn('[formDataToFeedConfiguration] Could not determine serversListId from formElement.id:', formElement.id);
|
|
349
|
+
}
|
|
350
|
+
|
|
330
351
|
if (!forExistingCategoryTab) {
|
|
331
352
|
feedConfiguration.name = currentFormData.get('name') || '';
|
|
332
353
|
feedConfiguration.displayName = currentFormData.get('displayName') || '';
|
|
@@ -420,8 +441,13 @@ export function formDataToFeedConfiguration(formElement, forExistingCategoryTab
|
|
|
420
441
|
}
|
|
421
442
|
}
|
|
422
443
|
|
|
423
|
-
serverDataMap.
|
|
444
|
+
// console.log('[formDataToFeedConfiguration] serverDataMap keys before processing:', Array.from(serverDataMap.keys())); // DEBUG
|
|
445
|
+
// console.log('[formDataToFeedConfiguration] serverDataMap size:', serverDataMap.size); // DEBUG
|
|
446
|
+
|
|
447
|
+
// Process servers found in the form data (new/adhoc or edited original servers)
|
|
448
|
+
serverDataMap.forEach((serverRaw, serverIndex) => {
|
|
424
449
|
let mcpServer;
|
|
450
|
+
// ... (existing logic to build mcpServer from serverRaw)
|
|
425
451
|
if (serverRaw.mode === 'sse') {
|
|
426
452
|
mcpServer = {
|
|
427
453
|
name: serverRaw.name,
|
|
@@ -436,7 +462,7 @@ export function formDataToFeedConfiguration(formElement, forExistingCategoryTab
|
|
|
436
462
|
requirements: []
|
|
437
463
|
}
|
|
438
464
|
};
|
|
439
|
-
} else {
|
|
465
|
+
} else { // stdio or other modes
|
|
440
466
|
mcpServer = {
|
|
441
467
|
name: serverRaw.name,
|
|
442
468
|
description: serverRaw.description,
|
|
@@ -446,7 +472,7 @@ export function formDataToFeedConfiguration(formElement, forExistingCategoryTab
|
|
|
446
472
|
installation: {
|
|
447
473
|
command: serverRaw.installation.command,
|
|
448
474
|
args: serverRaw.installation.args || [],
|
|
449
|
-
env: {}
|
|
475
|
+
env: {} // Initialize env
|
|
450
476
|
},
|
|
451
477
|
dependencies: {
|
|
452
478
|
requirements: []
|
|
@@ -466,7 +492,7 @@ export function formDataToFeedConfiguration(formElement, forExistingCategoryTab
|
|
|
466
492
|
if (Object.keys(envVars).length > 0) {
|
|
467
493
|
mcpServer.installation.env = envVars;
|
|
468
494
|
} else {
|
|
469
|
-
delete mcpServer.installation.env;
|
|
495
|
+
delete mcpServer.installation.env; // Clean up if no env vars
|
|
470
496
|
}
|
|
471
497
|
}
|
|
472
498
|
|
|
@@ -500,6 +526,7 @@ export function formDataToFeedConfiguration(formElement, forExistingCategoryTab
|
|
|
500
526
|
assetName: reqRaw.registry.local.assetName,
|
|
501
527
|
};
|
|
502
528
|
}
|
|
529
|
+
// Clean up empty registry objects
|
|
503
530
|
if (fullRequirementConfig.registry.githubRelease && !fullRequirementConfig.registry.githubRelease.repository) delete fullRequirementConfig.registry.githubRelease;
|
|
504
531
|
if (fullRequirementConfig.registry.artifacts && !fullRequirementConfig.registry.artifacts.registryUrl) delete fullRequirementConfig.registry.artifacts;
|
|
505
532
|
if (fullRequirementConfig.registry.local && !fullRequirementConfig.registry.local.localPath) delete fullRequirementConfig.registry.local;
|
|
@@ -514,17 +541,103 @@ export function formDataToFeedConfiguration(formElement, forExistingCategoryTab
|
|
|
514
541
|
|
|
515
542
|
const reqKey = `${reqRaw.type}|${reqRaw.name}|${reqRaw.version}`;
|
|
516
543
|
if (!globalRequirementsMap.has(reqKey)) {
|
|
517
|
-
const { order, ...reqConfigForGlobal } = fullRequirementConfig;
|
|
544
|
+
const { order, ...reqConfigForGlobal } = fullRequirementConfig; // Exclude order for global list
|
|
518
545
|
globalRequirementsMap.set(reqKey, reqConfigForGlobal);
|
|
519
546
|
}
|
|
520
547
|
});
|
|
521
548
|
if (mcpServer.dependencies.requirements.length === 0) {
|
|
522
|
-
delete mcpServer.dependencies;
|
|
549
|
+
delete mcpServer.dependencies; // Clean up if no requirements
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Attempt to retrieve and add systemTags from the DOM element,
|
|
553
|
+
// ONLY if we are in the 'Create Server in Existing Category' tab context.
|
|
554
|
+
// For 'Create New Category' tab, systemTags should not be assigned from DOM.
|
|
555
|
+
if (formElement.id === 'onboardServerForm' && serversListId) {
|
|
556
|
+
const selector = `#${serversListId} .server-item[data-index="${serverIndex}"]`;
|
|
557
|
+
const serverItemElement = document.querySelector(selector);
|
|
558
|
+
if (serverItemElement && serverItemElement.dataset.systemTags) {
|
|
559
|
+
try {
|
|
560
|
+
mcpServer.systemTags = JSON.parse(serverItemElement.dataset.systemTags);
|
|
561
|
+
} catch (e) {
|
|
562
|
+
console.error(`[formDataToFeedConfiguration] Error parsing systemTags for server index ${serverIndex} ('${mcpServer.name}') on ${formElement.id}:`, e, serverItemElement.dataset.systemTags);
|
|
563
|
+
mcpServer.systemTags = { parseError: true };
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
// If no dataset.systemTags or not onboardServerForm, mcpServer.systemTags remains undefined.
|
|
567
|
+
} else {
|
|
568
|
+
// Ensure systemTags is not carried over if not in the correct context or not present in dataset
|
|
569
|
+
delete mcpServer.systemTags;
|
|
523
570
|
}
|
|
524
571
|
|
|
525
572
|
feedConfiguration.mcpServers.push(mcpServer);
|
|
526
573
|
});
|
|
527
574
|
|
|
575
|
+
|
|
576
|
+
// If processing for an existing category, ensure original non-adhoc servers are included
|
|
577
|
+
// if they weren't picked up by the form (e.g., because they were read-only and disabled).
|
|
578
|
+
if (forExistingCategoryTab && baseCategoryData && Array.isArray(baseCategoryData.mcpServers)) {
|
|
579
|
+
baseCategoryData.mcpServers.forEach(originalServer => {
|
|
580
|
+
// Check if this original server (by name) is already in our processed list.
|
|
581
|
+
// We use name as the primary identifier for existing servers.
|
|
582
|
+
const isAlreadyProcessed = feedConfiguration.mcpServers.some(
|
|
583
|
+
processedServer => processedServer.name === originalServer.name
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
if (!isAlreadyProcessed && (!originalServer.systemTags || originalServer.systemTags.adhoc !== 'true')) {
|
|
587
|
+
// This original server was not in the form data (likely read-only) and is not adhoc. Add it.
|
|
588
|
+
// Ensure its requirements are also added to the global list if not already present.
|
|
589
|
+
feedConfiguration.mcpServers.push(JSON.parse(JSON.stringify(originalServer))); // Add a clone
|
|
590
|
+
|
|
591
|
+
if (originalServer.dependencies && Array.isArray(originalServer.dependencies.requirements)) {
|
|
592
|
+
originalServer.dependencies.requirements.forEach(req => {
|
|
593
|
+
// We need the full requirement definition for the global map.
|
|
594
|
+
// This might require looking up the full definition from baseCategoryData.requirements
|
|
595
|
+
// if originalServer.dependencies.requirements only has name/version/order.
|
|
596
|
+
// For simplicity here, we assume baseCategoryData.requirements contains full definitions.
|
|
597
|
+
const originalGlobalReq = baseCategoryData.requirements?.find(
|
|
598
|
+
gReq => gReq.name === req.name && gReq.type && gReq.version === req.version // Type might not be in server's dep list
|
|
599
|
+
);
|
|
600
|
+
|
|
601
|
+
if (originalGlobalReq) {
|
|
602
|
+
const reqKey = `${originalGlobalReq.type}|${originalGlobalReq.name}|${originalGlobalReq.version}`;
|
|
603
|
+
if (!globalRequirementsMap.has(reqKey)) {
|
|
604
|
+
globalRequirementsMap.set(reqKey, JSON.parse(JSON.stringify(originalGlobalReq)));
|
|
605
|
+
}
|
|
606
|
+
} else {
|
|
607
|
+
// Fallback if full definition not found, add what we have, though type might be missing.
|
|
608
|
+
// This part might need refinement based on actual structure of baseCategoryData.requirements
|
|
609
|
+
// and how server-specific dependencies link to global ones.
|
|
610
|
+
// The current server-specific req usually has name, version, order. Type is global.
|
|
611
|
+
// We need to find the type from the global requirements list.
|
|
612
|
+
// This logic assumes that if a server has a dependency, its full definition (including type)
|
|
613
|
+
// must exist in the global `baseCategoryData.requirements`.
|
|
614
|
+
|
|
615
|
+
// Let's find the type from baseCategoryData.requirements based on name and version
|
|
616
|
+
const matchingGlobalReqForType = baseCategoryData.requirements?.find(
|
|
617
|
+
gReq => gReq.name === req.name && gReq.version === req.version
|
|
618
|
+
);
|
|
619
|
+
if (matchingGlobalReqForType && matchingGlobalReqForType.type) {
|
|
620
|
+
const reqKey = `${matchingGlobalReqForType.type}|${req.name}|${req.version}`;
|
|
621
|
+
if (!globalRequirementsMap.has(reqKey)) {
|
|
622
|
+
// Construct a basic global requirement if not found, though ideally it should exist.
|
|
623
|
+
globalRequirementsMap.set(reqKey, {
|
|
624
|
+
name: req.name,
|
|
625
|
+
version: req.version,
|
|
626
|
+
type: matchingGlobalReqForType.type
|
|
627
|
+
// Other fields like alias, registry would be missing here if not in matchingGlobalReqForType
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
} else {
|
|
631
|
+
console.warn(`Could not find full global requirement definition (or type) for ${req.name} v${req.version} from original server ${originalServer.name}`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
|
|
528
641
|
feedConfiguration.requirements = Array.from(globalRequirementsMap.values());
|
|
529
642
|
|
|
530
643
|
// Validate the entire configuration
|
|
@@ -668,47 +781,95 @@ export function populateForm(feedConfig, formId = 'onboardForm', renderServersAs
|
|
|
668
781
|
clearEnvCountersForTab(serversListId);
|
|
669
782
|
clearServerRequirementCountersForTab(serversListId);
|
|
670
783
|
|
|
671
|
-
(feedConfig.mcpServers || []).forEach((
|
|
784
|
+
(feedConfig.mcpServers || []).forEach((serverData) => { // Renamed 'server' to 'serverData' for clarity
|
|
672
785
|
// Get the correct current index for this tab before adding the server
|
|
673
786
|
const currentServerIndex = getServerCounter(serversListId);
|
|
674
787
|
// window.addServer will increment the counter for serversListId internally
|
|
675
|
-
|
|
676
|
-
|
|
788
|
+
// It also returns the server item, but we'll query it again for safety after DOM manipulation.
|
|
789
|
+
window.addServer(serversListId, renderServersAsReadOnly, serverData);
|
|
790
|
+
|
|
791
|
+
// After addServer, the server item should exist in the DOM.
|
|
792
|
+
const serverItem = currentForm.querySelector(`#${serversListId} .server-item[data-index="${currentServerIndex}"]`);
|
|
793
|
+
|
|
794
|
+
if (serverItem) {
|
|
795
|
+
if (formId === 'onboardServerForm') {
|
|
796
|
+
if (serverData.systemTags?.adhoc === "true") {
|
|
797
|
+
// Case 1: JSON data explicitly marks it as adhoc. Respect this.
|
|
798
|
+
serverItem.dataset.systemTags = JSON.stringify(serverData.systemTags);
|
|
799
|
+
// console.log(`[populateForm] Server ${serverData.name || currentServerIndex} in ${formId} retains adhoc status from JSON.`);
|
|
800
|
+
} else {
|
|
801
|
+
// Case 2: JSON data does NOT explicitly mark it adhoc.
|
|
802
|
+
// Check if it was an original server from the category.
|
|
803
|
+
// state.originalServerNamesForFormPopulation is set when toggling from JSON to Form view for an existing category.
|
|
804
|
+
if (state.originalServerNamesForFormPopulation && serverData.name && state.originalServerNamesForFormPopulation.has(serverData.name)) {
|
|
805
|
+
// It's an original server from the category, now treated as adhoc because it passed through JSON view.
|
|
806
|
+
serverItem.dataset.systemTags = JSON.stringify({ adhoc: "true" });
|
|
807
|
+
// console.log(`[populateForm] Original server ${serverData.name} in ${formId} marked as adhoc after JSON view.`);
|
|
808
|
+
} else {
|
|
809
|
+
// It's a new server (not in original list) and JSON didn't mark it adhoc.
|
|
810
|
+
// Or, it's an original server but its JSON representation explicitly removed/lacked adhoc tag.
|
|
811
|
+
// Ensure it's NOT adhoc.
|
|
812
|
+
// If serverData.systemTags exists but doesn't have adhoc:true, preserve those other tags.
|
|
813
|
+
if (serverData.systemTags && Object.keys(serverData.systemTags).length > 0) {
|
|
814
|
+
const newTags = { ...serverData.systemTags };
|
|
815
|
+
delete newTags.adhoc; // Ensure adhoc is not true
|
|
816
|
+
if (Object.keys(newTags).length > 0) {
|
|
817
|
+
serverItem.dataset.systemTags = JSON.stringify(newTags);
|
|
818
|
+
} else {
|
|
819
|
+
delete serverItem.dataset.systemTags;
|
|
820
|
+
}
|
|
821
|
+
} else {
|
|
822
|
+
delete serverItem.dataset.systemTags;
|
|
823
|
+
}
|
|
824
|
+
// console.log(`[populateForm] Server ${serverData.name || currentServerIndex} in ${formId} is NOT marked adhoc.`);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
} else {
|
|
828
|
+
// For 'onboardForm' (Create Category tab), or if serverData had systemTags not making it adhoc.
|
|
829
|
+
// If serverData has systemTags, reflect them. Otherwise, ensure no systemTags.
|
|
830
|
+
if (serverData.systemTags) {
|
|
831
|
+
serverItem.dataset.systemTags = JSON.stringify(serverData.systemTags);
|
|
832
|
+
} else {
|
|
833
|
+
delete serverItem.dataset.systemTags;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
// Continue with populating fields using serverData
|
|
677
838
|
const serverNameInput = currentForm.querySelector(`[name="servers[${currentServerIndex}].name"]`);
|
|
678
|
-
if (serverNameInput) serverNameInput.value =
|
|
839
|
+
if (serverNameInput) serverNameInput.value = serverData.name || '';
|
|
679
840
|
|
|
680
841
|
const modeInput = currentForm.querySelector(`[name="servers[${currentServerIndex}].mode"]`);
|
|
681
842
|
if (modeInput) {
|
|
682
|
-
modeInput.value =
|
|
843
|
+
modeInput.value = serverData.mode || 'stdio';
|
|
683
844
|
if (typeof window.renderInstallationConfig === 'function') {
|
|
684
|
-
window.renderInstallationConfig(currentServerIndex, serversListId,
|
|
845
|
+
window.renderInstallationConfig(currentServerIndex, serversListId, serverData.mode || 'stdio', renderServersAsReadOnly, serverData.installation);
|
|
685
846
|
}
|
|
686
847
|
}
|
|
687
848
|
const descInput = currentForm.querySelector(`[name="servers[${currentServerIndex}].description"]`);
|
|
688
|
-
if (descInput) descInput.value =
|
|
849
|
+
if (descInput) descInput.value = serverData.description || '';
|
|
689
850
|
|
|
690
|
-
if (
|
|
851
|
+
if (serverData.schemas) {
|
|
691
852
|
const schemaPathEl = document.getElementById(`schema-path-${currentServerIndex}`);
|
|
692
|
-
if (schemaPathEl) schemaPathEl.value =
|
|
853
|
+
if (schemaPathEl) schemaPathEl.value = serverData.schemas;
|
|
693
854
|
}
|
|
694
|
-
if (
|
|
855
|
+
if (serverData.repository) {
|
|
695
856
|
const repoInput = currentForm.querySelector(`[name="servers[${currentServerIndex}].repository"]`);
|
|
696
|
-
if (repoInput) repoInput.value =
|
|
857
|
+
if (repoInput) repoInput.value = serverData.repository;
|
|
697
858
|
}
|
|
698
859
|
|
|
699
|
-
if (
|
|
700
|
-
if (
|
|
860
|
+
if (serverData.installation) {
|
|
861
|
+
if (serverData.mode === 'sse') {
|
|
701
862
|
const urlInput = currentForm.querySelector(`[name="servers[${currentServerIndex}].installation.url"]`);
|
|
702
|
-
if (urlInput) urlInput.value =
|
|
863
|
+
if (urlInput) urlInput.value = serverData.installation.url || '';
|
|
703
864
|
} else {
|
|
704
865
|
const cmdInput = currentForm.querySelector(`[name="servers[${currentServerIndex}].installation.command"]`);
|
|
705
|
-
if (cmdInput) cmdInput.value =
|
|
706
|
-
if (
|
|
866
|
+
if (cmdInput) cmdInput.value = serverData.installation.command || '';
|
|
867
|
+
if (serverData.installation.args && Array.isArray(serverData.installation.args)) {
|
|
707
868
|
const argsInput = currentForm.querySelector(`[name="servers[${currentServerIndex}].installation.args"]`);
|
|
708
|
-
if (argsInput) argsInput.value =
|
|
869
|
+
if (argsInput) argsInput.value = serverData.installation.args.join(', ');
|
|
709
870
|
}
|
|
710
|
-
if (
|
|
711
|
-
Object.entries(
|
|
871
|
+
if (serverData.installation.env) {
|
|
872
|
+
Object.entries(serverData.installation.env).forEach(([envName, envConfig]) => {
|
|
712
873
|
const currentEnvIndex = window.addEnvVariable(currentServerIndex, serversListId, renderServersAsReadOnly);
|
|
713
874
|
|
|
714
875
|
const nameInput = currentForm.querySelector(`[name="servers[${currentServerIndex}].installation.env[${currentEnvIndex}].name"]`);
|
|
@@ -730,8 +891,12 @@ export function populateForm(feedConfig, formId = 'onboardForm', renderServersAs
|
|
|
730
891
|
}
|
|
731
892
|
}
|
|
732
893
|
|
|
733
|
-
if (
|
|
734
|
-
server
|
|
894
|
+
if (serverData.dependencies && serverData.dependencies.requirements) {
|
|
895
|
+
// Determine if this server's requirements should be effectively read-only
|
|
896
|
+
const serverIsEffectivelyReadOnlyForReqs = renderServersAsReadOnly && !(serverData.systemTags?.adhoc === 'true');
|
|
897
|
+
// console.log(`[populateForm] Server: ${serverData.name}, Adhoc: ${serverData.systemTags?.adhoc === 'true'}, renderServersAsReadOnly: ${renderServersAsReadOnly}, Calculated serverIsEffectivelyReadOnlyForReqs: ${serverIsEffectivelyReadOnlyForReqs}`); // DEBUG
|
|
898
|
+
|
|
899
|
+
serverData.dependencies.requirements.forEach((depReq) => {
|
|
735
900
|
// Find requirement by name only, as requested.
|
|
736
901
|
const fullReq = (feedConfig.requirements || []).find(r => r.name === depReq.name);
|
|
737
902
|
if (!fullReq) {
|
|
@@ -739,7 +904,8 @@ export function populateForm(feedConfig, formId = 'onboardForm', renderServersAs
|
|
|
739
904
|
return;
|
|
740
905
|
}
|
|
741
906
|
|
|
742
|
-
|
|
907
|
+
// Pass serverIsEffectivelyReadOnlyForReqs to addServerRequirement
|
|
908
|
+
const currentReqIndex = window.addServerRequirement(currentServerIndex, serversListId, serverIsEffectivelyReadOnlyForReqs);
|
|
743
909
|
|
|
744
910
|
currentForm.querySelector(`[name="servers[${currentServerIndex}].requirements[${currentReqIndex}].name"]`).value = fullReq.name || '';
|
|
745
911
|
currentForm.querySelector(`[name="servers[${currentServerIndex}].requirements[${currentReqIndex}].type"]`).value = fullReq.type || '';
|
|
@@ -293,11 +293,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
|
293
293
|
// addRequirementBtn.addEventListener('click', addRequirement); // addRequirement from uiHandlers.js
|
|
294
294
|
// }
|
|
295
295
|
|
|
296
|
-
const addServerBtnNewCategory = document.getElementById('
|
|
296
|
+
const addServerBtnNewCategory = document.getElementById('addServerBtnNewCategory'); // For "Create New Category" tab
|
|
297
297
|
if (addServerBtnNewCategory) {
|
|
298
298
|
// addServer in uiHandlers defaults serversListId to 'serversList', which is correct for this button.
|
|
299
299
|
// It also defaults isReadOnly to false.
|
|
300
|
-
addServerBtnNewCategory.addEventListener('click', () => addServer());
|
|
300
|
+
addServerBtnNewCategory.addEventListener('click', () => window.addServer('serversList', false, null));
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
const addServerBtnExistingCategory = document.getElementById('addServerToExistingCategoryBtn'); // For "Create Server in Existing Category" tab
|