diff --git a/src/components/CippComponents/CippAppTemplateDrawer.jsx b/src/components/CippComponents/CippAppTemplateDrawer.jsx index 6be184eebaa6..e9db8701f3d6 100644 --- a/src/components/CippComponents/CippAppTemplateDrawer.jsx +++ b/src/components/CippComponents/CippAppTemplateDrawer.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useCallback, useState } from "react"; +import React, { useEffect, useCallback, useState } from 'react' import { Button, Divider, @@ -10,263 +10,265 @@ import { ListItemText, ListItemSecondaryAction, Alert, -} from "@mui/material"; -import { Grid } from "@mui/system"; -import { useForm, useWatch } from "react-hook-form"; -import { Add, Delete, Edit, Save } from "@mui/icons-material"; -import { CippOffCanvas } from "./CippOffCanvas"; -import CippFormComponent from "./CippFormComponent"; -import { CippFormCondition } from "./CippFormCondition"; -import { CippApiResults } from "./CippApiResults"; -import { ApiGetCall, ApiPostCall } from "../../api/ApiCall"; -import languageList from "../../data/languageList.json"; +} from '@mui/material' +import { Grid } from '@mui/system' +import { useForm, useWatch } from 'react-hook-form' +import { Add, Delete, Edit, Save } from '@mui/icons-material' +import { CippOffCanvas } from './CippOffCanvas' +import CippFormComponent from './CippFormComponent' +import { CippFormCondition } from './CippFormCondition' +import { CippApiResults } from './CippApiResults' +import { ApiGetCall, ApiPostCall } from '../../api/ApiCall' +import languageList from '../../data/languageList.json' const appTypeLabels = { - mspApp: "MSP Vendor App", - StoreApp: "Store App", - chocolateyApp: "Chocolatey App", - officeApp: "Microsoft Office", - win32ScriptApp: "Custom Application", -}; + mspApp: 'MSP Vendor App', + StoreApp: 'Store App', + chocolateyApp: 'Chocolatey App', + officeApp: 'Microsoft Office', + win32ScriptApp: 'Custom Application', +} export const CippAppTemplateDrawer = ({ - buttonText = "Create Template", + buttonText = 'Create Template', editData = null, open = false, onClose, }) => { - const [drawerVisible, setDrawerVisible] = useState(false); - const [apps, setApps] = useState([]); - const [editGUID, setEditGUID] = useState(null); - const formControl = useForm({ mode: "onChange" }); - const templateFormControl = useForm({ mode: "onChange" }); + const [drawerVisible, setDrawerVisible] = useState(false) + const [apps, setApps] = useState([]) + const [editGUID, setEditGUID] = useState(null) + const formControl = useForm({ mode: 'onChange' }) + const templateFormControl = useForm({ mode: 'onChange' }) - const [fetchKey, setFetchKey] = useState(null); + const [fetchKey, setFetchKey] = useState(null) useEffect(() => { if (open && editData?.GUID) { - setFetchKey(`AppTemplate-${editData.GUID}-${Date.now()}`); + setFetchKey(`AppTemplate-${editData.GUID}-${Date.now()}`) } - }, [open, editData?.GUID]); + }, [open, editData?.GUID]) const templateFetch = ApiGetCall({ url: editData?.GUID ? `/api/ListAppTemplates?ID=${editData.GUID}` : null, queryKey: fetchKey, waiting: !!(open && editData?.GUID && fetchKey), - }); + }) useEffect(() => { if (open && editData && templateFetch.isSuccess && templateFetch.data) { - const template = Array.isArray(templateFetch.data) ? templateFetch.data[0] : templateFetch.data; - if (!template) return; + const template = Array.isArray(templateFetch.data) + ? templateFetch.data[0] + : templateFetch.data + if (!template) return - setEditGUID(template.GUID || editData.GUID || null); + setEditGUID(template.GUID || editData.GUID || null) templateFormControl.reset({ - templateName: template.displayName || editData.displayName || "", - templateDescription: template.description || editData.description || "", - }); + templateName: template.displayName || editData.displayName || '', + templateDescription: template.description || editData.description || '', + }) - let appsArray = template.Apps || []; - if (typeof appsArray === "string") { + let appsArray = template.Apps || [] + if (typeof appsArray === 'string') { try { - appsArray = JSON.parse(appsArray); + appsArray = JSON.parse(appsArray) } catch { - appsArray = []; + appsArray = [] } } if (!Array.isArray(appsArray)) { - appsArray = []; + appsArray = [] } const loadedApps = appsArray.map((app) => ({ appType: app.appType, appName: app.appName, - config: typeof app.config === "string" ? app.config : JSON.stringify(app.config), - })); - setApps(loadedApps); - setDrawerVisible(true); + config: typeof app.config === 'string' ? app.config : JSON.stringify(app.config), + })) + setApps(loadedApps) + setDrawerVisible(true) } - }, [open, editData, templateFetch.isSuccess, templateFetch.data]); + }, [open, editData, templateFetch.isSuccess, templateFetch.data]) const applicationType = useWatch({ control: formControl.control, - name: "appType", - }); + name: 'appType', + }) const searchQuerySelection = useWatch({ control: formControl.control, - name: "packageSearch", - }); + name: 'packageSearch', + }) const updateSearchSelection = useCallback( (searchQuerySelection) => { if (searchQuerySelection) { - formControl.setValue("packagename", searchQuerySelection.value.packagename); - formControl.setValue("applicationName", searchQuerySelection.value.applicationName); - formControl.setValue("description", searchQuerySelection.value.description); + formControl.setValue('packagename', searchQuerySelection.value.packagename) + formControl.setValue('applicationName', searchQuerySelection.value.applicationName) + formControl.setValue('description', searchQuerySelection.value.description) if (searchQuerySelection.value.customRepo) { - formControl.setValue("customRepo", searchQuerySelection.value.customRepo); + formControl.setValue('customRepo', searchQuerySelection.value.customRepo) } } }, - [formControl.setValue], - ); + [formControl.setValue] + ) useEffect(() => { - updateSearchSelection(searchQuerySelection); - }, [updateSearchSelection, searchQuerySelection]); + updateSearchSelection(searchQuerySelection) + }, [updateSearchSelection, searchQuerySelection]) - const ChocosearchResults = ApiPostCall({ urlFromData: true }); - const winGetSearchResults = ApiPostCall({ urlFromData: true }); + const ChocosearchResults = ApiPostCall({ urlFromData: true }) + const winGetSearchResults = ApiPostCall({ urlFromData: true }) const saveTemplate = ApiPostCall({ urlFromData: true, - relatedQueryKeys: ["ListAppTemplates"], - }); + relatedQueryKeys: ['ListAppTemplates'], + }) const searchApp = (searchText, type) => { - if (type === "choco") { + if (type === 'choco') { ChocosearchResults.mutate({ - url: "/api/ListAppsRepository", + url: '/api/ListAppsRepository', data: { search: searchText }, queryKey: `SearchApp-${searchText}-${type}`, - }); + }) } - if (type === "StoreApp") { + if (type === 'StoreApp') { winGetSearchResults.mutate({ - url: "/api/ListPotentialApps", - data: { searchString: searchText, type: "WinGet" }, + url: '/api/ListPotentialApps', + data: { searchString: searchText, type: 'WinGet' }, queryKey: `SearchApp-${searchText}-${type}`, - }); + }) } - }; + } const getAppName = (formData) => { - const type = formData.appType?.value; - if (type === "mspApp") return formData.displayName || formData.rmmname?.label || "MSP App"; - if (type === "officeApp") return "Microsoft 365 Apps"; - return formData.applicationName || formData.packagename || "Unnamed App"; - }; + const type = formData.appType?.value + if (type === 'mspApp') return formData.displayName || formData.rmmname?.label || 'MSP App' + if (type === 'officeApp') return 'Microsoft 365 Apps' + return formData.applicationName || formData.packagename || 'Unnamed App' + } const handleAddApp = () => { - const formData = formControl.getValues(); - if (!formData.appType?.value) return; + const formData = formControl.getValues() + if (!formData.appType?.value) return const appEntry = { appType: formData.appType.value, appName: getAppName(formData), config: JSON.stringify(formData), - }; + } - setApps((prev) => [...prev, appEntry]); - formControl.reset({ appType: null }); - }; + setApps((prev) => [...prev, appEntry]) + formControl.reset({ appType: null }) + } const handleEditApp = (index) => { - const currentForm = formControl.getValues(); - const appToEdit = apps[index]; + const currentForm = formControl.getValues() + const appToEdit = apps[index] setApps((prev) => { - const updated = [...prev]; + const updated = [...prev] if (currentForm.appType?.value) { updated.push({ appType: currentForm.appType.value, appName: getAppName(currentForm), config: JSON.stringify(currentForm), - }); + }) } - return updated.filter((_, i) => i !== index); - }); + return updated.filter((_, i) => i !== index) + }) - const config = JSON.parse(appToEdit.config); - if (!config.appType || typeof config.appType === "string") { - const typeValue = appToEdit.appType || config.appType; + const config = JSON.parse(appToEdit.config) + if (!config.appType || typeof config.appType === 'string') { + const typeValue = appToEdit.appType || config.appType config.appType = { label: appTypeLabels[typeValue] || typeValue, value: typeValue, - }; + } } // Normalize "Save as Template" configs (IntuneBody format) to form fields if (config.IntuneBody && !config.applicationName) { - const body = config.IntuneBody; - config.applicationName = config.ApplicationName || body.displayName || ""; - config.description = body.description || ""; - config.AssignTo = config.assignTo || "On"; + const body = config.IntuneBody + config.applicationName = config.ApplicationName || body.displayName || '' + config.description = body.description || '' + config.AssignTo = config.assignTo || 'On' // WinGet/Store: packageIdentifier if (body.packageIdentifier) { - config.packagename = body.packageIdentifier; + config.packagename = body.packageIdentifier } // Chocolatey: extract package name from detection rules or install command if (!config.packagename && body.detectionRules?.[0]?.fileOrFolderName) { - config.packagename = body.detectionRules[0].fileOrFolderName; + config.packagename = body.detectionRules[0].fileOrFolderName } if (!config.packagename && body.installCommandLine) { - const match = body.installCommandLine.match(/-Packagename\s+(\S+)/i); - if (match) config.packagename = match[1]; + const match = body.installCommandLine.match(/-Packagename\s+(\S+)/i) + if (match) config.packagename = match[1] } // Chocolatey: custom repo if (body.installCommandLine) { - const repoMatch = body.installCommandLine.match(/-CustomRepo\s+(\S+)/i); - if (repoMatch) config.customRepo = repoMatch[1]; + const repoMatch = body.installCommandLine.match(/-CustomRepo\s+(\S+)/i) + if (repoMatch) config.customRepo = repoMatch[1] } } - formControl.reset({ appType: config.appType }); + formControl.reset({ appType: config.appType }) setTimeout(() => { Object.entries(config).forEach(([key, value]) => { - if (key !== "appType") { - formControl.setValue(key, value); + if (key !== 'appType') { + formControl.setValue(key, value) } - }); - }, 100); - }; + }) + }, 100) + } const handleRemoveApp = (index) => { - setApps((prev) => prev.filter((_, i) => i !== index)); - }; + setApps((prev) => prev.filter((_, i) => i !== index)) + } const getTotalApps = () => { - const currentForm = formControl.getValues(); - const formHasApp = !!currentForm.appType?.value; - return apps.length + (formHasApp ? 1 : 0); - }; + const currentForm = formControl.getValues() + const formHasApp = !!currentForm.appType?.value + return apps.length + (formHasApp ? 1 : 0) + } const handleSaveTemplate = () => { - const templateData = templateFormControl.getValues(); - const currentForm = formControl.getValues(); + const templateData = templateFormControl.getValues() + const currentForm = formControl.getValues() - const allApps = [...apps]; + const allApps = [...apps] if (currentForm.appType?.value) { allApps.push({ appType: currentForm.appType.value, appName: getAppName(currentForm), config: JSON.stringify(currentForm), - }); + }) } - if (!templateData.templateName || allApps.length === 0) return; + if (!templateData.templateName || allApps.length === 0) return const payload = { displayName: templateData.templateName, - description: templateData.templateDescription || "", + description: templateData.templateDescription || '', apps: allApps, - }; + } if (editGUID) { - payload.GUID = editGUID; + payload.GUID = editGUID } saveTemplate.mutate({ - url: "/api/AddAppTemplate", + url: '/api/AddAppTemplate', data: payload, - }); - }; + }) + } const handleClose = () => { - setDrawerVisible(false); - formControl.reset({ appType: null }); - templateFormControl.reset({ templateName: "", templateDescription: "" }); - setApps([]); - setEditGUID(null); - saveTemplate.reset(); - if (onClose) onClose(); - }; + setDrawerVisible(false) + formControl.reset({ appType: null }) + templateFormControl.reset({ templateName: '', templateDescription: '' }) + setApps([]) + setEditGUID(null) + saveTemplate.reset() + if (onClose) onClose() + } return ( <> @@ -276,12 +278,12 @@ export const CippAppTemplateDrawer = ({ )} +