imcp 0.2.3 → 0.2.4
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 +8 -8
- package/dist/cli/index.js +0 -0
- package/dist/cli/tui/components/ClientSelector.js +1 -1
- package/dist/cli/tui/components/ClientSelector.js.map +1 -1
- package/dist/core/installers/clients/BaseClientInstaller.js +1 -1
- package/dist/core/installers/clients/BaseClientInstaller.js.map +1 -1
- package/dist/core/installers/clients/ClientInstallerFactory.js +1 -1
- package/dist/core/installers/clients/ClientInstallerFactory.js.map +1 -1
- package/dist/core/installers/clients/CopilotCLIInstaller.d.ts +18 -0
- package/dist/core/installers/clients/CopilotCLIInstaller.js +2 -0
- package/dist/core/installers/clients/CopilotCLIInstaller.js.map +1 -0
- package/dist/core/installers/clients/ExtensionInstaller.d.ts +1 -0
- package/dist/core/installers/clients/ExtensionInstaller.js +1 -1
- package/dist/core/installers/clients/ExtensionInstaller.js.map +1 -1
- package/dist/core/installers/requirements/NpmInstaller.js +1 -1
- package/dist/core/installers/requirements/NpmInstaller.js.map +1 -1
- package/dist/core/metadatas/constants.d.ts +4 -0
- package/dist/core/metadatas/constants.js +1 -1
- package/dist/core/metadatas/constants.js.map +1 -1
- package/dist/utils/versionUtils.js +1 -1
- package/dist/utils/versionUtils.js.map +1 -1
- package/dist/web/public/js/api.js.map +1 -1
- package/dist/web/public/js/detailsWidget.js.map +1 -1
- package/dist/web/public/js/flights/flights.js.map +1 -1
- package/dist/web/public/js/modal/index.js.map +1 -1
- package/dist/web/public/js/modal/installModal.js.map +1 -1
- package/dist/web/public/js/modal/installation.js.map +1 -1
- package/dist/web/public/js/modal/loadingModal.js.map +1 -1
- package/dist/web/public/js/modal/modalSetup.js.map +1 -1
- package/dist/web/public/js/modal/modalUtils.js.map +1 -1
- package/dist/web/public/js/modal/versionUtils.js.map +1 -1
- package/dist/web/public/js/modal.js.map +1 -1
- package/dist/web/public/js/notifications.js.map +1 -1
- package/dist/web/public/js/onboard/formProcessor.js.map +1 -1
- package/dist/web/public/js/onboard/index.js.map +1 -1
- package/dist/web/public/js/onboard/publishHandler.js.map +1 -1
- package/dist/web/public/js/onboard/state.js.map +1 -1
- package/dist/web/public/js/onboard/templates.js.map +1 -1
- package/dist/web/public/js/onboard/uiHandlers.js.map +1 -1
- package/dist/web/public/js/onboard/validationHandlers.js.map +1 -1
- package/dist/web/public/js/serverCategoryDetails.js.map +1 -1
- package/dist/web/public/js/serverCategoryList.js.map +1 -1
- package/dist/web/public/js/settings.js.map +1 -1
- package/package.json +1 -1
- package/dist/core/installers/clients/CodexInstaller.d.ts +0 -45
- package/dist/core/installers/clients/CodexInstaller.js +0 -2
- package/dist/core/installers/clients/CodexInstaller.js.map +0 -1
- package/dist/utils/tomlUtils.d.ts +0 -17
- package/dist/utils/tomlUtils.js +0 -2
- package/dist/utils/tomlUtils.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":[],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["showToast","state","setServerCounter","getServerCounter","clearEnvCountersForTab","clearServerRequirementCountersForTab","setupRealTimeValidation","formId","form","document","getElementById","nameInput","querySelector","addEventListener","e","value","target","trim","test","length","showValidationMessage","displayNameInput","descriptionInput","repoInput","URL","err","nextElementSibling","remove","name","match","serverIndex","commandInput","urlInput","argsInput","required","includes","matches","envIndex","field","async","submitForm","event","activeTab","currentSelectedCategoryData","preventDefault","formElement","feedConfiguration","isUpdateOperation","formDataToFeedConfiguration","urlParams","URLSearchParams","window","location","search","get","validationError","console","error","formDerivedData","JSON","parse","stringify","mcpServers","existingReqKeys","Set","requirements","map","r","type","version","forEach","newReq","reqKey","has","push","add","response","fetch","method","headers","body","categoryData","isUpdate","ok","errorData","json","catch","Error","status","statusText","message","getFormData","forExistingCategoryTab","baseCategoryData","validateServerConfig","serverConfig","errors","description","mode","installation","command","args","arg","index","url","env","Object","entries","config","Required","Default","Description","schemas","currentFormData","FormData","serversListId","id","warn","displayName","repository","undefined","serverDataMap","Map","globalRequirementsMap","key","startsWith","serverMatchKey","serverIndexInForm","parseInt","fieldPathFromMatch","actualServerDataIndex","set","dependencies","isNew","currentServerData","split","filter","isLocal","startingCommand","envMatch","envField","currentEnv","reqMatch","reqIndex","reqFieldPath","registry","currentReq","order","alias","registryType","githubRelease","substring","artifacts","local","serverRaw","mcpServer","envVars","default","keys","reqRaw","fullRequirementConfig","assetsName","assetName","registryUrl","registryName","localPath","reqConfigForGlobal","selector","serverItemElement","dataset","systemTags","parseError","Array","isArray","originalReq","originalServer","some","processedServer","adhoc","from","values","server","serverErrors","join","req","querySelectorAll","el","errorMsg","input","errorDiv","createElement","className","textContent","insertAdjacentElement","populateForm","feedConfig","renderServersAsReadOnly","targetServersListId","currentForm","resetOnboardFormDynamicContent","readOnly","classList","basicInfoContainer","mcpServersContainer","serverData","currentServerIndex","addServer","serverItem","originalServerNamesForFormPopulation","newTags","serverNameInput","modeInput","renderInstallationConfig","descInput","schemaPathEl","cmdInput","envName","envConfig","currentEnvIndex","addEnvVariable","defInput","reqInput","checked","serverIsEffectivelyReadOnlyForReqs","depReq","fullReq","find","currentReqIndex","addServerRequirement","toggleServerAliasField","registrySelect","toggleServerRegistryConfig","gh","art","loc","formToReset","reset","serversListContainer","validationPanelIdToReset","validationContentIdToReset","innerHTML","envCounters","clear","serverRequirementCounters","validationPanel","validationContent","element","isError","messageDiv","contains"],"sources":["0"],"sourcesContent":["// Form data processing and API calls\nimport { showToast } from '../notifications.js';\nimport { state, setServerCounter, getServerCounter, clearEnvCountersForTab, clearServerRequirementCountersForTab } from './state.js';\n\n/**\n * Adds real-time validation to form inputs.\n * @param {string} formId - The ID of the form to add validation to.\n */\nfunction setupRealTimeValidation(formId) {\n const form = document.getElementById(formId);\n if (!form) return;\n\n if (!form) return;\n\n // Name input validation (category or server)\n const nameInput = form.querySelector('input[name=\"name\"]');\n if (nameInput) {\n nameInput.addEventListener('input', (e) => {\n const value = e.target.value.trim();\n if (!value) {\n showValidationMessage(e.target, 'Name is required');\n } else if (!/^[a-zA-Z0-9-_]+$/.test(value)) {\n showValidationMessage(e.target, 'Only alphanumeric characters, hyphens, and underscores allowed');\n } else if (value.length > 50) {\n showValidationMessage(e.target, 'Must not exceed 50 characters');\n } else {\n showValidationMessage(e.target, 'Valid name', false);\n }\n });\n }\n\n // Display name validation\n const displayNameInput = form.querySelector('input[name=\"displayName\"]');\n if (displayNameInput) {\n displayNameInput.addEventListener('input', (e) => {\n const value = e.target.value.trim();\n if (!value) {\n showValidationMessage(e.target, 'Display name is required');\n } else if (value.length > 100) {\n showValidationMessage(e.target, 'Must not exceed 100 characters');\n } else {\n showValidationMessage(e.target, 'Valid display name', false);\n }\n });\n }\n\n // Description validation\n const descriptionInput = form.querySelector('textarea[name=\"description\"]');\n if (descriptionInput) {\n descriptionInput.addEventListener('input', (e) => {\n const value = e.target.value.trim();\n if (value.length > 500) {\n showValidationMessage(e.target, 'Must not exceed 500 characters');\n } else if (value.length === 0) {\n showValidationMessage(e.target, 'Description is required');\n } else {\n showValidationMessage(e.target, 'Valid description', false);\n }\n });\n }\n\n // Repository URL validation\n const repoInput = form.querySelector('input[name=\"repository\"]');\n if (repoInput) {\n repoInput.addEventListener('input', (e) => {\n const value = e.target.value.trim();\n if (value) {\n try {\n new URL(value);\n showValidationMessage(e.target, 'Valid URL', false);\n } catch (err) {\n showValidationMessage(e.target, 'Invalid URL format');\n }\n } else {\n e.target.nextElementSibling?.remove(); // Remove validation message if empty\n }\n });\n }\n\n // Server mode validation\n form.addEventListener('change', (e) => {\n if (e.target.name?.match(/servers\\[\\d+\\]\\.mode/)) {\n const serverIndex = e.target.name.match(/servers\\[(\\d+)\\]/)[1];\n const commandInput = form.querySelector(`[name=\"servers[${serverIndex}].installation.command\"]`);\n const urlInput = form.querySelector(`[name=\"servers[${serverIndex}].installation.url\"]`);\n const argsInput = form.querySelector(`[name=\"servers[${serverIndex}].installation.args\"]`);\n\n if (e.target.value === 'stdio') {\n if (commandInput) {\n commandInput.required = true;\n showValidationMessage(commandInput, 'Command is required for stdio mode');\n }\n if (urlInput) {\n urlInput.required = false;\n urlInput.value = '';\n urlInput.nextElementSibling?.remove();\n }\n } else if (e.target.value === 'sse' || e.target.value === 'streamable-http') {\n if (urlInput) {\n urlInput.required = true;\n showValidationMessage(urlInput, `URL is required for ${e.target.value} mode`);\n }\n if (commandInput) {\n commandInput.required = false;\n commandInput.value = '';\n commandInput.nextElementSibling?.remove();\n }\n if (argsInput) {\n argsInput.value = '';\n argsInput.nextElementSibling?.remove();\n }\n }\n }\n });\n\n // Environment variable validation\n form.addEventListener('input', (e) => {\n if (e.target.name?.includes('.installation.env[')) {\n const matches = e.target.name.match(/servers\\[(\\d+)\\]\\.installation\\.env\\[(\\d+)\\]\\.(name|default)/);\n if (matches) {\n const [, serverIndex, envIndex, field] = matches;\n if (field === 'name') {\n const value = e.target.value.trim();\n if (!value) {\n showValidationMessage(e.target, 'Environment variable name is required');\n } else if (!/^[A-Z_][A-Z0-9_]*$/.test(value)) {\n showValidationMessage(e.target, 'Must be uppercase with only letters, numbers, and underscores');\n } else if (value.length > 50) {\n showValidationMessage(e.target, 'Must not exceed 50 characters');\n } else {\n showValidationMessage(e.target, 'Valid name', false);\n }\n }\n }\n }\n });\n}\n\n/**\n * Submits the form data for onboarding or updating a server category.\n * @param {Event} event - The form submission event.\n * @param {string} activeTab - Identifier for the active tab ('create-category' or 'create-server').\n * @param {object|null} currentSelectedCategoryData - Full FeedConfiguration of the selected category if activeTab is 'create-server'.\n */\nexport async function submitForm(event, activeTab, currentSelectedCategoryData = null) {\n event.preventDefault();\n const formElement = event.target;\n let feedConfiguration;\n let isUpdateOperation = false;\n\n if (activeTab === 'create-category') {\n try {\n feedConfiguration = formDataToFeedConfiguration(formElement);\n const urlParams = new URLSearchParams(window.location.search);\n isUpdateOperation = urlParams.get('action') === 'edit' && urlParams.get('category') === feedConfiguration.name;\n } catch (validationError) {\n console.error('Validation error:', validationError);\n return;\n }\n } else if (activeTab === 'create-server') {\n if (!currentSelectedCategoryData || !currentSelectedCategoryData.name) {\n showToast('No existing category selected or category data is missing.', 'error');\n return;\n }\n\n // Get the complete state of servers and their requirements from the current form.\n // The `true` flag for `forExistingCategoryTab` tells formDataToFeedConfiguration\n // to only process server data and not category-level fields from this form.\n // It should return ALL servers currently in this form, including modified adhoc and new ones.\n const formDerivedData = formDataToFeedConfiguration(formElement, true, currentSelectedCategoryData);\n\n // Start with a deep clone of the original category data (for name, description, etc.)\n feedConfiguration = JSON.parse(JSON.stringify(currentSelectedCategoryData));\n\n // Replace the mcpServers list entirely with what was parsed from the form.\n // This ensures that the list reflects the current state of the form (original read-only, modified adhoc, new).\n feedConfiguration.mcpServers = formDerivedData.mcpServers || [];\n\n // Merge requirements: start with original requirements, then add any new ones from the form.\n // `formDerivedData.requirements` should ideally only contain requirements introduced by\n // servers in the current form that are not already in `currentSelectedCategoryData.requirements`.\n // The existing logic for merging requirements seems okay if `formDerivedData.requirements` is correctly populated.\n const existingReqKeys = new Set((feedConfiguration.requirements || []).map(r => `${r.type}|${r.name}|${r.version}`));\n (formDerivedData.requirements || []).forEach(newReq => {\n const reqKey = `${newReq.type}|${newReq.name}|${newReq.version}`;\n if (!existingReqKeys.has(reqKey)) {\n feedConfiguration.requirements.push(newReq);\n existingReqKeys.add(reqKey);\n }\n });\n isUpdateOperation = true;\n } else {\n showToast('Invalid tab context for submission.', 'error');\n return;\n }\n\n try {\n const response = await fetch('/api/categories/onboard', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n categoryData: feedConfiguration,\n isUpdate: isUpdateOperation\n })\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Failed to parse error response' }));\n throw new Error(`HTTP error! status: ${response.status}, message: ${errorData.error || response.statusText}`);\n }\n\n const result = await response.json();\n // console.log('Form submitted successfully:', result);\n showToast('Form submitted successfully! See console for operation details.', 'success');\n } catch (error) {\n console.error('Error submitting form:', error);\n showToast(`Error submitting form: ${error.message}. Please try again.`, 'error');\n }\n}\n\n/**\n * Retrieves form data from a given HTMLFormElement.\n * @param {HTMLFormElement} formElement - The form element to process.\n * @param {boolean} [forExistingCategoryTab=false] - True if processing for the \"Create Server in Existing Category\" tab.\n * @param {object|null} [baseCategoryData=null] - The base FeedConfiguration of the selected category (used if forExistingCategoryTab is true).\n * @returns {object} The FeedConfiguration object (or partial for new servers if forExistingCategoryTab is true).\n */\nexport function getFormData(formElement, forExistingCategoryTab = false, baseCategoryData = null) {\n return formDataToFeedConfiguration(formElement, forExistingCategoryTab, baseCategoryData);\n}\n\n/**\n * Converts form data to a FeedConfiguration object.\n * @param {HTMLFormElement} formElement - The form element.\n * @param {boolean} [forExistingCategoryTab=false] - True if processing for the \"Create Server in Existing Category\" tab.\n * @param {object|null} [baseCategoryData=null] - The base FeedConfiguration of the selected category.\n * @returns {object} The FeedConfiguration object. If forExistingCategoryTab is true, this will be a partial\n * FeedConfiguration containing only newly added servers and their requirements.\n */\nfunction validateServerConfig(serverConfig) {\n const errors = [];\n\n // Validate required fields\n if (!serverConfig.name) {\n errors.push('Server name is required');\n } else if (!/^[a-zA-Z0-9-_]+$/.test(serverConfig.name)) {\n errors.push('Server name must only contain alphanumeric characters, hyphens, and underscores');\n } else if (serverConfig.name.length > 50) {\n errors.push('Server name must not exceed 50 characters');\n }\n\n if (!serverConfig.description || serverConfig.description.trim() === '') {\n errors.push('Server description is required');\n } else if (serverConfig.description.length > 200) {\n errors.push('Server description must not exceed 200 characters');\n }\n\n if (!serverConfig.mode) {\n errors.push('Server mode is required');\n } else if (!['stdio', 'sse', 'streamable-http'].includes(serverConfig.mode)) {\n errors.push('Server mode must be either \"stdio\", \"sse\", or \"streamable-http\"');\n }\n\n // Validate installation config based on mode\n if (serverConfig.mode === 'stdio') {\n if (!serverConfig.installation?.command) {\n errors.push('Command is required for stdio server');\n } else if (!/^[a-zA-Z0-9-_.\\\\/]+$/.test(serverConfig.installation.command)) {\n errors.push('Command must only contain alphanumeric characters, hyphens, underscores, dots, and slashes');\n }\n\n // Validate arguments format if present\n if (serverConfig.installation?.args?.length > 0) {\n serverConfig.installation.args.forEach((arg, index) => {\n if (!/^[a-zA-Z0-9-_./\\\\]+$/.test(arg)) {\n errors.push(`Argument ${index + 1} must only contain alphanumeric characters, hyphens, underscores, dots, and slashes`);\n }\n });\n }\n } else if (serverConfig.mode === 'sse' || serverConfig.mode === 'streamable-http') {\n if (!serverConfig.installation?.url) {\n errors.push('URL is required for sse server');\n } else {\n try {\n new URL(serverConfig.installation.url);\n } catch (e) {\n errors.push('Invalid URL format');\n }\n }\n }\n\n // Validate env variables if present\n if (serverConfig.installation?.env) {\n Object.entries(serverConfig.installation.env).forEach(([name, config]) => {\n if (!name) {\n errors.push('Environment variable name is required');\n } else if (!/^[A-Z_][A-Z0-9_]*$/.test(name)) {\n errors.push(`Environment variable name \"${name}\" must be uppercase with only letters, numbers, and underscores`);\n } else if (name.length > 50) {\n errors.push(`Environment variable name \"${name}\" must not exceed 50 characters`);\n }\n\n if (config.Required && !config.Default) {\n errors.push(`Required environment variable \"${name}\" should have a default value`);\n }\n\n if (config.Description && config.Description.length > 200) {\n errors.push(`Description for environment variable \"${name}\" must not exceed 200 characters`);\n }\n });\n }\n\n // Validate schemas if present\n if (serverConfig.schemas) {\n try {\n JSON.parse(serverConfig.schemas);\n } catch (e) {\n errors.push('Invalid JSON format in schemas');\n }\n }\n\n return errors;\n}\n\nexport function formDataToFeedConfiguration(formElement, forExistingCategoryTab = false, baseCategoryData = null) {\n const currentFormData = new FormData(formElement);\n const feedConfiguration = {\n requirements: [],\n mcpServers: []\n };\n\n let serversListId;\n if (formElement.id === 'onboardForm') {\n serversListId = 'serversList';\n } else if (formElement.id === 'onboardServerForm') {\n serversListId = 'existingCategoryServersList';\n } else {\n console.warn('[formDataToFeedConfiguration] Could not determine serversListId from formElement.id:', formElement.id);\n }\n\n if (!forExistingCategoryTab) {\n feedConfiguration.name = currentFormData.get('name') || '';\n feedConfiguration.displayName = currentFormData.get('displayName') || '';\n feedConfiguration.description = currentFormData.get('description') || '';\n feedConfiguration.repository = currentFormData.get('repository') || undefined;\n } else if (baseCategoryData) {\n feedConfiguration.name = baseCategoryData.name;\n }\n\n const serverDataMap = new Map();\n const globalRequirementsMap = new Map();\n\n for (const [key, value] of currentFormData.entries()) {\n if (forExistingCategoryTab && !key.startsWith('servers[')) {\n continue;\n }\n\n const serverMatchKey = key.match(/^servers\\[(\\d+)\\]\\.(.+)$/);\n if (serverMatchKey) {\n let serverIndexInForm = parseInt(serverMatchKey[1], 10);\n const fieldPathFromMatch = serverMatchKey[2];\n let actualServerDataIndex = serverIndexInForm;\n\n if (!serverDataMap.has(actualServerDataIndex)) {\n serverDataMap.set(actualServerDataIndex, {\n installation: { env: new Map() },\n dependencies: { requirements: new Map() },\n isNew: true // Assuming all servers processed this way are new additions to the form\n });\n }\n const currentServerData = serverDataMap.get(actualServerDataIndex);\n\n if (fieldPathFromMatch === 'name') currentServerData.name = value;\n else if (fieldPathFromMatch === 'description') currentServerData.description = value;\n else if (fieldPathFromMatch === 'mode') currentServerData.mode = value;\n else if (fieldPathFromMatch === 'repository') currentServerData.repository = value || undefined;\n else if (fieldPathFromMatch === 'schemas') currentServerData.schemas = value || undefined;\n else if (fieldPathFromMatch === 'installation.command') currentServerData.installation.command = value;\n else if (fieldPathFromMatch === 'installation.args') {\n currentServerData.installation.args = value ? value.split(',').map(arg => arg.trim()).filter(arg => arg) : [];\n }\n else if (fieldPathFromMatch === 'installation.url') {\n currentServerData.installation.url = value;\n }\n else if (fieldPathFromMatch === 'installation.isLocal') {\n // The value will be 'on' if checked, otherwise this field won't appear in FormData\n currentServerData.installation.isLocal = (value === 'on');\n }\n else if (fieldPathFromMatch === 'installation.startingCommand') {\n // This will only be present in FormData if the input was enabled (i.e., isLocal was checked)\n // and had a value.\n currentServerData.installation.startingCommand = value.trim() || undefined;\n }\n else if (fieldPathFromMatch.startsWith('installation.env[')) {\n const envMatch = fieldPathFromMatch.match(/^installation\\.env\\[(\\d+)\\]\\.(name|default|required|description)$/);\n if (envMatch) {\n const envIndex = parseInt(envMatch[1], 10);\n const envField = envMatch[2];\n if (!currentServerData.installation.env.has(envIndex)) {\n currentServerData.installation.env.set(envIndex, {});\n }\n const currentEnv = currentServerData.installation.env.get(envIndex);\n if (envField === 'required') {\n currentEnv[envField] = currentFormData.get(key) === 'on';\n } else {\n currentEnv[envField] = value || undefined;\n }\n }\n }\n else if (fieldPathFromMatch.startsWith('requirements[')) {\n const reqMatch = fieldPathFromMatch.match(/^requirements\\[(\\d+)\\]\\.(.+)$/);\n if (reqMatch) {\n const reqIndex = parseInt(reqMatch[1], 10);\n const reqFieldPath = reqMatch[2];\n\n if (!currentServerData.dependencies.requirements.has(reqIndex)) {\n currentServerData.dependencies.requirements.set(reqIndex, { registry: {} });\n }\n const currentReq = currentServerData.dependencies.requirements.get(reqIndex);\n\n if (reqFieldPath === 'name') currentReq.name = value;\n else if (reqFieldPath === 'type') currentReq.type = value;\n else if (reqFieldPath === 'version') currentReq.version = value;\n else if (reqFieldPath === 'order') currentReq.order = value ? parseInt(value, 10) : undefined;\n else if (reqFieldPath === 'alias') currentReq.alias = value || undefined;\n else if (reqFieldPath === 'registryType') {\n currentReq.registryType = value;\n } else if (reqFieldPath.startsWith('registry.githubRelease.')) {\n currentReq.registry.githubRelease = currentReq.registry.githubRelease || {};\n currentReq.registry.githubRelease[reqFieldPath.substring('registry.githubRelease.'.length)] = value || undefined;\n } else if (reqFieldPath.startsWith('registry.artifacts.')) {\n currentReq.registry.artifacts = currentReq.registry.artifacts || {};\n currentReq.registry.artifacts[reqFieldPath.substring('registry.artifacts.'.length)] = value || undefined;\n } else if (reqFieldPath.startsWith('registry.local.')) {\n currentReq.registry.local = currentReq.registry.local || {};\n currentReq.registry.local[reqFieldPath.substring('registry.local.'.length)] = value || undefined;\n }\n }\n }\n }\n }\n\n // console.log('[formDataToFeedConfiguration] serverDataMap keys before processing:', Array.from(serverDataMap.keys())); // DEBUG\n // console.log('[formDataToFeedConfiguration] serverDataMap size:', serverDataMap.size); // DEBUG\n\n // Process servers found in the form data (new/adhoc or edited original servers)\n serverDataMap.forEach((serverRaw, serverIndexInForm) => { // Renamed serverIndex to serverIndexInForm for clarity\n let mcpServer;\n // ... (existing logic to build mcpServer from serverRaw)\n if (serverRaw.mode === 'sse' || serverRaw.mode === 'streamable-http') {\n mcpServer = {\n name: serverRaw.name,\n description: serverRaw.description,\n mode: serverRaw.mode,\n schemas: serverRaw.schemas,\n repository: serverRaw.repository,\n installation: { // Initialize with fields always present for SSE\n url: serverRaw.installation.url || ''\n },\n dependencies: {\n requirements: []\n }\n };\n\n if (serverRaw.installation.isLocal && serverRaw.installation.startingCommand) {\n mcpServer.installation.startingCommand = serverRaw.installation.startingCommand;\n }\n\n } else { // stdio or other modes\n mcpServer = {\n name: serverRaw.name,\n description: serverRaw.description,\n mode: serverRaw.mode,\n schemas: serverRaw.schemas,\n repository: serverRaw.repository,\n installation: {\n command: serverRaw.installation.command,\n args: serverRaw.installation.args || [],\n env: {} // Initialize env\n },\n dependencies: {\n requirements: []\n }\n };\n\n const envVars = {};\n serverRaw.installation.env.forEach(env => {\n if (env.name) {\n envVars[env.name] = {\n Required: env.required || false,\n Description: env.description || '',\n Default: env.default || undefined\n };\n }\n });\n if (Object.keys(envVars).length > 0) {\n mcpServer.installation.env = envVars;\n } else {\n delete mcpServer.installation.env; // Clean up if no env vars\n }\n }\n\n serverRaw.dependencies.requirements.forEach(reqRaw => {\n if (!reqRaw.name || !reqRaw.type || !reqRaw.version) return;\n\n const fullRequirementConfig = {\n name: reqRaw.name,\n type: reqRaw.type,\n version: reqRaw.version,\n alias: reqRaw.alias,\n order: reqRaw.order,\n };\n\n if (reqRaw.registryType && reqRaw.registryType !== 'public') {\n fullRequirementConfig.registry = {};\n if (reqRaw.registryType === 'github' && reqRaw.registry.githubRelease) {\n fullRequirementConfig.registry.githubRelease = {\n repository: reqRaw.registry.githubRelease.repository,\n assetsName: reqRaw.registry.githubRelease.assetsName,\n assetName: reqRaw.registry.githubRelease.assetName,\n };\n } else if (reqRaw.registryType === 'artifacts' && reqRaw.registry.artifacts) {\n fullRequirementConfig.registry.artifacts = {\n registryUrl: reqRaw.registry.artifacts.registryUrl,\n registryName: reqRaw.registry.artifacts.registryName,\n };\n } else if (reqRaw.registryType === 'local' && reqRaw.registry.local) {\n fullRequirementConfig.registry.local = {\n localPath: reqRaw.registry.local.localPath,\n assetName: reqRaw.registry.local.assetName,\n };\n }\n // Clean up empty registry objects\n if (fullRequirementConfig.registry.githubRelease && !fullRequirementConfig.registry.githubRelease.repository) delete fullRequirementConfig.registry.githubRelease;\n if (fullRequirementConfig.registry.artifacts && !fullRequirementConfig.registry.artifacts.registryUrl) delete fullRequirementConfig.registry.artifacts;\n if (fullRequirementConfig.registry.local && !fullRequirementConfig.registry.local.localPath) delete fullRequirementConfig.registry.local;\n if (Object.keys(fullRequirementConfig.registry).length === 0) delete fullRequirementConfig.registry;\n }\n\n mcpServer.dependencies.requirements.push({\n name: reqRaw.name,\n version: reqRaw.version,\n order: reqRaw.order\n });\n\n const reqKey = `${reqRaw.type}|${reqRaw.name}|${reqRaw.version}`;\n if (!globalRequirementsMap.has(reqKey)) {\n const { order, ...reqConfigForGlobal } = fullRequirementConfig; // Exclude order for global list\n globalRequirementsMap.set(reqKey, reqConfigForGlobal);\n }\n });\n if (mcpServer.dependencies.requirements.length === 0) {\n delete mcpServer.dependencies; // Clean up if no requirements\n }\n\n // Attempt to retrieve and add systemTags from the DOM element,\n // ONLY if we are in the 'Create Server in Existing Category' tab context.\n // For 'Create New Category' tab, systemTags should not be assigned from DOM.\n if (formElement.id === 'onboardServerForm' && serversListId) {\n const selector = `#${serversListId} .server-item[data-index=\"${serverIndexInForm}\"]`;\n const serverItemElement = document.querySelector(selector);\n if (serverItemElement && serverItemElement.dataset.systemTags) {\n try {\n mcpServer.systemTags = JSON.parse(serverItemElement.dataset.systemTags);\n } catch (e) {\n console.error(`[formDataToFeedConfiguration] Error parsing systemTags for server index ${serverIndexInForm} ('${mcpServer.name}') on ${formElement.id}:`, e, serverItemElement.dataset.systemTags);\n mcpServer.systemTags = { parseError: true };\n }\n }\n // If no dataset.systemTags or not onboardServerForm, mcpServer.systemTags remains undefined.\n } else {\n // Ensure systemTags is not carried over if not in the correct context or not present in dataset\n delete mcpServer.systemTags;\n }\n\n feedConfiguration.mcpServers.push(mcpServer);\n });\n\n\n // If processing for an existing category, ensure original non-adhoc servers are included\n // if they weren't picked up by the form (e.g., because they were read-only and disabled).\n if (forExistingCategoryTab && baseCategoryData && Array.isArray(baseCategoryData.mcpServers)) {\n // First, ensure ALL original requirements are preserved in the global requirements map\n if (baseCategoryData.requirements && Array.isArray(baseCategoryData.requirements)) {\n baseCategoryData.requirements.forEach(originalReq => {\n const reqKey = `${originalReq.type}|${originalReq.name}|${originalReq.version}`;\n if (!globalRequirementsMap.has(reqKey)) {\n globalRequirementsMap.set(reqKey, JSON.parse(JSON.stringify(originalReq)));\n }\n });\n }\n\n baseCategoryData.mcpServers.forEach(originalServer => {\n // Check if this original server (by name) is already in our processed list.\n // We use name as the primary identifier for existing servers.\n const isAlreadyProcessed = feedConfiguration.mcpServers.some(\n processedServer => processedServer.name === originalServer.name\n );\n\n if (!isAlreadyProcessed && (!originalServer.systemTags || originalServer.systemTags.adhoc !== 'true')) {\n // This original server was not in the form data (likely read-only) and is not adhoc. Add it.\n // Ensure its requirements are also added to the global list if not already present.\n feedConfiguration.mcpServers.push(JSON.parse(JSON.stringify(originalServer))); // Add a clone\n\n // Note: Requirements have already been preserved above, so no need to process them again here\n }\n });\n }\n\n\n feedConfiguration.requirements = Array.from(globalRequirementsMap.values());\n\n // Validate the entire configuration\n const errors = [];\n\n // Validate basic category information\n if (!forExistingCategoryTab) {\n if (!feedConfiguration.name) {\n errors.push('Category name is required');\n } else if (!/^[a-zA-Z0-9-_]+$/.test(feedConfiguration.name)) {\n errors.push('Category name must only contain alphanumeric characters, hyphens, and underscores');\n }\n\n if (!feedConfiguration.displayName) {\n errors.push('Display name is required');\n }\n }\n\n // Validate each server configuration\n feedConfiguration.mcpServers.forEach((server, index) => {\n const serverErrors = validateServerConfig(server);\n if (serverErrors.length > 0) {\n errors.push(`Server ${index + 1} (${server.name || 'unnamed'}): ${serverErrors.join(', ')}`);\n }\n });\n\n // Validate requirements\n feedConfiguration.requirements.forEach((req, index) => {\n if (!req.name || !req.type || !req.version) {\n errors.push(`Requirement ${index + 1}: name, type, and version are required`);\n }\n if (req.registry) {\n const registryType = Object.keys(req.registry)[0];\n if (!['githubRelease', 'artifacts', 'local'].includes(registryType)) {\n errors.push(`Requirement ${index + 1}: Invalid registry type ${registryType}`);\n }\n }\n });\n\n if (errors.length > 0) {\n // Remove previous error messages\n formElement.querySelectorAll('.validation-error-message').forEach(el => el.remove());\n\n // Map field names to input selectors\n const fieldMap = {\n 'Category name is required': 'input[name=\"name\"]',\n 'Category name must only contain alphanumeric characters, hyphens, and underscores': 'input[name=\"name\"]',\n 'Category name must not exceed 50 characters': 'input[name=\"name\"]',\n 'Display name is required': 'input[name=\"displayName\"]',\n 'Display name must not exceed 100 characters': 'input[name=\"displayName\"]',\n 'Description must not exceed 500 characters': 'textarea[name=\"description\"]',\n 'Repository URL must be a valid URL': 'input[name=\"repository\"]'\n };\n\n // Show error messages below relevant fields\n errors.forEach(errorMsg => {\n let selector = null;\n if (errorMsg.includes('Category name')) selector = 'input[name=\"name\"]';\n else if (errorMsg.includes('Display name')) selector = 'input[name=\"displayName\"]';\n // Add more mappings as needed\n\n if (selector) {\n const input = formElement.querySelector(selector);\n if (input) {\n const errorDiv = document.createElement('div');\n errorDiv.className = 'validation-error-message text-red-500 text-xs mt-1';\n errorDiv.textContent = errorMsg;\n input.insertAdjacentElement('afterend', errorDiv);\n }\n }\n });\n }\n\n return feedConfiguration;\n}\n\n/**\n * Populates the form with data from a FeedConfiguration object.\n * @param {object} feedConfig - The FeedConfiguration object.\n * @param {string} [formId='onboardForm'] - The ID of the form to populate.\n * @param {boolean} [renderServersAsReadOnly=false] - If true, renders servers from feedConfig as read-only.\n * This is used for the \"Create Server in Existing Category\" tab.\n * @param {string|null} [targetServersListId=null] - The ID of the servers list container. Defaults based on formId.\n */\nexport function populateForm(feedConfig, formId = 'onboardForm', renderServersAsReadOnly = false, targetServersListId = null) {\n const currentForm = document.getElementById(formId);\n if (!currentForm) {\n console.error(`populateForm: Form with ID \"${formId}\" not found.`);\n return;\n }\n\n const serversListId = targetServersListId || (formId === 'onboardForm' ? 'serversList' : 'existingCategoryServersList');\n\n resetOnboardFormDynamicContent(formId, serversListId); // This also clears the target server list's innerHTML\n\n // Setup real-time validation\n setupRealTimeValidation(formId);\n\n if (!feedConfig) return;\n\n if (formId === 'onboardForm') {\n currentForm.querySelector('[name=\"name\"]').value = feedConfig.name || '';\n currentForm.querySelector('[name=\"displayName\"]').value = feedConfig.displayName || '';\n currentForm.querySelector('[name=\"description\"]').value = feedConfig.description || '';\n if (feedConfig.repository) {\n currentForm.querySelector('[name=\"repository\"]').value = feedConfig.repository;\n }\n const urlParams = new URLSearchParams(window.location.search);\n if (urlParams.get('action') === 'edit' && urlParams.get('category') === feedConfig.name) {\n const nameInput = currentForm.querySelector('[name=\"name\"]');\n if (nameInput) {\n nameInput.readOnly = true;\n nameInput.classList.add('bg-gray-100', 'cursor-not-allowed');\n }\n }\n } else if (formId === 'onboardServerForm' && feedConfig) {\n // Populate basic category information for the \"Create Server in Existing Category\" tab\n // These fields are read-only in this tab, but their values need to be set from feedConfig.\n currentForm.querySelector('input[name=\"name\"]').value = feedConfig.name || '';\n currentForm.querySelector('input[name=\"displayName\"]').value = feedConfig.displayName || '';\n currentForm.querySelector('textarea[name=\"description\"]').value = feedConfig.description || '';\n currentForm.querySelector('input[name=\"repository\"]').value = feedConfig.repository || '';\n\n // Ensure the containers for basic info and MCP servers are visible,\n // as resetOnboardFormDynamicContent might have hidden them.\n const basicInfoContainer = document.getElementById('existingCategoryBasicInfoContainer');\n if (basicInfoContainer) {\n basicInfoContainer.classList.remove('hidden');\n }\n const mcpServersContainer = document.getElementById('existingCategoryMcpServersContainer');\n if (mcpServersContainer) {\n // Visibility of mcpServersContainer is also handled by whether servers exist,\n // but ensuring it's not hidden here is a good measure after reset.\n mcpServersContainer.classList.remove('hidden');\n }\n }\n\n // Reset tab-specific server counters before populating a list of servers from data.\n // This ensures that servers rendered by this populateForm call start their numbering fresh for this tab.\n setServerCounter(serversListId, 0);\n clearEnvCountersForTab(serversListId);\n clearServerRequirementCountersForTab(serversListId);\n\n (feedConfig.mcpServers || []).forEach((serverData) => { // Renamed 'server' to 'serverData' for clarity\n // Get the correct current index for this tab before adding the server\n const currentServerIndex = getServerCounter(serversListId);\n // window.addServer will increment the counter for serversListId internally\n // It also returns the server item, but we'll query it again for safety after DOM manipulation.\n window.addServer(serversListId, renderServersAsReadOnly, serverData);\n\n // After addServer, the server item should exist in the DOM.\n const serverItem = currentForm.querySelector(`#${serversListId} .server-item[data-index=\"${currentServerIndex}\"]`);\n\n if (serverItem) {\n if (formId === 'onboardServerForm') {\n if (serverData.systemTags?.adhoc === \"true\") {\n // Case 1: JSON data explicitly marks it as adhoc. Respect this.\n serverItem.dataset.systemTags = JSON.stringify(serverData.systemTags);\n // console.log(`[populateForm] Server ${serverData.name || currentServerIndex} in ${formId} retains adhoc status from JSON.`);\n } else {\n // Case 2: JSON data does NOT explicitly mark it adhoc.\n // Check if it was an original server from the category.\n // state.originalServerNamesForFormPopulation is set when toggling from JSON to Form view for an existing category.\n if (state.originalServerNamesForFormPopulation && serverData.name && state.originalServerNamesForFormPopulation.has(serverData.name)) {\n // It's an original server from the category, now treated as adhoc because it passed through JSON view.\n serverItem.dataset.systemTags = JSON.stringify({ adhoc: \"true\" });\n // console.log(`[populateForm] Original server ${serverData.name} in ${formId} marked as adhoc after JSON view.`);\n } else {\n // It's a new server (not in original list) and JSON didn't mark it adhoc.\n // Or, it's an original server but its JSON representation explicitly removed/lacked adhoc tag.\n // Ensure it's NOT adhoc.\n // If serverData.systemTags exists but doesn't have adhoc:true, preserve those other tags.\n if (serverData.systemTags && Object.keys(serverData.systemTags).length > 0) {\n const newTags = { ...serverData.systemTags };\n delete newTags.adhoc; // Ensure adhoc is not true\n if (Object.keys(newTags).length > 0) {\n serverItem.dataset.systemTags = JSON.stringify(newTags);\n } else {\n delete serverItem.dataset.systemTags;\n }\n } else {\n delete serverItem.dataset.systemTags;\n }\n // console.log(`[populateForm] Server ${serverData.name || currentServerIndex} in ${formId} is NOT marked adhoc.`);\n }\n }\n } else {\n // For 'onboardForm' (Create Category tab), or if serverData had systemTags not making it adhoc.\n // If serverData has systemTags, reflect them. Otherwise, ensure no systemTags.\n if (serverData.systemTags) {\n serverItem.dataset.systemTags = JSON.stringify(serverData.systemTags);\n } else {\n delete serverItem.dataset.systemTags;\n }\n }\n }\n // Continue with populating fields using serverData\n const serverNameInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].name\"]`);\n if (serverNameInput) serverNameInput.value = serverData.name || '';\n\n const modeInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].mode\"]`);\n if (modeInput) {\n modeInput.value = serverData.mode || 'stdio';\n if (typeof window.renderInstallationConfig === 'function') {\n window.renderInstallationConfig(currentServerIndex, serversListId, serverData.mode || 'stdio', renderServersAsReadOnly, serverData.installation);\n }\n }\n const descInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].description\"]`);\n if (descInput) descInput.value = serverData.description || '';\n\n if (serverData.schemas) {\n const schemaPathEl = document.getElementById(`schema-path-${currentServerIndex}`);\n if (schemaPathEl) schemaPathEl.value = serverData.schemas;\n }\n if (serverData.repository) {\n const repoInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].repository\"]`);\n if (repoInput) repoInput.value = serverData.repository;\n }\n\n if (serverData.installation) {\n if (serverData.mode === 'sse' || serverData.mode === 'streamable-http') {\n const urlInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].installation.url\"]`);\n if (urlInput) urlInput.value = serverData.installation.url || '';\n } else {\n const cmdInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].installation.command\"]`);\n if (cmdInput) cmdInput.value = serverData.installation.command || '';\n if (serverData.installation.args && Array.isArray(serverData.installation.args)) {\n const argsInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].installation.args\"]`);\n if (argsInput) argsInput.value = serverData.installation.args.join(', ');\n }\n if (serverData.installation.env) {\n Object.entries(serverData.installation.env).forEach(([envName, envConfig]) => {\n const currentEnvIndex = window.addEnvVariable(currentServerIndex, serversListId, renderServersAsReadOnly);\n\n const nameInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].installation.env[${currentEnvIndex}].name\"]`);\n if (nameInput) nameInput.value = envName;\n if (envConfig.Default) {\n const defInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].installation.env[${currentEnvIndex}].default\"]`);\n if (defInput) defInput.value = envConfig.Default;\n }\n if (envConfig.Required) {\n const reqInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].installation.env[${currentEnvIndex}].required\"]`);\n if (reqInput) reqInput.checked = true;\n }\n if (envConfig.Description) {\n const descInput = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].installation.env[${currentEnvIndex}].description\"]`);\n if (descInput) descInput.value = envConfig.Description;\n }\n });\n }\n }\n }\n\n if (serverData.dependencies && serverData.dependencies.requirements) {\n // Determine if this server's requirements should be effectively read-only\n const serverIsEffectivelyReadOnlyForReqs = renderServersAsReadOnly && !(serverData.systemTags?.adhoc === 'true');\n // console.log(`[populateForm] Server: ${serverData.name}, Adhoc: ${serverData.systemTags?.adhoc === 'true'}, renderServersAsReadOnly: ${renderServersAsReadOnly}, Calculated serverIsEffectivelyReadOnlyForReqs: ${serverIsEffectivelyReadOnlyForReqs}`); // DEBUG\n\n serverData.dependencies.requirements.forEach((depReq) => {\n // Find requirement by name only, as requested.\n const fullReq = (feedConfig.requirements || []).find(r => r.name === depReq.name);\n if (!fullReq) {\n console.warn(`Could not find full requirement config for dependency name: ${depReq.name} (version ${depReq.version} specified by server, but lookup is by name only). Skipping.`);\n return;\n }\n\n // Pass serverIsEffectivelyReadOnlyForReqs to addServerRequirement\n const currentReqIndex = window.addServerRequirement(currentServerIndex, serversListId, serverIsEffectivelyReadOnlyForReqs);\n\n currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].name\"]`).value = fullReq.name || '';\n currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].type\"]`).value = fullReq.type || '';\n currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].version\"]`).value = fullReq.version || '';\n\n if (depReq.order !== undefined) {\n currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].order\"]`).value = depReq.order;\n }\n\n if (fullReq.type === 'command' && fullReq.alias) {\n currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].alias\"]`).value = fullReq.alias;\n window.toggleServerAliasField(currentServerIndex, currentReqIndex, serversListId);\n }\n\n let registryType = 'public';\n if (fullReq.registry) {\n if (fullReq.registry.githubRelease) registryType = 'github';\n else if (fullReq.registry.artifacts) registryType = 'artifacts';\n else if (fullReq.registry.local) registryType = 'local';\n }\n\n const registrySelect = currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].registryType\"]`);\n if (registrySelect) {\n registrySelect.value = registryType;\n // Pass serversListId to ensure context is correct for toggling UI elements\n window.toggleServerRegistryConfig(currentServerIndex, currentReqIndex, serversListId);\n }\n\n if (registryType === 'github' && fullReq.registry.githubRelease) {\n const gh = fullReq.registry.githubRelease;\n if (gh.repository) currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].registry.githubRelease.repository\"]`).value = gh.repository;\n if (gh.assetsName) currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].registry.githubRelease.assetsName\"]`).value = gh.assetsName;\n if (gh.assetName) currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].registry.githubRelease.assetName\"]`).value = gh.assetName;\n } else if (registryType === 'artifacts' && fullReq.registry.artifacts) {\n const art = fullReq.registry.artifacts;\n if (art.registryUrl) currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].registry.artifacts.registryUrl\"]`).value = art.registryUrl;\n if (art.registryName) currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].registry.artifacts.registryName\"]`).value = art.registryName;\n } else if (registryType === 'local' && fullReq.registry.local) {\n const loc = fullReq.registry.local;\n if (loc.localPath) currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].registry.local.localPath\"]`).value = loc.localPath;\n if (loc.assetName) currentForm.querySelector(`[name=\"servers[${currentServerIndex}].requirements[${currentReqIndex}].registry.local.assetName\"]`).value = loc.assetName;\n }\n });\n }\n });\n}\n\n/**\n * Resets the dynamic parts of the onboarding form, specifically the servers list.\n * Also resets server-related counters in the state.\n * This function is called before populating the form with new data (e.g., when loading an existing category\n * or switching from JSON view to form view).\n * @param {string} formId - The ID of the form whose dynamic content is to be reset.\n * @param {string} serversListId - The ID of the server list container to clear.\n */\nexport function resetOnboardFormDynamicContent(formId = 'onboardForm', serversListId = 'serversList') {\n const formToReset = document.getElementById(formId);\n if (formToReset) {\n // formToReset.reset(); // This resets the entire form, including the category dropdown.\n // We want to avoid resetting the dropdown when a category is selected.\n // Other parts of this function handle clearing specific dynamic content.\n if (formId !== 'onboardServerForm') { // Only reset other forms, not the one with the category select that triggers loading\n formToReset.reset();\n }\n }\n\n const serversListContainer = document.getElementById(serversListId);\n if (serversListContainer) {\n serversListContainer.innerHTML = '';\n }\n\n setServerCounter(0);\n if (state && state.envCounters && typeof state.envCounters.clear === 'function') {\n state.envCounters.clear();\n }\n if (state && state.serverRequirementCounters && typeof state.serverRequirementCounters.clear === 'function') {\n state.serverRequirementCounters.clear();\n }\n\n // Determine the correct validation panel and content IDs based on formId\n let validationPanelIdToReset;\n let validationContentIdToReset;\n\n if (formId === 'onboardForm') {\n validationPanelIdToReset = 'validationStatusPanelNewCategory';\n validationContentIdToReset = 'validationStatusContentNewCategory';\n } else if (formId === 'onboardServerForm') {\n validationPanelIdToReset = 'validationStatusPanelExistingCategory';\n validationContentIdToReset = 'validationStatusContentExistingCategoryTab';\n }\n // else if other forms have validation panels, add conditions here\n\n if (validationPanelIdToReset) {\n const validationPanel = document.getElementById(validationPanelIdToReset);\n if (validationPanel) {\n validationPanel.classList.add('hidden');\n }\n }\n if (validationContentIdToReset) {\n const validationContent = document.getElementById(validationContentIdToReset);\n if (validationContent) {\n validationContent.innerHTML = '';\n }\n }\n\n if (formId === 'onboardServerForm') {\n // const existingCategorySelect = document.getElementById('existingCategorySelect');\n // if (existingCategorySelect) existingCategorySelect.value = ''; // This was incorrectly resetting the dropdown\n\n const basicInfoContainer = document.getElementById('existingCategoryBasicInfoContainer');\n if (basicInfoContainer) basicInfoContainer.classList.add('hidden');\n\n const mcpServersContainer = document.getElementById('existingCategoryMcpServersContainer');\n if (mcpServersContainer) mcpServersContainer.classList.add('hidden');\n }\n\n // Setup real-time validation after reset\n setupRealTimeValidation(formId);\n}\n\n/**\n * Shows validation message under an input field\n * @param {HTMLElement} element - The element to show validation message for\n * @param {string} message - The validation message to display\n * @param {boolean} isError - Whether this is an error message\n */\nexport function showValidationMessage(element, message, isError = true) {\n let messageDiv = element.nextElementSibling;\n if (!messageDiv || !messageDiv.classList.contains('validation-message')) {\n messageDiv = document.createElement('div');\n messageDiv.className = `validation-message text-xs mt-1 ${isError ? 'text-red-500' : 'text-green-500'}`;\n element.insertAdjacentElement('afterend', messageDiv);\n }\n messageDiv.textContent = message;\n messageDiv.className = `validation-message text-xs mt-1 ${isError ? 'text-red-500' : 'text-green-500'}`;\n}\n\n// Export setupRealTimeValidation for external use if needed\nexport { setupRealTimeValidation };"],"mappings":"OACSA,cAAiB,6BACjBC,MAAOC,iBAAkBC,iBAAkBC,uBAAwBC,yCAA4C,aAMxH,SAASC,wBAAwBC,GAC/B,MAAMC,EAAOC,SAASC,eAAeH,GACrC,IAAKC,EAAM,OAEX,IAAKA,EAAM,OAGX,MAAMG,EAAYH,EAAKI,cAAc,sBACjCD,GACFA,EAAUE,iBAAiB,SAAUC,IACnC,MAAMC,EAAQD,EAAEE,OAAOD,MAAME,OACxBF,EAEO,mBAAmBG,KAAKH,GAEzBA,EAAMI,OAAS,GACxBC,sBAAsBN,EAAEE,OAAQ,iCAEhCI,sBAAsBN,EAAEE,OAAQ,cAAc,GAJ9CI,sBAAsBN,EAAEE,OAAQ,kEAFhCI,sBAAsBN,EAAEE,OAAQ,mBAOlC,IAKJ,MAAMK,EAAmBb,EAAKI,cAAc,6BACxCS,GACFA,EAAiBR,iBAAiB,SAAUC,IAC1C,MAAMC,EAAQD,EAAEE,OAAOD,MAAME,OACxBF,EAEMA,EAAMI,OAAS,IACxBC,sBAAsBN,EAAEE,OAAQ,kCAEhCI,sBAAsBN,EAAEE,OAAQ,sBAAsB,GAJtDI,sBAAsBN,EAAEE,OAAQ,2BAKlC,IAKJ,MAAMM,EAAmBd,EAAKI,cAAc,gCACxCU,GACFA,EAAiBT,iBAAiB,SAAUC,IAC1C,MAAMC,EAAQD,EAAEE,OAAOD,MAAME,OACzBF,EAAMI,OAAS,IACjBC,sBAAsBN,EAAEE,OAAQ,kCACN,IAAjBD,EAAMI,OACfC,sBAAsBN,EAAEE,OAAQ,2BAEhCI,sBAAsBN,EAAEE,OAAQ,qBAAqB,EACvD,IAKJ,MAAMO,EAAYf,EAAKI,cAAc,4BACjCW,GACFA,EAAUV,iBAAiB,SAAUC,IACnC,MAAMC,EAAQD,EAAEE,OAAOD,MAAME,OAC7B,GAAIF,EACF,IACE,IAAIS,IAAIT,GACRK,sBAAsBN,EAAEE,OAAQ,aAAa,EAC/C,CAAE,MAAOS,GACPL,sBAAsBN,EAAEE,OAAQ,qBAClC,MAEAF,EAAEE,OAAOU,oBAAoBC,QAC/B,IAKJnB,EAAKK,iBAAiB,UAAWC,IAC/B,GAAIA,EAAEE,OAAOY,MAAMC,MAAM,wBAAyB,CAChD,MAAMC,EAAchB,EAAEE,OAAOY,KAAKC,MAAM,oBAAoB,GACtDE,EAAevB,EAAKI,cAAc,kBAAkBkB,6BACpDE,EAAWxB,EAAKI,cAAc,kBAAkBkB,yBAChDG,EAAYzB,EAAKI,cAAc,kBAAkBkB,0BAEhC,UAAnBhB,EAAEE,OAAOD,OACPgB,IACFA,EAAaG,UAAW,EACxBd,sBAAsBW,EAAc,uCAElCC,IACFA,EAASE,UAAW,EACpBF,EAASjB,MAAQ,GACjBiB,EAASN,oBAAoBC,WAEH,QAAnBb,EAAEE,OAAOD,OAAsC,oBAAnBD,EAAEE,OAAOD,QAC1CiB,IACFA,EAASE,UAAW,EACpBd,sBAAsBY,EAAU,uBAAuBlB,EAAEE,OAAOD,eAE9DgB,IACFA,EAAaG,UAAW,EACxBH,EAAahB,MAAQ,GACrBgB,EAAaL,oBAAoBC,UAE/BM,IACFA,EAAUlB,MAAQ,GAClBkB,EAAUP,oBAAoBC,UAGpC,KAIFnB,EAAKK,iBAAiB,SAAUC,IAC9B,GAAIA,EAAEE,OAAOY,MAAMO,SAAS,sBAAuB,CACjD,MAAMC,EAAUtB,EAAEE,OAAOY,KAAKC,MAAM,gEACpC,GAAIO,EAAS,CACX,MAAO,CAAEN,EAAaO,EAAUC,GAASF,EACzC,GAAc,SAAVE,EAAkB,CACpB,MAAMvB,EAAQD,EAAEE,OAAOD,MAAME,OACxBF,EAEO,qBAAqBG,KAAKH,GAE3BA,EAAMI,OAAS,GACxBC,sBAAsBN,EAAEE,OAAQ,iCAEhCI,sBAAsBN,EAAEE,OAAQ,cAAc,GAJ9CI,sBAAsBN,EAAEE,OAAQ,iEAFhCI,sBAAsBN,EAAEE,OAAQ,wCAQpC,CACF,CACF,IAEJ,QAQOuB,eAAeC,WAAWC,EAAOC,EAAWC,EAA8B,MAC/EF,EAAMG,iBACN,MAAMC,EAAcJ,EAAMzB,OAC1B,IAAI8B,EACAC,GAAoB,EAExB,GAAkB,oBAAdL,EACF,IACEI,EAAoBE,4BAA4BH,GAChD,MAAMI,EAAY,IAAIC,gBAAgBC,OAAOC,SAASC,QACtDN,EAAgD,SAA5BE,EAAUK,IAAI,WAAwBL,EAAUK,IAAI,cAAgBR,EAAkBlB,IAC5G,CAAE,MAAO2B,GAEP,YADAC,QAAQC,MAAM,oBAAqBF,EAErC,KACK,IAAkB,kBAAdb,EAkCT,YADA1C,UAAU,sCAAuC,SAjCT,CACxC,IAAK2C,IAAgCA,EAA4Bf,KAE/D,YADA5B,UAAU,6DAA8D,SAQ1E,MAAM0D,EAAkBV,4BAA4BH,GAAa,EAAMF,GAGvEG,EAAoBa,KAAKC,MAAMD,KAAKE,UAAUlB,IAI9CG,EAAkBgB,WAAaJ,EAAgBI,YAAc,GAM7D,MAAMC,EAAkB,IAAIC,KAAKlB,EAAkBmB,cAAgB,IAAIC,KAAIC,GAAK,GAAGA,EAAEC,QAAQD,EAAEvC,QAAQuC,EAAEE,cACxGX,EAAgBO,cAAgB,IAAIK,SAAQC,IAC3C,MAAMC,EAAS,GAAGD,EAAOH,QAAQG,EAAO3C,QAAQ2C,EAAOF,UAClDN,EAAgBU,IAAID,KACvB1B,EAAkBmB,aAAaS,KAAKH,GACpCR,EAAgBY,IAAIH,GACtB,IAEFzB,GAAoB,CACtB,CAGA,CAEA,IACI,MAAM6B,QAAiBC,MAAM,0BAA2B,CACxDC,OAAQ,OACRC,QAAS,CAAE,eAAgB,oBAC3BC,KAAMrB,KAAKE,UAAU,CACnBoB,aAAcnC,EACdoC,SAAUnC,MAId,IAAK6B,EAASO,GAAI,CAChB,MAAMC,QAAkBR,EAASS,OAAOC,OAAM,KAAM,CAAG7B,MAAO,qCAC9D,MAAM,IAAI8B,MAAM,uBAAuBX,EAASY,oBAAoBJ,EAAU3B,OAASmB,EAASa,aAClG,OAEqBb,EAASS,OAE9BrF,UAAU,kEAAmE,UAC/E,CAAE,MAAOyD,GACPD,QAAQC,MAAM,yBAA0BA,GACxCzD,UAAU,0BAA0ByD,EAAMiC,6BAA8B,QAC1E,CACF,QASO,SAASC,YAAY9C,EAAa+C,GAAyB,EAAOC,EAAmB,MAC1F,OAAO7C,4BAA4BH,EAAa+C,EAAwBC,EAC1E,CAUA,SAASC,qBAAqBC,GAC5B,MAAMC,EAAS,GAwBf,GArBKD,EAAanE,KAEN,mBAAmBV,KAAK6E,EAAanE,MAEtCmE,EAAanE,KAAKT,OAAS,IACpC6E,EAAOtB,KAAK,6CAFZsB,EAAOtB,KAAK,mFAFZsB,EAAOtB,KAAK,2BAOTqB,EAAaE,aAAmD,KAApCF,EAAaE,YAAYhF,OAE/C8E,EAAaE,YAAY9E,OAAS,KAC3C6E,EAAOtB,KAAK,qDAFZsB,EAAOtB,KAAK,kCAKTqB,EAAaG,KAEN,CAAC,QAAS,MAAO,mBAAmB/D,SAAS4D,EAAaG,OACpEF,EAAOtB,KAAK,mEAFZsB,EAAOtB,KAAK,2BAMY,UAAtBqB,EAAaG,KACVH,EAAaI,cAAcC,QAEpB,uBAAuBlF,KAAK6E,EAAaI,aAAaC,UAChEJ,EAAOtB,KAAK,8FAFZsB,EAAOtB,KAAK,wCAMVqB,EAAaI,cAAcE,MAAMlF,OAAS,GAC5C4E,EAAaI,aAAaE,KAAK/B,SAAQ,CAACgC,EAAKC,KACtC,uBAAuBrF,KAAKoF,IAC/BN,EAAOtB,KAAK,YAAY6B,EAAQ,uFAClC,SAGC,GAA0B,QAAtBR,EAAaG,MAAwC,oBAAtBH,EAAaG,KACrD,GAAKH,EAAaI,cAAcK,IAG9B,IACE,IAAIhF,IAAIuE,EAAaI,aAAaK,IACpC,CAAE,MAAO1F,GACPkF,EAAOtB,KAAK,qBACd,MANAsB,EAAOtB,KAAK,kCAgChB,GArBIqB,EAAaI,cAAcM,KAC7BC,OAAOC,QAAQZ,EAAaI,aAAaM,KAAKnC,SAAQ,EAAE1C,EAAMgF,MACvDhF,EAEO,qBAAqBV,KAAKU,GAE3BA,EAAKT,OAAS,IACvB6E,EAAOtB,KAAK,8BAA8B9C,oCAF1CoE,EAAOtB,KAAK,8BAA8B9C,oEAF1CoE,EAAOtB,KAAK,yCAOVkC,EAAOC,WAAaD,EAAOE,SAC7Bd,EAAOtB,KAAK,kCAAkC9C,kCAG5CgF,EAAOG,aAAeH,EAAOG,YAAY5F,OAAS,KACpD6E,EAAOtB,KAAK,yCAAyC9C,oCACvD,IAKAmE,EAAaiB,QACf,IACErD,KAAKC,MAAMmC,EAAaiB,QAC1B,CAAE,MAAOlG,GACPkF,EAAOtB,KAAK,iCACd,CAGF,OAAOsB,CACT,QAEO,SAAShD,4BAA4BH,EAAa+C,GAAyB,EAAOC,EAAmB,MAC1G,MAAMoB,EAAkB,IAAIC,SAASrE,GAC/BC,EAAoB,CACxBmB,aAAc,GACdH,WAAY,IAGd,IAAIqD,EACmB,gBAAnBtE,EAAYuE,GACdD,EAAgB,cACY,sBAAnBtE,EAAYuE,GACrBD,EAAgB,8BAEhB3D,QAAQ6D,KAAK,uFAAwFxE,EAAYuE,IAG9GxB,EAKMC,IACT/C,EAAkBlB,KAAOiE,EAAiBjE,OAL1CkB,EAAkBlB,KAAOqF,EAAgB3D,IAAI,SAAW,GACxDR,EAAkBwE,YAAcL,EAAgB3D,IAAI,gBAAkB,GACtER,EAAkBmD,YAAcgB,EAAgB3D,IAAI,gBAAkB,GACtER,EAAkByE,WAAaN,EAAgB3D,IAAI,oBAAiBkE,GAKtE,MAAMC,EAAgB,IAAIC,IACpBC,EAAwB,IAAID,IAElC,IAAK,MAAOE,EAAK7G,KAAUkG,EAAgBN,UAAW,CACpD,GAAIf,IAA2BgC,EAAIC,WAAW,YAC5C,SAGF,MAAMC,EAAiBF,EAAI/F,MAAM,4BACjC,GAAIiG,EAAgB,CAClB,IAAIC,EAAoBC,SAASF,EAAe,GAAI,IACpD,MAAMG,EAAqBH,EAAe,GAC1C,IAAII,EAAwBH,EAEvBN,EAAchD,IAAIyD,IACrBT,EAAcU,IAAID,EAAuB,CACvC/B,aAAc,CAAEM,IAAK,IAAIiB,KACzBU,aAAc,CAAEnE,aAAc,IAAIyD,KAClCW,OAAO,IAGX,MAAMC,EAAoBb,EAAcnE,IAAI4E,GAE5C,GAA2B,SAAvBD,EAA+BK,EAAkB1G,KAAOb,OACvD,GAA2B,gBAAvBkH,EAAsCK,EAAkBrC,YAAclF,OAC1E,GAA2B,SAAvBkH,EAA+BK,EAAkBpC,KAAOnF,OAC5D,GAA2B,eAAvBkH,EAAqCK,EAAkBf,WAAaxG,QAASyG,OACjF,GAA2B,YAAvBS,EAAkCK,EAAkBtB,QAAUjG,QAASyG,OAC3E,GAA2B,yBAAvBS,EAA+CK,EAAkBnC,aAAaC,QAAUrF,OAC5F,GAA2B,sBAAvBkH,EACPK,EAAkBnC,aAAaE,KAAOtF,EAAQA,EAAMwH,MAAM,KAAKrE,KAAIoC,GAAOA,EAAIrF,SAAQuH,QAAOlC,GAAOA,IAAO,QAExG,GAA2B,qBAAvB2B,EACPK,EAAkBnC,aAAaK,IAAMzF,OAElC,GAA2B,yBAAvBkH,EAEPK,EAAkBnC,aAAasC,QAAqB,OAAV1H,OAEvC,GAA2B,iCAAvBkH,EAGPK,EAAkBnC,aAAauC,gBAAkB3H,EAAME,aAAUuG,OAE9D,GAAIS,EAAmBJ,WAAW,qBAAsB,CAC3D,MAAMc,EAAWV,EAAmBpG,MAAM,qEAC1C,GAAI8G,EAAU,CACZ,MAAMtG,EAAW2F,SAASW,EAAS,GAAI,IACjCC,EAAWD,EAAS,GACrBL,EAAkBnC,aAAaM,IAAIhC,IAAIpC,IAC1CiG,EAAkBnC,aAAaM,IAAI0B,IAAI9F,EAAU,CAAC,GAEpD,MAAMwG,EAAaP,EAAkBnC,aAAaM,IAAInD,IAAIjB,GAExDwG,EAAWD,GADI,aAAbA,EACkD,OAA7B3B,EAAgB3D,IAAIsE,GAEpB7G,QAASyG,CAEpC,CACF,MACK,GAAIS,EAAmBJ,WAAW,iBAAkB,CACvD,MAAMiB,EAAWb,EAAmBpG,MAAM,iCAC1C,GAAIiH,EAAU,CACZ,MAAMC,EAAWf,SAASc,EAAS,GAAI,IACjCE,EAAeF,EAAS,GAEzBR,EAAkBF,aAAanE,aAAaQ,IAAIsE,IACnDT,EAAkBF,aAAanE,aAAakE,IAAIY,EAAU,CAAEE,SAAU,CAAC,IAEzE,MAAMC,EAAaZ,EAAkBF,aAAanE,aAAaX,IAAIyF,GAE9C,SAAjBC,EAAyBE,EAAWtH,KAAOb,EACrB,SAAjBiI,EAAyBE,EAAW9E,KAAOrD,EAC1B,YAAjBiI,EAA4BE,EAAW7E,QAAUtD,EAChC,UAAjBiI,EAA0BE,EAAWC,MAAQpI,EAAQiH,SAASjH,EAAO,SAAMyG,EAC1D,UAAjBwB,EAA0BE,EAAWE,MAAQrI,QAASyG,EACrC,iBAAjBwB,EACPE,EAAWG,aAAetI,EACjBiI,EAAanB,WAAW,4BACjCqB,EAAWD,SAASK,cAAgBJ,EAAWD,SAASK,eAAiB,CAAC,EAC1EJ,EAAWD,SAASK,cAAcN,EAAaO,UAAU,KAAqCxI,QAASyG,GAC9FwB,EAAanB,WAAW,wBACjCqB,EAAWD,SAASO,UAAYN,EAAWD,SAASO,WAAa,CAAC,EAClEN,EAAWD,SAASO,UAAUR,EAAaO,UAAU,KAAiCxI,QAASyG,GACtFwB,EAAanB,WAAW,qBACjCqB,EAAWD,SAASQ,MAAQP,EAAWD,SAASQ,OAAS,CAAC,EAC1DP,EAAWD,SAASQ,MAAMT,EAAaO,UAAU,KAA6BxI,QAASyG,EAE3F,CACF,CACF,CACF,CAMAC,EAAcnD,SAAQ,CAACoF,EAAW3B,KAChC,IAAI4B,EAEJ,GAAuB,QAAnBD,EAAUxD,MAAqC,oBAAnBwD,EAAUxD,KACxCyD,EAAY,CACV/H,KAAM8H,EAAU9H,KAChBqE,YAAayD,EAAUzD,YACvBC,KAAMwD,EAAUxD,KAChBc,QAAS0C,EAAU1C,QACnBO,WAAYmC,EAAUnC,WACtBpB,aAAc,CACZK,IAAKkD,EAAUvD,aAAaK,KAAO,IAErC4B,aAAc,CACZnE,aAAc,KAIdyF,EAAUvD,aAAasC,SAAWiB,EAAUvD,aAAauC,kBAC3DiB,EAAUxD,aAAauC,gBAAkBgB,EAAUvD,aAAauC,qBAG7D,CACLiB,EAAY,CACV/H,KAAM8H,EAAU9H,KAChBqE,YAAayD,EAAUzD,YACvBC,KAAMwD,EAAUxD,KAChBc,QAAS0C,EAAU1C,QACnBO,WAAYmC,EAAUnC,WACtBpB,aAAc,CACZC,QAASsD,EAAUvD,aAAaC,QAChCC,KAAMqD,EAAUvD,aAAaE,MAAQ,GACrCI,IAAK,CAAC,GAER2B,aAAc,CACZnE,aAAc,KAIlB,MAAM2F,EAAU,CAAC,EACjBF,EAAUvD,aAAaM,IAAInC,SAAQmC,IAC7BA,EAAI7E,OACNgI,EAAQnD,EAAI7E,MAAQ,CAClBiF,SAAUJ,EAAIvE,WAAY,EAC1B6E,YAAaN,EAAIR,aAAe,GAChCa,QAASL,EAAIoD,cAAWrC,GAE5B,IAEEd,OAAOoD,KAAKF,GAASzI,OAAS,EAChCwI,EAAUxD,aAAaM,IAAMmD,SAEtBD,EAAUxD,aAAaM,GAElC,CA0DA,GAxDAiD,EAAUtB,aAAanE,aAAaK,SAAQyF,IAC1C,IAAKA,EAAOnI,OAASmI,EAAO3F,OAAS2F,EAAO1F,QAAS,OAErD,MAAM2F,EAAwB,CAC5BpI,KAAMmI,EAAOnI,KACbwC,KAAM2F,EAAO3F,KACbC,QAAS0F,EAAO1F,QAChB+E,MAAOW,EAAOX,MACdD,MAAOY,EAAOZ,OAGZY,EAAOV,cAAwC,WAAxBU,EAAOV,eAChCW,EAAsBf,SAAW,CAAC,EACN,WAAxBc,EAAOV,cAA6BU,EAAOd,SAASK,cACtDU,EAAsBf,SAASK,cAAgB,CAC7C/B,WAAYwC,EAAOd,SAASK,cAAc/B,WAC1C0C,WAAYF,EAAOd,SAASK,cAAcW,WAC1CC,UAAWH,EAAOd,SAASK,cAAcY,WAEV,cAAxBH,EAAOV,cAAgCU,EAAOd,SAASO,UAChEQ,EAAsBf,SAASO,UAAY,CACzCW,YAAaJ,EAAOd,SAASO,UAAUW,YACvCC,aAAcL,EAAOd,SAASO,UAAUY,cAET,UAAxBL,EAAOV,cAA4BU,EAAOd,SAASQ,QAC5DO,EAAsBf,SAASQ,MAAQ,CACrCY,UAAWN,EAAOd,SAASQ,MAAMY,UACjCH,UAAWH,EAAOd,SAASQ,MAAMS,YAIjCF,EAAsBf,SAASK,gBAAkBU,EAAsBf,SAASK,cAAc/B,mBAAmByC,EAAsBf,SAASK,cAChJU,EAAsBf,SAASO,YAAcQ,EAAsBf,SAASO,UAAUW,oBAAoBH,EAAsBf,SAASO,UACzIQ,EAAsBf,SAASQ,QAAUO,EAAsBf,SAASQ,MAAMY,kBAAkBL,EAAsBf,SAASQ,MACxE,IAAvD/C,OAAOoD,KAAKE,EAAsBf,UAAU9H,eAAqB6I,EAAsBf,UAG7FU,EAAUvB,aAAanE,aAAaS,KAAK,CACvC9C,KAAMmI,EAAOnI,KACbyC,QAAS0F,EAAO1F,QAChB8E,MAAOY,EAAOZ,QAGhB,MAAM3E,EAAS,GAAGuF,EAAO3F,QAAQ2F,EAAOnI,QAAQmI,EAAO1F,UACvD,IAAKsD,EAAsBlD,IAAID,GAAS,CACtC,MAAM2E,MAAEA,KAAUmB,GAAuBN,EACzCrC,EAAsBQ,IAAI3D,EAAQ8F,EACpC,KAEiD,IAA/CX,EAAUvB,aAAanE,aAAa9C,eAC/BwI,EAAUvB,aAMI,sBAAnBvF,EAAYuE,IAA8BD,EAAe,CAC3D,MAAMoD,EAAW,IAAIpD,8BAA0CY,MACzDyC,EAAoB/J,SAASG,cAAc2J,GACjD,GAAIC,GAAqBA,EAAkBC,QAAQC,WACjD,IACEf,EAAUe,WAAa/G,KAAKC,MAAM4G,EAAkBC,QAAQC,WAC9D,CAAE,MAAO5J,GACP0C,QAAQC,MAAM,2EAA2EsE,OAAuB4B,EAAU/H,aAAaiB,EAAYuE,MAAOtG,EAAG0J,EAAkBC,QAAQC,YACvLf,EAAUe,WAAa,CAAEC,YAAY,EACvC,CAGJ,aAEShB,EAAUe,WAGnB5H,EAAkBgB,WAAWY,KAAKiF,EAAU,IAM1C/D,GAA0BC,GAAoB+E,MAAMC,QAAQhF,EAAiB/B,cAE3E+B,EAAiB5B,cAAgB2G,MAAMC,QAAQhF,EAAiB5B,eAClE4B,EAAiB5B,aAAaK,SAAQwG,IACpC,MAAMtG,EAAS,GAAGsG,EAAY1G,QAAQ0G,EAAYlJ,QAAQkJ,EAAYzG,UACjEsD,EAAsBlD,IAAID,IAC7BmD,EAAsBQ,IAAI3D,EAAQb,KAAKC,MAAMD,KAAKE,UAAUiH,IAC9D,IAIJjF,EAAiB/B,WAAWQ,SAAQyG,IAGPjI,EAAkBgB,WAAWkH,MACtDC,GAAmBA,EAAgBrJ,OAASmJ,EAAenJ,QAGhCmJ,EAAeL,YAAkD,SAApCK,EAAeL,WAAWQ,OAGlFpI,EAAkBgB,WAAWY,KAAKf,KAAKC,MAAMD,KAAKE,UAAUkH,IAG9D,KAKJjI,EAAkBmB,aAAe2G,MAAMO,KAAKxD,EAAsByD,UAGlE,MAAMpF,EAAS,GAoCf,GAjCKJ,IACE9C,EAAkBlB,KAEX,mBAAmBV,KAAK4B,EAAkBlB,OACpDoE,EAAOtB,KAAK,qFAFZsB,EAAOtB,KAAK,6BAKT5B,EAAkBwE,aACrBtB,EAAOtB,KAAK,6BAKhB5B,EAAkBgB,WAAWQ,SAAQ,CAAC+G,EAAQ9E,KAC5C,MAAM+E,EAAexF,qBAAqBuF,GACtCC,EAAanK,OAAS,GACxB6E,EAAOtB,KAAK,UAAU6B,EAAQ,MAAM8E,EAAOzJ,MAAQ,eAAe0J,EAAaC,KAAK,QACtF,IAIFzI,EAAkBmB,aAAaK,SAAQ,CAACkH,EAAKjF,KAI3C,GAHKiF,EAAI5J,MAAS4J,EAAIpH,MAASoH,EAAInH,SACjC2B,EAAOtB,KAAK,eAAe6B,EAAQ,2CAEjCiF,EAAIvC,SAAU,CAChB,MAAMI,EAAe3C,OAAOoD,KAAK0B,EAAIvC,UAAU,GAC1C,CAAC,gBAAiB,YAAa,SAAS9G,SAASkH,IACpDrD,EAAOtB,KAAK,eAAe6B,EAAQ,4BAA4B8C,IAEnE,KAGErD,EAAO7E,OAAS,EAAG,CAErB0B,EAAY4I,iBAAiB,6BAA6BnH,SAAQoH,GAAMA,EAAG/J,WAc3EqE,EAAO1B,SAAQqH,IACb,IAAIpB,EAAW,KAKf,GAJIoB,EAASxJ,SAAS,iBAAkBoI,EAAW,qBAC1CoB,EAASxJ,SAAS,kBAAiBoI,EAAW,6BAGnDA,EAAU,CACZ,MAAMqB,EAAQ/I,EAAYjC,cAAc2J,GACxC,GAAIqB,EAAO,CACT,MAAMC,EAAWpL,SAASqL,cAAc,OACxCD,EAASE,UAAY,qDACrBF,EAASG,YAAcL,EACvBC,EAAMK,sBAAsB,WAAYJ,EAC1C,CACF,IAEJ,CAEA,OAAO/I,CACT,QAUO,SAASoJ,aAAaC,EAAY5L,EAAS,cAAe6L,GAA0B,EAAOC,EAAsB,MACtH,MAAMC,EAAc7L,SAASC,eAAeH,GAC5C,IAAK+L,EAEH,YADA9I,QAAQC,MAAM,+BAA+BlD,iBAI/C,MAAM4G,EAAgBkF,IAAmC,gBAAX9L,EAA2B,cAAgB,+BAOzF,GALAgM,+BAA+BhM,EAAQ4G,GAGvC7G,wBAAwBC,GAEnB4L,EAAL,CAEA,GAAe,gBAAX5L,EAA0B,CAC5B+L,EAAY1L,cAAc,iBAAiBG,MAAQoL,EAAWvK,MAAQ,GACtE0K,EAAY1L,cAAc,wBAAwBG,MAAQoL,EAAW7E,aAAe,GACpFgF,EAAY1L,cAAc,wBAAwBG,MAAQoL,EAAWlG,aAAe,GAChFkG,EAAW5E,aACb+E,EAAY1L,cAAc,uBAAuBG,MAAQoL,EAAW5E,YAEtE,MAAMtE,EAAY,IAAIC,gBAAgBC,OAAOC,SAASC,QACtD,GAAgC,SAA5BJ,EAAUK,IAAI,WAAwBL,EAAUK,IAAI,cAAgB6I,EAAWvK,KAAM,CACvF,MAAMjB,EAAY2L,EAAY1L,cAAc,iBACxCD,IACFA,EAAU6L,UAAW,EACrB7L,EAAU8L,UAAU9H,IAAI,cAAe,sBAE3C,CACF,MAAO,GAAe,sBAAXpE,GAAkC4L,EAAY,CAGvDG,EAAY1L,cAAc,sBAAsBG,MAAQoL,EAAWvK,MAAQ,GAC3E0K,EAAY1L,cAAc,6BAA6BG,MAAQoL,EAAW7E,aAAe,GACzFgF,EAAY1L,cAAc,gCAAgCG,MAAQoL,EAAWlG,aAAe,GAC5FqG,EAAY1L,cAAc,4BAA4BG,MAAQoL,EAAW5E,YAAc,GAIvF,MAAMmF,EAAqBjM,SAASC,eAAe,sCAC/CgM,GACFA,EAAmBD,UAAU9K,OAAO,UAEtC,MAAMgL,EAAsBlM,SAASC,eAAe,uCAChDiM,GAGFA,EAAoBF,UAAU9K,OAAO,SAEzC,CAIAzB,iBAAiBiH,EAAe,GAChC/G,uBAAuB+G,GACvB9G,qCAAqC8G,IAEpCgF,EAAWrI,YAAc,IAAIQ,SAASsI,IAErC,MAAMC,EAAqB1M,iBAAiBgH,GAG5ChE,OAAO2J,UAAU3F,EAAeiF,EAAyBQ,GAGzD,MAAMG,EAAaT,EAAY1L,cAAc,IAAIuG,8BAA0C0F,OAE3F,GAAIE,EACF,GAAe,sBAAXxM,EACF,GAAqC,SAAjCqM,EAAWlC,YAAYQ,MAEzB6B,EAAWtC,QAAQC,WAAa/G,KAAKE,UAAU+I,EAAWlC,iBAM1D,GAAIzK,MAAM+M,sCAAwCJ,EAAWhL,MAAQ3B,MAAM+M,qCAAqCvI,IAAImI,EAAWhL,MAE7HmL,EAAWtC,QAAQC,WAAa/G,KAAKE,UAAU,CAAEqH,MAAO,cAOxD,GAAI0B,EAAWlC,YAAchE,OAAOoD,KAAK8C,EAAWlC,YAAYvJ,OAAS,EAAG,CACxE,MAAM8L,EAAU,IAAKL,EAAWlC,mBACzBuC,EAAQ/B,MACXxE,OAAOoD,KAAKmD,GAAS9L,OAAS,EAC9B4L,EAAWtC,QAAQC,WAAa/G,KAAKE,UAAUoJ,UAExCF,EAAWtC,QAAQC,UAElC,aACWqC,EAAWtC,QAAQC,gBAQ9BkC,EAAWlC,WACbqC,EAAWtC,QAAQC,WAAa/G,KAAKE,UAAU+I,EAAWlC,mBAEnDqC,EAAWtC,QAAQC,WAKhC,MAAMwC,EAAkBZ,EAAY1L,cAAc,kBAAkBiM,aAChEK,IAAiBA,EAAgBnM,MAAQ6L,EAAWhL,MAAQ,IAEhE,MAAMuL,EAAYb,EAAY1L,cAAc,kBAAkBiM,aAC1DM,IACFA,EAAUpM,MAAQ6L,EAAW1G,MAAQ,QACU,mBAApC/C,OAAOiK,0BAChBjK,OAAOiK,yBAAyBP,EAAoB1F,EAAeyF,EAAW1G,MAAQ,QAASkG,EAAyBQ,EAAWzG,eAGvI,MAAMkH,EAAYf,EAAY1L,cAAc,kBAAkBiM,oBAG9D,GAFIQ,IAAWA,EAAUtM,MAAQ6L,EAAW3G,aAAe,IAEvD2G,EAAW5F,QAAS,CACtB,MAAMsG,EAAe7M,SAASC,eAAe,eAAemM,KACxDS,IAAcA,EAAavM,MAAQ6L,EAAW5F,QACpD,CACA,GAAI4F,EAAWrF,WAAY,CACzB,MAAMhG,EAAY+K,EAAY1L,cAAc,kBAAkBiM,mBAC1DtL,IAAWA,EAAUR,MAAQ6L,EAAWrF,WAC9C,CAEA,GAAIqF,EAAWzG,aACb,GAAwB,QAApByG,EAAW1G,MAAsC,oBAApB0G,EAAW1G,KAA4B,CACtE,MAAMlE,EAAWsK,EAAY1L,cAAc,kBAAkBiM,yBACzD7K,IAAUA,EAASjB,MAAQ6L,EAAWzG,aAAaK,KAAO,GAChE,KAAO,CACL,MAAM+G,EAAWjB,EAAY1L,cAAc,kBAAkBiM,6BAE7D,GADIU,IAAUA,EAASxM,MAAQ6L,EAAWzG,aAAaC,SAAW,IAC9DwG,EAAWzG,aAAaE,MAAQuE,MAAMC,QAAQ+B,EAAWzG,aAAaE,MAAO,CAC/E,MAAMpE,EAAYqK,EAAY1L,cAAc,kBAAkBiM,0BAC1D5K,IAAWA,EAAUlB,MAAQ6L,EAAWzG,aAAaE,KAAKkF,KAAK,MACrE,CACIqB,EAAWzG,aAAaM,KAC1BC,OAAOC,QAAQiG,EAAWzG,aAAaM,KAAKnC,SAAQ,EAAEkJ,EAASC,MAC7D,MAAMC,EAAkBvK,OAAOwK,eAAed,EAAoB1F,EAAeiF,GAE3EzL,EAAY2L,EAAY1L,cAAc,kBAAkBiM,uBAAwCa,aAEtG,GADI/M,IAAWA,EAAUI,MAAQyM,GAC7BC,EAAU3G,QAAS,CACrB,MAAM8G,EAAWtB,EAAY1L,cAAc,kBAAkBiM,uBAAwCa,gBACjGE,IAAUA,EAAS7M,MAAQ0M,EAAU3G,QAC3C,CACA,GAAI2G,EAAU5G,SAAU,CACtB,MAAMgH,EAAWvB,EAAY1L,cAAc,kBAAkBiM,uBAAwCa,iBACjGG,IAAUA,EAASC,SAAU,EACnC,CACA,GAAIL,EAAU1G,YAAa,CACzB,MAAMsG,EAAYf,EAAY1L,cAAc,kBAAkBiM,uBAAwCa,oBAClGL,IAAWA,EAAUtM,MAAQ0M,EAAU1G,YAC7C,IAGN,CAGF,GAAI6F,EAAWxE,cAAgBwE,EAAWxE,aAAanE,aAAc,CAEnE,MAAM8J,EAAqC3B,KAA8D,SAAjCQ,EAAWlC,YAAYQ,OAG/F0B,EAAWxE,aAAanE,aAAaK,SAAS0J,IAE5C,MAAMC,GAAW9B,EAAWlI,cAAgB,IAAIiK,MAAK/J,GAAKA,EAAEvC,OAASoM,EAAOpM,OAC5E,IAAKqM,EAEH,YADAzK,QAAQ6D,KAAK,+DAA+D2G,EAAOpM,iBAAiBoM,EAAO3J,uEAK7G,MAAM8J,EAAkBhL,OAAOiL,qBAAqBvB,EAAoB1F,EAAe4G,GAEvFzB,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,aAA2BpN,MAAQkN,EAAQrM,MAAQ,GACnI0K,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,aAA2BpN,MAAQkN,EAAQ7J,MAAQ,GACnIkI,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,gBAA8BpN,MAAQkN,EAAQ5J,SAAW,QAEpHmD,IAAjBwG,EAAO7E,QACTmD,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,cAA4BpN,MAAQiN,EAAO7E,OAGxG,YAAjB8E,EAAQ7J,MAAsB6J,EAAQ7E,QACxCkD,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,cAA4BpN,MAAQkN,EAAQ7E,MAC5HjG,OAAOkL,uBAAuBxB,EAAoBsB,EAAiBhH,IAGrE,IAAIkC,EAAe,SACf4E,EAAQhF,WACNgF,EAAQhF,SAASK,cAAeD,EAAe,SAC1C4E,EAAQhF,SAASO,UAAWH,EAAe,YAC3C4E,EAAQhF,SAASQ,QAAOJ,EAAe,UAGlD,MAAMiF,EAAiBhC,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,qBAOvG,GANIG,IACFA,EAAevN,MAAQsI,EAEvBlG,OAAOoL,2BAA2B1B,EAAoBsB,EAAiBhH,IAGpD,WAAjBkC,GAA6B4E,EAAQhF,SAASK,cAAe,CAC/D,MAAMkF,EAAKP,EAAQhF,SAASK,cACxBkF,EAAGjH,aAAY+E,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,0CAAwDpN,MAAQyN,EAAGjH,YAClKiH,EAAGvE,aAAYqC,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,0CAAwDpN,MAAQyN,EAAGvE,YAClKuE,EAAGtE,YAAWoC,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,yCAAuDpN,MAAQyN,EAAGtE,UACtK,MAAO,GAAqB,cAAjBb,GAAgC4E,EAAQhF,SAASO,UAAW,CACrE,MAAMiF,EAAMR,EAAQhF,SAASO,UACzBiF,EAAItE,cAAamC,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,uCAAqDpN,MAAQ0N,EAAItE,aAClKsE,EAAIrE,eAAckC,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,wCAAsDpN,MAAQ0N,EAAIrE,aAC1K,MAAO,GAAqB,UAAjBf,GAA4B4E,EAAQhF,SAASQ,MAAO,CAC7D,MAAMiF,EAAMT,EAAQhF,SAASQ,MACzBiF,EAAIrE,YAAWiC,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,iCAA+CpN,MAAQ2N,EAAIrE,WAC1JqE,EAAIxE,YAAWoC,EAAY1L,cAAc,kBAAkBiM,mBAAoCsB,iCAA+CpN,MAAQ2N,EAAIxE,UAChK,IAEJ,IArNqB,CAuNzB,QAUO,SAASqC,+BAA+BhM,EAAS,cAAe4G,EAAgB,eACrF,MAAMwH,EAAclO,SAASC,eAAeH,GACxCoO,GAIa,sBAAXpO,GACFoO,EAAYC,QAIhB,MAAMC,EAAuBpO,SAASC,eAAeyG,GAcrD,IAAI2H,EACAC,EAWJ,GAzBIF,IACFA,EAAqBG,UAAY,IAGnC9O,iBAAiB,GACbD,OAASA,MAAMgP,aAAkD,mBAA5BhP,MAAMgP,YAAYC,OACzDjP,MAAMgP,YAAYC,QAEhBjP,OAASA,MAAMkP,2BAA8E,mBAA1ClP,MAAMkP,0BAA0BD,OACrFjP,MAAMkP,0BAA0BD,QAOnB,gBAAX3O,GACFuO,EAA2B,mCAC3BC,EAA6B,sCACT,sBAAXxO,IACTuO,EAA2B,wCAC3BC,EAA6B,8CAI3BD,EAA0B,CAC5B,MAAMM,EAAkB3O,SAASC,eAAeoO,GAC5CM,GACFA,EAAgB3C,UAAU9H,IAAI,SAElC,CACA,GAAIoK,EAA4B,CAC9B,MAAMM,EAAoB5O,SAASC,eAAeqO,GAC9CM,IACFA,EAAkBL,UAAY,GAElC,CAEA,GAAe,sBAAXzO,EAAgC,CAIlC,MAAMmM,EAAqBjM,SAASC,eAAe,sCAC/CgM,GAAoBA,EAAmBD,UAAU9H,IAAI,UAEzD,MAAMgI,EAAsBlM,SAASC,eAAe,uCAChDiM,GAAqBA,EAAoBF,UAAU9H,IAAI,SAC7D,CAGArE,wBAAwBC,EAC1B,QAQO,SAASa,sBAAsBkO,EAAS5J,EAAS6J,GAAU,GAChE,IAAIC,EAAaF,EAAQ5N,mBACpB8N,GAAeA,EAAW/C,UAAUgD,SAAS,wBAChDD,EAAa/O,SAASqL,cAAc,OACpC0D,EAAWzD,UAAY,oCAAmCwD,EAAU,eAAiB,kBACrFD,EAAQrD,sBAAsB,WAAYuD,IAE5CA,EAAWxD,YAActG,EACzB8J,EAAWzD,UAAY,oCAAmCwD,EAAU,eAAiB,iBACvF,QAGSjP","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":[],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["addServer","toggleViewMode","saveJsonData","copyJsonToClipboard","toggleSectionContent","populateForm","resetOnboardFormDynamicContent","showToast","handleValidation","handlePublish","showOnboardModal","window","location","href","activeTab","categoriesLoaded","currentSelectedCategoryData","async","loadExistingCategoryForEdit","urlParams","URLSearchParams","search","categoryName","get","editMode","isEditingCategory","document","getElementById","click","response","fetch","ok","Error","status","result","json","success","data","error","feedConfiguration","categoryNameInput","querySelector","readOnly","classList","add","console","message","loadAndPopulateCategoriesDropdown","selectElement","innerHTML","Array","isArray","forEach","category","option","createElement","value","name","textContent","displayName","appendChild","handleExistingCategorySelection","event","target","basicInfoContainer","mcpServersContainer","serversList","form","description","repository","remove","mcpServers","length","addServerBtnExisting","disabled","addEventListener","existingCategorySelect","tabCreateCategory","tabCreateServer","panelCreateCategory","panelCreateServer","switchTab","targetTab","viewModeToggle","checked","jsonEditorPanel","addServerBtnNewCategory","addServerBtnExistingCategory","log","validateButtonNewCategory","validateButtonExistingCategory","publishButtonNewCategory","publishButtonExistingCategory","currentFormId","currentServersListId","saveJsonButton","copyJsonBtn","Object","assign"],"sources":["0"],"sourcesContent":["import {\n addServer,\n // removeServer, // Not directly used by index.js listeners, uiHandlers makes it global\n // addEnvVariable, // Not directly used by index.js listeners, uiHandlers makes it global\n // removeEnvVariable, // Not directly used by index.js listeners, uiHandlers makes it global\n toggleViewMode,\n saveJsonData,\n copyJsonToClipboard,\n toggleSectionContent\n} from './uiHandlers.js';\n\nimport {\n // submitForm, // Will be replaced by handlePublish for async behavior\n populateForm,\n resetOnboardFormDynamicContent,\n // getFormData // Used internally by validation/publish handlers\n} from './formProcessor.js';\n\n// state and setServerCounter are likely not needed directly in index.js anymore\n// import { state, setServerCounter } from './state.js';\nimport { showToast } from '../notifications.js';\nimport { handleValidation } from './validationHandlers.js';\nimport { handlePublish } from './publishHandler.js'; // Moved handlePublish to its own file\n\n// Modal functions (as per original)\nexport function showOnboardModal() {\n window.location.href = 'onboard.html';\n}\n\n// Make functions available globally (as per original)\nwindow.showOnboardModal = showOnboardModal;\n\nlet activeTab = 'create-category'; // 'create-category' or 'create-server'\nlet categoriesLoaded = false;\nlet currentSelectedCategoryData = null;\nwindow.isEditingCategory = false; // Flag to indicate if editing an existing category on the first tab\n\n// Load existing category data if editing (primarily for \"Create New Category\" tab in edit mode)\nasync function loadExistingCategoryForEdit() {\n const urlParams = new URLSearchParams(window.location.search);\n const categoryName = urlParams.get('category');\n const editMode = urlParams.get('action') === 'edit';\n\n window.isEditingCategory = false; // Reset flag\n\n if (categoryName && editMode) {\n // This implies editing a whole category, so activate the first tab.\n document.getElementById('tab-create-category').click();\n try {\n const response = await fetch(`/api/categories/${categoryName}`);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n const result = await response.json();\n if (result.success && result.data) {\n // populateForm for the 'Create New Category' tab\n populateForm(result.data.feedConfiguration, 'onboardForm');\n // Set category name input as readonly if it's an update\n const categoryNameInput = document.querySelector('#panel-create-category input[name=\"name\"]');\n if (categoryNameInput) {\n categoryNameInput.readOnly = true;\n categoryNameInput.classList.add('bg-gray-100', 'cursor-not-allowed');\n }\n window.isEditingCategory = true; // Set flag as we are editing\n } else {\n throw new Error(result.error || 'Failed to load category data.');\n }\n } catch (error) {\n console.error('Error loading category for editing:', error);\n showToast(`Error loading category for editing: ${error.message}`, 'error');\n window.isEditingCategory = false;\n }\n } else if (categoryName && !editMode) {\n // This could imply pre-selecting a category in the \"Create New Server in Existing Category\" tab\n // For now, we handle this by just loading the categories and letting the user select.\n // Future enhancement: pre-select if categoryName is provided without 'action=edit'.\n if (document.getElementById('tab-create-server')) {\n document.getElementById('tab-create-server').click(); // Switch to the correct tab\n }\n }\n}\n\n\nasync function loadAndPopulateCategoriesDropdown() {\n if (categoriesLoaded) return;\n\n const selectElement = document.getElementById('existingCategorySelect');\n if (!selectElement) return;\n\n selectElement.innerHTML = '<option value=\"\">Loading categories...</option>';\n try {\n const response = await fetch('/api/categories?local=true'); // Assuming local=true fetches editable categories\n if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\n const result = await response.json();\n\n if (result.success && Array.isArray(result.data)) {\n selectElement.innerHTML = '<option value=\"\">Select a category</option>';\n result.data.forEach(category => {\n const option = document.createElement('option');\n option.value = category.name;\n option.textContent = category.displayName || category.name;\n selectElement.appendChild(option);\n });\n categoriesLoaded = true;\n } else {\n throw new Error(result.error || 'Failed to load categories.');\n }\n } catch (error) {\n console.error('Error loading categories:', error);\n selectElement.innerHTML = '<option value=\"\">Error loading categories</option>';\n showToast(`Error loading categories: ${error.message}`, 'error');\n }\n}\n\nasync function handleExistingCategorySelection(event) {\n const categoryName = event.target.value;\n // const selectElement = event.target; // Removed diagnostic log related variable\n // console.log(`[index.js] handleExistingCategorySelection: Category '${categoryName}' selected. Dropdown display value: ${selectElement.options[selectElement.selectedIndex].text}, actual value: ${categoryName}`); // Removed diagnostic log\n const basicInfoContainer = document.getElementById('existingCategoryBasicInfoContainer');\n const mcpServersContainer = document.getElementById('existingCategoryMcpServersContainer');\n const serversList = document.getElementById('existingCategoryServersList'); // Target for servers\n // console.log(`[index.js] Before changes - mcpServersContainer hidden: ${mcpServersContainer.classList.contains('hidden')}, serversList children: ${serversList.children.length}`); // Removed diagnostic log\n // Clear previous category details\n serversList.innerHTML = ''; // Clear out old servers\n document.querySelector('#existingCategoryBasicInfoContainer input[name=\"name\"]').value = '';\n document.querySelector('#existingCategoryBasicInfoContainer input[name=\"displayName\"]').value = '';\n document.querySelector('#existingCategoryBasicInfoContainer textarea[name=\"description\"]').value = '';\n document.querySelector('#existingCategoryBasicInfoContainer input[name=\"repository\"]').value = '';\n\n\n if (!categoryName) {\n basicInfoContainer.classList.add('hidden');\n mcpServersContainer.classList.add('hidden');\n currentSelectedCategoryData = null;\n return;\n }\n\n try {\n const response = await fetch(`/api/categories/${categoryName}`);\n if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);\n const result = await response.json();\n\n if (result.success && result.data && result.data.feedConfiguration) {\n currentSelectedCategoryData = result.data.feedConfiguration;\n\n // Populate Basic Information (read-only)\n const form = document.getElementById('onboardServerForm'); // Form for the second tab\n form.querySelector('input[name=\"name\"]').value = currentSelectedCategoryData.name || '';\n form.querySelector('input[name=\"displayName\"]').value = currentSelectedCategoryData.displayName || '';\n form.querySelector('textarea[name=\"description\"]').value = currentSelectedCategoryData.description || '';\n form.querySelector('input[name=\"repository\"]').value = currentSelectedCategoryData.repository || '';\n\n basicInfoContainer.classList.remove('hidden');\n mcpServersContainer.classList.remove('hidden');\n // console.log(`[index.js] After making containers visible - mcpServersContainer hidden: ${mcpServersContainer.classList.contains('hidden')}`); // Ensure this is removed\n\n // Populate MCP Servers (existing ones as read-only)\n // populateForm will need to be adapted or a new function created to handle read-only state\n // and target the correct server list.\n // For now, let's assume populateForm can handle this or we'll call a specialized version.\n if (currentSelectedCategoryData.mcpServers && currentSelectedCategoryData.mcpServers.length > 0) {\n // This will call populateForm which needs to be aware of the context (read-only for existing servers)\n // We pass 'onboardServerForm' to indicate the target form context.\n // And 'existingCategoryServersList' for where servers should be rendered.\n // The 'true' flag indicates these are existing servers and should be read-only.\n populateForm(currentSelectedCategoryData, 'onboardServerForm', true); // This calls reset and then populates\n\n // Ensure the container is visible after populating. This was the key fix.\n mcpServersContainer.classList.remove('hidden');\n // const isMcpContainerHiddenAfterPopulate = mcpServersContainer.classList.contains('hidden'); // Removed diagnostic log variable\n // console.log(`[index.js] After populateForm AND EXPLICIT RE-SHOW - mcpServersContainer hidden: ${isMcpContainerHiddenAfterPopulate}, serversList children: ${serversList.children.length}`); // Removed diagnostic log\n\n // const firstServerItem = serversList.querySelector('.server-item'); // Removed diagnostic log block\n // if (firstServerItem) {\n // const styles = window.getComputedStyle(firstServerItem);\n // console.log(`[index.js] First server item in serversList computed display: ${styles.display}, visibility: ${styles.visibility}`);\n // } else if (currentSelectedCategoryData.mcpServers && currentSelectedCategoryData.mcpServers.length > 0) {\n // console.warn(\"[index.js] populateForm was called for servers, but no .server-item found in serversList afterwards.\");\n // }\n } else {\n serversList.innerHTML = '<p class=\"text-gray-500\">No servers defined in this category yet. You can add new ones.</p>';\n // console.log(\"[index.js] No MCP servers in this category (innerHTML set).\"); // Removed diagnostic log\n }\n // Ensure \"Add MCP Server\" button is enabled for this tab\n const addServerBtnExisting = mcpServersContainer.querySelector('button[onclick*=\"addServer\"]');\n if (addServerBtnExisting) addServerBtnExisting.disabled = false;\n\n } else {\n throw new Error(result.error || 'Failed to load category details.');\n }\n } catch (error) {\n console.error('[index.js] Error in handleExistingCategorySelection (fetch/parse block):', error); // Keep this more specific error log\n showToast(`Error fetching category details: ${error.message}`, 'error');\n basicInfoContainer.classList.add('hidden');\n mcpServersContainer.classList.add('hidden');\n currentSelectedCategoryData = null;\n }\n}\n\n// Initialize event listeners\ndocument.addEventListener('DOMContentLoaded', async () => {\n // Load existing category data if URL indicates edit mode for the first tab\n await loadExistingCategoryForEdit();\n\n // Remove old form submit handlers, as publish buttons will now handle submission with polling\n // const onboardForm = document.getElementById('onboardForm');\n // if (onboardForm) {\n // onboardForm.addEventListener('submit', (event) => submitForm(event, 'create-category', currentSelectedCategoryData));\n // }\n // const onboardServerForm = document.getElementById('onboardServerForm');\n // if (onboardServerForm) {\n // onboardServerForm.addEventListener('submit', (event) => submitForm(event, 'create-server', currentSelectedCategoryData));\n // }\n\n const existingCategorySelect = document.getElementById('existingCategorySelect');\n if (existingCategorySelect) {\n existingCategorySelect.addEventListener('change', handleExistingCategorySelection);\n }\n\n // Setup tab switching functionality\n const tabCreateCategory = document.getElementById('tab-create-category');\n const tabCreateServer = document.getElementById('tab-create-server');\n const panelCreateCategory = document.getElementById('panel-create-category');\n const panelCreateServer = document.getElementById('panel-create-server');\n\n if (tabCreateCategory && tabCreateServer && panelCreateCategory && panelCreateServer) {\n function switchTab(targetTab) {\n if (targetTab === activeTab) {\n // If the clicked tab is already the active tab, do nothing.\n return;\n }\n const viewModeToggle = document.getElementById('viewModeToggle');\n const isJsonView = viewModeToggle.checked;\n\n if (isJsonView) {\n // If JSON view is active, switch back to form view first.\n // This will hide the JSON panel and show the form panel of the *currently active* tab.\n const currentFormIdForJsonExit = activeTab === 'create-category' ? 'onboardForm' : 'onboardServerForm';\n const currentServersListIdForJsonExit = activeTab === 'create-category' ? 'serversList' : 'existingCategoryServersList';\n const baseDataForJsonExit = activeTab === 'create-server' ? currentSelectedCategoryData : null;\n const isExistingCategoryForJsonExit = activeTab === 'create-server';\n\n toggleViewMode(false, currentFormIdForJsonExit, currentServersListIdForJsonExit, baseDataForJsonExit, isExistingCategoryForJsonExit);\n // Ensure the toggle reflects the change back to form view\n viewModeToggle.checked = false;\n }\n\n if (targetTab === 'create-category') {\n activeTab = 'create-category';\n tabCreateCategory.classList.add('text-blue-600', 'border-blue-600');\n tabCreateCategory.classList.remove('text-gray-600', 'border-transparent', 'hover:border-blue-600');\n tabCreateServer.classList.remove('text-blue-600', 'border-blue-600');\n tabCreateServer.classList.add('text-gray-600', 'border-transparent', 'hover:border-blue-600');\n\n panelCreateCategory.classList.remove('hidden');\n panelCreateServer.classList.add('hidden');\n // Removed automatic reset of 'onboardForm' when switching to 'create-category' tab\n // to preserve form content when tabbing away and back in non-edit scenarios.\n // The form is reset by default on page load if not editing,\n // or specifically when loading an existing category for edit.\n } else if (targetTab === 'create-server') {\n activeTab = 'create-server';\n tabCreateServer.classList.add('text-blue-600', 'border-blue-600');\n tabCreateServer.classList.remove('text-gray-600', 'border-transparent', 'hover:border-blue-600');\n tabCreateCategory.classList.remove('text-blue-600', 'border-blue-600');\n tabCreateCategory.classList.add('text-gray-600', 'border-transparent', 'hover:border-blue-600');\n\n panelCreateServer.classList.remove('hidden');\n panelCreateCategory.classList.add('hidden');\n // console.log(`[index.js] switchTab to 'create-server': panelCreateServer hidden: ${panelCreateServer.classList.contains('hidden')}, existingCategoryMcpServersContainer hidden: ${document.getElementById('existingCategoryMcpServersContainer').classList.contains('hidden')}`); // Ensure this is removed\n loadAndPopulateCategoriesDropdown(); // Load categories if not already loaded\n }\n // At this point, we are definitely in a form view (either switched from JSON or was already in form view).\n // The JSON editor panel should be hidden.\n const jsonEditorPanel = document.getElementById('panel-json-editor');\n if (jsonEditorPanel) { // Ensure it exists\n jsonEditorPanel.classList.add('hidden');\n }\n }\n\n tabCreateCategory.addEventListener('click', () => switchTab('create-category'));\n tabCreateServer.addEventListener('click', () => switchTab('create-server'));\n\n // Set initial tab based on activeTab (default 'create-category')\n // switchTab(activeTab); // Initial call might be problematic if DOM isn't fully ready for it.\n // loadExistingCategoryForEdit might click a tab, making this redundant or causing issues.\n // Let's rely on default HTML state or explicit clicks.\n }\n\n // Initialize button handlers\n // const addRequirementBtn = document.getElementById('addRequirementBtn');\n // if (addRequirementBtn) {\n // addRequirementBtn.addEventListener('click', addRequirement); // addRequirement from uiHandlers.js\n // }\n\n const addServerBtnNewCategory = document.getElementById('addServerBtnNewCategory'); // For \"Create New Category\" tab\n if (addServerBtnNewCategory) {\n // addServer in uiHandlers defaults serversListId to 'serversList', which is correct for this button.\n // It also defaults isReadOnly to false.\n addServerBtnNewCategory.addEventListener('click', () => window.addServer('serversList', false, null));\n }\n\n const addServerBtnExistingCategory = document.getElementById('addServerToExistingCategoryBtn'); // For \"Create Server in Existing Category\" tab\n if (addServerBtnExistingCategory) {\n addServerBtnExistingCategory.addEventListener('click', () => {\n // console.log('[index.js] \"Add MCP Server\" button clicked for EXISTING CATEGORY tab.'); // Kept for verbosity if needed\n console.log('[index.js] \"Add MCP Server\" button clicked for EXISTING CATEGORY tab.');\n // Explicitly pass the correct serversListId and ensure isReadOnly is false for new servers.\n addServer('existingCategoryServersList', false, null);\n });\n }\n\n // Validation buttons\n const validateButtonNewCategory = document.getElementById('validateButtonNewCategory');\n if (validateButtonNewCategory) {\n validateButtonNewCategory.addEventListener('click', (event) => handleValidation(event, 'create-category', currentSelectedCategoryData));\n }\n const validateButtonExistingCategory = document.getElementById('validateButtonExistingCategory');\n if (validateButtonExistingCategory) {\n validateButtonExistingCategory.addEventListener('click', (event) => handleValidation(event, 'create-server', currentSelectedCategoryData));\n }\n\n // Publish buttons\n const publishButtonNewCategory = document.getElementById('publishButtonNewCategory');\n if (publishButtonNewCategory) {\n publishButtonNewCategory.addEventListener('click', (event) => {\n handlePublish(event, 'create-category', currentSelectedCategoryData, window.isEditingCategory);\n });\n }\n const publishButtonExistingCategory = document.getElementById('publishButtonExistingCategory');\n if (publishButtonExistingCategory) {\n publishButtonExistingCategory.addEventListener('click', (event) => {\n // Publishing from \"Create Server in Existing Category\" tab is always an update to that category.\n handlePublish(event, 'create-server', currentSelectedCategoryData, true);\n });\n }\n\n const viewModeToggle = document.getElementById('viewModeToggle');\n if (viewModeToggle) {\n viewModeToggle.addEventListener('change', (event) => {\n const currentFormId = activeTab === 'create-category' ? 'onboardForm' : 'onboardServerForm';\n const currentServersListId = activeTab === 'create-category' ? 'serversList' : 'existingCategoryServersList';\n toggleViewMode(event.target.checked, currentFormId, currentServersListId, activeTab === 'create-server' ? currentSelectedCategoryData : null, activeTab === 'create-server');\n });\n }\n\n const saveJsonButton = document.getElementById('saveJsonButton');\n if (saveJsonButton) {\n saveJsonButton.addEventListener('click', () => saveJsonData(activeTab, currentSelectedCategoryData));\n }\n\n // A button to trigger copyJsonToClipboard might exist, e.g.\n const copyJsonBtn = document.getElementById('copyJsonButton'); // Assuming an ID like 'copyJsonButton'\n if (copyJsonBtn) {\n copyJsonBtn.addEventListener('click', copyJsonToClipboard); // copyJsonToClipboard from uiHandlers.js\n }\n\n // Expose necessary functions to window for HTML event handlers.\n // Functions from uiHandlers.js (addServer, removeServer, etc., toggleSectionContent, copyJsonToClipboard)\n // are already made global by uiHandlers.js itself.\n // We only need to expose functions imported by index.js that were previously global\n // and might still be called directly from HTML, and are not made global by their source module.\n Object.assign(window, {\n // handleValidation was originally in index.js and exposed.\n // It's used by an event listener here, but exposing it maintains compatibility if HTML calls it.\n handleValidation,\n handlePublish, // Expose handlePublish globally\n\n // showOnboardModal is defined in this file and already explicitly put on window.\n\n // Other functions like addServer, copyJsonToClipboard, toggleSectionContent etc.\n // are made global by uiHandlers.js.\n });\n});"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":[],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["showToast","getFormData","validateFormFields","pollOperationStatus","updateOperationDisplay","getElementIdsByTab","ensureStatusPanelVisible","POLLING_INTERVAL","pollingIntervalId","async","handlePublish","event","activeTab","currentSelectedCategoryData","isUpdate","panelId","contentId","formId","validateButtonId","publishButtonId","statusContentElement","document","getElementById","ensureProgressToggleListener","onboardForm","validateButton","publishButton","console","error","isValid","hasErrors","formData","mcpServers","length","nameInput","querySelector","value","trim","test","showValidationMessage","disabled","innerHTML","clearInterval","forExistingCategoryTab","newServersData","finalFeedConfiguration","JSON","parse","stringify","requirements","payload","categoryData","forExistingCategory","response","fetch","method","headers","body","result","json","success","data","categoryName","name","operationTypeForPolling","initialStatus","status","toUpperCase","setInterval","classList","remove","message","errorMessage"],"sources":["0"],"sourcesContent":["// src/web/public/js/onboard/publishHandler.js\r\nimport { showToast } from '../notifications.js';\r\nimport { getFormData } from './formProcessor.js';\r\nimport {\r\n validateFormFields,\r\n pollOperationStatus,\r\n updateOperationDisplay,\r\n getElementIdsByTab,\r\n ensureStatusPanelVisible\r\n} from './validationHandlers.js';\r\n\r\nconst POLLING_INTERVAL = 3000; // 3 seconds\r\nlet pollingIntervalId = null;\r\n\r\n/**\r\n * Handles the publish process for the onboarding form.\r\n * @param {Event} event - The click event.\r\n * @param {string} activeTab - Identifier for the active tab ('create-category' or 'create-server').\r\n * @param {object|null} currentSelectedCategoryData - Data for the currently selected category if activeTab is 'create-server'.\r\n * @param {boolean} isUpdate - Flag indicating if this is an update to an existing category.\r\n */\r\nexport async function handlePublish(event, activeTab, currentSelectedCategoryData = null, isUpdate = false) {\r\n const { panelId, contentId, formId, validateButtonId, publishButtonId } = getElementIdsByTab(activeTab);\r\n\r\n const statusContentElement = document.getElementById(contentId);\r\n // Ensure the progress toggle listener is attached when handlePublish is called\r\n if (typeof ensureProgressToggleListener === 'function') { // Check if imported correctly\r\n ensureProgressToggleListener(statusContentElement);\r\n }\r\n\r\n const onboardForm = document.getElementById(formId);\r\n const validateButton = document.getElementById(validateButtonId);\r\n const publishButton = document.getElementById(publishButtonId);\r\n\r\n if (!onboardForm || !statusContentElement || !validateButton || !publishButton) {\r\n console.error('Required form or panel elements not found for publishing.');\r\n showToast('Required form or panel elements not found for publishing.', 'error');\r\n return;\r\n }\r\n\r\n // Validate form fields\r\n const validationResult = validateFormFields(onboardForm, activeTab);\r\n if (!validationResult.isValid) {\r\n showToast('Please fix all validation errors before proceeding.', 'error');\r\n return;\r\n }\r\n\r\n let hasErrors = false;\r\n\r\n if (activeTab === 'create-category') {\r\n const formData = getFormData(onboardForm, false);\r\n if (!formData.mcpServers || formData.mcpServers.length === 0) {\r\n showToast('At least one MCP server must be configured for a new category.', 'error');\r\n return;\r\n }\r\n\r\n // Check category name format\r\n const nameInput = onboardForm.querySelector('input[name=\"name\"]');\r\n if (nameInput && nameInput.value.trim()) {\r\n if (!/^[a-zA-Z0-9-_]+$/.test(nameInput.value.trim())) {\r\n showValidationMessage(nameInput, 'Only alphanumeric characters, hyphens, and underscores allowed', true);\r\n hasErrors = true;\r\n }\r\n }\r\n }\r\n\r\n if (hasErrors) {\r\n showToast('Please fix all validation errors before proceeding.', 'error');\r\n return;\r\n }\r\n\r\n publishButton.disabled = true;\r\n publishButton.innerHTML = \"<i class='bx bx-loader-alt bx-spin mr-2'></i>Publishing...\";\r\n validateButton.disabled = true; // Also disable validate button during publish\r\n\r\n if (pollingIntervalId) {\r\n clearInterval(pollingIntervalId);\r\n pollingIntervalId = null;\r\n }\r\n\r\n const forExistingCategoryTab = activeTab === 'create-server';\r\n const newServersData = getFormData(onboardForm, forExistingCategoryTab, currentSelectedCategoryData);\r\n let finalFeedConfiguration;\r\n\r\n if (forExistingCategoryTab && currentSelectedCategoryData) {\r\n finalFeedConfiguration = JSON.parse(JSON.stringify(currentSelectedCategoryData)); // Deep clone\r\n\r\n // Replace MCP Servers and Requirements with the current state from the form (newServersData)\r\n // This aligns with the logic in handleValidation\r\n finalFeedConfiguration.mcpServers = newServersData.mcpServers || [];\r\n finalFeedConfiguration.requirements = newServersData.requirements || [];\r\n } else {\r\n finalFeedConfiguration = newServersData;\r\n }\r\n\r\n statusContentElement.innerHTML = '<p class=\"text-gray-500\">Initiating publish...</p>';\r\n ensureStatusPanelVisible(panelId, contentId);\r\n\r\n try {\r\n const payload = {\r\n categoryData: finalFeedConfiguration,\r\n isUpdate: isUpdate,\r\n forExistingCategory: forExistingCategoryTab\r\n };\r\n\r\n const response = await fetch('/api/categories/onboard', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n });\r\n\r\n const result = await response.json();\r\n\r\n if (result.success && result.data) {\r\n updateOperationDisplay(result.data, statusContentElement);\r\n const categoryName = finalFeedConfiguration.name; // Use the original category name for polling\r\n const operationTypeForPolling = 'FULL_ONBOARDING'; // Publish always initiates 'FULL_ONBOARDING'\r\n const initialStatus = result.data.status;\r\n\r\n if (categoryName && typeof initialStatus === 'string' && initialStatus.toUpperCase() !== 'COMPLETED' && initialStatus.toUpperCase() !== 'FAILED' && initialStatus.toUpperCase() !== 'SUCCEEDED') {\r\n pollingIntervalId = setInterval(async () => {\r\n const shouldContinue = await pollOperationStatus(categoryName, contentId, validateButtonId, publishButtonId, 'publish', operationTypeForPolling);\r\n if (!shouldContinue) {\r\n clearInterval(pollingIntervalId);\r\n pollingIntervalId = null;\r\n }\r\n }, POLLING_INTERVAL);\r\n } else {\r\n // Restore buttons to their original state fully\r\n publishButton.disabled = false;\r\n publishButton.innerHTML = \"<i class='bx bx-cloud-upload mr-2'></i>Publish\";\r\n publishButton.classList.remove('opacity-50');\r\n validateButton.disabled = false;\r\n validateButton.innerHTML = \"<i class='bx bx-check-shield mr-2'></i>Validate\";\r\n validateButton.classList.remove('opacity-50');\r\n if (initialStatus.toUpperCase() === 'COMPLETED' || initialStatus.toUpperCase() === 'SUCCEEDED') {\r\n showToast(result.data.message || 'Publish successful!', 'success');\r\n } else if (initialStatus.toUpperCase() === 'FAILED') {\r\n showToast(result.data.errorMessage || result.data.message || 'Publish failed.', 'error');\r\n }\r\n }\r\n } else {\r\n // Handle cases where result.success is false or result.data is missing\r\n const errorMessage = (result.data && result.data.message) || result.error || result.message || 'Publish request failed: Unknown error';\r\n if (result.data) { // If data is present (even if success is false), update display\r\n updateOperationDisplay(result.data, statusContentElement);\r\n } else {\r\n statusContentElement.innerHTML = `<p class=\"text-red-500\">${errorMessage}</p>`;\r\n }\r\n showToast(errorMessage, 'error');\r\n\r\n // Restore buttons to their original state fully\r\n publishButton.disabled = false;\r\n publishButton.innerHTML = \"<i class='bx bx-cloud-upload mr-2'></i>Publish\";\r\n publishButton.classList.remove('opacity-50');\r\n validateButton.disabled = false;\r\n validateButton.innerHTML = \"<i class='bx bx-check-shield mr-2'></i>Validate\";\r\n validateButton.classList.remove('opacity-50');\r\n }\r\n } catch (error) {\r\n console.error('Error during publish:', error);\r\n statusContentElement.innerHTML = `<p class=\"text-red-500\">An error occurred while initiating publish. Please check the console.</p>`;\r\n showToast('An error occurred during publish. Check console.', 'error');\r\n // Restore buttons to their original state fully\r\n publishButton.disabled = false;\r\n publishButton.innerHTML = \"<i class='bx bx-cloud-upload mr-2'></i>Publish\";\r\n publishButton.classList.remove('opacity-50');\r\n validateButton.disabled = false;\r\n validateButton.innerHTML = \"<i class='bx bx-check-shield mr-2'></i>Validate\";\r\n validateButton.classList.remove('opacity-50');\r\n }\r\n}"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":[],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["state","serverCounters","Map","envCountersPerTab","serverRequirementCountersPerTab","setServerCounter","serversListId","count","set","getServerCounter","get","setEnvCounter","serverIndex","value","has","getEnvCounter","tabCounters","deleteEnvCounter","delete","clearEnvCountersForTab","clear","setServerRequirementCounter","getServerRequirementCounter","deleteServerRequirementCounter","clearServerRequirementCountersForTab"],"sources":["0"],"sourcesContent":["// Global state management\nexport const state = {\n serverCounters: new Map(), // Tracks server count per serversListId: serversListId -> serverCount\n envCountersPerTab: new Map(), // Tracks env var count per server per tab: serversListId -> Map(serverIndex -> envCount)\n serverRequirementCountersPerTab: new Map() // Tracks requirement count per server per tab: serversListId -> Map(serverIndex -> reqCount)\n};\n\n// export const incrementRequirementCounter = () => state.requirementCounter++; // Removed\n// export const incrementServerCounter = () => state.serverCounter++; // Will be managed by counting elements\n/**\n * Sets the server counter for a specific serversListId.\n * @param {string} serversListId - The ID of the server list.\n * @param {number} count - The new server count for this list.\n */\nexport const setServerCounter = (serversListId, count) => {\n state.serverCounters.set(serversListId, count);\n};\n\n/**\n * Gets the server counter for a specific serversListId.\n * @param {string} serversListId - The ID of the server list.\n * @returns {number} The server count for this list.\n */\nexport const getServerCounter = (serversListId) => {\n return state.serverCounters.get(serversListId) || 0;\n};\n\nexport const setEnvCounter = (serversListId, serverIndex, value) => {\n if (!state.envCountersPerTab.has(serversListId)) {\n state.envCountersPerTab.set(serversListId, new Map());\n }\n state.envCountersPerTab.get(serversListId).set(serverIndex, value);\n};\n\nexport const getEnvCounter = (serversListId, serverIndex) => {\n const tabCounters = state.envCountersPerTab.get(serversListId);\n return tabCounters ? tabCounters.get(serverIndex) || 0 : 0;\n};\n\nexport const deleteEnvCounter = (serversListId, serverIndex) => {\n const tabCounters = state.envCountersPerTab.get(serversListId);\n if (tabCounters) {\n tabCounters.delete(serverIndex);\n }\n};\n\nexport const clearEnvCountersForTab = (serversListId) => {\n if (state.envCountersPerTab.has(serversListId)) {\n state.envCountersPerTab.get(serversListId).clear();\n }\n};\n\nexport const setServerRequirementCounter = (serversListId, serverIndex, value) => {\n if (!state.serverRequirementCountersPerTab.has(serversListId)) {\n state.serverRequirementCountersPerTab.set(serversListId, new Map());\n }\n state.serverRequirementCountersPerTab.get(serversListId).set(serverIndex, value);\n};\n\nexport const getServerRequirementCounter = (serversListId, serverIndex) => {\n const tabCounters = state.serverRequirementCountersPerTab.get(serversListId);\n return tabCounters ? tabCounters.get(serverIndex) || 0 : 0;\n};\n\nexport const deleteServerRequirementCounter = (serversListId, serverIndex) => {\n const tabCounters = state.serverRequirementCountersPerTab.get(serversListId);\n if (tabCounters) {\n tabCounters.delete(serverIndex);\n }\n};\n\nexport const clearServerRequirementCountersForTab = (serversListId) => {\n if (state.serverRequirementCountersPerTab.has(serversListId)) {\n state.serverRequirementCountersPerTab.get(serversListId).clear();\n }\n};"],"mappings":"OACO,MAAMA,MAAQ,CACnBC,eAAgB,IAAIC,IACpBC,kBAAmB,IAAID,IACvBE,gCAAiC,IAAIF,YAUhC,MAAMG,iBAAmB,CAACC,EAAeC,KAC9CP,MAAMC,eAAeO,IAAIF,EAAeC,EAAM,SAQzC,MAAME,iBAAoBH,GACxBN,MAAMC,eAAeS,IAAIJ,IAAkB,SAG7C,MAAMK,cAAgB,CAACL,EAAeM,EAAaC,KACnDb,MAAMG,kBAAkBW,IAAIR,IAC/BN,MAAMG,kBAAkBK,IAAIF,EAAe,IAAIJ,KAEjDF,MAAMG,kBAAkBO,IAAIJ,GAAeE,IAAII,EAAaC,EAAM,SAG7D,MAAME,cAAgB,CAACT,EAAeM,KAC3C,MAAMI,EAAchB,MAAMG,kBAAkBO,IAAIJ,GAChD,OAAOU,GAAcA,EAAYN,IAAIE,IAAoB,CAAC,SAGrD,MAAMK,iBAAmB,CAACX,EAAeM,KAC9C,MAAMI,EAAchB,MAAMG,kBAAkBO,IAAIJ,GAC5CU,GACFA,EAAYE,OAAON,EACrB,SAGK,MAAMO,uBAA0Bb,IACjCN,MAAMG,kBAAkBW,IAAIR,IAC9BN,MAAMG,kBAAkBO,IAAIJ,GAAec,OAC7C,SAGK,MAAMC,4BAA8B,CAACf,EAAeM,EAAaC,KACjEb,MAAMI,gCAAgCU,IAAIR,IAC7CN,MAAMI,gCAAgCI,IAAIF,EAAe,IAAIJ,KAE/DF,MAAMI,gCAAgCM,IAAIJ,GAAeE,IAAII,EAAaC,EAAM,SAG3E,MAAMS,4BAA8B,CAAChB,EAAeM,KACzD,MAAMI,EAAchB,MAAMI,gCAAgCM,IAAIJ,GAC9D,OAAOU,GAAcA,EAAYN,IAAIE,IAAoB,CAAC,SAGrD,MAAMW,+BAAiC,CAACjB,EAAeM,KAC5D,MAAMI,EAAchB,MAAMI,gCAAgCM,IAAIJ,GAC1DU,GACFA,EAAYE,OAAON,EACrB,SAGK,MAAMY,qCAAwClB,IAC/CN,MAAMI,gCAAgCU,IAAIR,IAC5CN,MAAMI,gCAAgCM,IAAIJ,GAAec,OAC3D","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":[],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["serverTemplate","serverIndex","isReadOnly","serverData","serversListId","isServerAdhoc","systemTags","adhoc","makeServerFullyEditable","disabledAttr","readOnlyClasses","hideActionButtonsClass","envVariableTemplate","envIndex","serverRequirementTemplate","reqIndex"],"sources":["0"],"sourcesContent":["// HTML templates for onboarding form\n// Global requirementTemplate is removed as requirements are now server-specific.\n\n/**\n * Generates HTML for a server item.\n * @param {number} serverIndex - The index of the server.\n * @param {boolean} [isReadOnly=false] - If true, renders the server item as read-only.\n * @param {object|null} [serverData=null] - Pre-existing server data (currently not used for pre-filling in template, handled by populateForm).\n * @param {string} [serversListId='serversList'] - The ID of the servers list container this server belongs to.\n * @returns {string} HTML string for the server item.\n */\nexport const serverTemplate = (serverIndex, isReadOnly = false, serverData = null, serversListId = 'serversList') => {\n const isServerAdhoc = serverData?.systemTags?.adhoc === 'true';\n // Server is fully editable if the category isn't read-only OR if the server itself is adhoc.\n const makeServerFullyEditable = !isReadOnly || isServerAdhoc;\n // DEBUG: console.log(`[serverTemplate] ServerIndex: ${serverIndex}, isContextReadOnly(isReadOnly): ${isReadOnly}, isServerAdhoc: ${isServerAdhoc}, makeServerFullyEditable: ${makeServerFullyEditable}, flag for addReq/addEnv: ${!makeServerFullyEditable}`);\n\n const disabledAttr = makeServerFullyEditable ? '' : 'disabled';\n const readOnlyClasses = makeServerFullyEditable ? '' : 'bg-gray-100 cursor-not-allowed opacity-70';\n\n // \"Remove Server\" button should be hidden if the server is NOT fully editable.\n // A server is fully editable if the context isn't read-only OR if it's an adhoc server.\n const hideRemoveServerButtonClass = !makeServerFullyEditable ? 'hidden' : '';\n // Other action buttons (add dependency, add env var) also respect makeServerFullyEditable.\n const hideActionButtonsClass = !makeServerFullyEditable ? 'hidden' : '';\n\n\n // Note: The 'serversListId' parameter is crucial for ensuring that actions (like removeServer, addEnvVariable)\n // are correctly scoped to the server list in the current tab (e.g., 'serversList' or 'existingCategoryServersList').\n // The onclick handlers in this template dynamically include this 'serversListId'.\n\n return `\n <div class=\"server-item p-4 border border-gray-300 rounded-lg mb-6 bg-white shadow\" data-index=\"${serverIndex}\">\n <div id=\"${serversListId}-server-header-${serverIndex}\" class=\"server-header-toggle flex justify-between items-center mb-3 cursor-pointer\"\n role=\"button\" tabindex=\"0\"\n aria-expanded=\"false\" aria-controls=\"${serversListId}-server-content-${serverIndex}\"\n onclick=\"window.toggleSectionContent('${serversListId}-server-content-${serverIndex}', this.querySelector('i.toggle-icon'), this)\"\n onkeydown=\"if(event.key==='Enter' || event.key===' ') { window.toggleSectionContent('${serversListId}-server-content-${serverIndex}', this.querySelector('i.toggle-icon'), this); event.preventDefault(); }\">\n <h3 id=\"${serversListId}-server-title-${serverIndex}\" class=\"text-lg font-semibold text-gray-800\">MCP Server #${serverIndex + 1}${isServerAdhoc ? ' <span class=\"text-sm text-blue-600 ml-1\">(Adhoc - Editable)</span>' : ''}</h3>\n <div class=\"flex items-center\">\n <button type=\"button\" onclick=\"event.stopPropagation(); removeServer(${serverIndex}, '${serversListId}')\"\n class=\"action-button-in-server p-1.5 text-sm text-red-600 hover:text-red-800 hover:bg-red-50 rounded-md flex items-center mr-2 ${hideRemoveServerButtonClass}\" title=\"Remove Server\">\n <i class='bx bx-trash text-lg'></i>\n </button>\n <button type=\"button\" onclick=\"event.stopPropagation(); window.duplicateServer(${serverIndex}, '${serversListId}')\"\n class=\"action-button-in-server duplicate-mcp-server-button p-1.5 text-sm text-blue-600 hover:text-blue-800 hover:bg-blue-50 rounded-md flex items-center mr-2\" title=\"Duplicate Server\">\n <i class='bx bx-copy text-lg'></i>\n </button>\n <i class='bx bxs-chevron-down text-xl toggle-icon'></i>\n </div>\n </div>\n <div id=\"${serversListId}-server-content-${serverIndex}\" class=\"collapsible-content server-content-scrollable hidden\" role=\"region\" aria-labelledby=\"${serversListId}-server-title-${serverIndex}\">\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Server Name*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].name\" required ${disabledAttr}\n class=\"w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"e.g., ado-tools-server\">\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Mode*</label>\n <select name=\"servers[${serverIndex}].mode\" required ${disabledAttr}\n class=\"w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\">\n <option value=\"stdio\">stdio</option>\n <option value=\"sse\">sse</option>\n <option value=\"streamable-http\">streamable-http</option>\n </select>\n </div>\n <div class=\"md:col-span-2\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Description*</label>\n <textarea name=\"servers[${serverIndex}].description\" required rows=\"3\" ${disabledAttr}\n class=\"w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"Detailed description of the server's capabilities\"></textarea>\n </div>\n <div class=\"md:col-span-2 flex gap-x-4 items-end\">\n <div class=\"flex-grow\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Schema File Path\n <span class=\"text-xs text-gray-500 ml-1\" title=\"Optional for listing available tools, please fill full path of the schema file\">\n <i class='bx bx-info-circle'></i> Optional\n </span>\n </label>\n <input type=\"text\" name=\"servers[${serverIndex}].schemas\" id=\"schema-path-${serverIndex}\" ${disabledAttr}\n class=\"w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"e.g., /Users/xxx/schemas/my_server_schema.json\">\n </div>\n </div>\n <div class=\"md:col-span-2\">\n <label class=\"block text-sm font-medium text-gray-700 mb-1\">Repository URL</label>\n <input type=\"url\" name=\"servers[${serverIndex}].repository\" ${disabledAttr}\n class=\"w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"e.g., https://github.com/org/repo\">\n </div>\n </div>\n\n <!-- Package Dependencies -->\n <div class=\"mt-4 p-3 bg-gray-50 rounded-lg border border-gray-200\">\n <h4 id=\"${serversListId}-deps-header-${serverIndex}\" class=\"text-md font-semibold text-gray-700 mb-2 flex justify-between items-center cursor-pointer\"\n role=\"button\" tabindex=\"0\"\n aria-expanded=\"false\" aria-controls=\"${serversListId}-server-deps-content-${serverIndex}\"\n onclick=\"window.toggleSectionContent('${serversListId}-server-deps-content-${serverIndex}', this.querySelector('i'), this)\"\n onkeydown=\"if(event.key==='Enter' || event.key===' ') { window.toggleSectionContent('${serversListId}-server-deps-content-${serverIndex}', this.querySelector('i'), this); event.preventDefault(); }\">\n <span>Package Dependencies</span>\n <i class='bx bxs-chevron-down text-xl'></i>\n </h4>\n <div id=\"${serversListId}-server-deps-content-${serverIndex}\" class=\"collapsible-content mt-2 hidden\" role=\"region\" aria-labelledby=\"${serversListId}-deps-header-${serverIndex}\">\n <div id=\"server-requirements-list-${serverIndex}\" class=\"space-y-4\">\n <!-- Server requirements will be populated here by serverRequirementTemplate -->\n </div>\n <button type=\"button\" onclick=\"addServerRequirement(${serverIndex}, '${serversListId}', ${!makeServerFullyEditable})\"\n class=\"action-button-in-server mt-3 px-3 py-1.5 text-sm border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-100 flex items-center ${hideActionButtonsClass}\">\n <i class='bx bx-plus mr-1'></i> Add Dependency\n </button>\n </div>\n </div>\n\n <!-- Startup Configuration -->\n <div class=\"mt-4 p-3 bg-gray-50 rounded-lg border border-gray-200\">\n <h4 id=\"${serversListId}-startup-header-${serverIndex}\" class=\"text-md font-semibold text-gray-700 mb-2 flex justify-between items-center cursor-pointer\"\n role=\"button\" tabindex=\"0\"\n aria-expanded=\"false\" aria-controls=\"${serversListId}-installation-content-${serverIndex}\"\n onclick=\"window.toggleSectionContent('${serversListId}-installation-content-${serverIndex}', this.querySelector('i'), this)\"\n onkeydown=\"if(event.key==='Enter' || event.key===' ') { window.toggleSectionContent('${serversListId}-installation-content-${serverIndex}', this.querySelector('i'), this); event.preventDefault(); }\">\n <span>Startup Configuration</span>\n <i class='bx bxs-chevron-down text-xl'></i>\n </h4>\n <div id=\"${serversListId}-installation-content-${serverIndex}\" class=\"collapsible-content mt-2 hidden\" role=\"region\" aria-labelledby=\"${serversListId}-startup-header-${serverIndex}\">\n <div id=\"installation-config-${serverIndex}\">\n <!-- Installation fields will be rendered here based on mode by renderInstallationConfig -->\n </div>\n </div>\n </div>\n\n <!-- Environment Variables -->\n <div class=\"mt-4 p-3 bg-gray-50 rounded-lg border border-gray-200\" id=\"env-vars-block-${serverIndex}\">\n <h4 id=\"${serversListId}-envars-header-${serverIndex}\" class=\"text-md font-semibold text-gray-700 mb-2 flex justify-between items-center cursor-pointer\"\n role=\"button\" tabindex=\"0\"\n aria-expanded=\"false\" aria-controls=\"${serversListId}-env-vars-content-${serverIndex}\"\n onclick=\"window.toggleSectionContent('${serversListId}-env-vars-content-${serverIndex}', this.querySelector('i'), this)\"\n onkeydown=\"if(event.key==='Enter' || event.key===' ') { window.toggleSectionContent('${serversListId}-env-vars-content-${serverIndex}', this.querySelector('i'), this); event.preventDefault(); }\">\n <span>Environment Variables</span>\n <i class='bx bxs-chevron-down text-xl'></i>\n </h4>\n <div id=\"${serversListId}-env-vars-content-${serverIndex}\" class=\"collapsible-content mt-2 hidden\" role=\"region\" aria-labelledby=\"${serversListId}-envars-header-${serverIndex}\">\n <div id=\"envVarsContainer_${serverIndex}\" class=\"space-y-3\">\n <!-- Environment variables will be added here by envVariableTemplate -->\n </div>\n <button type=\"button\" onclick=\"addEnvVariable(${serverIndex}, '${serversListId}', ${!makeServerFullyEditable})\"\n class=\"action-button-in-server mt-3 px-3 py-1.5 text-sm border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-100 flex items-center ${hideActionButtonsClass}\">\n <i class='bx bx-plus mr-1'></i> Add Environment Variable\n </button>\n </div>\n </div>\n </div><!-- Closing server-content-${serverIndex} -->\n </div>\n`;\n};\n\n/**\n * Generates HTML for an environment variable item.\n * @param {number} serverIndex - The index of the server.\n * @param {number} envIndex - The index of the environment variable.\n * @param {boolean} [isReadOnly=false] - If true, renders the item as read-only.\n * @param {string} [serversListId='serversList'] - The ID of the servers list container.\n * @returns {string} HTML string for the environment variable item.\n */\nexport const envVariableTemplate = (serverIndex, envIndex, isReadOnly = false, serversListId = 'serversList') => {\n const disabledAttr = isReadOnly ? 'disabled' : '';\n const readOnlyClasses = isReadOnly ? 'bg-gray-100 cursor-not-allowed opacity-70' : '';\n const hideButtonClass = isReadOnly ? 'hidden' : '';\n\n return `\n <div class=\"env-var-item grid grid-cols-1 gap-2\" data-env-index=\"${envIndex}\">\n <div class=\"grid grid-cols-3 gap-2 items-end\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Name*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].installation.env[${envIndex}].name\" required ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"ENV_VAR_NAME\">\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Default Value</label>\n <input type=\"text\" name=\"servers[${serverIndex}].installation.env[${envIndex}].default\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"Default value\">\n </div>\n <div class=\"flex items-center gap-2\">\n <label class=\"inline-flex items-center text-sm\">\n <input type=\"checkbox\" name=\"servers[${serverIndex}].installation.env[${envIndex}].required\" ${disabledAttr}\n class=\"text-blue-600 focus:ring-blue-500 ${isReadOnly ? 'opacity-70 cursor-not-allowed' : ''}\">\n <span class=\"ml-1 ${isReadOnly ? 'text-gray-500' : ''}\">Required</span>\n </label>\n <button type=\"button\" onclick=\"removeEnvVariable(${serverIndex}, ${envIndex}, '${serversListId}')\"\n class=\"action-button-in-env px-2 py-1 text-red-600 hover:text-red-800 ${hideButtonClass}\">\n <i class='bx bx-trash'></i>\n </button>\n </div>\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Description</label>\n <textarea name=\"servers[${serverIndex}].installation.env[${envIndex}].description\" rows=\"2\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"Environment variable description\"></textarea>\n </div>\n </div>\n`;\n};\n\n/**\n * Generates HTML for a server requirement item.\n * @param {number} serverIndex - The index of the server.\n * @param {number} reqIndex - The index of the requirement.\n * @param {boolean} [isReadOnly=false] - If true, renders the item as read-only.\n * @param {string} [serversListId='serversList'] - The ID of the servers list container.\n * @returns {string} HTML string for the server requirement item.\n */\nexport const serverRequirementTemplate = (serverIndex, reqIndex, isReadOnly = false, serversListId = 'serversList') => {\n // DEBUG: console.log(`[serverRequirementTemplate] ServerIndex: ${serverIndex}, ReqIndex: ${reqIndex}, isReadOnly received: ${isReadOnly}`);\n const disabledAttr = isReadOnly ? 'disabled' : '';\n const readOnlyClasses = isReadOnly ? 'bg-gray-100 cursor-not-allowed opacity-70' : '';\n const hideButtonClass = isReadOnly ? 'hidden' : '';\n\n return `\n <div class=\"server-requirement-item p-3 border border-gray-200 rounded-lg mb-3\" data-req-index=\"${reqIndex}\">\n <div class=\"grid grid-cols-2 gap-3\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Name*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].name\" required ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"Package or command name\">\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Type*</label>\n <select name=\"servers[${serverIndex}].requirements[${reqIndex}].type\" required onchange=\"toggleServerAliasField(${serverIndex}, ${reqIndex}, '${serversListId}')\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\">\n <option value=\"\">Select Type</option>\n <option value=\"npm\">NPM Package</option>\n <option value=\"pip\">PIP Package</option>\n <option value=\"nuget\">Nuget Package</option>\n <option value=\"command\">Command</option>\n </select>\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Version*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].version\" required ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"e.g., latest, v\\${latest}, 1.0.0\">\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Order</label>\n <input type=\"number\" name=\"servers[${serverIndex}].requirements[${reqIndex}].order\" min=\"0\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"Installation order\">\n </div>\n <div id=\"server-alias-field-${serverIndex}-${reqIndex}\" class=\"hidden\">\n <label class=\"block text-sm font-medium text-gray-700\">Alias</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].alias\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"Command alias\">\n </div>\n <div class=\"col-span-2\">\n <label class=\"block text-sm font-medium text-gray-700\">Registry*</label>\n <select name=\"servers[${serverIndex}].requirements[${reqIndex}].registryType\" onchange=\"toggleServerRegistryConfig(${serverIndex}, ${reqIndex}, '${serversListId}')\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\" required>\n <option value=\"public\" selected>Public Registry</option>\n <option value=\"github\">GitHub Release</option>\n <option value=\"artifacts\">Private Artifacts</option>\n </select>\n </div>\n \n <div id=\"server-registry-config-${serverIndex}-${reqIndex}\" class=\"col-span-2 registry-configs\">\n <!-- GitHub Registry Config -->\n <div id=\"server-github-config-${serverIndex}-${reqIndex}\" class=\"registry-config mt-3 p-2 bg-gray-50 rounded-lg hidden\">\n <h3 class=\"text-sm font-medium text-gray-900 mb-2\">GitHub Registry Details</h3>\n <div class=\"grid grid-cols-1 gap-3\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Repository*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].registry.githubRelease.repository\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"org/repo\">\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Assets Name Pattern</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].registry.githubRelease.assetsName\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"package-\\${latest}.zip (e.g. for multiple assets)\">\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Asset Name Pattern*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].registry.githubRelease.assetName\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"package-\\${latest}.tgz (specific asset)\">\n </div>\n </div>\n </div>\n \n <!-- Artifacts Registry Config -->\n <div id=\"server-artifacts-config-${serverIndex}-${reqIndex}\" class=\"registry-config mt-3 p-2 bg-gray-50 rounded-lg hidden\">\n <h3 class=\"text-sm font-medium text-gray-900 mb-2\">Private Artifacts Registry Details</h3>\n <div class=\"grid grid-cols-1 gap-3\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Registry Name*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].registry.artifacts.registryName\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"My-Artifacts-Registry\">\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Registry URL*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].registry.artifacts.registryUrl\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"https://artifacts.example.com\">\n </div>\n </div>\n </div>\n\n <!-- Local Registry Config -->\n <div id=\"server-local-config-${serverIndex}-${reqIndex}\" class=\"registry-config mt-3 p-2 bg-gray-50 rounded-lg hidden\">\n <h3 class=\"text-sm font-medium text-gray-900 mb-2\">Local Path Details</h3>\n <div class=\"grid grid-cols-1 gap-3\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Local Path*</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].registry.local.localPath\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"/path/to/local/registry_or_file\">\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Asset Name Pattern</label>\n <input type=\"text\" name=\"servers[${serverIndex}].requirements[${reqIndex}].registry.local.assetName\" ${disabledAttr}\n class=\"w-full px-2 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${readOnlyClasses}\"\n placeholder=\"package-\\${latest}.tgz (if localPath is a dir)\">\n </div>\n </div>\n </div>\n </div>\n </div>\n <button type=\"button\" onclick=\"removeServerRequirement(${serverIndex}, ${reqIndex}, '${serversListId}')\"\n class=\"action-button-in-req mt-2 px-2 py-1 text-red-600 hover:text-red-800 flex items-center text-sm ${hideButtonClass}\">\n <i class='bx bx-trash mr-1'></i>\n Remove\n </button>\n </div>\n`;\n};"],"mappings":"OAWO,MAAMA,eAAiB,CAACC,EAAaC,GAAa,EAAOC,EAAa,KAAMC,EAAgB,iBACjG,MAAMC,EAAkD,SAAlCF,GAAYG,YAAYC,MAExCC,GAA2BN,GAAcG,EAGzCI,EAAeD,EAA0B,GAAK,WAC9CE,EAAkBF,EAA0B,GAAK,4CAMjDG,EAA0BH,EAAqC,GAAX,SAO1D,MAAO,uGAC2FP,qBACrFG,mBAA+BH,6KAEEG,oBAAgCH,sDAC/BG,oBAAgCH,kJACeG,oBAAgCH,+FAC/GG,kBAA8BH,8DAAwEA,EAAc,IAAII,EAAgB,sEAAwE,kIAEjJJ,OAAiBG,mJAlB1DI,EAAqC,GAAX,iMAsByBP,OAAiBG,4XAO5FA,oBAAgCH,kGAA4GG,kBAA8BH,mNAK9IA,qBAA+BQ,yIAC2DC,oMAKrGT,qBAA+BQ,yIACsEC,sWAQnGT,qCAA+CQ,yIACoDC,4jBAUxFT,+BAAyCA,MAAgBQ,2IACiCC,yRAM7FT,kBAA4BQ,yIAC+DC,+NAOrHN,iBAA6BH,8LAEIG,yBAAqCH,uDACpCG,yBAAqCH,uIACUG,yBAAqCH,gMAIrHG,yBAAqCH,6EAAuFG,iBAA6BH,kDAC9HA,0MAGkBA,OAAiBG,QAAoBI,gKACuDG,oPAQ1IP,oBAAgCH,8LAECG,0BAAsCH,uDACrCG,0BAAsCH,uIACSG,0BAAsCH,iMAItHG,0BAAsCH,6EAAuFG,oBAAgCH,6CACvIA,sSAOqDA,sBAC5EG,mBAA+BH,8LAEEG,sBAAkCH,uDACjCG,sBAAkCH,uIACaG,sBAAkCH,iMAIlHG,sBAAkCH,6EAAuFG,mBAA+BH,0CACrIA,0LAGoBA,OAAiBG,QAAoBI,8JAC2DG,kKAKhHV,sBAEvC,SAWM,MAAMW,oBAAsB,CAACX,EAAaY,EAAUX,GAAa,EAAOE,EAAgB,iBAC7F,MAAMK,EAAeP,EAAa,WAAa,GACzCQ,EAAkBR,EAAa,4CAA8C,GAGnF,MAAO,wEAC4DW,gMAI1BZ,uBAAiCY,qBAA4BJ,2IAC+BC,wMAK5FT,uBAAiCY,eAAsBJ,2IACqCC,mNAKtFT,uBAAiCY,gBAAuBJ,2DAClDP,EAAa,gCAAkC,qCACxEA,EAAa,gBAAkB,mGAEFD,MAAgBY,OAAcT,yFAvB/DF,EAAa,SAAW,wNA+BlBD,uBAAiCY,4BAAmCJ,yIACiCC,gGAIpI,SAWM,MAAMI,0BAA4B,CAACb,EAAac,EAAUb,GAAa,EAAOE,EAAgB,iBAEnG,MAAMK,EAAeP,EAAa,WAAa,GACzCQ,EAAkBR,EAAa,4CAA8C,GAGnF,MAAO,uGAC2Fa,sLAIzDd,mBAA6Bc,qBAA4BN,2IACmCC,gMAKvGT,mBAA6Bc,sDAA6Dd,MAAgBc,OAAcX,QAAoBK,2IACrCC,qbAU5FT,mBAA6Bc,wBAA+BN,2IACgCC,sNAK1FT,mBAA6Bc,qBAA4BN,2IACiCC,oGAGnGT,KAAec,8IAERd,mBAA6Bc,aAAoBN,2IAC2CC,6MAKvGT,mBAA6Bc,yDAAgEd,MAAgBc,OAAcX,QAAoBK,2IACxCC,8RAO/FT,KAAec,iIAEfd,KAAec,6WAKNd,mBAA6Bc,yCAAgDN,iJACeC,wOAK5FT,mBAA6Bc,yCAAgDN,iJACeC,iRAK5FT,mBAA6Bc,wCAA+CN,iJACgBC,yOAOnGT,KAAec,sXAKTd,mBAA6Bc,uCAA8CN,gJACiBC,0OAK5FT,mBAA6Bc,sCAA6CN,gJACkBC,8MAOrGT,KAAec,wWAKLd,mBAA6Bc,gCAAuCN,iJACwBC,8PAK5FT,mBAA6Bc,gCAAuCN,iJACwBC,iOAOhFT,MAAgBc,OAAcX,oHAnHjEF,EAAa,SAAW,uFAyHjD","ignoreList":[]}
|