From bde0722eb2d11b7edc42091daf848ef395094139 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 29 Jan 2026 13:13:16 -0500 Subject: [PATCH 1/7] feat: add DKIM selectors action to domain analyser - Introduced a new action for adding/modifying DKIM selectors. - Changed the HTTP method for the "Delete from analyser" action from GET to POST. --- package.json | 2 +- public/version.json | 4 ++-- .../standards/domains-analyser/index.js | 22 +++++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index aa76e8c186f5..e7a888033252 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "10.0.3", + "version": "10.0.6", "author": "CIPP Contributors", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version.json b/public/version.json index c05615499486..90d764a5ec57 100644 --- a/public/version.json +++ b/public/version.json @@ -1,3 +1,3 @@ { - "version": "10.0.3" -} + "version": "10.0.6" +} \ No newline at end of file diff --git a/src/pages/tenant/standards/domains-analyser/index.js b/src/pages/tenant/standards/domains-analyser/index.js index 58ee11a13fb4..aef98643e21c 100644 --- a/src/pages/tenant/standards/domains-analyser/index.js +++ b/src/pages/tenant/standards/domains-analyser/index.js @@ -6,7 +6,7 @@ import { ApiGetCall } from "../../../../api/ApiCall"; import { useSettings } from "../../../../hooks/use-settings"; import { CippApiResults } from "../../../../components/CippComponents/CippApiResults"; import { CippDomainCards } from "../../../../components/CippCards/CippDomainCards"; -import { DeleteForever, TravelExplore, Refresh } from "@mui/icons-material"; +import { DeleteForever, TravelExplore, Refresh, Settings } from "@mui/icons-material"; import { DomainAnalyserDialog } from "../../../../components/CippComponents/DomainAnalyserDialog"; import { useDialog } from "../../../../hooks/use-dialog"; @@ -19,9 +19,27 @@ const Page = () => { waiting: false, }); const actions = [ + { + label: "Add/Modify DKIM Selectors", + type: "POST", + icon: , + url: "/api/ExecDnsConfig", + data: { Action: "!SetDkimConfig", Domain: "Domain" }, + confirmText: "Enter the DKIM selectors for [Domain] (comma-separated)", + fields: [ + { + type: "textField", + name: "Selector", + label: "DKIM Selectors", + placeholder: "selector1, selector2, selector3", + required: true, + }, + ], + multiPost: false, + }, { label: "Delete from analyser", - type: "GET", + type: "POST", icon: , url: "/api/ExecDnsConfig", data: { Action: "!RemoveDomain", Domain: "Domain" }, From 3a9bcc1af9d59a8ce2aca390fd41e923a907c24a Mon Sep 17 00:00:00 2001 From: Logan Cook <2997336+MWG-Logan@users.noreply.github.com> Date: Sat, 3 Jan 2026 20:10:17 -0500 Subject: [PATCH 2/7] feat(reusable-settings): reusable settings page feat(reusable-settings): add deploy and template management pages feat(reusable-settings): add reusable settings standard and UI links chore(reusable-settings): remove deploy page component fix(reusable-settings): ensure form reset on record change fix(reusable-settings): remove formControl from dependencies fix(reusable-settings): remove formControl from dependencies fix(reusable-settings): update tenant filter handling in deploy refactor(reusable-settings): optimize intune definition lookup fix(reusable-settings): add error logging for RawJSON parsing refactor(reusable-settings): normalize rawId handling and improve data formatting refactor(reusable-settings): replace Button with PermissionAwareButton fix(reusable-settings): update GUID handling to use normalizedId refactor(reusable-settings): include formControl in useEffect dependencies --- .../CippReusableSettingsDeployDrawer.jsx | 165 ++++++++ .../CippTemplateFieldRenderer.jsx | 99 ++++- ...ppAddIntuneReusableSettingTemplateForm.jsx | 54 +++ src/data/standards.json | 40 ++ src/layouts/config.js | 10 + .../MEM/reusable-settings-templates/add.jsx | 36 ++ .../MEM/reusable-settings-templates/edit.jsx | 374 ++++++++++++++++++ .../MEM/reusable-settings-templates/index.js | 108 +++++ .../endpoint/MEM/reusable-settings/edit.jsx | 136 +++++++ .../endpoint/MEM/reusable-settings/index.js | 65 +++ 10 files changed, 1080 insertions(+), 7 deletions(-) create mode 100644 src/components/CippComponents/CippReusableSettingsDeployDrawer.jsx create mode 100644 src/components/CippFormPages/CippAddIntuneReusableSettingTemplateForm.jsx create mode 100644 src/pages/endpoint/MEM/reusable-settings-templates/add.jsx create mode 100644 src/pages/endpoint/MEM/reusable-settings-templates/edit.jsx create mode 100644 src/pages/endpoint/MEM/reusable-settings-templates/index.js create mode 100644 src/pages/endpoint/MEM/reusable-settings/edit.jsx create mode 100644 src/pages/endpoint/MEM/reusable-settings/index.js diff --git a/src/components/CippComponents/CippReusableSettingsDeployDrawer.jsx b/src/components/CippComponents/CippReusableSettingsDeployDrawer.jsx new file mode 100644 index 000000000000..06365e32d50c --- /dev/null +++ b/src/components/CippComponents/CippReusableSettingsDeployDrawer.jsx @@ -0,0 +1,165 @@ +import { useEffect, useState } from "react"; +import { Button, Stack } from "@mui/material"; +import { RocketLaunch } from "@mui/icons-material"; +import { useForm, useWatch, useFormState } from "react-hook-form"; +import { CippOffCanvas } from "./CippOffCanvas"; +import { ApiGetCall, ApiPostCall } from "../../api/ApiCall"; +import CippFormComponent from "./CippFormComponent"; +import CippJsonView from "../CippFormPages/CippJSONView"; +import { Grid } from "@mui/system"; +import { CippApiResults } from "./CippApiResults"; +import { useSettings } from "../../hooks/use-settings"; +import { CippFormTenantSelector } from "./CippFormTenantSelector"; +import { PermissionButton as PermissionAwareButton } from "../../utils/permissions"; + +export const CippReusableSettingsDeployDrawer = ({ + buttonText = "Deploy Reusable Settings", + requiredPermissions = [], + PermissionButton = PermissionAwareButton, +}) => { + const [drawerVisible, setDrawerVisible] = useState(false); + const formControl = useForm({ mode: "onChange" }); + const { isValid } = useFormState({ control: formControl.control }); + const tenantFilter = useSettings()?.tenantFilter; + const selectedTemplate = useWatch({ control: formControl.control, name: "TemplateList" }); + const rawJson = useWatch({ control: formControl.control, name: "rawJSON" }); + const selectedTenants = useWatch({ control: formControl.control, name: "tenantFilter" }); + + const templates = ApiGetCall({ url: "/api/ListIntuneReusableSettingTemplates", queryKey: "ListIntuneReusableSettingTemplates" }); + + useEffect(() => { + if (templates.isSuccess && selectedTemplate?.value) { + const match = templates.data?.find((t) => t.GUID === selectedTemplate.value); + if (match) { + formControl.setValue("rawJSON", match.RawJSON || ""); + formControl.setValue("TemplateId", match.GUID); + } + } + }, [templates.isSuccess, templates.data, selectedTemplate, formControl]); + + const effectiveTenants = Array.isArray(selectedTenants) && selectedTenants.length > 0 + ? selectedTenants + : tenantFilter + ? [tenantFilter] + : []; + + const deploy = ApiPostCall({ + urlFromData: true, + relatedQueryKeys: [ + "ListIntuneReusableSettingTemplates", + `ListIntuneReusableSettings-${effectiveTenants.join(",")}`, + ], + }); + + const handleSubmit = async () => { + const isFormValid = await formControl.trigger(); + if (!isFormValid) { + return; + } + const values = formControl.getValues(); + deploy.mutate({ + url: "/api/AddIntuneReusableSetting", + data: { + tenantFilter: effectiveTenants, + TemplateId: values?.TemplateList?.value, + rawJSON: values?.rawJSON, + }, + }); + }; + + const handleCloseDrawer = () => { + setDrawerVisible(false); + formControl.reset(); + deploy.reset(); + }; + + const safeJson = () => { + if (!rawJson) return null; + try { + return JSON.parse(rawJson); + } catch (e) { + return null; + } + }; + + return ( + <> + setDrawerVisible(true)} + startIcon={} + > + {buttonText} + + + + + + } + > + + + ({ + label: + t.displayName || + t.DisplayName || + t.templateName || + t.TemplateName || + t.name || + `Template ${t.GUID}`, + value: t.GUID, + })) + : [] + } + validators={{ required: { value: true, message: "Template selection is required" } }} + /> + + + + + + + + + ); +}; diff --git a/src/components/CippComponents/CippTemplateFieldRenderer.jsx b/src/components/CippComponents/CippTemplateFieldRenderer.jsx index 5f385bfdda64..1757e400acda 100644 --- a/src/components/CippComponents/CippTemplateFieldRenderer.jsx +++ b/src/components/CippComponents/CippTemplateFieldRenderer.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useMemo } from "react"; import { Typography, Divider } from "@mui/material"; import { Grid } from "@mui/system"; import CippFormComponent from "./CippFormComponent"; @@ -10,6 +10,15 @@ const CippTemplateFieldRenderer = ({ formControl, templateType = "conditionalAccess", }) => { + const intuneDefinitionMap = useMemo(() => { + const map = new Map(); + (intuneCollection || []).forEach((def) => { + if (def?.id) { + map.set(def.id, def); + } + }); + return map; + }, []); // Default blacklisted fields with wildcard support const defaultBlacklistedFields = [ "id", @@ -253,6 +262,86 @@ const CippTemplateFieldRenderer = ({ return null; } + // Render Intune group setting collections with child-friendly fields instead of raw [object Object] + if ( + templateType === "intune" && + key.toLowerCase() === "groupsettingcollectionvalue" && + Array.isArray(value) + ) { + return ( + + + {getCippTranslation(key)} + + + + {value.map((groupEntry, groupIndex) => ( + + + {`Entry ${groupIndex + 1}`} + + + {(groupEntry?.children || []).map((child, childIndex) => { + const childPath = `${fieldPath}.${groupIndex}.children.${childIndex}`; + const intuneDefinition = intuneDefinitionMap.get(child?.settingDefinitionId); + const childLabel = + intuneDefinition?.displayName || child?.settingDefinitionId || `Child ${ + childIndex + 1 + }`; + + if (child?.simpleSettingValue) { + return ( + + + + ); + } + + if (child?.choiceSettingValue) { + const options = + intuneDefinition?.options?.map((option) => ({ + label: option.displayName || option.id, + value: option.id, + })) || []; + + return ( + + + + ); + } + + return ( + + + Unsupported group entry type — edit in JSON if needed. + + + ); + })} + + + ))} + + + ); + } + // Check for custom schema handling const schemaField = schemaFields[key.toLowerCase()]; if (schemaField) { @@ -299,9 +388,7 @@ const CippTemplateFieldRenderer = ({ // Handle different setting types if (settingInstance.choiceSettingValue) { // Find the setting definition in the intune collection - const intuneObj = intuneCollection.find( - (item) => item.id === settingInstance.settingDefinitionId - ); + const intuneObj = intuneDefinitionMap.get(settingInstance.settingDefinitionId); const label = intuneObj?.displayName || `Setting ${index + 1}`; const options = @@ -327,9 +414,7 @@ const CippTemplateFieldRenderer = ({ if (settingInstance.simpleSettingValue) { // Find the setting definition in the intune collection - const intuneObj = intuneCollection.find( - (item) => item.id === settingInstance.settingDefinitionId - ); + const intuneObj = intuneDefinitionMap.get(settingInstance.settingDefinitionId); const label = intuneObj?.displayName || `Setting ${index + 1}`; diff --git a/src/components/CippFormPages/CippAddIntuneReusableSettingTemplateForm.jsx b/src/components/CippFormPages/CippAddIntuneReusableSettingTemplateForm.jsx new file mode 100644 index 000000000000..6fdf41b42d40 --- /dev/null +++ b/src/components/CippFormPages/CippAddIntuneReusableSettingTemplateForm.jsx @@ -0,0 +1,54 @@ +import { Grid } from "@mui/system"; +import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; + +const CippAddIntuneReusableSettingTemplateForm = ({ formControl }) => { + return ( + + + + + + + + + + + + + + + + + + + ); +}; + +export default CippAddIntuneReusableSettingTemplateForm; diff --git a/src/data/standards.json b/src/data/standards.json index 9864918bdf39..4e89eadb5656 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -5344,6 +5344,46 @@ } ] }, + { + "name": "standards.ReusableSettingsTemplate", + "cat": "Templates", + "label": "Reusable Settings Template", + "multiple": true, + "disabledFeatures": { + "report": false, + "warn": false, + "remediate": false + }, + "impact": "High Impact", + "impactColour": "info", + "addedDate": "2026-01-02", + "helpText": "Deploy and maintain Intune reusable settings templates that can be referenced by multiple policies.", + "executiveText": "Creates and keeps reusable Intune settings templates consistent so common firewall and configuration blocks can be reused across many policies.", + "addedComponent": [ + { + "type": "autoComplete", + "multiple": true, + "creatable": false, + "required": true, + "name": "TemplateList", + "label": "Select Reusable Settings Template", + "api": { + "queryKey": "ListIntuneReusableSettingTemplates", + "url": "/api/ListIntuneReusableSettingTemplates", + "labelField": "displayName", + "valueField": "GUID", + "showRefresh": true, + "templateView": { + "title": "Reusable Settings", + "property": "RawJSON", + "type": "intune" + } + } + } + ], + "powershellEquivalent": "", + "recommendedBy": [] + }, { "name": "standards.TransportRuleTemplate", "label": "Transport Rule Template", diff --git a/src/layouts/config.js b/src/layouts/config.js index 07ca170abc5b..3bfc34eeb508 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -447,6 +447,16 @@ export const nativeMenuItems = [ path: "/endpoint/MEM/list-templates", permissions: ["Endpoint.MEM.*"], }, + { + title: "Reusable Settings", + path: "/endpoint/MEM/reusable-settings", + permissions: ["Endpoint.MEM.*"], + }, + { + title: "Reusable Settings Templates", + path: "/endpoint/MEM/reusable-settings-templates", + permissions: ["Endpoint.MEM.*"], + }, { title: "Assignment Filters", path: "/endpoint/MEM/assignment-filters", diff --git a/src/pages/endpoint/MEM/reusable-settings-templates/add.jsx b/src/pages/endpoint/MEM/reusable-settings-templates/add.jsx new file mode 100644 index 000000000000..c2ef4ec5a281 --- /dev/null +++ b/src/pages/endpoint/MEM/reusable-settings-templates/add.jsx @@ -0,0 +1,36 @@ +import { Box } from "@mui/material"; +import { useForm } from "react-hook-form"; +import { useSettings } from "../../../../hooks/use-settings"; +import CippFormPage from "../../../../components/CippFormPages/CippFormPage"; +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import CippAddIntuneReusableSettingTemplateForm from "../../../../components/CippFormPages/CippAddIntuneReusableSettingTemplateForm"; + +const Page = () => { + const userSettingsDefaults = useSettings(); + + const formControl = useForm({ + mode: "onChange", + defaultValues: { + tenantFilter: userSettingsDefaults.currentTenant, + }, + }); + + return ( + + + + + + ); +}; + +Page.getLayout = (page) => {page}; + +export default Page; diff --git a/src/pages/endpoint/MEM/reusable-settings-templates/edit.jsx b/src/pages/endpoint/MEM/reusable-settings-templates/edit.jsx new file mode 100644 index 000000000000..d1ca5e5f444b --- /dev/null +++ b/src/pages/endpoint/MEM/reusable-settings-templates/edit.jsx @@ -0,0 +1,374 @@ +import { Alert, Box, Button, Stack, Table, TableBody, TableCell, TableHead, TableRow, Typography, Divider } from "@mui/material"; +import { useForm, useFieldArray } from "react-hook-form"; +import { useRouter } from "next/router"; +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import CippFormPage from "../../../../components/CippFormPages/CippFormPage"; +import CippFormSkeleton from "../../../../components/CippFormPages/CippFormSkeleton"; +import CippFormComponent from "../../../../components/CippComponents/CippFormComponent"; +import { ApiGetCall } from "../../../../api/ApiCall"; +import { useSettings } from "../../../../hooks/use-settings"; +import { useEffect, useMemo } from "react"; + +// Structured clone helper for older runtimes +const deepClone = (obj) => JSON.parse(JSON.stringify(obj)); + +const generateGuid = () => { + const wrap = (val) => `{${val}}`; + if (typeof crypto !== "undefined" && crypto.randomUUID) return wrap(crypto.randomUUID()); + const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); + return wrap(`${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`); +}; + +const EditReusableSettingsTemplate = () => { + const router = useRouter(); + const { id: rawId } = router.query; + const { currentTenant } = useSettings(); + + const normalizedId = useMemo(() => { + if (typeof rawId === "string") return rawId; + if (Array.isArray(rawId) && rawId.length > 0) return rawId[0]; + return undefined; + }, [rawId]); + + const formControl = useForm({ + mode: "onChange", + defaultValues: { + tenantFilter: currentTenant, + GUID: normalizedId, + }, + }); + + const templateQuery = ApiGetCall({ + url: "/api/ListIntuneReusableSettingTemplates", + data: normalizedId ? { id: normalizedId } : undefined, + queryKey: `ReusableSettingTemplate-${normalizedId}`, + waiting: !!normalizedId, + }); + + const templateData = Array.isArray(templateQuery.data) + ? templateQuery.data[0] + : templateQuery.data; + + const normalizedTemplate = useMemo(() => { + if (!templateData) return null; + return { + ...templateData, + // Normalize all known casing variants to the canonical RawJSON property + RawJSON: templateData.RawJSON ?? templateData.RAWJson ?? templateData.RAWJSON, + }; + }, [templateData]); + + const parsedRaw = useMemo(() => { + if (!normalizedTemplate?.RawJSON) return null; + try { + return JSON.parse(normalizedTemplate.RawJSON); + } catch (e) { + return null; + } + }, [normalizedTemplate]); + + // Strip the group collection out of the parsed RAW for cleaner form state + const sanitizedParsedRaw = useMemo(() => { + if (!parsedRaw) return null; + const clone = deepClone(parsedRaw); + if (clone?.settingInstance?.groupSettingCollectionValue) { + delete clone.settingInstance.groupSettingCollectionValue; + } + return clone; + }, [parsedRaw]); + + const groupCollection = useMemo(() => { + return ( + parsedRaw?.settingInstance?.groupSettingCollectionValue || + templateData?.settingInstance?.groupSettingCollectionValue || + [] + ); + }, [parsedRaw, templateData]); + + const groupChildDefinitions = useMemo(() => { + const first = groupCollection?.[0]?.children || []; + return { + idDef: first.find((c) => c.settingDefinitionId?.toLowerCase().includes("_id"))?.settingDefinitionId, + autoresolveDef: first.find((c) => c.settingDefinitionId?.toLowerCase().includes("_autoresolve"))?.settingDefinitionId, + keywordDef: first.find((c) => c.settingDefinitionId?.toLowerCase().includes("_keyword"))?.settingDefinitionId, + }; + }, [groupCollection]); + + useEffect(() => { + if (groupCollection) { + formControl.setValue("groupSettingCollectionValue", groupCollection); + if (sanitizedParsedRaw) { + formControl.setValue("parsedRAWJson", sanitizedParsedRaw); + } + } + }, [groupCollection, sanitizedParsedRaw, formControl]); + + useEffect(() => { + if (normalizedTemplate) { + formControl.setValue("displayName", normalizedTemplate.displayName || normalizedTemplate.name); + formControl.setValue("description", normalizedTemplate.description || normalizedTemplate.Description); + } + }, [normalizedTemplate, formControl]); + + /** + * Convert RHF form values into the API payload while preserving Graph @odata fields. + * - Flattens react-hook-form autocomplete objects to their .value. + * - Restores @odata.* keys from the original template to avoid dot-notation loss from RHF. + * - Syncs displayName/description into parsed RAW JSON and reinserts the edited groupSettingCollectionValue. + * - Builds the final payload expected by /api/AddIntuneReusableSettingTemplate, including tenant fallback. + */ + const customDataFormatter = useMemo(() => { + const getOriginalValueByPath = (obj, path) => { + if (!obj) return undefined; + const keys = path.split("."); + let current = obj; + for (const key of keys) { + if (current && typeof current === "object" && key in current) { + current = current[key]; + } else { + return undefined; + } + } + return current; + }; + + const extractValues = (obj) => { + if (obj === null || obj === undefined) return obj; + + if ( + obj && + typeof obj === "object" && + obj.hasOwnProperty("value") && + obj.hasOwnProperty("label") + ) { + return obj.value; + } + + if (Array.isArray(obj)) { + return obj.map((item) => extractValues(item)); + } + + if (typeof obj === "object") { + const result = {}; + Object.keys(obj).forEach((key) => { + const value = extractValues(obj[key]); + + if (key.endsWith("@odata") && value && typeof value === "object") { + // Restore @odata.* keys from the original template to avoid RHF dot-notation artifacts + Object.keys(value).forEach((odataKey) => { + const baseKey = key.replace("@odata", ""); + const originalKey = `${baseKey}@odata.${odataKey}`; + const originalValue = getOriginalValueByPath(normalizedTemplate, originalKey); + if (originalValue !== undefined) { + result[originalKey] = originalValue; + } + }); + } else { + result[key] = value; + } + }); + return result; + } + + return obj; + }; + + return (values) => { + const processedValues = extractValues(values) || {}; + + // Sync template/policy name & description into parsed RAW JSON, and merge edited group collection + if (processedValues.parsedRAWJson) { + if (processedValues.displayName) { + processedValues.parsedRAWJson.displayName = processedValues.displayName; + } + if (processedValues.description) { + processedValues.parsedRAWJson.description = processedValues.description; + } + + if (processedValues.groupSettingCollectionValue && processedValues.parsedRAWJson.settingInstance) { + processedValues.parsedRAWJson.settingInstance.groupSettingCollectionValue = + processedValues.groupSettingCollectionValue; + } + } + + return { + GUID: processedValues.GUID || normalizedId, + displayName: processedValues.displayName, + description: processedValues.description, + package: processedValues.package, + rawJSON: JSON.stringify(processedValues.parsedRAWJson || processedValues, null, 2), + tenantFilter: processedValues.tenantFilter || currentTenant, + }; + }; + }, [currentTenant, normalizedId, normalizedTemplate]); + + const { fields, append, remove } = useFieldArray({ + control: formControl.control, + name: "groupSettingCollectionValue", + }); + + const createEmptyEntry = () => { + const { idDef, autoresolveDef, keywordDef } = groupChildDefinitions; + const children = []; + + if (idDef) { + children.push({ + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + settingDefinitionId: idDef, + simpleSettingValue: { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationStringSettingValue", + value: generateGuid(), + }, + }); + } + + if (autoresolveDef) { + children.push({ + "@odata.type": "#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance", + settingDefinitionId: autoresolveDef, + choiceSettingValue: { value: "", children: [] }, + }); + } + + if (keywordDef) { + children.push({ + "@odata.type": "#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance", + settingDefinitionId: keywordDef, + simpleSettingValue: { + "@odata.type": "#microsoft.graph.deviceManagementConfigurationStringSettingValue", + value: "", + }, + }); + } + + return { children }; + }; + + return ( + + + {templateQuery.isLoading ? ( + + ) : templateQuery.isError || !normalizedTemplate ? ( + Error loading reusable settings template. + ) : ( + <> + + Template + + + + + + + {fields?.length > 0 && ( + + + Group Setting Collection (Policy) + + + + + ID + Autoresolve + Keyword + Actions + + + + {fields.map((field, index) => { + const idPath = `groupSettingCollectionValue.${index}.children.0.simpleSettingValue.value`; + const autoresolvePath = `groupSettingCollectionValue.${index}.children.1.choiceSettingValue.value`; + const keywordPath = `groupSettingCollectionValue.${index}.children.2.simpleSettingValue.value`; + + const autoresolveBase = groupChildDefinitions.autoresolveDef || "autoresolve"; + const autoresolveTrue = `${autoresolveBase}_true`; + const autoresolveFalse = `${autoresolveBase}_false`; + + return ( + + + + + + + + + + + + + + + ); + })} + +
+ + + +
+ )} + + )} +
+
+ ); +}; + +EditReusableSettingsTemplate.getLayout = (page) => {page}; + +export default EditReusableSettingsTemplate; diff --git a/src/pages/endpoint/MEM/reusable-settings-templates/index.js b/src/pages/endpoint/MEM/reusable-settings-templates/index.js new file mode 100644 index 000000000000..230f214e3fca --- /dev/null +++ b/src/pages/endpoint/MEM/reusable-settings-templates/index.js @@ -0,0 +1,108 @@ +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import CippJsonView from "../../../../components/CippFormPages/CippJSONView"; +import { Button } from "@mui/material"; +import Link from "next/link"; +import { AddBox, GitHub, Delete, Edit } from "@mui/icons-material"; +import { ApiGetCall } from "/src/api/ApiCall"; + +const Page = () => { + const pageTitle = "Reusable Settings Templates"; + + const integrations = ApiGetCall({ + url: "/api/ListExtensionsConfig", + queryKey: "Integrations", + refetchOnMount: false, + refetchOnReconnect: false, + }); + + const actions = [ + { + label: "Edit Template", + icon: , + link: "/endpoint/MEM/reusable-settings-templates/edit?id=[GUID]", + }, + { + label: "Save to GitHub", + type: "POST", + url: "/api/ExecCommunityRepo", + icon: , + data: { + Action: "UploadTemplate", + GUID: "GUID", + }, + fields: [ + { + label: "Repository", + name: "FullName", + type: "select", + api: { + url: "/api/ListCommunityRepos", + data: { + WriteAccess: true, + }, + queryKey: "CommunityRepos-Write", + dataKey: "Results", + valueField: "FullName", + labelField: "FullName", + }, + multiple: false, + creatable: false, + required: true, + validators: { + required: { value: true, message: "This field is required" }, + }, + }, + { + label: "Commit Message", + placeholder: "Enter a commit message for adding this file to GitHub", + name: "Message", + type: "textField", + multiline: true, + required: true, + rows: 4, + }, + ], + confirmText: "Are you sure you want to save this template to the selected repository?", + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, + }, + { + label: "Delete Template", + type: "POST", + url: "/api/RemoveIntuneReusableSettingTemplate", + icon: , + data: { + ID: "GUID", + }, + confirmText: "Do you want to delete the template?", + multiPost: false, + }, + ]; + + const offCanvas = { + children: (row) => , + size: "lg", + }; + + const simpleColumns = ["displayName", "package", "description", "isSynced"]; + + return ( + }> + Add Reusable Settings Template + + } + apiUrl="/api/ListIntuneReusableSettingTemplates" + tenantInTitle={false} + actions={actions} + offCanvas={offCanvas} + simpleColumns={simpleColumns} + queryKey="ListIntuneReusableSettingTemplates-table" + /> + ); +}; + +Page.getLayout = (page) => {page}; +export default Page; diff --git a/src/pages/endpoint/MEM/reusable-settings/edit.jsx b/src/pages/endpoint/MEM/reusable-settings/edit.jsx new file mode 100644 index 000000000000..b6dcd1825ffa --- /dev/null +++ b/src/pages/endpoint/MEM/reusable-settings/edit.jsx @@ -0,0 +1,136 @@ +import { useEffect } from "react"; +import { Alert, Box, Stack } from "@mui/material"; +import { Grid } from "@mui/system"; +import { useForm } from "react-hook-form"; +import { useRouter } from "next/router"; +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import CippFormPage from "/src/components/CippFormPages/CippFormPage"; +import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; +import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; +import CippJsonView from "/src/components/CippFormPages/CippJSONView"; +import { ApiGetCall } from "/src/api/ApiCall"; +import { useSettings } from "/src/hooks/use-settings"; + +const EditReusableSetting = () => { + const router = useRouter(); + const { id, tenant } = router.query; + const { currentTenant } = useSettings(); + + const effectiveTenant = tenant || currentTenant; + + const formControl = useForm({ + mode: "onChange", + defaultValues: { + tenantFilter: effectiveTenant, + }, + }); + + const { reset } = formControl; + + const settingQuery = ApiGetCall({ + url: "/api/ListIntuneReusableSettings", + queryKey: ["ListIntuneReusableSettings", effectiveTenant, id], + enabled: !!id && !!effectiveTenant, + data: { tenantFilter: effectiveTenant, ID: id }, + }); + + const record = Array.isArray(settingQuery.data) ? settingQuery.data[0] : settingQuery.data; + + useEffect(() => { + if (record) { + reset({ + tenantFilter: effectiveTenant, + ID: record.id, + displayName: record.displayName, + description: record.description, + rawJSON: record.RawJSON, + }); + } + }, [record, effectiveTenant, reset]); + + const safeJson = () => { + if (!record?.RawJSON) return null; + try { + return JSON.parse(record.RawJSON); + } catch (e) { + console.error("Failed to parse RawJSON for reusable setting preview", { + error: e, + recordId: record?.id, + }); + return null; + } + }; + + const customDataformatter = (values) => ({ + tenantFilter: values.tenantFilter || effectiveTenant, + ID: values.ID, // forward the existing setting id so the API updates the same record + TemplateId: values.ID, // keep legacy TemplateId for API compatibility + displayName: values.displayName, + description: values.description, + rawJSON: values.rawJSON, + }); + + return ( + + + {settingQuery.isLoading ? ( + + ) : settingQuery.isError || !record ? ( + Error loading reusable setting or setting not found. + ) : ( + + + + + + + + + + + + + + + + + + + )} + + + ); +}; + +EditReusableSetting.getLayout = (page) => {page}; + +export default EditReusableSetting; diff --git a/src/pages/endpoint/MEM/reusable-settings/index.js b/src/pages/endpoint/MEM/reusable-settings/index.js new file mode 100644 index 000000000000..2ac91d5d9955 --- /dev/null +++ b/src/pages/endpoint/MEM/reusable-settings/index.js @@ -0,0 +1,65 @@ +import { Book, DeleteForever } from "@mui/icons-material"; +import { CippReusableSettingsDeployDrawer } from "/src/components/CippComponents/CippReusableSettingsDeployDrawer.jsx"; +import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import { useSettings } from "../../../../hooks/use-settings"; +import CippJsonView from "../../../../components/CippFormPages/CippJSONView"; + +const Page = () => { + const { currentTenant } = useSettings(); + const pageTitle = "Reusable Settings"; + + const actions = [ + { + label: "Edit Reusable Setting", + link: `/endpoint/MEM/reusable-settings/edit?id=[id]&tenant=${currentTenant}&tenantFilter=${currentTenant}`, + }, + { + label: "Delete Reusable Setting", + type: "POST", + url: "/api/RemoveIntuneReusableSetting", + icon: , + color: "error", + data: { + ID: "id", + DisplayName: "displayName", + }, + confirmText: "Delete this reusable setting from the tenant?", + multiPost: false, + }, + { + label: "Create Template from Setting", + type: "POST", + url: "/api/AddIntuneReusableSettingTemplate", + icon: , + data: { + displayName: "displayName", + description: "description", + rawJSON: "RawJSON", + }, + confirmText: "Create a reusable settings template from this entry?", + multiPost: false, + }, + ]; + + const offCanvas = { + children: (row) => , + size: "lg", + }; + + return ( + } + apiUrl="/api/ListIntuneReusableSettings" + queryKey={`ListIntuneReusableSettings-${currentTenant}`} + actions={actions} + offCanvas={offCanvas} + simpleColumns={["displayName", "description", "id", "version"]} + /> + ); +}; + +Page.getLayout = (page) => {page}; + +export default Page; From 0138336bfaa1fb871e17019ccbf66868815a1206 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 11 Feb 2026 11:40:01 -0500 Subject: [PATCH 3/7] Update features.js --- src/pages/cipp/settings/features.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/cipp/settings/features.js b/src/pages/cipp/settings/features.js index 930636e3205c..15b6fd3a111e 100644 --- a/src/pages/cipp/settings/features.js +++ b/src/pages/cipp/settings/features.js @@ -49,7 +49,7 @@ const Page = () => { actions: actions, }; - const simpleColumns = ["Name", "Enabled"]; + const simpleColumns = ["Name", "Enabled", "Description"]; return ( Date: Wed, 11 Feb 2026 23:43:59 +0000 Subject: [PATCH 4/7] Bump @tiptap/starter-kit from 3.13.0 to 3.19.0 Bumps [@tiptap/starter-kit](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/starter-kit) from 3.13.0 to 3.19.0. - [Release notes](https://github.com/ueberdosis/tiptap/releases) - [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.19.0/packages/starter-kit/CHANGELOG.md) - [Commits](https://github.com/ueberdosis/tiptap/commits/v3.19.0/packages/starter-kit) --- updated-dependencies: - dependency-name: "@tiptap/starter-kit" dependency-version: 3.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 250 +++++++++++++++++++++++++-------------------------- 2 files changed, 126 insertions(+), 126 deletions(-) diff --git a/package.json b/package.json index 059e1aabea30..014f40f3f4bf 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@tiptap/extension-table": "^3.4.1", "@tiptap/pm": "^3.4.1", "@tiptap/react": "^3.4.1", - "@tiptap/starter-kit": "^3.4.1", + "@tiptap/starter-kit": "^3.19.0", "@uiw/react-json-view": "^2.0.0-alpha.30", "@vvo/tzdb": "^6.198.0", "apexcharts": "5.3.5", diff --git a/yarn.lock b/yarn.lock index 309852f41632..282446934fc1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2134,20 +2134,20 @@ resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.11.2.tgz#00409e743ac4eea9afe5b7708594d5fcebb00212" integrity sha512-vTtpNt7mKCiZ1pwU9hfKPhpdVO2sVzFQsxoVBGtOSHxlrRRzYr8iQ2TlwbAcRYCcEiZ9ECAM8kBzH0v2+VzfKw== -"@tiptap/core@^3.13.0", "@tiptap/core@^3.4.1": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-3.13.0.tgz#ae3fe6fe7732f36b6ea8a2198e1fc53a4ad0d0d2" - integrity sha512-iUelgiTMgPVMpY5ZqASUpk8mC8HuR9FWKaDzK27w9oWip9tuB54Z8mePTxNcQaSPb6ErzEaC8x8egrRt7OsdGQ== +"@tiptap/core@^3.19.0", "@tiptap/core@^3.4.1": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-3.19.0.tgz#dca483b50e1b8a596f695aecde387a79fe7da717" + integrity sha512-bpqELwPW+DG8gWiD8iiFtSl4vIBooG5uVJod92Qxn3rA9nFatyXRr4kNbMJmOZ66ezUvmCjXVe/5/G4i5cyzKA== -"@tiptap/extension-blockquote@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-3.13.0.tgz#33508ad7f0bd4d74d5065f11d6e33c50ef8835a2" - integrity sha512-K1z/PAIIwEmiWbzrP//4cC7iG1TZknDlF1yb42G7qkx2S2X4P0NiqX7sKOej3yqrPjKjGwPujLMSuDnCF87QkQ== +"@tiptap/extension-blockquote@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-3.19.0.tgz#86c52e8e3b6d1e072ae0d9c895723034a1e37096" + integrity sha512-y3UfqY9KD5XwWz3ndiiJ089Ij2QKeiXy/g1/tlAN/F1AaWsnkHEHMLxCP1BIqmMpwsX7rZjMLN7G5Lp7c9682A== -"@tiptap/extension-bold@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-3.13.0.tgz#1fbff35b20da292172fc5a1886576c3410e1e3ca" - integrity sha512-VYiDN9EEwR6ShaDLclG8mphkb/wlIzqfk7hxaKboq1G+NSDj8PcaSI9hldKKtTCLeaSNu6UR5nkdu/YHdzYWTw== +"@tiptap/extension-bold@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-3.19.0.tgz#ef0ddfd9b242ef9c25e3348aef9bf2dc681cdc19" + integrity sha512-UZgb1d0XK4J/JRIZ7jW+s4S6KjuEDT2z1PPM6ugcgofgJkWQvRZelCPbmtSFd3kwsD+zr9UPVgTh9YIuGQ8t+Q== "@tiptap/extension-bubble-menu@^3.13.0": version "3.13.0" @@ -2156,127 +2156,127 @@ dependencies: "@floating-ui/dom" "^1.0.0" -"@tiptap/extension-bullet-list@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-3.13.0.tgz#277c9380704f618d71b63278da7bba45ed2b7905" - integrity sha512-fFQmmEUoPzRGiQJ/KKutG35ZX21GE+1UCDo8Q6PoWH7Al9lex47nvyeU1BiDYOhcTKgIaJRtEH5lInsOsRJcSA== +"@tiptap/extension-bullet-list@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-3.19.0.tgz#acf12e952b6a5873dc20b58530f2f524807bbd6f" + integrity sha512-F9uNnqd0xkJbMmRxVI5RuVxwB9JaCH/xtRqOUNQZnRBt7IdAElCY+Dvb4hMCtiNv+enGM/RFGJuFHR9TxmI7rw== -"@tiptap/extension-code-block@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-3.13.0.tgz#ded41a224db15e938c6a871462a0c33c00acd657" - integrity sha512-kIwfQ4iqootsWg9e74iYJK54/YMIj6ahUxEltjZRML5z/h4gTDcQt2eTpnEC8yjDjHeUVOR94zH9auCySyk9CQ== +"@tiptap/extension-code-block@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-3.19.0.tgz#71a7a362b3fa68c1789c8b9ac224ca89eb410630" + integrity sha512-b/2qR+tMn8MQb+eaFYgVk4qXnLNkkRYmwELQ8LEtEDQPxa5Vl7J3eu8+4OyoIFhZrNDZvvoEp80kHMCP8sI6rg== -"@tiptap/extension-code@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-3.13.0.tgz#7c05fb8477356aebe8b1f00117a32d3abbf24357" - integrity sha512-sF5raBni6iSVpXWvwJCAcOXw5/kZ+djDHx1YSGWhopm4+fsj0xW7GvVO+VTwiFjZGKSw+K5NeAxzcQTJZd3Vhw== +"@tiptap/extension-code@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-3.19.0.tgz#15d53c139ad64d1debcc08c7ca5afbcc8e531f0b" + integrity sha512-2kqqQIXBXj2Or+4qeY3WoE7msK+XaHKL6EKOcKlOP2BW8eYqNTPzNSL+PfBDQ3snA7ljZQkTs/j4GYDj90vR1A== -"@tiptap/extension-document@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-3.13.0.tgz#74757e23bf92bba82226a91580ce738bc68bd3af" - integrity sha512-RjU7hTJwjKXIdY57o/Pc+Yr8swLkrwT7PBQ/m+LCX5oO/V2wYoWCjoBYnK5KSHrWlNy/aLzC33BvLeqZZ9nzlQ== +"@tiptap/extension-document@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-3.19.0.tgz#dfa6889cff748d489e0bc1028918bf4571372ba5" + integrity sha512-AOf0kHKSFO0ymjVgYSYDncRXTITdTcrj1tqxVazrmO60KNl1Rc2dAggDvIVTEBy5NvceF0scc7q3sE/5ZtVV7A== -"@tiptap/extension-dropcursor@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.13.0.tgz#04f7659c86558ebeb068fd7d5c2474d8bd28b430" - integrity sha512-m7GPT3c/83ni+bbU8c+3dpNa8ug+aQ4phNB1Q52VQG3oTonDJnZS7WCtn3lB/Hi1LqoqMtEHwhepU2eD+JeXqQ== +"@tiptap/extension-dropcursor@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.19.0.tgz#fbef441944842f23fe0a35154b519103166a4848" + integrity sha512-sf3dEZXiLvsGqVK2maUIzXY6qtYYCvBumag7+VPTMGQ0D4hiZ1X/4ukt4+6VXDg5R2WP1CoIt/QvUetUjWNhbQ== "@tiptap/extension-floating-menu@^3.13.0": version "3.13.0" resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.13.0.tgz#03d03292add49d1b380cdb1ff3890b2956d4e3f5" integrity sha512-OsezV2cMofZM4c13gvgi93IEYBUzZgnu8BXTYZQiQYekz4bX4uulBmLa1KOA9EN71FzS+SoLkXHU0YzlbLjlxA== -"@tiptap/extension-gapcursor@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-3.13.0.tgz#5e4fbd3b066fa10656314bbbff2e329709be5d2c" - integrity sha512-KVxjQKkd964nin+1IdM2Dvej/Jy4JTMcMgq5seusUhJ9T9P8F9s2D5Iefwgkps3OCzub/aF+eAsZe+1P5KSIgA== +"@tiptap/extension-gapcursor@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-3.19.0.tgz#64e5462a4ab2f0bd110738410dcbf3597d76349f" + integrity sha512-w7DACS4oSZaDWjz7gropZHPc9oXqC9yERZTcjWxyORuuIh1JFf0TRYspleK+OK28plK/IftojD/yUDn1MTRhvA== -"@tiptap/extension-hard-break@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-3.13.0.tgz#b1444339c544f27fe8cff8dcbdb99007e0cdc3e1" - integrity sha512-nH1OBaO+/pakhu+P1jF208mPgB70IKlrR/9d46RMYoYbqJTNf4KVLx5lHAOHytIhjcNg+MjyTfJWfkK+dyCCyg== +"@tiptap/extension-hard-break@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-3.19.0.tgz#7120524cec9ed4b957963693cb4c57cbecbaecf8" + integrity sha512-lAmQraYhPS5hafvCl74xDB5+bLuNwBKIEsVoim35I0sDJj5nTrfhaZgMJ91VamMvT+6FF5f1dvBlxBxAWa8jew== -"@tiptap/extension-heading@^3.13.0", "@tiptap/extension-heading@^3.4.1": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-3.13.0.tgz#ead7f224de24ac66bb198cabe6b2af9617967583" - integrity sha512-8VKWX8waYPtUWN97J89em9fOtxNteh6pvUEd0htcOAtoxjt2uZjbW5N4lKyWhNKifZBrVhH2Cc2NUPuftCVgxw== +"@tiptap/extension-heading@^3.19.0", "@tiptap/extension-heading@^3.4.1": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-3.19.0.tgz#d0bc93426c01a2ed36b9124c1a8205ab3945e77a" + integrity sha512-uLpLlfyp086WYNOc0ekm1gIZNlEDfmzOhKzB0Hbyi6jDagTS+p9mxUNYeYOn9jPUxpFov43+Wm/4E24oY6B+TQ== -"@tiptap/extension-horizontal-rule@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.13.0.tgz#c51eb35f3b3bf6308ab6b354a06c0e96c19dbff6" - integrity sha512-ZUFyORtjj22ib8ykbxRhWFQOTZjNKqOsMQjaAGof30cuD2DN5J5pMz7Haj2fFRtLpugWYH+f0Mi+WumQXC3hCw== +"@tiptap/extension-horizontal-rule@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.19.0.tgz#0e77078fcd53beca786277ce83d259e2103cc361" + integrity sha512-iqUHmgMGhMgYGwG6L/4JdelVQ5Mstb4qHcgTGd/4dkcUOepILvhdxajPle7OEdf9sRgjQO6uoAU5BVZVC26+ng== "@tiptap/extension-image@^3.4.1": version "3.13.0" resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-3.13.0.tgz#55edb952e86c2ebed436cd53def8b2e743d71d7e" integrity sha512-223uzLUkIa1rkK7aQK3AcIXe6LbCtmnpVb7sY5OEp+LpSaSPyXwyrZ4A0EO1o98qXG68/0B2OqMntFtA9c5Fbw== -"@tiptap/extension-italic@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-3.13.0.tgz#c855521360c8079574f7b0855148e4f561ba396a" - integrity sha512-XbVTgmzk1kgUMTirA6AGdLTcKHUvEJoh3R4qMdPtwwygEOe7sBuvKuLtF6AwUtpnOM+Y3tfWUTNEDWv9AcEdww== +"@tiptap/extension-italic@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-3.19.0.tgz#af2a9c095ec846e379041f3e17e1dd101a5a4bf8" + integrity sha512-6GffxOnS/tWyCbDkirWNZITiXRta9wrCmrfa4rh+v32wfaOL1RRQNyqo9qN6Wjyl1R42Js+yXTzTTzZsOaLMYA== -"@tiptap/extension-link@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-3.13.0.tgz#c6b087a39860068b93d1fb8fcbebbd360f0188b4" - integrity sha512-LuFPJ5GoL12GHW4A+USsj60O90pLcwUPdvEUSWewl9USyG6gnLnY/j5ZOXPYH7LiwYW8+lhq7ABwrDF2PKyBbA== +"@tiptap/extension-link@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-3.19.0.tgz#e8e656735bda6ca1d4b6577821e06274ab0ff6c8" + integrity sha512-HEGDJnnCPfr7KWu7Dsq+eRRe/mBCsv6DuI+7fhOCLDJjjKzNgrX2abbo/zG3D/4lCVFaVb+qawgJubgqXR/Smw== dependencies: linkifyjs "^4.3.2" -"@tiptap/extension-list-item@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-3.13.0.tgz#03f17af7ed2d0643638e07ce96ad0f9c044ff69b" - integrity sha512-63NbcS/XeQP2jcdDEnEAE3rjJICDj8y1SN1h/MsJmSt1LusnEo8WQ2ub86QELO6XnD3M04V03cY6Knf6I5mTkw== +"@tiptap/extension-list-item@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-3.19.0.tgz#b2218ff6be694b581fd7d817810a33ee1c218311" + integrity sha512-VsSKuJz4/Tb6ZmFkXqWpDYkRzmaLTyE6dNSEpNmUpmZ32sMqo58mt11/huADNwfBFB0Ve7siH/VnFNIJYY3xvg== -"@tiptap/extension-list-keymap@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list-keymap/-/extension-list-keymap-3.13.0.tgz#75ee2c28f5d944c407309ce987d07ae23c4cd45a" - integrity sha512-P+HtIa1iwosb1feFc8B/9MN5EAwzS+/dZ0UH0CTF2E4wnp5Z9OMxKl1IYjfiCwHzZrU5Let+S/maOvJR/EmV0g== +"@tiptap/extension-list-keymap@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-keymap/-/extension-list-keymap-3.19.0.tgz#41b87b154560aad92e779bff5c6e32e125b792ea" + integrity sha512-bxgmAgA3RzBGA0GyTwS2CC1c+QjkJJq9hC+S6PSOWELGRiTbwDN3MANksFXLjntkTa0N5fOnL27vBHtMStURqw== -"@tiptap/extension-list@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list/-/extension-list-3.13.0.tgz#6981a395f2fbe46d9ad20deb75cf65aa9e33feba" - integrity sha512-MMFH0jQ4LeCPkJJFyZ77kt6eM/vcKujvTbMzW1xSHCIEA6s4lEcx9QdZMPpfmnOvTzeoVKR4nsu2t2qT9ZXzAw== +"@tiptap/extension-list@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list/-/extension-list-3.19.0.tgz#737dcb56ba9838a4431c1afb035bd622fab46d21" + integrity sha512-N6nKbFB2VwMsPlCw67RlAtYSK48TAsAUgjnD+vd3ieSlIufdQnLXDFUP6hFKx9mwoUVUgZGz02RA6bkxOdYyTw== -"@tiptap/extension-ordered-list@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-3.13.0.tgz#552d4a57e9116fd7d32e49c5cdc346baf0bbfd74" - integrity sha512-QuDyLzuK/3vCvx9GeKhgvHWrGECBzmJyAx6gli2HY+Iil7XicbfltV4nvhIxgxzpx3LDHLKzJN9pBi+2MzX60g== +"@tiptap/extension-ordered-list@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-3.19.0.tgz#f6f8bfe41d3429c505b44764b473b6dfd7bcd2a1" + integrity sha512-cxGsINquwHYE1kmhAcLNLHAofmoDEG6jbesR5ybl7tU5JwtKVO7S/xZatll2DU1dsDAXWPWEeeMl4e/9svYjCg== -"@tiptap/extension-paragraph@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-3.13.0.tgz#01881b5954136de5059e7882be5b210eca0dac46" - integrity sha512-9csQde1i0yeZI5oQQ9e1GYNtGL2JcC2d8Fwtw9FsGC8yz2W0h+Fmk+3bc2kobbtO5LGqupSc1fKM8fAg5rSRDg== +"@tiptap/extension-paragraph@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-3.19.0.tgz#91adde189aabf13a2bfbb2d961833d3bc2bc055f" + integrity sha512-xWa6gj82l5+AzdYyrSk9P4ynySaDzg/SlR1FarXE5yPXibYzpS95IWaVR0m2Qaz7Rrk+IiYOTGxGRxcHLOelNg== -"@tiptap/extension-strike@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.13.0.tgz#f753bae727549fb32ee9251036890ed5f39bc443" - integrity sha512-VHhWNqTAMOfrC48m2FcPIZB0nhl6XHQviAV16SBc+EFznKNv9tQUsqQrnuQ2y6ZVfqq5UxvZ3hKF/JlN/Ff7xw== +"@tiptap/extension-strike@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.19.0.tgz#eac7712cc791488f4c1c48baf3aed1a8d95f398c" + integrity sha512-xYpabHsv7PccLUBQaP8AYiFCnYbx6P93RHPd0lgNwhdOjYFd931Zy38RyoxPHAgbYVmhf1iyx7lpuLtBnhS5dA== "@tiptap/extension-table@^3.4.1": version "3.13.0" resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-3.13.0.tgz#83283bc818582e621cefabf173beeb37fe6f30ba" integrity sha512-LcH9KE4QBUJ6IPwt1Uo5iU7zatFjUUvXbctIu2fKQ9nqJ7nNSFxRhkNyporVFkTWYH7/rb0qMoF1VxSUGefG5w== -"@tiptap/extension-text@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.13.0.tgz#90d38438eb99135b1221d7f2944a06545f21d39d" - integrity sha512-VcZIna93rixw7hRkHGCxDbL3kvJWi80vIT25a2pXg0WP1e7Pi3nBYvZIL4SQtkbBCji9EHrbZx3p8nNPzfazYw== +"@tiptap/extension-text@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.19.0.tgz#353278c97bd8f5bdc29f06942fbd1e856bdb5b18" + integrity sha512-K95+SnbZy0h6hNFtfy23n8t/nOcTFEf69In9TSFVVmwn/Nwlke+IfiESAkqbt1/7sKJeegRXYO7WzFEmFl9Q/g== -"@tiptap/extension-underline@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-3.13.0.tgz#7fc969c3b7adc7d7cc7def498f85c4cb30cf3aba" - integrity sha512-VDQi+UYw0tFnfghpthJTFmtJ3yx90kXeDwFvhmT8G+O+si5VmP05xYDBYBmYCix5jqKigJxEASiBL0gYOgMDEg== +"@tiptap/extension-underline@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-3.19.0.tgz#bbc81d085725981d256127ab416f91d0802ec2a4" + integrity sha512-800MGEWfG49j10wQzAFiW/ele1HT04MamcL8iyuPNu7ZbjbGN2yknvdrJlRy7hZlzIrVkZMr/1tz62KN33VHIw== -"@tiptap/extensions@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/extensions/-/extensions-3.13.0.tgz#542ee8a97575ae32090302b7f09522e025715297" - integrity sha512-i7O0ptSibEtTy+2PIPsNKEvhTvMaFJg1W4Oxfnbuxvaigs7cJV9Q0lwDUcc7CPsNw2T1+44wcxg431CzTvdYoA== +"@tiptap/extensions@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/extensions/-/extensions-3.19.0.tgz#5747c0ebf460b9669e8b4362561872448f66abfe" + integrity sha512-ZmGUhLbMWaGqnJh2Bry+6V4M6gMpUDYo4D1xNux5Gng/E/eYtc+PMxMZ/6F7tNTAuujLBOQKj6D+4SsSm457jw== -"@tiptap/pm@^3.13.0", "@tiptap/pm@^3.4.1": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-3.13.0.tgz#d01e9f08e2be3e6bfa69ed4457a1c2fee87157b3" - integrity sha512-WKR4ucALq+lwx0WJZW17CspeTpXorbIOpvKv5mulZica6QxqfMhn8n1IXCkDws/mCoLRx4Drk5d377tIjFNsvQ== +"@tiptap/pm@^3.19.0", "@tiptap/pm@^3.4.1": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-3.19.0.tgz#5cb499c7b2603ec6550d0c7a70b924f27fdb7692" + integrity sha512-789zcnM4a8OWzvbD2DL31d0wbSm9BVeO/R7PLQwLIGysDI3qzrcclyZ8yhqOEVuvPitRRwYLq+mY14jz7kY4cw== dependencies: prosemirror-changeset "^2.3.0" prosemirror-collab "^1.3.1" @@ -2309,35 +2309,35 @@ "@tiptap/extension-bubble-menu" "^3.13.0" "@tiptap/extension-floating-menu" "^3.13.0" -"@tiptap/starter-kit@^3.4.1": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-3.13.0.tgz#7f803f0e089a7c2cbd016ad79b257c4cbe910208" - integrity sha512-Ojn6sRub04CRuyQ+9wqN62JUOMv+rG1vXhc2s6DCBCpu28lkCMMW+vTe7kXJcEdbot82+5swPbERw9vohswFzg== - dependencies: - "@tiptap/core" "^3.13.0" - "@tiptap/extension-blockquote" "^3.13.0" - "@tiptap/extension-bold" "^3.13.0" - "@tiptap/extension-bullet-list" "^3.13.0" - "@tiptap/extension-code" "^3.13.0" - "@tiptap/extension-code-block" "^3.13.0" - "@tiptap/extension-document" "^3.13.0" - "@tiptap/extension-dropcursor" "^3.13.0" - "@tiptap/extension-gapcursor" "^3.13.0" - "@tiptap/extension-hard-break" "^3.13.0" - "@tiptap/extension-heading" "^3.13.0" - "@tiptap/extension-horizontal-rule" "^3.13.0" - "@tiptap/extension-italic" "^3.13.0" - "@tiptap/extension-link" "^3.13.0" - "@tiptap/extension-list" "^3.13.0" - "@tiptap/extension-list-item" "^3.13.0" - "@tiptap/extension-list-keymap" "^3.13.0" - "@tiptap/extension-ordered-list" "^3.13.0" - "@tiptap/extension-paragraph" "^3.13.0" - "@tiptap/extension-strike" "^3.13.0" - "@tiptap/extension-text" "^3.13.0" - "@tiptap/extension-underline" "^3.13.0" - "@tiptap/extensions" "^3.13.0" - "@tiptap/pm" "^3.13.0" +"@tiptap/starter-kit@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-3.19.0.tgz#312440bd18c3cce379ea8eab3fe174b8141dd313" + integrity sha512-dTCkHEz+Y8ADxX7h+xvl6caAj+3nII/wMB1rTQchSuNKqJTOrzyUsCWm094+IoZmLT738wANE0fRIgziNHs/ug== + dependencies: + "@tiptap/core" "^3.19.0" + "@tiptap/extension-blockquote" "^3.19.0" + "@tiptap/extension-bold" "^3.19.0" + "@tiptap/extension-bullet-list" "^3.19.0" + "@tiptap/extension-code" "^3.19.0" + "@tiptap/extension-code-block" "^3.19.0" + "@tiptap/extension-document" "^3.19.0" + "@tiptap/extension-dropcursor" "^3.19.0" + "@tiptap/extension-gapcursor" "^3.19.0" + "@tiptap/extension-hard-break" "^3.19.0" + "@tiptap/extension-heading" "^3.19.0" + "@tiptap/extension-horizontal-rule" "^3.19.0" + "@tiptap/extension-italic" "^3.19.0" + "@tiptap/extension-link" "^3.19.0" + "@tiptap/extension-list" "^3.19.0" + "@tiptap/extension-list-item" "^3.19.0" + "@tiptap/extension-list-keymap" "^3.19.0" + "@tiptap/extension-ordered-list" "^3.19.0" + "@tiptap/extension-paragraph" "^3.19.0" + "@tiptap/extension-strike" "^3.19.0" + "@tiptap/extension-text" "^3.19.0" + "@tiptap/extension-underline" "^3.19.0" + "@tiptap/extensions" "^3.19.0" + "@tiptap/pm" "^3.19.0" "@trysound/sax@0.2.0": version "0.2.0" From 19b1ec9b85f50fa6bda7a42b42024b9346bb5fd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:44:10 +0000 Subject: [PATCH 5/7] Bump monaco-editor from 0.53.0 to 0.55.1 Bumps [monaco-editor](https://github.com/microsoft/monaco-editor) from 0.53.0 to 0.55.1. - [Release notes](https://github.com/microsoft/monaco-editor/releases) - [Changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md) - [Commits](https://github.com/microsoft/monaco-editor/compare/v0.53.0...v0.55.1) --- updated-dependencies: - dependency-name: monaco-editor dependency-version: 0.55.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 059e1aabea30..2acadc977386 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "leaflet.markercluster": "^1.5.3", "lodash.isequal": "4.5.0", "material-react-table": "^3.0.1", - "monaco-editor": "^0.53.0", + "monaco-editor": "^0.55.1", "mui-tiptap": "^1.14.0", "next": "^16.1.2", "nprogress": "0.2.0", diff --git a/yarn.lock b/yarn.lock index 309852f41632..286ffea43432 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2567,11 +2567,6 @@ dependencies: csstype "^3.2.2" -"@types/trusted-types@^1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.6.tgz#569b8a08121d3203398290d602d84d73c8dcf5da" - integrity sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw== - "@types/trusted-types@^2.0.7": version "2.0.7" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" @@ -3728,6 +3723,13 @@ domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +dompurify@3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.2.7.tgz#721d63913db5111dd6dfda8d3a748cfd7982d44a" + integrity sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw== + optionalDependencies: + "@types/trusted-types" "^2.0.7" + dompurify@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.3.1.tgz#c7e1ddebfe3301eacd6c0c12a4af284936dbbb86" @@ -5360,6 +5362,11 @@ markdown-table@^3.0.0: resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.4.tgz#fe44d6d410ff9d6f2ea1797a3f60aa4d2b631c2a" integrity sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw== +marked@14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-14.0.0.tgz#79a1477358a59e0660276f8fec76de2c33f35d83" + integrity sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ== + material-react-table@^3.0.1: version "3.2.1" resolved "https://registry.yarnpkg.com/material-react-table/-/material-react-table-3.2.1.tgz#56f595755cab3b669b399999fed9eb305fbb6dd7" @@ -5902,12 +5909,13 @@ minimist@^1.2.0, minimist@^1.2.6, minimist@~1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -monaco-editor@^0.53.0: - version "0.53.0" - resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.53.0.tgz#2f485492e0ee822be13b1b45e3092922963737ae" - integrity sha512-0WNThgC6CMWNXXBxTbaYYcunj08iB5rnx4/G56UOPeL9UVIUGGHA1GR0EWIh9Ebabj7NpCRawQ5b0hfN1jQmYQ== +monaco-editor@^0.55.1: + version "0.55.1" + resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.55.1.tgz#e74c6fe5a6bf985b817d2de3eb88d56afc494a1b" + integrity sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A== dependencies: - "@types/trusted-types" "^1.0.6" + dompurify "3.2.7" + marked "14.0.0" ms@^2.1.1, ms@^2.1.3: version "2.1.3" From 7625d3ffa4a9b738b1ea506eeb90709605745cd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:45:02 +0000 Subject: [PATCH 6/7] Bump javascript-time-ago from 2.5.12 to 2.6.2 Bumps [javascript-time-ago](https://gitlab.com/catamphetamine/javascript-time-ago) from 2.5.12 to 2.6.2. - [Changelog](https://gitlab.com/catamphetamine/javascript-time-ago/blob/main/CHANGELOG.md) - [Commits](https://gitlab.com/catamphetamine/javascript-time-ago/compare/v2.5.12...v2.6.2) --- updated-dependencies: - dependency-name: javascript-time-ago dependency-version: 2.6.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 059e1aabea30..99653da72b5e 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "formik": "2.4.6", "gray-matter": "4.0.3", "i18next": "25.5.2", - "javascript-time-ago": "^2.5.11", + "javascript-time-ago": "^2.6.2", "jspdf": "^4.1.0", "jspdf-autotable": "^5.0.2", "leaflet": "^1.9.4", diff --git a/yarn.lock b/yarn.lock index 309852f41632..da73af1a0788 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5100,12 +5100,12 @@ iterator.prototype@^1.1.5: has-symbols "^1.1.0" set-function-name "^2.0.2" -javascript-time-ago@^2.5.11: - version "2.5.12" - resolved "https://registry.yarnpkg.com/javascript-time-ago/-/javascript-time-ago-2.5.12.tgz#b789f5c84b0518b38700722627c404a09299c5f9" - integrity sha512-s8PPq2HQ3HIbSU0SjhNvTitf5VoXbQWof9q6k3gIX7F2il0ptjD5lONTDccpuKt/2U7RjbCp/TCHPK7eDwO7zQ== +javascript-time-ago@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/javascript-time-ago/-/javascript-time-ago-2.6.2.tgz#b66ada9080440c472e53845d7912e9d2e7088045" + integrity sha512-gagMB4fetS1M1ZHaxQ9kX2amORXa5Los5PGh8NZzWSKrytz43KnpJlaPFTXbg/R7iPMN7U/6MoevgxqJ0QQ5lA== dependencies: - relative-time-format "^1.1.7" + relative-time-format "^1.1.11" jay-peg@^1.1.1: version "1.1.1" @@ -6918,7 +6918,7 @@ rehype-raw@^7.0.0: hast-util-raw "^9.0.0" vfile "^6.0.0" -relative-time-format@^1.1.7: +relative-time-format@^1.1.11: version "1.1.11" resolved "https://registry.yarnpkg.com/relative-time-format/-/relative-time-format-1.1.11.tgz#b193d5192434e7c1c6a53e362f811c68a4f18c45" integrity sha512-TH+oV/w77hjaB9xCzoFYJ/Icmr/12+02IAoCI/YGS2UBTbjCbBjHGEBxGnVy4EJvOR1qadGzyFRI6hGaJJG93Q== From b2389b2778dde2024035927186670f4b28fddc48 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 11 Feb 2026 18:57:18 -0500 Subject: [PATCH 7/7] Add Overwrite switch to template creation UI Add an "Overwrite" switch field to the deployment template creation dialogs for App Registrations and Enterprise Apps so users can choose to overwrite an existing template when creating one. Also included a minor formatting change (trailing comma) in the new Date(...) call used for credential expiration labels. --- .../administration/applications/app-registrations.js | 9 ++++++++- .../administration/applications/enterprise-apps.js | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/pages/tenant/administration/applications/app-registrations.js b/src/pages/tenant/administration/applications/app-registrations.js index 74dcf8b4e072..1adcf038947c 100644 --- a/src/pages/tenant/administration/applications/app-registrations.js +++ b/src/pages/tenant/administration/applications/app-registrations.js @@ -47,6 +47,13 @@ const Page = () => { DisplayName: "displayName", Type: "application", }, + fields: [ + { + type: "switch", + name: "Overwrite", + label: "Overwrite Existing Template", + }, + ], confirmText: "Create a deployment template from '[displayName]'? This will copy all permissions and create a reusable template. If you run this from a customer tenant, the App Registration will first be copied to the partner tenant as a multi-tenant app.", condition: (row) => canWriteApplication && !row?.applicationTemplateId, @@ -130,7 +137,7 @@ const Page = () => { options={ row?.passwordCredentials?.map((cred) => ({ label: `${cred.displayName || "Unnamed"} (Expiration: ${new Date( - cred.endDateTime + cred.endDateTime, ).toLocaleDateString()})`, value: cred.keyId, })) || [] diff --git a/src/pages/tenant/administration/applications/enterprise-apps.js b/src/pages/tenant/administration/applications/enterprise-apps.js index 39aac9021b60..6a408ca37021 100644 --- a/src/pages/tenant/administration/applications/enterprise-apps.js +++ b/src/pages/tenant/administration/applications/enterprise-apps.js @@ -49,6 +49,13 @@ const Page = () => { DisplayName: "displayName", Type: "servicePrincipal", }, + fields: [ + { + type: "switch", + name: "Overwrite", + label: "Overwrite Existing Template", + }, + ], confirmText: "Create a deployment template from '[displayName]'? This will copy all permissions and create a reusable template.", condition: (row) => canWriteApplication && row?.signInAudience === "AzureADMultipleOrgs", @@ -78,7 +85,7 @@ const Page = () => { options={ row?.passwordCredentials?.map((cred) => ({ label: `${cred.displayName || "Unnamed"} (Expiration: ${new Date( - cred.endDateTime + cred.endDateTime, ).toLocaleDateString()})`, value: cred.keyId, })) || []