From ff1928192988ffb11aa57a798a39679e94891932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 21 Jan 2025 01:08:55 +0100 Subject: [PATCH 001/231] Change Delete Policy request type from GET to POST --- src/pages/endpoint/MEM/list-policies/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/endpoint/MEM/list-policies/index.js b/src/pages/endpoint/MEM/list-policies/index.js index 299881df53fe..21c2f1962a24 100644 --- a/src/pages/endpoint/MEM/list-policies/index.js +++ b/src/pages/endpoint/MEM/list-policies/index.js @@ -60,7 +60,7 @@ const Page = () => { }, { label: "Delete Policy", - type: "GET", + type: "POST", url: "/api/RemovePolicy", data: { ID: "id", From fe3b29355744e49dd08b669ad35c086d8a49f812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 21 Jan 2025 01:09:07 +0100 Subject: [PATCH 002/231] Add "Scripts" menu item to the endpoint navigation --- src/layouts/config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/layouts/config.js b/src/layouts/config.js index e74843605127..3ba6ec3a98b1 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -251,6 +251,7 @@ export const nativeMenuItems = [ { title: "Protection Policies", path: "/endpoint/MEM/list-appprotection-policies" }, { title: "Apply Policy", path: "/endpoint/MEM/add-policy" }, { title: "Policy Templates", path: "/endpoint/MEM/list-templates" }, + { title: "Scripts", path: "/endpoint/MEM/list-scripts" }, ], }, { From 1f3b7558adacf81b570e05a37010d4ddcd9fc1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 21 Jan 2025 01:21:07 +0100 Subject: [PATCH 003/231] Add Intune scripts page --- src/pages/endpoint/MEM/list-scripts/index.js | 69 ++++++++++++++++++ src/pages/endpoint/MEM/list-scripts/linux.js | 61 ++++++++++++++++ src/pages/endpoint/MEM/list-scripts/macOS.js | 70 +++++++++++++++++++ .../endpoint/MEM/list-scripts/remediation.js | 69 ++++++++++++++++++ .../endpoint/MEM/list-scripts/tabOptions.json | 18 +++++ 5 files changed, 287 insertions(+) create mode 100644 src/pages/endpoint/MEM/list-scripts/index.js create mode 100644 src/pages/endpoint/MEM/list-scripts/linux.js create mode 100644 src/pages/endpoint/MEM/list-scripts/macOS.js create mode 100644 src/pages/endpoint/MEM/list-scripts/remediation.js create mode 100644 src/pages/endpoint/MEM/list-scripts/tabOptions.json diff --git a/src/pages/endpoint/MEM/list-scripts/index.js b/src/pages/endpoint/MEM/list-scripts/index.js new file mode 100644 index 000000000000..6ce9383bb2fd --- /dev/null +++ b/src/pages/endpoint/MEM/list-scripts/index.js @@ -0,0 +1,69 @@ +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Code, TrashIcon } from "@heroicons/react/24/outline"; +import { TabbedLayout } from "/src/layouts/TabbedLayout"; +import tabOptions from "./tabOptions"; + +const Page = () => { + const pageTitle = "Windows Scripts"; + + const actions = [ + { + label: "Delete Script", + type: "POST", + url: "/api/RemoveIntuneScript", + data: { + ID: "id", + displayName: "displayName", + ScriptType: "!windows", + }, + confirmText: "Are you sure you want to delete this script?", + icon: , + color: "danger", + }, + ]; + + const offCanvas = { + extendedInfoFields: [ + "id", + "fileName", + "displayName", + "description", + "lastModifiedDateTime", + "createdDateTime", + ], + actions: actions, + }; + + const simpleColumns = [ + "displayName", + "description", + "runAsAccount", + "runAs32Bit", + "enforceSignatureCheck", + "lastModifiedDateTime", + ]; + + return ( + + ); +}; + +Page.getLayout = (page) => ( + + {page} + +); +export default Page; diff --git a/src/pages/endpoint/MEM/list-scripts/linux.js b/src/pages/endpoint/MEM/list-scripts/linux.js new file mode 100644 index 000000000000..be139e47205f --- /dev/null +++ b/src/pages/endpoint/MEM/list-scripts/linux.js @@ -0,0 +1,61 @@ +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Code, TrashIcon } from "@heroicons/react/24/outline"; +import { TabbedLayout } from "/src/layouts/TabbedLayout"; +import tabOptions from "./tabOptions"; + +const Page = () => { + const pageTitle = "Linux Scripts"; + + const actions = [ + { + label: "Delete Script", + type: "POST", + url: "/api/RemovePolicy", + data: { + ID: "id", + URLName: "URLName", + }, + confirmText: "Are you sure you want to delete this script?", + icon: , + color: "danger", + }, + ]; + + const offCanvas = { + extendedInfoFields: [ + "id", + "displayName", + "description", + "lastModifiedDateTime", + "createdDateTime", + ], + actions: actions, + }; + + const simpleColumns = [ + "displayName", + "description", + "runAsAccount", + "executionFrequency", + "enforceSignatureCheck", + "lastModifiedDateTime", + ]; + + return ( + + ); +}; + +Page.getLayout = (page) => ( + + {page} + +); +export default Page; diff --git a/src/pages/endpoint/MEM/list-scripts/macOS.js b/src/pages/endpoint/MEM/list-scripts/macOS.js new file mode 100644 index 000000000000..5fcf6fca1202 --- /dev/null +++ b/src/pages/endpoint/MEM/list-scripts/macOS.js @@ -0,0 +1,70 @@ +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Code, TrashIcon } from "@heroicons/react/24/outline"; +import { TabbedLayout } from "/src/layouts/TabbedLayout"; +import tabOptions from "./tabOptions"; + +const Page = () => { + const pageTitle = "MacOS Scripts"; + + const actions = [ + { + label: "Delete Script", + type: "POST", + url: "/api/RemoveIntuneScript", + data: { + ID: "id", + displayName: "displayName", + ScriptType: "!macOS", + }, + confirmText: "Are you sure you want to delete this script?", + icon: , + color: "danger", + }, + ]; + + const offCanvas = { + extendedInfoFields: [ + "id", + "fileName", + "displayName", + "description", + "lastModifiedDateTime", + "createdDateTime", + "retryCount", + ], + actions: actions, + }; + + const simpleColumns = [ + "displayName", + "description", + "runAsAccount", + "executionFrequency", + "enforceSignatureCheck", + "lastModifiedDateTime", + ]; + + return ( + + ); +}; + +Page.getLayout = (page) => ( + + {page} + +); +export default Page; diff --git a/src/pages/endpoint/MEM/list-scripts/remediation.js b/src/pages/endpoint/MEM/list-scripts/remediation.js new file mode 100644 index 000000000000..f08106b87099 --- /dev/null +++ b/src/pages/endpoint/MEM/list-scripts/remediation.js @@ -0,0 +1,69 @@ +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Code, TrashIcon } from "@heroicons/react/24/outline"; +import { TabbedLayout } from "/src/layouts/TabbedLayout"; +import tabOptions from "./tabOptions"; + +const Page = () => { + const pageTitle = "Remediation Scripts"; + + const actions = [ + { + label: "Delete Script", + type: "POST", + url: "/api/RemoveIntuneScript", + data: { + ID: "id", + displayName: "displayName", + ScriptType: "!remediate", + }, + confirmText: "Are you sure you want to delete this script?", + icon: , + color: "danger", + }, + ]; + + const offCanvas = { + extendedInfoFields: [ + "id", + "fileName", + "displayName", + "description", + "lastModifiedDateTime", + "createdDateTime", + ], + actions: actions, + }; + + const simpleColumns = [ + "displayName", + "description", + "runAsAccount", + "runAs32Bit", + "enforceSignatureCheck", + "lastModifiedDateTime", + ]; + + return ( + + ); +}; + +Page.getLayout = (page) => ( + + {page} + +); +export default Page; diff --git a/src/pages/endpoint/MEM/list-scripts/tabOptions.json b/src/pages/endpoint/MEM/list-scripts/tabOptions.json new file mode 100644 index 000000000000..0e10ef91f490 --- /dev/null +++ b/src/pages/endpoint/MEM/list-scripts/tabOptions.json @@ -0,0 +1,18 @@ +[ + { + "label": "Windows Scripts", + "path": "/endpoint/MEM/list-scripts" + }, + { + "label": "MacOS Scripts", + "path": "/endpoint/MEM/list-scripts/macOS" + }, + { + "label": "Linux Scripts", + "path": "/endpoint/MEM/list-scripts/linux" + }, + { + "label": "Remediation Scripts", + "path": "/endpoint/MEM/list-scripts/remediation" + } +] From a45dc747ec2415334ce811c0e0f52fd993c56f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Thu, 23 Jan 2025 22:55:59 +0100 Subject: [PATCH 004/231] Make into 1 page --- .../email/tools/mailbox-restores/index.js | 6 +- src/pages/endpoint/MEM/list-scripts/index.js | 28 +++----- src/pages/endpoint/MEM/list-scripts/linux.js | 61 ---------------- src/pages/endpoint/MEM/list-scripts/macOS.js | 70 ------------------- .../endpoint/MEM/list-scripts/remediation.js | 69 ------------------ .../endpoint/MEM/list-scripts/tabOptions.json | 18 ----- 6 files changed, 13 insertions(+), 239 deletions(-) delete mode 100644 src/pages/endpoint/MEM/list-scripts/linux.js delete mode 100644 src/pages/endpoint/MEM/list-scripts/macOS.js delete mode 100644 src/pages/endpoint/MEM/list-scripts/remediation.js delete mode 100644 src/pages/endpoint/MEM/list-scripts/tabOptions.json diff --git a/src/pages/email/tools/mailbox-restores/index.js b/src/pages/email/tools/mailbox-restores/index.js index ffa463800bd5..16ffea192996 100644 --- a/src/pages/email/tools/mailbox-restores/index.js +++ b/src/pages/email/tools/mailbox-restores/index.js @@ -15,7 +15,7 @@ const Page = () => { data: { TenantFilter: "Tenant", Identity: "Identity", - Action: "Resume", + Action: "!Resume", }, confirmText: "Are you sure you want to resume this restore request?", color: "info", @@ -27,7 +27,7 @@ const Page = () => { data: { TenantFilter: "Tenant", Identity: "Identity", - Action: "Suspend", + Action: "!Suspend", }, confirmText: "Are you sure you want to suspend this restore request?", color: "warning", @@ -39,7 +39,7 @@ const Page = () => { data: { TenantFilter: "Tenant", Identity: "Identity", - Action: "Remove", + Action: "!Remove", }, confirmText: "Are you sure you want to remove this restore request?", color: "danger", diff --git a/src/pages/endpoint/MEM/list-scripts/index.js b/src/pages/endpoint/MEM/list-scripts/index.js index 6ce9383bb2fd..db6dd7a1d1eb 100644 --- a/src/pages/endpoint/MEM/list-scripts/index.js +++ b/src/pages/endpoint/MEM/list-scripts/index.js @@ -1,11 +1,9 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Code, TrashIcon } from "@heroicons/react/24/outline"; -import { TabbedLayout } from "/src/layouts/TabbedLayout"; -import tabOptions from "./tabOptions"; const Page = () => { - const pageTitle = "Windows Scripts"; + const pageTitle = "Scripts"; const actions = [ { @@ -15,7 +13,7 @@ const Page = () => { data: { ID: "id", displayName: "displayName", - ScriptType: "!windows", + ScriptType: "scriptType", }, confirmText: "Are you sure you want to delete this script?", icon: , @@ -25,35 +23,33 @@ const Page = () => { const offCanvas = { extendedInfoFields: [ + "scriptType", "id", "fileName", "displayName", "description", "lastModifiedDateTime", + "runAsAccount", "createdDateTime", + "runAs32Bit", + "executionFrequency", + "enforceSignatureCheck", ], actions: actions, }; const simpleColumns = [ + "scriptType", "displayName", "description", "runAsAccount", - "runAs32Bit", - "enforceSignatureCheck", "lastModifiedDateTime", ]; return ( { ); }; -Page.getLayout = (page) => ( - - {page} - -); +Page.getLayout = (page) => {page}; export default Page; diff --git a/src/pages/endpoint/MEM/list-scripts/linux.js b/src/pages/endpoint/MEM/list-scripts/linux.js deleted file mode 100644 index be139e47205f..000000000000 --- a/src/pages/endpoint/MEM/list-scripts/linux.js +++ /dev/null @@ -1,61 +0,0 @@ -import { Layout as DashboardLayout } from "/src/layouts/index.js"; -import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; -import { Code, TrashIcon } from "@heroicons/react/24/outline"; -import { TabbedLayout } from "/src/layouts/TabbedLayout"; -import tabOptions from "./tabOptions"; - -const Page = () => { - const pageTitle = "Linux Scripts"; - - const actions = [ - { - label: "Delete Script", - type: "POST", - url: "/api/RemovePolicy", - data: { - ID: "id", - URLName: "URLName", - }, - confirmText: "Are you sure you want to delete this script?", - icon: , - color: "danger", - }, - ]; - - const offCanvas = { - extendedInfoFields: [ - "id", - "displayName", - "description", - "lastModifiedDateTime", - "createdDateTime", - ], - actions: actions, - }; - - const simpleColumns = [ - "displayName", - "description", - "runAsAccount", - "executionFrequency", - "enforceSignatureCheck", - "lastModifiedDateTime", - ]; - - return ( - - ); -}; - -Page.getLayout = (page) => ( - - {page} - -); -export default Page; diff --git a/src/pages/endpoint/MEM/list-scripts/macOS.js b/src/pages/endpoint/MEM/list-scripts/macOS.js deleted file mode 100644 index 5fcf6fca1202..000000000000 --- a/src/pages/endpoint/MEM/list-scripts/macOS.js +++ /dev/null @@ -1,70 +0,0 @@ -import { Layout as DashboardLayout } from "/src/layouts/index.js"; -import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; -import { Code, TrashIcon } from "@heroicons/react/24/outline"; -import { TabbedLayout } from "/src/layouts/TabbedLayout"; -import tabOptions from "./tabOptions"; - -const Page = () => { - const pageTitle = "MacOS Scripts"; - - const actions = [ - { - label: "Delete Script", - type: "POST", - url: "/api/RemoveIntuneScript", - data: { - ID: "id", - displayName: "displayName", - ScriptType: "!macOS", - }, - confirmText: "Are you sure you want to delete this script?", - icon: , - color: "danger", - }, - ]; - - const offCanvas = { - extendedInfoFields: [ - "id", - "fileName", - "displayName", - "description", - "lastModifiedDateTime", - "createdDateTime", - "retryCount", - ], - actions: actions, - }; - - const simpleColumns = [ - "displayName", - "description", - "runAsAccount", - "executionFrequency", - "enforceSignatureCheck", - "lastModifiedDateTime", - ]; - - return ( - - ); -}; - -Page.getLayout = (page) => ( - - {page} - -); -export default Page; diff --git a/src/pages/endpoint/MEM/list-scripts/remediation.js b/src/pages/endpoint/MEM/list-scripts/remediation.js deleted file mode 100644 index f08106b87099..000000000000 --- a/src/pages/endpoint/MEM/list-scripts/remediation.js +++ /dev/null @@ -1,69 +0,0 @@ -import { Layout as DashboardLayout } from "/src/layouts/index.js"; -import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; -import { Code, TrashIcon } from "@heroicons/react/24/outline"; -import { TabbedLayout } from "/src/layouts/TabbedLayout"; -import tabOptions from "./tabOptions"; - -const Page = () => { - const pageTitle = "Remediation Scripts"; - - const actions = [ - { - label: "Delete Script", - type: "POST", - url: "/api/RemoveIntuneScript", - data: { - ID: "id", - displayName: "displayName", - ScriptType: "!remediate", - }, - confirmText: "Are you sure you want to delete this script?", - icon: , - color: "danger", - }, - ]; - - const offCanvas = { - extendedInfoFields: [ - "id", - "fileName", - "displayName", - "description", - "lastModifiedDateTime", - "createdDateTime", - ], - actions: actions, - }; - - const simpleColumns = [ - "displayName", - "description", - "runAsAccount", - "runAs32Bit", - "enforceSignatureCheck", - "lastModifiedDateTime", - ]; - - return ( - - ); -}; - -Page.getLayout = (page) => ( - - {page} - -); -export default Page; diff --git a/src/pages/endpoint/MEM/list-scripts/tabOptions.json b/src/pages/endpoint/MEM/list-scripts/tabOptions.json deleted file mode 100644 index 0e10ef91f490..000000000000 --- a/src/pages/endpoint/MEM/list-scripts/tabOptions.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "label": "Windows Scripts", - "path": "/endpoint/MEM/list-scripts" - }, - { - "label": "MacOS Scripts", - "path": "/endpoint/MEM/list-scripts/macOS" - }, - { - "label": "Linux Scripts", - "path": "/endpoint/MEM/list-scripts/linux" - }, - { - "label": "Remediation Scripts", - "path": "/endpoint/MEM/list-scripts/remediation" - } -] From a85b9b7deddc84b465296c31e09e289a74524641 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 27 Jan 2025 12:17:18 +0100 Subject: [PATCH 005/231] querykey confusion --- src/pages/tenant/gdap-management/invites/add.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/tenant/gdap-management/invites/add.js b/src/pages/tenant/gdap-management/invites/add.js index 22d72810f0c8..b470cde23584 100644 --- a/src/pages/tenant/gdap-management/invites/add.js +++ b/src/pages/tenant/gdap-management/invites/add.js @@ -40,12 +40,12 @@ const Page = () => { const createCippDefaults = ApiPostCall({ urlFromData: true, - relatedQueryKeys: ["ListGDAPRoleTemplatesAutocomplete"], + relatedQueryKeys: ["ListGDAPRoleTemplatesAutocomplete", "ListGDAPRoleTemplates"], }); const templateList = ApiGetCall({ url: "/api/ExecGDAPRoleTemplate", - queryKey: "ListGDAPRoleTemplatesAutocomplete", + queryKey: "ListGDAPRoleTemplates", }); const selectedTemplate = useWatch({ control: formControl.control, name: "roleMappings" }); From ba54a291d04f2af520ac4a1cc47fc0766c9562c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= <31723128+kris6673@users.noreply.github.com> Date: Mon, 27 Jan 2025 14:23:21 +0100 Subject: [PATCH 006/231] FIX space typo --- src/data/alerts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/alerts.json b/src/data/alerts.json index d027afab9869..1e2b8bdc0fc8 100644 --- a/src/data/alerts.json +++ b/src/data/alerts.json @@ -92,7 +92,7 @@ "recommendedRunInterval": "30d" }, { - "name": "AppCertificateExpiry ", + "name": "AppCertificateExpiry", "label": "Alert on expiring application certificates", "recommendedRunInterval": "1d" }, From 5c84a91be79f82fba487aa6eec56c229240809b3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 27 Jan 2025 10:48:10 -0500 Subject: [PATCH 007/231] set tenantfilter on table action if tenant filter is all tenants --- src/components/CippTable/CippDataTable.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/components/CippTable/CippDataTable.js b/src/components/CippTable/CippDataTable.js index 914c0d7675c5..005678d16998 100644 --- a/src/components/CippTable/CippDataTable.js +++ b/src/components/CippTable/CippDataTable.js @@ -17,11 +17,13 @@ import { ApiGetCallWithPagination } from "../../api/ApiCall"; import { utilTableMode } from "./util-tablemode"; import { utilColumnsFromAPI } from "./util-columnsFromAPI"; import { CIPPTableToptoolbar } from "./CIPPTableToptoolbar"; -import { More, MoreHoriz } from "@mui/icons-material"; +import { Info, More, MoreHoriz } from "@mui/icons-material"; import { CippOffCanvas } from "../CippComponents/CippOffCanvas"; import { useDialog } from "../../hooks/use-dialog"; import { CippApiDialog } from "../CippComponents/CippApiDialog"; import { getCippError } from "../../utils/get-cipp-error"; +import { Box } from "@mui/system"; +import { useSettings } from "../../hooks/use-settings"; export const CippDataTable = (props) => { const { @@ -61,6 +63,9 @@ export const CippDataTable = (props) => { const [actionData, setActionData] = useState({ data: {}, action: {}, ready: false }); const [graphFilterData, setGraphFilterData] = useState({}); const waitingBool = api?.url ? true : false; + + const settings = useSettings(); + const getRequestData = ApiGetCallWithPagination({ url: api.url, data: { ...api.data }, @@ -177,7 +182,11 @@ export const CippDataTable = (props) => { }, renderEmptyRowsFallback: ({ table }) => getRequestData.data?.pages?.[0].Metadata?.QueueMessage ? ( -
{getRequestData.data?.pages?.[0].Metadata?.QueueMessage}
+ +
+ {getRequestData.data?.pages?.[0].Metadata?.QueueMessage} +
+
) : undefined, onColumnVisibilityChange: setColumnVisibility, ...modeInfo, @@ -188,6 +197,11 @@ export const CippDataTable = (props) => { sx={{ color: action.color }} key={`actions-list-row-${index}`} onClick={() => { + if (settings.currentTenant === "AllTenants" && row.original?.Tenant) { + settings.handleUpdate({ + currentTenant: row.original.Tenant, + }); + } setActionData({ data: row.original, action: action, From 3510fc233e352b32b7c34e2ec388c658dd2880b1 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 27 Jan 2025 10:49:11 -0500 Subject: [PATCH 008/231] Update ApiCall.jsx --- src/api/ApiCall.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/api/ApiCall.jsx b/src/api/ApiCall.jsx index c9c62c1f8048..fa953247204c 100644 --- a/src/api/ApiCall.jsx +++ b/src/api/ApiCall.jsx @@ -190,7 +190,11 @@ export function ApiGetCallWithPagination({ return response.data; }, getNextPageParam: (lastPage) => { - if (data?.noPagination || data?.manualPagination === false) { + if ( + data?.noPagination || + data?.manualPagination === false || + data?.tenantFilter === "AllTenants" + ) { return undefined; } return lastPage?.Metadata?.nextLink ? { nextLink: lastPage.Metadata.nextLink } : undefined; From 77ec401b5ee29e5247aeb3b29f2fe04ec07deabe Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 27 Jan 2025 13:44:22 -0500 Subject: [PATCH 009/231] fix button sizes --- src/pages/cipp/integrations/configure.js | 81 ++++++++++++++---------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/src/pages/cipp/integrations/configure.js b/src/pages/cipp/integrations/configure.js index 52d4766d9c09..2861a241edad 100644 --- a/src/pages/cipp/integrations/configure.js +++ b/src/pages/cipp/integrations/configure.js @@ -120,51 +120,62 @@ const Page = () => { {extension.alertText} )} - + {extension?.hideTestButton !== true && ( - + + + )} {extension?.forceSyncButton && ( - + + + )} {extension?.links && ( <> {extension.links.map((link, index) => ( - + + + ))} )} + From d805803291b882e1aa1b1e07246e203cdb8e2d02 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 27 Jan 2025 14:47:58 -0500 Subject: [PATCH 010/231] up version minor package/workflow tweaks --- .github/workflows/Check_for_Version_Update.yml | 8 ++++---- package.json | 1 + public/version.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Check_for_Version_Update.yml b/.github/workflows/Check_for_Version_Update.yml index ec6f3e68769b..0958e8190cea 100644 --- a/.github/workflows/Check_for_Version_Update.yml +++ b/.github/workflows/Check_for_Version_Update.yml @@ -7,17 +7,17 @@ on: jobs: build: if: github.repository_owner == 'KelvinTegelaar' - name: 'Check for Version Update' + name: "Check for Version Update" runs-on: ubuntu-latest steps: - name: Check for Changed Files uses: brettcannon/check-for-changed-files@v1.1.0 with: - file-pattern: version_latest.txt - failure-message: 'You have not updated version_latest.txt. This is a required file to update at each PR. Please sync your latest changes and update the version number.' + file-pattern: version.json + failure-message: "You have not updated version.json. This is a required file to update at each PR. Please sync your latest changes and update the version number." - name: Prevent changes to workflow files uses: DovnarAlexander/github-action-file-detection@v0.3.0 with: - wildcard: '.github/workflows/*.yml' + wildcard: ".github/workflows/*.yml" exit_code_found: 1 exit_code_not_found: 0 diff --git a/package.json b/package.json index 6c2c57ba925d..eb70d4b08762 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "bugs": { "url": "https://github.com/KelvinTegelaar/CIPP/issues" }, + "license": "AGPL-3.0", "engines": { "node": "^18.17.0" }, diff --git a/public/version.json b/public/version.json index fa68337146a1..ef511cf84994 100644 --- a/public/version.json +++ b/public/version.json @@ -1,3 +1,3 @@ { - "version": "7.1.1" + "version": "7.1.2" } From be8347685b0325a96892ca7278bbb86b96315a77 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 27 Jan 2025 14:50:23 -0500 Subject: [PATCH 011/231] Update Check_for_Version_Update.yml --- .github/workflows/Check_for_Version_Update.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Check_for_Version_Update.yml b/.github/workflows/Check_for_Version_Update.yml index 0958e8190cea..f8a7db0343f2 100644 --- a/.github/workflows/Check_for_Version_Update.yml +++ b/.github/workflows/Check_for_Version_Update.yml @@ -13,7 +13,7 @@ jobs: - name: Check for Changed Files uses: brettcannon/check-for-changed-files@v1.1.0 with: - file-pattern: version.json + file-pattern: public/version.json failure-message: "You have not updated version.json. This is a required file to update at each PR. Please sync your latest changes and update the version number." - name: Prevent changes to workflow files uses: DovnarAlexander/github-action-file-detection@v0.3.0 From da746cde6ecf76ec9eb31fbd55164da8ada978e9 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 27 Jan 2025 15:09:50 -0500 Subject: [PATCH 012/231] Update offboarding.js --- src/pages/tenant/gdap-management/offboarding.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/tenant/gdap-management/offboarding.js b/src/pages/tenant/gdap-management/offboarding.js index 1fb872a6d2da..1fe26d282b70 100644 --- a/src/pages/tenant/gdap-management/offboarding.js +++ b/src/pages/tenant/gdap-management/offboarding.js @@ -7,7 +7,7 @@ import { CippFormComponent } from "/src/components/CippComponents/CippFormCompon import vendorTenantList from "/src/data/vendorTenantList"; import { Box, Grid, Stack } from "@mui/system"; import { Alert, Divider, Typography } from "@mui/material"; -import { ApiGetCall } from "/src/api/ApiCall"; +import { ApiGetCall, ApiGetCallWithPagination } from "/src/api/ApiCall"; import { CippInfoBar } from "../../../components/CippCards/CippInfoBar"; import { ShieldCheckIcon } from "@heroicons/react/24/outline"; import { Apps, Description, Widgets } from "@mui/icons-material"; @@ -60,7 +60,7 @@ const Page = () => { queryKey: "ListMSPApps-" + tenantId?.value, }); - const vendorApps = ApiGetCall({ + const vendorApps = ApiGetCallWithPagination({ url: "/api/ListGraphRequest", data: { Endpoint: "servicePrincipals", @@ -193,7 +193,7 @@ const Page = () => { }, valueField: "appId", }} - disabled={vendorApps?.data?.Results?.length > 0 ? false : true} + disabled={vendorApps?.data?.pages?.[0]?.Results?.length > 0 ? false : true} /> Date: Mon, 27 Jan 2025 12:51:56 -0800 Subject: [PATCH 013/231] Update required engine to Node 20. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c2c57ba925d..6ee40b74d760 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/KelvinTegelaar/CIPP/issues" }, "engines": { - "node": "^18.17.0" + "node": "^20.18.2" }, "repository": { "type": "git", From 56242de9403fb97e68a51b0474914374d3c21724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 27 Jan 2025 23:12:57 +0100 Subject: [PATCH 014/231] Add fallback message for empty license translations --- src/utils/get-cipp-license-translation.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils/get-cipp-license-translation.js b/src/utils/get-cipp-license-translation.js index 813e52a5d1e9..e77574c713a9 100644 --- a/src/utils/get-cipp-license-translation.js +++ b/src/utils/get-cipp-license-translation.js @@ -21,5 +21,9 @@ export const getCippLicenseTranslation = (licenseArray) => { } }); - return licenses.join(", "); + const result = licenses.join(", "); + if (!result) { + return "No Licenses Assigned"; + } + return result; }; From 2968075eb198bbe524b011bd08ae774e6fb607d6 Mon Sep 17 00:00:00 2001 From: redanthrax Date: Mon, 27 Jan 2025 14:38:19 -0800 Subject: [PATCH 015/231] Trim standards search, show output with 0 results, min width --- .../CippStandards/CippStandardDialog.jsx | 224 ++++++++++-------- 1 file changed, 126 insertions(+), 98 deletions(-) diff --git a/src/components/CippStandards/CippStandardDialog.jsx b/src/components/CippStandards/CippStandardDialog.jsx index 2fb081155944..d2b94853e6ee 100644 --- a/src/components/CippStandards/CippStandardDialog.jsx +++ b/src/components/CippStandards/CippStandardDialog.jsx @@ -42,13 +42,18 @@ const CippStandardDialog = ({ const handleSearchQueryChange = useCallback( debounce((query) => { - setSearchQuery(query); + setSearchQuery(query.trim()); }, 50), [] ); return ( - + Select a Standard to Add handleSearchQueryChange(e.target.value.toLowerCase())} /> - {Object.keys(categories).map((category) => - filterStandards(categories[category]).map((standard) => ( - - - - - {standard.label} - - {standard.helpText && ( - <> - - Description: - - - {standard.helpText} - - - )} - - Category: - - - {standard.tag?.filter((tag) => !tag.toLowerCase().includes("impact")).length > - 0 && ( - <> - - Tags: - - - {standard.tag - .filter((tag) => !tag.toLowerCase().includes("impact")) - .map((tag, idx) => ( - - ))} - - - )} - - Impact: - - - {standard.recommendedBy?.length > 0 && ( - <> - - Recommended By: - - - {standard.recommendedBy.join(", ")} - - - )} - - - - {standard.multiple ? ( - filterStandards(categories[category]).length === 0 + ) ? ( + + Search returned no results + + ) : ( + Object.keys(categories).map((category) => + filterStandards(categories[category]).map((standard) => ( + + + + + {standard.label} + + {standard.helpText && ( + <> + + Description: + + + {standard.helpText} + + + )} + + Category: + + handleAddClick(standard.name)} - > - - - ) : ( - handleToggleSingleStandard(standard.name)} - /> + sx={{ mt: 1, mb: 2 }} + /> + {standard.tag?.filter((tag) => !tag.toLowerCase().includes("impact")).length > + 0 && ( + <> + + Tags: + + + {standard.tag + .filter((tag) => !tag.toLowerCase().includes("impact")) + .map((tag, idx) => ( + + ))} + + + )} + + Impact: + + - )} - - - - )) + {standard.recommendedBy?.length > 0 && ( + <> + + Recommended By: + + + {standard.recommendedBy.join(", ")} + + + )} + + + + {standard.multiple ? ( + handleAddClick(standard.name)} + > + + + ) : ( + + handleToggleSingleStandard(standard.name) + } + /> + } + label="Add this standard to the template" + /> + )} + + + + )) + ) )} From 6005b874999d0db4d1c8f71bd6528509a78f304f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 27 Jan 2025 23:41:21 +0100 Subject: [PATCH 016/231] Add User ID display to user tabs --- src/components/CippCards/CippUserInfoCard.jsx | 5 ++ .../administration/users/user/bec.jsx | 48 +++++++++---------- .../users/user/conditional-access.jsx | 6 ++- .../administration/users/user/devices.jsx | 6 ++- .../administration/users/user/edit.jsx | 8 +++- .../administration/users/user/exchange.jsx | 8 +++- .../administration/users/user/index.jsx | 8 +++- 7 files changed, 56 insertions(+), 33 deletions(-) diff --git a/src/components/CippCards/CippUserInfoCard.jsx b/src/components/CippCards/CippUserInfoCard.jsx index 8b9048f46fec..49c0ec716ab1 100644 --- a/src/components/CippCards/CippUserInfoCard.jsx +++ b/src/components/CippCards/CippUserInfoCard.jsx @@ -91,6 +91,11 @@ export const CippUserInfoCard = (props) => { ) } /> + : user?.id || "N/A"} + /> { return "No mailbox permission changes found."; }; + const subtitle = userRequest.isSuccess + ? [ + { + icon: , + text: , + }, + { + icon: , + text: , + }, + { + icon: , + text: ( + <> + Created: + + ), + }, + ] + : []; + return ( , - text: ( - - ), - }, - { - icon: , - text: ( - <> - Created:{" "} - - - ), - }, - ] - : [] - } + subtitle={subtitle} isFetching={userRequest.isFetching} > {/* Loading State: Show only Remediation Card and Check 1 with Loading Skeleton */} diff --git a/src/pages/identity/administration/users/user/conditional-access.jsx b/src/pages/identity/administration/users/user/conditional-access.jsx index 6bda3f8534c2..5d85ae736cff 100644 --- a/src/pages/identity/administration/users/user/conditional-access.jsx +++ b/src/pages/identity/administration/users/user/conditional-access.jsx @@ -4,7 +4,7 @@ import { useSettings } from "/src/hooks/use-settings"; import { useRouter } from "next/router"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { Mail, Forward } from "@mui/icons-material"; +import { Mail, Forward, Fingerprint } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import ReactTimeAgo from "react-time-ago"; @@ -41,6 +41,10 @@ const Page = () => { icon: , text: , }, + { + icon: , + text: , + }, { icon: , text: ( diff --git a/src/pages/identity/administration/users/user/devices.jsx b/src/pages/identity/administration/users/user/devices.jsx index b0d5d9649b89..23cda503df3a 100644 --- a/src/pages/identity/administration/users/user/devices.jsx +++ b/src/pages/identity/administration/users/user/devices.jsx @@ -4,7 +4,7 @@ import { useRouter } from "next/router"; import { ApiGetCall } from "/src/api/ApiCall"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { Check, Mail } from "@mui/icons-material"; +import { Check, Mail, Fingerprint } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import ReactTimeAgo from "react-time-ago"; @@ -50,6 +50,10 @@ const Page = () => { icon: , text: , }, + { + icon: , + text: , + }, { icon: , text: ( diff --git a/src/pages/identity/administration/users/user/edit.jsx b/src/pages/identity/administration/users/user/edit.jsx index 8cd113275022..539ed69d1d98 100644 --- a/src/pages/identity/administration/users/user/edit.jsx +++ b/src/pages/identity/administration/users/user/edit.jsx @@ -9,7 +9,7 @@ import { useEffect } from "react"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import { getCippLicenseTranslation } from "/src/utils/get-cipp-license-translation"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { Mail } from "@mui/icons-material"; +import { Mail, Fingerprint } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import { CippCopyToClipBoard } from "../../../../../components/CippComponents/CippCopyToClipboard"; @@ -55,11 +55,15 @@ const Page = () => { icon: , text: , }, + { + icon: , + text: , + }, { icon: , text: ( <> - Created + Created: ), }, diff --git a/src/pages/identity/administration/users/user/exchange.jsx b/src/pages/identity/administration/users/user/exchange.jsx index 29082e3b6fb8..beccf92393e2 100644 --- a/src/pages/identity/administration/users/user/exchange.jsx +++ b/src/pages/identity/administration/users/user/exchange.jsx @@ -4,7 +4,7 @@ import { useRouter } from "next/router"; import { ApiGetCall } from "/src/api/ApiCall"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { Check, Error, Mail } from "@mui/icons-material"; +import { Check, Error, Mail, Fingerprint } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import { CippTimeAgo } from "../../../../../components/CippComponents/CippTimeAgo"; @@ -101,11 +101,15 @@ const Page = () => { ), }, + { + icon: , + text: , + }, { icon: , text: ( <> - Created + Created: ), }, diff --git a/src/pages/identity/administration/users/user/index.jsx b/src/pages/identity/administration/users/user/index.jsx index 984371102e4f..f7d8937590d5 100644 --- a/src/pages/identity/administration/users/user/index.jsx +++ b/src/pages/identity/administration/users/user/index.jsx @@ -4,7 +4,7 @@ import { useRouter } from "next/router"; import { ApiGetCall } from "/src/api/ApiCall"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { AdminPanelSettings, Check, Group, Mail } from "@mui/icons-material"; +import { AdminPanelSettings, Check, Group, Mail, Fingerprint } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import { CippCopyToClipBoard } from "../../../../../components/CippComponents/CippCopyToClipboard"; @@ -122,11 +122,15 @@ const Page = () => { icon: , text: , }, + { + icon: , + text: , + }, { icon: , text: ( <> - Created + Created: ), }, From bcdbd1a081cd6cc2cd3538b4a2cf5db3e6027536 Mon Sep 17 00:00:00 2001 From: Esco Date: Tue, 28 Jan 2025 13:11:17 +0100 Subject: [PATCH 017/231] fix: revert back to location --- src/pages/identity/reports/risk-detections/index.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pages/identity/reports/risk-detections/index.js b/src/pages/identity/reports/risk-detections/index.js index f6fe5e6b07da..3c54fc260e31 100644 --- a/src/pages/identity/reports/risk-detections/index.js +++ b/src/pages/identity/reports/risk-detections/index.js @@ -23,8 +23,7 @@ const Page = () => { "userDisplayName", "userPrincipalName", "detectedDateTime", - "location.city", - "location.countryOrRegion", + "location", "ipAddress", "riskLevel", "riskState", @@ -39,8 +38,7 @@ const Page = () => { const simpleColumns = [ "detectedDateTime", "userPrincipalName", - "location.city", - "location.countryOrRegion", + "location", "ipAddress", "riskState", "riskDetail", From 45fa3756cf91cea07fc8093feea85952826ae10b Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Tue, 28 Jan 2025 13:04:52 +0000 Subject: [PATCH 018/231] Add speed dial actions for bug reporting and feature requests --- .../CippComponents/CippSpeedDial.jsx | 222 ++++++++++++++++++ src/pages/_app.js | 15 ++ 2 files changed, 237 insertions(+) create mode 100644 src/components/CippComponents/CippSpeedDial.jsx diff --git a/src/components/CippComponents/CippSpeedDial.jsx b/src/components/CippComponents/CippSpeedDial.jsx new file mode 100644 index 000000000000..805ca4a66fe9 --- /dev/null +++ b/src/components/CippComponents/CippSpeedDial.jsx @@ -0,0 +1,222 @@ +import React, { useState, useEffect } from "react"; +import { + SpeedDial, + SpeedDialAction, + SpeedDialIcon, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + Snackbar, + Alert, + CircularProgress, +} from "@mui/material"; +import { Close as CloseIcon } from "@mui/icons-material"; +import { useForm } from "react-hook-form"; +import { CippFormComponent } from "/src/components/CippComponents/CippFormComponent"; + +const CippSpeedDial = ({ + actions = [], + position = { bottom: 16, right: 16 }, + icon, + openIcon = , +}) => { + const [openDialogs, setOpenDialogs] = useState({}); + const [loading, setLoading] = useState(false); + const [showSnackbar, setShowSnackbar] = useState(false); + const [speedDialOpen, setSpeedDialOpen] = useState(false); + const [isHovering, setIsHovering] = useState(false); + const [snackbarMessage, setSnackbarMessage] = useState(""); + + const formControls = actions.reduce((acc, action) => { + if (action.form) { + acc[action.id] = useForm({ + mode: "onChange", + defaultValues: action.form.defaultValues || {}, + }); + } + return acc; + }, {}); + + const handleSpeedDialClose = () => { + if (!isHovering) { + setTimeout(() => { + setSpeedDialOpen(false); + }, 200); + } + }; + + const handleMouseEnter = () => { + setIsHovering(true); + setSpeedDialOpen(true); + }; + + const handleMouseLeave = () => { + setIsHovering(false); + handleSpeedDialClose(); + }; + + const handleDialogOpen = (actionId) => { + setOpenDialogs((prev) => ({ ...prev, [actionId]: true })); + }; + + const handleDialogClose = (actionId) => { + setOpenDialogs((prev) => ({ ...prev, [actionId]: false })); + }; + + const handleSubmit = async (actionId, data) => { + if (!actions.find((a) => a.id === actionId)?.onSubmit) return; + + setLoading(true); + try { + const action = actions.find((a) => a.id === actionId); + const result = await action.onSubmit(data); + + if (result.success) { + formControls[actionId]?.reset(); + handleDialogClose(actionId); + } + setSnackbarMessage(result.message); + setShowSnackbar(true); + } catch (error) { + console.error(`Error submitting ${actionId}:`, error); + setSnackbarMessage("An error occurred while submitting"); + setShowSnackbar(true); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + const handleClickOutside = (event) => { + if (speedDialOpen) { + const speedDial = document.querySelector('[aria-label="Navigation SpeedDial"]'); + if (speedDial && !speedDial.contains(event.target)) { + setSpeedDialOpen(false); + } + } + }; + + document.addEventListener("click", handleClickOutside); + return () => { + document.removeEventListener("click", handleClickOutside); + }; + }, [speedDialOpen]); + + return ( + <> + } + open={speedDialOpen} + onClose={handleSpeedDialClose} + onOpen={() => setSpeedDialOpen(true)} + onMouseEnter={handleMouseEnter} + onMouseLeave={handleMouseLeave} + > + {actions.map((action) => ( + { + if (action.form) { + handleDialogOpen(action.id); + } else if (action.onClick) { + action.onClick(); + } + setSpeedDialOpen(false); + }} + tooltipOpen + sx={{ + "&.MuiSpeedDialAction-fab": { + backgroundColor: "background.paper", + "&:hover": { + backgroundColor: "action.hover", + }, + }, + "& .MuiSpeedDialAction-staticTooltipLabel": { + cursor: "pointer", + whiteSpace: "nowrap", + marginRight: "10px", + padding: "6px 10px", + "&:hover": { + backgroundColor: "action.hover", + }, + }, + }} + /> + ))} + + + {actions + .filter((action) => action.form) + .map((action) => ( + handleDialogClose(action.id)} + maxWidth="md" + fullWidth + > + {action.form.title} + + + + + + + + + ))} + + setShowSnackbar(false)} + anchorOrigin={{ vertical: "bottom", horizontal: "center" }} + > + setShowSnackbar(false)} severity="success" sx={{ width: "100%" }}> + {snackbarMessage} + + + + ); +}; + +export default CippSpeedDial; diff --git a/src/pages/_app.js b/src/pages/_app.js index 702eb328927c..1dd1e6971768 100644 --- a/src/pages/_app.js +++ b/src/pages/_app.js @@ -36,6 +36,21 @@ const App = (props) => { const getLayout = Component.getLayout ?? ((page) => page); const preferredTheme = useMediaPredicate("(prefers-color-scheme: dark)") ? "dark" : "light"; + const speedDialActions = [ + { + id: "bug-report", + icon: , + name: "Report Bug", + href: "https://github.com/KelvinTegelaar/CIPP/issues/new?template=bug.yml", + }, + { + id: "feature-request", + icon: , + name: "Request Feature", + href: "https://github.com/KelvinTegelaar/CIPP/issues/new?template=feature.yml", + }, + ]; + return ( From 0523c8cc4db8a5f9b25cf3708af11f76d6c916ed Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 28 Jan 2025 10:59:24 -0500 Subject: [PATCH 019/231] bring back offboarding defaults --- .../CippWizard/CippWizardOffboarding.jsx | 10 ++++++++++ src/pages/cipp/preferences.js | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/components/CippWizard/CippWizardOffboarding.jsx b/src/components/CippWizard/CippWizardOffboarding.jsx index 7d69817bcf52..d61e9365c1e5 100644 --- a/src/components/CippWizard/CippWizardOffboarding.jsx +++ b/src/components/CippWizard/CippWizardOffboarding.jsx @@ -5,12 +5,14 @@ import { CippFormCondition } from "../CippComponents/CippFormCondition"; import { useWatch } from "react-hook-form"; import { useEffect, useState } from "react"; import { Grid } from "@mui/system"; +import { useSettings } from "../../hooks/use-settings"; export const CippWizardOffboarding = (props) => { const { postUrl, formControl, onPreviousStep, onNextStep, currentStep } = props; const currentTenant = formControl.watch("tenantFilter"); const selectedUsers = useWatch({ control: formControl.control, name: "user" }); const [showAlert, setShowAlert] = useState(false); + const userSettingsDefaults = useSettings().userSettingsDefaults; useEffect(() => { if (selectedUsers.length >= 4) { @@ -19,6 +21,14 @@ export const CippWizardOffboarding = (props) => { } }, [selectedUsers]); + useEffect(() => { + if (userSettingsDefaults?.offboardingDefaults) { + userSettingsDefaults.offboardingDefaults.forEach((setting) => { + formControl.setValue(setting.name, setting.value); + }); + } + }, [userSettingsDefaults]); + return ( diff --git a/src/pages/cipp/preferences.js b/src/pages/cipp/preferences.js index 6cc782d44508..a6c34d96bbab 100644 --- a/src/pages/cipp/preferences.js +++ b/src/pages/cipp/preferences.js @@ -255,6 +255,26 @@ const Page = () => { /> ), }, + { + label: "Disable Sign in", + value: ( + + ), + }, + { + label: "Remove all MFA Devices", + value: ( + + ), + }, ]} /> From 6dd731b63dfa29de61712c41f9bfaaf1d1a0b33e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 28 Jan 2025 22:44:59 +0100 Subject: [PATCH 020/231] Add icons for permission actions in OneDrive page --- src/pages/teams-share/onedrive/index.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/pages/teams-share/onedrive/index.js b/src/pages/teams-share/onedrive/index.js index c14fd268acb2..842b0737cbcc 100644 --- a/src/pages/teams-share/onedrive/index.js +++ b/src/pages/teams-share/onedrive/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { PersonAdd, PersonRemove } from "@mui/icons-material"; const Page = () => { const pageTitle = "OneDrive"; @@ -7,6 +8,7 @@ const Page = () => { const actions = [ { label: "Add permissions to OneDrive", + icon: , type: "POST", url: "/api/ExecSharePointPerms", data: { @@ -36,6 +38,7 @@ const Page = () => { }, { label: "Remove permissions from OneDrive", + icon: , type: "POST", url: "/api/ExecSharePointPerms", data: { @@ -65,17 +68,11 @@ const Page = () => { }, ]; - const offCanvas = { - extendedInfoFields: ["UPN"], - actions: actions, - }; - return ( Date: Tue, 28 Jan 2025 23:06:56 +0100 Subject: [PATCH 021/231] Remove unused actions and offCanvas variables from Azure AD Connect report --- src/pages/identity/reports/azure-ad-connect-report/index.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/pages/identity/reports/azure-ad-connect-report/index.js b/src/pages/identity/reports/azure-ad-connect-report/index.js index 529ce0333b4e..97594a13d6ac 100644 --- a/src/pages/identity/reports/azure-ad-connect-report/index.js +++ b/src/pages/identity/reports/azure-ad-connect-report/index.js @@ -9,9 +9,6 @@ const simpleColumns = [ ]; const apiUrl = "/api/ListAzureADConnectStatus"; -const actions = []; // No actions specified in the original code - -const offCanvas = null; // No off-canvas details provided const Page = () => { return ( @@ -21,8 +18,6 @@ const Page = () => { apiData={{ DataToReturn: "AzureADObjectsInError", }} - actions={actions} - offCanvas={offCanvas} simpleColumns={simpleColumns} /> ); From a4f8f1b45d02565cceab345a25d09daa0028ddd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 28 Jan 2025 23:07:01 +0100 Subject: [PATCH 022/231] Remove unused actions and offCanvas variables from Sign Ins Report --- src/pages/identity/reports/signin-report/index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/identity/reports/signin-report/index.js b/src/pages/identity/reports/signin-report/index.js index 6304b8fa0da6..619f99ef8bcd 100644 --- a/src/pages/identity/reports/signin-report/index.js +++ b/src/pages/identity/reports/signin-report/index.js @@ -7,8 +7,6 @@ import CippButtonCard from "/src/components/CippCards/CippButtonCard"; const Page = () => { const pageTitle = "Sign Ins Report"; const apiUrl = "/api/ListSignIns"; - const actions = []; - const offCanvas = null; const simpleColumns = [ "createdDateTime", "userPrincipalName", @@ -16,6 +14,7 @@ const Page = () => { "authenticationRequirement", "errorCode", "additionalDetails", + "ipAddress", "locationcipp", ]; @@ -102,8 +101,6 @@ const Page = () => { title={pageTitle} apiUrl={apiUrl} apiData={appliedFilters} - actions={actions} - offCanvas={offCanvas} simpleColumns={simpleColumns} queryKey={`ListSignIns-${JSON.stringify(appliedFilters)}`} /> From 2e095d04182ce497b60b05a4bca5a98c369ce791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 28 Jan 2025 23:21:52 +0100 Subject: [PATCH 023/231] Refactor user filters in administration page for improved readability --- .../identity/administration/users/index.js | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/pages/identity/administration/users/index.js b/src/pages/identity/administration/users/index.js index c03a62bb56cd..ec4552915b18 100644 --- a/src/pages/identity/administration/users/index.js +++ b/src/pages/identity/administration/users/index.js @@ -9,6 +9,24 @@ const Page = () => { const pageTitle = "Users"; const tenant = useSettings().currentTenant; + const filters = [ + { + filterName: "Account Enabled", + value: [{ id: "accountEnabled", value: "Yes" }], + type: "column", + }, + { + filterName: "Account Disabled", + value: [{ id: "accountEnabled", value: "No" }], + type: "column", + }, + { + filterName: "Guest Accounts", + value: [{ id: "userType", value: "Guest" }], + type: "column", + }, + ]; + const offCanvas = { extendedInfoFields: [ "createdDateTime", // Created Date (UTC) @@ -67,24 +85,7 @@ const Page = () => { "proxyAddresses", "assignedLicenses", ]} - filters={[ - { - filterName: "Account Enabled", - //true or false filters by yes/no - value: [{ id: "accountEnabled", value: "Yes" }], - type: "column", - }, - { - filterName: "Account Disabled", - value: [{ id: "accountEnabled", value: "No" }], - type: "column", - }, - { - filterName: "Guest Accounts", - value: [{ id: "userType", value: "Guest" }], - type: "column", - }, - ]} + filters={filters} /> ); }; From 4745883169c56171d618cea04c07d979373b64af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 28 Jan 2025 23:22:02 +0100 Subject: [PATCH 024/231] Add filters and actions to MFA Report page --- .../identity/reports/mfa-report/index.js | 75 ++++++++++++++++--- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/src/pages/identity/reports/mfa-report/index.js b/src/pages/identity/reports/mfa-report/index.js index fd18f1bdef0c..02ee1058648e 100644 --- a/src/pages/identity/reports/mfa-report/index.js +++ b/src/pages/identity/reports/mfa-report/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { LockPerson } from "@mui/icons-material"; const Page = () => { const pageTitle = "MFA Report"; @@ -15,19 +16,71 @@ const Page = () => { "MFAMethods", "CAPolicies", ]; + const filters = [ + { + filterName: "Enabled, licensed users", + value: [ + { id: "AccountEnabled", value: "Yes" }, + { id: "isLicensed", value: "Yes" }, + ], + type: "column", + }, + { + filterName: "Enabled, licensed users missing MFA", + value: [ + { id: "AccountEnabled", value: "Yes" }, + { id: "isLicensed", value: "Yes" }, + { id: "MFARegistration", value: "No" }, + ], + type: "column", + }, + { + filterName: "No MFA methods registered", + value: [{ id: "MFARegistration", value: "No" }], + type: "column", + }, + { + filterName: "MFA methods registered", + value: [{ id: "MFARegistration", value: "Yes" }], + type: "column", + }, + ]; - /* Filters not supported in the current structure, need dev attention for integration. - filterlist: [ - { filterName: 'Enabled users', filter: '"accountEnabled":true' }, - { filterName: 'Non-guest users', filter: 'Complex: UPN notlike #EXT#' }, - { filterName: 'Licensed users', filter: 'Complex: IsLicensed eq true' }, - { filterName: 'Enabled, licensed non-guest users missing MFA', filter: 'Complex: UPN notlike #EXT#; IsLicensed eq true; accountEnabled eq true; MFARegistration ne true' }, - { filterName: 'No MFA methods registered', filter: 'Complex: MFARegistration ne true' }, - { filterName: 'MFA methods registered', filter: 'Complex: MFARegistration eq true' }, - ], - */ + const actions = [ + { + //tested + label: "Set Per-User MFA", + type: "POST", + icon: , + url: "/api/ExecPerUserMFA", + data: { userId: "UPN" }, + fields: [ + { + type: "autoComplete", + name: "State", + label: "State", + options: [ + { label: "Enforced", value: "Enforced" }, + { label: "Enabled", value: "Enabled" }, + { label: "Disabled", value: "Disabled" }, + ], + multiple: false, + }, + ], + confirmText: "Are you sure you want to set per-user MFA for these users?", + multiPost: false, + }, + ]; - return ; + return ( + + ); }; Page.getLayout = (page) => {page}; From 59adc40f8811ebe16bdd2f0f7c2fd643e2e0f945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 28 Jan 2025 23:24:02 +0100 Subject: [PATCH 025/231] Restrict creatable option for MFA user actions --- src/components/CippComponents/CippUserActions.jsx | 1 + src/pages/identity/reports/mfa-report/index.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/CippComponents/CippUserActions.jsx b/src/components/CippComponents/CippUserActions.jsx index fe532d259f4b..f88d909281e8 100644 --- a/src/components/CippComponents/CippUserActions.jsx +++ b/src/components/CippComponents/CippUserActions.jsx @@ -98,6 +98,7 @@ export const CippUserActions = () => { { label: "Disabled", value: "Disabled" }, ], multiple: false, + creatable: false, }, ], confirmText: "Are you sure you want to set per-user MFA for these users?", diff --git a/src/pages/identity/reports/mfa-report/index.js b/src/pages/identity/reports/mfa-report/index.js index 02ee1058648e..206e8337e2ef 100644 --- a/src/pages/identity/reports/mfa-report/index.js +++ b/src/pages/identity/reports/mfa-report/index.js @@ -48,7 +48,6 @@ const Page = () => { const actions = [ { - //tested label: "Set Per-User MFA", type: "POST", icon: , @@ -65,6 +64,7 @@ const Page = () => { { label: "Disabled", value: "Disabled" }, ], multiple: false, + creatable: false, }, ], confirmText: "Are you sure you want to set per-user MFA for these users?", From b363c663a22bc9113076e9d570f28e65a035456e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 28 Jan 2025 23:40:19 +0100 Subject: [PATCH 026/231] Remove unused actions and offCanvas variables --- .../tenant/administration/list-licenses/index.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/pages/tenant/administration/list-licenses/index.js b/src/pages/tenant/administration/list-licenses/index.js index 1a4abfc73707..417e1ef16910 100644 --- a/src/pages/tenant/administration/list-licenses/index.js +++ b/src/pages/tenant/administration/list-licenses/index.js @@ -5,28 +5,16 @@ const Page = () => { const pageTitle = "Licenses Report"; const apiUrl = "/api/ListLicenses"; - const actions = []; // No actions specified, setting to empty array - - const offCanvas = null; // No off-canvas details provided - const simpleColumns = [ "Tenant", "License", "CountUsed", "CountAvailable", "TotalLicenses", - "TermInfo", + "TermInfo", // TODO TermInfo is not showing as a clickable json object in the table, like CApolicies does in the mfa report. IDK how to fix it. -Bobby ]; - return ( - - ); + return ; }; Page.getLayout = (page) => {page}; From 8cf68f8379742398d95fef88b546f1e3acf3fb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 28 Jan 2025 23:47:09 +0100 Subject: [PATCH 027/231] Update tenant reports pathing to be the same as other pages --- src/layouts/config.js | 6 +++--- .../application-consent/index.js | 0 .../{administration => reports}/list-csp-licenses/index.jsx | 0 .../{administration => reports}/list-licenses/index.js | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/pages/tenant/{administration => reports}/application-consent/index.js (100%) rename src/pages/tenant/{administration => reports}/list-csp-licenses/index.jsx (100%) rename src/pages/tenant/{administration => reports}/list-licenses/index.js (100%) diff --git a/src/layouts/config.js b/src/layouts/config.js index d9685ba29de4..c2f375de7f8b 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -154,15 +154,15 @@ export const nativeMenuItems = [ items: [ { title: "Licence Report", - path: "/tenant/administration/list-licenses", + path: "/tenant/reports/list-licenses", }, { title: "Sherweb Licence Report", - path: "/tenant/administration/list-csp-licenses", + path: "/tenant/reports/list-csp-licenses", }, { title: "Consented Applications", - path: "/tenant/administration/application-consent", + path: "/tenant/reports/application-consent", }, ], }, diff --git a/src/pages/tenant/administration/application-consent/index.js b/src/pages/tenant/reports/application-consent/index.js similarity index 100% rename from src/pages/tenant/administration/application-consent/index.js rename to src/pages/tenant/reports/application-consent/index.js diff --git a/src/pages/tenant/administration/list-csp-licenses/index.jsx b/src/pages/tenant/reports/list-csp-licenses/index.jsx similarity index 100% rename from src/pages/tenant/administration/list-csp-licenses/index.jsx rename to src/pages/tenant/reports/list-csp-licenses/index.jsx diff --git a/src/pages/tenant/administration/list-licenses/index.js b/src/pages/tenant/reports/list-licenses/index.js similarity index 100% rename from src/pages/tenant/administration/list-licenses/index.js rename to src/pages/tenant/reports/list-licenses/index.js From 295d71f44c3872a29ed2379b09a66b7a2f3ca3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 28 Jan 2025 23:49:46 +0100 Subject: [PATCH 028/231] Update device management path to align with new endpoint structure --- src/layouts/config.js | 2 +- src/pages/endpoint/{reports => MEM}/devices/index.js | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/pages/endpoint/{reports => MEM}/devices/index.js (100%) diff --git a/src/layouts/config.js b/src/layouts/config.js index c2f375de7f8b..bc501b15c43e 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -244,7 +244,7 @@ export const nativeMenuItems = [ title: "Device Management", path: "/endpoint/MEM", items: [ - { title: "Devices", path: "/endpoint/reports/devices" }, + { title: "Devices", path: "/endpoint/MEM/devices" }, { title: "Configuration Policies", path: "/endpoint/MEM/list-policies" }, { title: "Compliance Policies", path: "/endpoint/MEM/list-compliance-policies" }, { title: "Protection Policies", path: "/endpoint/MEM/list-appprotection-policies" }, diff --git a/src/pages/endpoint/reports/devices/index.js b/src/pages/endpoint/MEM/devices/index.js similarity index 100% rename from src/pages/endpoint/reports/devices/index.js rename to src/pages/endpoint/MEM/devices/index.js From ac0f4523cf2f5bc4f2d6e68978559af2a5af94ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:02:51 +0100 Subject: [PATCH 029/231] forgot a spot --- generate-placeholders.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate-placeholders.js b/generate-placeholders.js index 9858fc7f7b7c..f1733c0eb830 100644 --- a/generate-placeholders.js +++ b/generate-placeholders.js @@ -82,7 +82,7 @@ const pages = [ { title: "Add Profile", path: "/endpoint/autopilot/add-profile" }, { title: "Status Pages", path: "/endpoint/autopilot/list-status-pages" }, { title: "Add Status Page", path: "/endpoint/autopilot/add-status-page" }, - { title: "Devices", path: "/endpoint/reports/devices" }, + { title: "Devices", path: "/endpoint/MEM/devices" }, { title: "Configuration Policies", path: "/endpoint/MEM/list-policies" }, { title: "Compliance Policies", path: "/endpoint/MEM/list-compliance-policies" }, { title: "Protection Policies", path: "/endpoint/MEM/list-appprotection-policies" }, From d41a0b72c806023d0b078f6fdd19e63be03ba5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:04:36 +0100 Subject: [PATCH 030/231] Update transport paths in email layout for consistency --- src/layouts/config.js | 6 +++--- .../list-connector-templates/index.js | 0 .../email/{connectors => transport}/list-connectors/add.jsx | 0 .../{connectors => transport}/list-connectors/index.js | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/pages/email/{connectors => transport}/list-connector-templates/index.js (100%) rename src/pages/email/{connectors => transport}/list-connectors/add.jsx (100%) rename src/pages/email/{connectors => transport}/list-connectors/index.js (100%) diff --git a/src/layouts/config.js b/src/layouts/config.js index bc501b15c43e..f14a9b4feb0b 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -315,17 +315,17 @@ export const nativeMenuItems = [ }, { title: "Transport", - path: "/email/Transport", + path: "/email/transport", items: [ { title: "Transport rules", path: "/email/transport/list-rules" }, { title: "Transport Templates", path: "/email/transport/list-templates", }, - { title: "Connectors", path: "/email/connectors/list-connectors" }, + { title: "Connectors", path: "/email/transport/list-connectors" }, { title: "Connector Templates", - path: "/email/connectors/list-connector-templates", + path: "/email/transport/list-connector-templates", }, ], }, diff --git a/src/pages/email/connectors/list-connector-templates/index.js b/src/pages/email/transport/list-connector-templates/index.js similarity index 100% rename from src/pages/email/connectors/list-connector-templates/index.js rename to src/pages/email/transport/list-connector-templates/index.js diff --git a/src/pages/email/connectors/list-connectors/add.jsx b/src/pages/email/transport/list-connectors/add.jsx similarity index 100% rename from src/pages/email/connectors/list-connectors/add.jsx rename to src/pages/email/transport/list-connectors/add.jsx diff --git a/src/pages/email/connectors/list-connectors/index.js b/src/pages/email/transport/list-connectors/index.js similarity index 100% rename from src/pages/email/connectors/list-connectors/index.js rename to src/pages/email/transport/list-connectors/index.js From db5f73f69e92ad766c3e0cb8fd3669abb70b9dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:05:26 +0100 Subject: [PATCH 031/231] Update connectors paths to align with transport structure --- generate-placeholders.js | 4 ++-- src/pages/email/transport/list-connectors/index.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/generate-placeholders.js b/generate-placeholders.js index f1733c0eb830..560e7680e3b1 100644 --- a/generate-placeholders.js +++ b/generate-placeholders.js @@ -108,9 +108,9 @@ const pages = [ { title: "Transport rules", path: "/email/transport/list-rules" }, { title: "Deploy Transport rule", path: "/email/transport/deploy-rules" }, { title: "Transport Templates", path: "/email/transport/list-templates" }, - { title: "Connectors", path: "/email/connectors/list-connectors" }, + { title: "Connectors", path: "/email/transport/list-connectors" }, { title: "Deploy Connector Templates", path: "/email/connectors/deploy-connector" }, - { title: "Connector Templates", path: "/email/connectors/list-connector-templates" }, + { title: "Connector Templates", path: "/email/transport/list-connector-templates" }, { title: "Spamfilter", path: "/email/spamfilter/list-spamfilter" }, { title: "Apply Spamfilter Template", path: "/email/spamfilter/deploy" }, { title: "Templates", path: "/email/spamfilter/list-templates" }, diff --git a/src/pages/email/transport/list-connectors/index.js b/src/pages/email/transport/list-connectors/index.js index 58799a4bd6dc..c61b44ad6fa2 100644 --- a/src/pages/email/transport/list-connectors/index.js +++ b/src/pages/email/transport/list-connectors/index.js @@ -83,7 +83,7 @@ const Page = () => { }} cardButton={ <> - From 311c3606565ecb4d4e64821c2f2d60ffc7099bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:09:48 +0100 Subject: [PATCH 032/231] Fix path casing in email administration and remove unused deploy connector page --- src/layouts/config.js | 2 +- .../email/connectors/deploy-connector/index.js | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 src/pages/email/connectors/deploy-connector/index.js diff --git a/src/layouts/config.js b/src/layouts/config.js index f14a9b4feb0b..75bf312ddd87 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -300,7 +300,7 @@ export const nativeMenuItems = [ items: [ { title: "Administration", - path: "/email/Administration", + path: "/email/administration", items: [ { title: "Mailboxes", path: "/email/administration/mailboxes" }, { title: "Deleted Mailboxes", path: "/email/administration/deleted-mailboxes" }, diff --git a/src/pages/email/connectors/deploy-connector/index.js b/src/pages/email/connectors/deploy-connector/index.js deleted file mode 100644 index cddfb2691027..000000000000 --- a/src/pages/email/connectors/deploy-connector/index.js +++ /dev/null @@ -1,17 +0,0 @@ - -import { Layout as DashboardLayout } from "/src/layouts/index.js"; - -const Page = () => { - const pageTitle = "Deploy Connector Templates"; - - return ( -
-

{pageTitle}

-

This is a placeholder page for the deploy connector templates section.

-
- ); -}; - -Page.getLayout = (page) => {page}; - -export default Page; From f040f64cecfd240b8844661a80039e98e17300e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:17:42 +0100 Subject: [PATCH 033/231] Remove unused placeholder and reorder to fit the rest of CIPPs pages --- src/layouts/config.js | 7 +++++-- .../email/connectionfilter/deploy/index.js | 17 ----------------- src/pages/email/spamfilter/deploy/index.js | 17 ----------------- .../list-connectionfilter-templates}/index.js | 0 .../list-connectionfilter/add.jsx | 0 .../list-connectionfilter/index.js | 10 ++-------- 6 files changed, 7 insertions(+), 44 deletions(-) delete mode 100644 src/pages/email/connectionfilter/deploy/index.js delete mode 100644 src/pages/email/spamfilter/deploy/index.js rename src/pages/email/{connectionfilter/list-templates => spamfilter/list-connectionfilter-templates}/index.js (100%) rename src/pages/email/{connectionfilter => spamfilter}/list-connectionfilter/add.jsx (100%) rename src/pages/email/{connectionfilter => spamfilter}/list-connectionfilter/index.js (85%) diff --git a/src/layouts/config.js b/src/layouts/config.js index 75bf312ddd87..d3e24167dc9d 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -335,8 +335,11 @@ export const nativeMenuItems = [ items: [ { title: "Spamfilter", path: "/email/spamfilter/list-spamfilter" }, { title: "Spamfilter templates", path: "/email/spamfilter/list-templates" }, - { title: "Connection filter", path: "/email/connectionfilter/list-connectionfilter" }, - { title: "Connection filter templates", path: "/email/connectionfilter/list-templates" }, + { title: "Connection filter", path: "/email/spamfilter/list-connectionfilter" }, + { + title: "Connection filter templates", + path: "/email/spamfilter/list-connectionfilter-templates", + }, ], }, { diff --git a/src/pages/email/connectionfilter/deploy/index.js b/src/pages/email/connectionfilter/deploy/index.js deleted file mode 100644 index 92cbabc77ae2..000000000000 --- a/src/pages/email/connectionfilter/deploy/index.js +++ /dev/null @@ -1,17 +0,0 @@ - -import { Layout as DashboardLayout } from "/src/layouts/index.js"; - -const Page = () => { - const pageTitle = "Apply Spamfilter Template"; - - return ( -
-

{pageTitle}

-

This is a placeholder page for the apply spamfilter template section.

-
- ); -}; - -Page.getLayout = (page) => {page}; - -export default Page; diff --git a/src/pages/email/spamfilter/deploy/index.js b/src/pages/email/spamfilter/deploy/index.js deleted file mode 100644 index 92cbabc77ae2..000000000000 --- a/src/pages/email/spamfilter/deploy/index.js +++ /dev/null @@ -1,17 +0,0 @@ - -import { Layout as DashboardLayout } from "/src/layouts/index.js"; - -const Page = () => { - const pageTitle = "Apply Spamfilter Template"; - - return ( -
-

{pageTitle}

-

This is a placeholder page for the apply spamfilter template section.

-
- ); -}; - -Page.getLayout = (page) => {page}; - -export default Page; diff --git a/src/pages/email/connectionfilter/list-templates/index.js b/src/pages/email/spamfilter/list-connectionfilter-templates/index.js similarity index 100% rename from src/pages/email/connectionfilter/list-templates/index.js rename to src/pages/email/spamfilter/list-connectionfilter-templates/index.js diff --git a/src/pages/email/connectionfilter/list-connectionfilter/add.jsx b/src/pages/email/spamfilter/list-connectionfilter/add.jsx similarity index 100% rename from src/pages/email/connectionfilter/list-connectionfilter/add.jsx rename to src/pages/email/spamfilter/list-connectionfilter/add.jsx diff --git a/src/pages/email/connectionfilter/list-connectionfilter/index.js b/src/pages/email/spamfilter/list-connectionfilter/index.js similarity index 85% rename from src/pages/email/connectionfilter/list-connectionfilter/index.js rename to src/pages/email/spamfilter/list-connectionfilter/index.js index cd6e9482ada8..be6506c4db26 100644 --- a/src/pages/email/connectionfilter/list-connectionfilter/index.js +++ b/src/pages/email/spamfilter/list-connectionfilter/index.js @@ -32,13 +32,7 @@ const Page = () => { actions: actions, }; - const simpleColumns = [ - "Name", - "IsDefault", - "IPAllowList", - "IPBlockList", - "EnableSafeList", - ]; + const simpleColumns = ["Name", "IsDefault", "IPAllowList", "IPBlockList", "EnableSafeList"]; return ( { simpleColumns={simpleColumns} cardButton={ <> - From dcdfc849ab8f8dd21abc29148433c06e46f5e85a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:20:26 +0100 Subject: [PATCH 034/231] Add Book icon to connection filter page --- src/pages/email/spamfilter/list-connectionfilter/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/email/spamfilter/list-connectionfilter/index.js b/src/pages/email/spamfilter/list-connectionfilter/index.js index be6506c4db26..97e8cd8f963f 100644 --- a/src/pages/email/spamfilter/list-connectionfilter/index.js +++ b/src/pages/email/spamfilter/list-connectionfilter/index.js @@ -1,6 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { Book } from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -14,6 +15,7 @@ const Page = () => { dataFunction: (data) => { return { ...data }; }, + icon: , confirmText: "Are you sure you want to create a template based on this rule?", }, ]; From c7c8a3e235d7c0969df67557ebaffa94b53c46d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:29:17 +0100 Subject: [PATCH 035/231] Update link in domains analyser to point to tools section --- src/pages/tenant/standards/domains-analyser/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/tenant/standards/domains-analyser/index.js b/src/pages/tenant/standards/domains-analyser/index.js index 218e8a8633b4..1a5c2e9b4a68 100644 --- a/src/pages/tenant/standards/domains-analyser/index.js +++ b/src/pages/tenant/standards/domains-analyser/index.js @@ -36,7 +36,7 @@ const Page = () => { apiUrl="/api/ListDomainAnalyser" cardButton={ <> - {/* This needs to be replaced with a CippApiDialog. */} From a1b4b46907719a9e524c62904ac768de203c403d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:31:46 +0100 Subject: [PATCH 036/231] Update paths for Graph Explorer, Application Approval, and Individual Domain Check to align with tools section --- generate-placeholders.js | 6 +++--- src/layouts/config.js | 6 +++--- .../tenant/{administration => tools}/appapproval/index.js | 0 .../{administration => tools}/graph-explorer/index.js | 0 .../tenant/{standards => tools}/individual-domains/index.js | 0 5 files changed, 6 insertions(+), 6 deletions(-) rename src/pages/tenant/{administration => tools}/appapproval/index.js (100%) rename src/pages/tenant/{administration => tools}/graph-explorer/index.js (100%) rename src/pages/tenant/{standards => tools}/individual-domains/index.js (100%) diff --git a/generate-placeholders.js b/generate-placeholders.js index 560e7680e3b1..2f6b614fe9a8 100644 --- a/generate-placeholders.js +++ b/generate-placeholders.js @@ -35,11 +35,11 @@ const pages = [ { title: "Backup Wizard", path: "/tenant/backup/backup-wizard" }, { title: "Restore Wizard", path: "/tenant/backup/restore-wizard" }, { title: "Tools", path: "/tenant/administration" }, - { title: "Graph Explorer", path: "/tenant/administration/graph-explorer" }, - { title: "Application Approval", path: "/tenant/administration/appapproval" }, + { title: "Graph Explorer", path: "/tenant/tools/graph-explorer" }, + { title: "Application Approval", path: "/tenant/tools/appapproval" }, { title: "IP Database", path: "/tenant/tools/geoiplookup" }, { title: "Tenant Lookup", path: "/tenant/administration/tenantlookup" }, - { title: "Individual Domain Check", path: "/tenant/standards/individual-domains" }, + { title: "Individual Domain Check", path: "/tenant/tools/individual-domains" }, { title: "BPA Report Builder", path: "/tenant/tools/bpa-report-builder" }, { title: "Standards", path: "/tenant/standards" }, { title: "Edit Standards", path: "/tenant/standards/list-applied-standards" }, diff --git a/src/layouts/config.js b/src/layouts/config.js index d3e24167dc9d..e8c6d541c9be 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -402,11 +402,11 @@ export const nativeMenuItems = [ items: [ { title: "Graph Explorer", - path: "/tenant/administration/graph-explorer", + path: "/tenant/tools/graph-explorer", }, { title: "Application Approval", - path: "/tenant/administration/appapproval", + path: "/tenant/tools/appapproval", }, { title: "Tenant Lookup", path: "/tenant/tools/tenantlookup" }, @@ -414,7 +414,7 @@ export const nativeMenuItems = [ { title: "Individual Domain Check", - path: "/tenant/standards/individual-domains", + path: "/tenant/tools/individual-domains", }, ], }, diff --git a/src/pages/tenant/administration/appapproval/index.js b/src/pages/tenant/tools/appapproval/index.js similarity index 100% rename from src/pages/tenant/administration/appapproval/index.js rename to src/pages/tenant/tools/appapproval/index.js diff --git a/src/pages/tenant/administration/graph-explorer/index.js b/src/pages/tenant/tools/graph-explorer/index.js similarity index 100% rename from src/pages/tenant/administration/graph-explorer/index.js rename to src/pages/tenant/tools/graph-explorer/index.js diff --git a/src/pages/tenant/standards/individual-domains/index.js b/src/pages/tenant/tools/individual-domains/index.js similarity index 100% rename from src/pages/tenant/standards/individual-domains/index.js rename to src/pages/tenant/tools/individual-domains/index.js From afbfd9c7d31babbdbb969ab5f7dacb4a0b93478c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 00:54:32 +0100 Subject: [PATCH 037/231] Add icons for device actions in the autopilot device list --- src/pages/endpoint/autopilot/list-devices/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/endpoint/autopilot/list-devices/index.js b/src/pages/endpoint/autopilot/list-devices/index.js index b738be0ba6af..d924ec33b3d5 100644 --- a/src/pages/endpoint/autopilot/list-devices/index.js +++ b/src/pages/endpoint/autopilot/list-devices/index.js @@ -1,6 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { PersonAdd, Delete } from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -9,6 +10,7 @@ const Page = () => { const actions = [ { label: "Assign device", + icon: , type: "POST", url: "/api/ExecAssignAPDevice", data: { @@ -38,6 +40,7 @@ const Page = () => { }, { label: "Delete Device", + icon: , type: "POST", url: "/api/RemoveAPDevice", data: { ID: "id" }, From 23bb3774e178fd14cfd6f76984bf6575957144c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 01:07:58 +0100 Subject: [PATCH 038/231] Fix Add Status Page placeholder --- .../autopilot/add-status-page/index.js | 118 ++++++++++++++++- .../autopilot/list-status-pages/add.jsx | 123 ------------------ .../autopilot/list-status-pages/index.js | 2 +- 3 files changed, 113 insertions(+), 130 deletions(-) delete mode 100644 src/pages/endpoint/autopilot/list-status-pages/add.jsx diff --git a/src/pages/endpoint/autopilot/add-status-page/index.js b/src/pages/endpoint/autopilot/add-status-page/index.js index 2ee87af41a8e..1a3454035a19 100644 --- a/src/pages/endpoint/autopilot/add-status-page/index.js +++ b/src/pages/endpoint/autopilot/add-status-page/index.js @@ -1,14 +1,120 @@ - +import React from "react"; +import { Grid, Divider } from "@mui/material"; +import { useForm, useWatch } from "react-hook-form"; import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import CippFormPage from "/src/components/CippFormPages/CippFormPage"; +import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; +import { CippFormTenantSelector } from "/src/components/CippComponents/CippFormTenantSelector"; const Page = () => { - const pageTitle = "Add Status Page"; + const formControl = useForm({ + mode: "onChange", + defaultValues: { + TimeOutInMinutes: "", + ErrorMessage: "", + ShowProgress: false, + EnableLog: false, + OBEEOnly: false, + blockDevice: false, + Allowretry: false, + AllowReset: false, + AllowFail: false, + }, + }); return ( -
-

{pageTitle}

-

This is a placeholder page for the add status page section.

-
+ + + {/* Tenant Selector */} + + + + + + + {/* Form Fields */} + + + + + + + + + {/* Switches */} + + + + + + + + + + + ); }; diff --git a/src/pages/endpoint/autopilot/list-status-pages/add.jsx b/src/pages/endpoint/autopilot/list-status-pages/add.jsx deleted file mode 100644 index 328283d07829..000000000000 --- a/src/pages/endpoint/autopilot/list-status-pages/add.jsx +++ /dev/null @@ -1,123 +0,0 @@ -import React from "react"; -import { Grid, Divider } from "@mui/material"; -import { useForm, useWatch } from "react-hook-form"; -import { Layout as DashboardLayout } from "/src/layouts/index.js"; -import CippFormPage from "/src/components/CippFormPages/CippFormPage"; -import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; -import { CippFormTenantSelector } from "/src/components/CippComponents/CippFormTenantSelector"; - -const AutopilotStatusPageForm = () => { - const formControl = useForm({ - mode: "onChange", - defaultValues: { - TimeOutInMinutes: "", - ErrorMessage: "", - ShowProgress: false, - EnableLog: false, - OBEEOnly: false, - blockDevice: false, - Allowretry: false, - AllowReset: false, - AllowFail: false, - }, - }); - - return ( - - - {/* Tenant Selector */} - - - - - - - {/* Form Fields */} - - - - - - - - - {/* Switches */} - - - - - - - - - - - - ); -}; - -AutopilotStatusPageForm.getLayout = (page) => {page}; - -export default AutopilotStatusPageForm; diff --git a/src/pages/endpoint/autopilot/list-status-pages/index.js b/src/pages/endpoint/autopilot/list-status-pages/index.js index 939685bd69ad..d49f4281b043 100644 --- a/src/pages/endpoint/autopilot/list-status-pages/index.js +++ b/src/pages/endpoint/autopilot/list-status-pages/index.js @@ -25,7 +25,7 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - From be8d2cfe068195d4e043f51149bcab77146214e9 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 28 Jan 2025 22:32:54 -0500 Subject: [PATCH 039/231] adjust logo size --- src/pages/cipp/integrations/configure.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/pages/cipp/integrations/configure.js b/src/pages/cipp/integrations/configure.js index 2861a241edad..62bc4990350b 100644 --- a/src/pages/cipp/integrations/configure.js +++ b/src/pages/cipp/integrations/configure.js @@ -101,7 +101,6 @@ const Page = () => { backButtonTitle="Integrations" headerText={extension.headerText} hideTitleText={true} - headerImage={logo} > {logo && ( @@ -109,7 +108,7 @@ const Page = () => { component="img" src={logo} alt={extension.name} - sx={{ width: "50%", mx: "auto" }} + sx={{ maxWidth: "50%", mx: "auto", maxHeight: "125px" }} /> )} @@ -187,6 +186,7 @@ const Page = () => { {extension?.mappingRequired && } {extension?.fieldMapping && } + {extension?.id === "cippapi" && } @@ -202,6 +202,11 @@ const Page = () => { )} + {extension?.id === "cippapi" && ( + + API Client component to go here + + )} )} From f75f84fc175b14202075523b81e511f3828fe508 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 13:36:09 +0100 Subject: [PATCH 040/231] fix: added condition to name location actions --- .../tenant/conditional/list-named-locations/index.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pages/tenant/conditional/list-named-locations/index.js b/src/pages/tenant/conditional/list-named-locations/index.js index 877d38a6411b..99e704323535 100644 --- a/src/pages/tenant/conditional/list-named-locations/index.js +++ b/src/pages/tenant/conditional/list-named-locations/index.js @@ -17,6 +17,7 @@ const Page = () => { }, fields: [{ type: "textField", name: "input", label: "Country Code" }], confirmText: "Enter a two-letter country code, e.g., US.", + condition: (row) => row["@odata.type"] == "#microsoft.graph.countryNamedLocation", }, { label: "Remove location from named location", @@ -28,6 +29,7 @@ const Page = () => { }, fields: [{ type: "textField", name: "input", label: "Country Code" }], confirmText: "Enter a two-letter country code, e.g., US.", + condition: (row) => row["@odata.type"] == "#microsoft.graph.countryNamedLocation", }, { label: "Add IP to named location", @@ -39,6 +41,7 @@ const Page = () => { }, fields: [{ type: "textField", name: "input", label: "IP" }], confirmText: "Enter an IP in CIDR format, e.g., 1.1.1.1/32.", + condition: (row) => row["@odata.type"] == "#microsoft.graph.ipNamedLocation", }, { label: "Remove IP from named location", @@ -49,13 +52,13 @@ const Page = () => { change: "removeIp", }, fields: [{ type: "textField", name: "input", label: "IP" }], - confirmText: "Enter an IP in CIDR format, e.g., 1.1.1.1/32.", + condition: (row) => row["@odata.type"] == "#microsoft.graph.ipNamedLocation", }, ]; const offCanvas = { - extendedInfoFields: ["displayName", "type", "rangeOrLocation"], + extendedInfoFields: ["displayName", "rangeOrLocation"], actions: actions, }; @@ -75,7 +78,7 @@ const Page = () => { simpleColumns={[ "displayName", "includeUnknownCountriesAndRegions", - "type", + "isTrusted", "rangeOrLocation", "modifiedDateTime", ]} From c3986009e8ca4b4c6268766bfa9bd108c05c2d9f Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 14:13:35 +0100 Subject: [PATCH 041/231] fix: added conditional action to Quarantine Management --- src/pages/email/administration/quarantine/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/email/administration/quarantine/index.js b/src/pages/email/administration/quarantine/index.js index e784d8888a0e..7415aa9dc5d0 100644 --- a/src/pages/email/administration/quarantine/index.js +++ b/src/pages/email/administration/quarantine/index.js @@ -101,6 +101,7 @@ const Page = () => { }, confirmText: "Are you sure you want to release this message?", icon: , + condition: (row) => row.ReleaseStatus !== "RELEASED", }, { label: "Deny", @@ -112,6 +113,7 @@ const Page = () => { }, confirmText: "Are you sure you want to deny this message?", icon: , + condition: (row) => row.ReleaseStatus !== "DENIED", }, { label: "Release & Allow Sender", @@ -125,6 +127,7 @@ const Page = () => { confirmText: "Are you sure you want to release this email and add the sender to the whitelist?", icon: , + condition: (row) => row.ReleaseStatus !== "RELEASED", }, ]; From f6029e362c72bd7d39d28bba3b2b382a6fb9e5f8 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 14:15:23 +0100 Subject: [PATCH 042/231] fix: added trashbin to Remove --- .../email/administration/tenant-allow-block-lists/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/email/administration/tenant-allow-block-lists/index.js b/src/pages/email/administration/tenant-allow-block-lists/index.js index 97925a29f708..508d5c67110e 100644 --- a/src/pages/email/administration/tenant-allow-block-lists/index.js +++ b/src/pages/email/administration/tenant-allow-block-lists/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; +import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; const Page = () => { const pageTitle = "Tenant Allow/Block Lists"; @@ -18,6 +19,7 @@ const Page = () => { }, confirmText: "Are you sure you want to delete?", color: "danger", + icon: , }, ]; From 3ed5d8019519c03fb7b24a11b091293e6df22042 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 14:32:36 +0100 Subject: [PATCH 043/231] fix: fixed Contacts Page --- src/pages/email/administration/contacts/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index d32c9f8a2a6b..89a6a65d74c8 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -3,6 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Edit } from "@mui/icons-material"; import { Button } from "@mui/material"; import Link from "next/link"; +import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; const Page = () => { const pageTitle = "Contacts"; @@ -13,19 +14,20 @@ const Page = () => { type: "POST", url: "/api/RemoveContact", data: { - TenantFilter: "Tenant", GUID: "id", }, confirmText: "Are you sure you want to delete this contact?", color: "danger", + icon: , }, + /* TODO: Implement edit contact { label: "Edit Contact", link: "/email/administration/edit-contact/[id]", multiPost: false, icon: , color: "warning", - }, + },*/ ]; const simpleColumns = ["displayName", "mail", "companyName", "onPremisesSyncEnabled"]; From 21ba3325d6858cad7911f23d104020e418e7cbe2 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 14:50:30 +0100 Subject: [PATCH 044/231] fix: added condition to Global Address list --- src/pages/email/reports/global-address-list/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/email/reports/global-address-list/index.js b/src/pages/email/reports/global-address-list/index.js index 5b0be1040072..6e78b2dacc26 100644 --- a/src/pages/email/reports/global-address-list/index.js +++ b/src/pages/email/reports/global-address-list/index.js @@ -12,6 +12,7 @@ const Page = () => { ID: "PrimarySmtpAddress", }, confirmText: "Are you sure you want to show this mailbox in the Global Address List?", + condition: (row) => row.HiddenFromAddressListsEnabled == true, }, { label: "Hide from Global Address List", @@ -22,6 +23,7 @@ const Page = () => { ID: "PrimarySmtpAddress", }, confirmText: "Are you sure you want to hide this mailbox from the Global Address List?", + condition: (row) => row.HiddenFromAddressListsEnabled == false, }, ]; From 360e2757c47c3b247bc128471b4122e6d5b4c008 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 14:56:18 +0100 Subject: [PATCH 045/231] fix: added edit icon --- src/pages/teams-share/teams/list-team/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/teams-share/teams/list-team/index.js b/src/pages/teams-share/teams/list-team/index.js index db874b1091da..b1a41a9adbb6 100644 --- a/src/pages/teams-share/teams/list-team/index.js +++ b/src/pages/teams-share/teams/list-team/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; +import { Edit } from "@mui/icons-material"; const Page = () => { const pageTitle = "Teams"; @@ -12,6 +13,7 @@ const Page = () => { link: "/identity/administration/groups/edit?groupId=[id]", multiPost: false, color: "warning", + icon: , }, ]; From 51fe974da2d5b32f4a2459d9797f30067081ae48 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 15:07:56 +0100 Subject: [PATCH 046/231] fix: added icon to global address list --- src/pages/email/reports/global-address-list/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/email/reports/global-address-list/index.js b/src/pages/email/reports/global-address-list/index.js index 6e78b2dacc26..314fb23f66f0 100644 --- a/src/pages/email/reports/global-address-list/index.js +++ b/src/pages/email/reports/global-address-list/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Visibility, VisibilityOff } from "@mui/icons-material"; const Page = () => { const actions = [ @@ -7,6 +8,7 @@ const Page = () => { label: "Unhide from Global Address List", type: "POST", url: "/api/ExecHideFromGAL", + icon: , data: { HideFromGAL: false, ID: "PrimarySmtpAddress", @@ -18,6 +20,7 @@ const Page = () => { label: "Hide from Global Address List", type: "POST", url: "/api/ExecHideFromGAL", + icon: , data: { HideFromGAL: true, ID: "PrimarySmtpAddress", From a99e4b75dd5914fdfdb69fb1634c08a068d560ed Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 Jan 2025 10:05:35 -0500 Subject: [PATCH 047/231] hide tenant in title for logbook --- src/pages/cipp/logs/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/cipp/logs/index.js b/src/pages/cipp/logs/index.js index f98368546531..fdee0356920d 100644 --- a/src/pages/cipp/logs/index.js +++ b/src/pages/cipp/logs/index.js @@ -95,6 +95,7 @@ const Page = () => { apiUrl={apiUrl} simpleColumns={simpleColumns} queryKey={`Listlogs-${dateFilter}-${filterEnabled}`} + tenantInTitle={false} apiData={{ DateFilter: dateFilter, // Pass date filter from state Filter: filterEnabled, // Pass filter toggle state From c0e01eb428a5dfe4827c1d5d1efcc79d481ee597 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 19:02:55 +0100 Subject: [PATCH 048/231] fix: irons for named location --- src/pages/tenant/conditional/list-named-locations/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pages/tenant/conditional/list-named-locations/index.js b/src/pages/tenant/conditional/list-named-locations/index.js index 99e704323535..2f72a57d5325 100644 --- a/src/pages/tenant/conditional/list-named-locations/index.js +++ b/src/pages/tenant/conditional/list-named-locations/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; +import { MinusIcon, PlusIcon } from "@heroicons/react/24/outline"; const Page = () => { const pageTitle = "Named Locations"; @@ -11,6 +12,7 @@ const Page = () => { label: "Add location to named location", type: "GET", url: "/api/ExecNamedLocation", + icon: , data: { namedLocationId: "id", change: "addLocation", @@ -23,6 +25,7 @@ const Page = () => { label: "Remove location from named location", type: "POST", url: "/api/ExecNamedLocation", + icon: , data: { namedLocationId: "id", change: "removeLocation", @@ -35,6 +38,7 @@ const Page = () => { label: "Add IP to named location", type: "POST", url: "/api/ExecNamedLocation", + icon: , data: { namedLocationId: "id", change: "addIp", @@ -47,6 +51,7 @@ const Page = () => { label: "Remove IP from named location", type: "POST", url: "/api/ExecNamedLocation", + icon: , data: { namedLocationId: "id", change: "removeIp", From 215c6a328991ec97697a908eccb1c956ec9845af Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 19:03:22 +0100 Subject: [PATCH 049/231] fix: icons and fix block signin on Shared Mailboxes --- .../email/reports/SharedMailboxEnabledAccount/index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/email/reports/SharedMailboxEnabledAccount/index.js b/src/pages/email/reports/SharedMailboxEnabledAccount/index.js index c72597ef6a25..186556bbe91e 100644 --- a/src/pages/email/reports/SharedMailboxEnabledAccount/index.js +++ b/src/pages/email/reports/SharedMailboxEnabledAccount/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Block } from "@mui/icons-material"; /* NOTE for Devs: @@ -18,10 +19,11 @@ const Page = () => { actions={[ { label: "Block Sign In", - type: "POST", + type: "GET", + icon: , url: "/api/ExecDisableUser", - data: { TenantFilter: "Tenant", ID: "id" }, - confirmText: "Are you sure you want to block this user from signing in?", + data: { ID: "id" }, + confirmText: "Are you sure you want to block the sign-in for this user?", }, ]} offCanvas={{ From 86ec1c9d29313d8645d5db9b444aa2ce45dd8fb7 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 19:07:17 +0100 Subject: [PATCH 050/231] fix: fix remove contact type --- src/pages/email/administration/contacts/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index 89a6a65d74c8..a6d7fa23c5fe 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -11,7 +11,7 @@ const Page = () => { const actions = [ { label: "Remove Contact", - type: "POST", + type: "GET", url: "/api/RemoveContact", data: { GUID: "id", From 6003bb18a69496c44066ace02fb02fb0f84101cb Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 19:18:17 +0100 Subject: [PATCH 051/231] fix: added icon to deleted items --- src/pages/identity/administration/deleted-items/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/identity/administration/deleted-items/index.js b/src/pages/identity/administration/deleted-items/index.js index ab568cfb92d9..43d9ddb9d817 100644 --- a/src/pages/identity/administration/deleted-items/index.js +++ b/src/pages/identity/administration/deleted-items/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import RestoreFromTrashIcon from '@mui/icons-material/RestoreFromTrash'; const Page = () => { const pageTitle = "Deleted Items"; @@ -8,8 +9,9 @@ const Page = () => { { label: "Restore Object", type: "GET", + icon: , url: "/api/ExecRestoreDeleted", - data: { TenantFilter: "Tenant", ID: "id" }, + data: { ID: "id" }, confirmText: "Are you sure you want to restore this user?", multiPost: false, }, From abd2d8c10e22e917bbb59af02280273455637325 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 20:20:42 +0100 Subject: [PATCH 052/231] fix: fix and add icons for email filter pages --- .../reports/antiphishing-filters/index.js | 18 ++- .../email/reports/malware-filters/index.js | 18 ++- .../reports/safeattachments-filters/index.js | 22 +-- .../email/reports/safelinks-filters/index.js | 141 ++++++++++-------- .../email/spamfilter/list-spamfilter/index.js | 20 ++- 5 files changed, 120 insertions(+), 99 deletions(-) diff --git a/src/pages/email/reports/antiphishing-filters/index.js b/src/pages/email/reports/antiphishing-filters/index.js index 96a1080d9498..0d3d3d26e736 100644 --- a/src/pages/email/reports/antiphishing-filters/index.js +++ b/src/pages/email/reports/antiphishing-filters/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Block, Check } from "@mui/icons-material"; const Page = () => { const pageTitle = "List of Anti-Phishing Filters"; @@ -8,25 +9,27 @@ const Page = () => { const actions = [ { label: "Enable Rule", - type: "POST", + type: "GET", + icon: , url: "/api/EditAntiPhishingFilter", data: { State: "Enable", - TenantFilter: "TenantFilter", // TenantFilter used in API path as per original file - RuleName: "id", + RuleName: "RuleName", }, confirmText: "Are you sure you want to enable this rule?", + condition: (row) => row.State === "Disabled", }, { label: "Disable Rule", - type: "POST", + type: "GET", + icon: , url: "/api/EditAntiPhishingFilter", data: { State: "Disable", - TenantFilter: "TenantFilter", - RuleName: "id", + RuleName: "RuleName", }, confirmText: "Are you sure you want to disable this rule?", + condition: (row) => row.State === "Enabled", }, // Uncomment the following block if Delete Rule is to be re-enabled in the future /* @@ -35,8 +38,7 @@ const Page = () => { type: "POST", url: "/api/RemoveAntiPhishingFilter", data: { - TenantFilter: "TenantFilter", - RuleName: "id", + RuleName: "RuleName", }, confirmText: "Are you sure you want to delete this rule?", }, diff --git a/src/pages/email/reports/malware-filters/index.js b/src/pages/email/reports/malware-filters/index.js index 4d5ffe472d98..5ede0778ed93 100644 --- a/src/pages/email/reports/malware-filters/index.js +++ b/src/pages/email/reports/malware-filters/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Block, Check } from "@mui/icons-material"; const Page = () => { return ( @@ -9,25 +10,27 @@ const Page = () => { actions={[ { label: "Enable Rule", - type: "POST", + type: "GET", + icon: , url: "/api/EditMalwareFilter", data: { State: "Enable", - TenantFilter: "tenant.defaultDomainName", - RuleName: "row.RuleName", + RuleName: "RuleName", }, confirmText: "Are you sure you want to enable this rule?", + condition: (row) => row.State === "Disabled", }, { label: "Disable Rule", - type: "POST", + type: "GET", + icon: , url: "/api/EditMalwareFilter", data: { State: "Disable", - TenantFilter: "tenant.defaultDomainName", - RuleName: "row.RuleName", + RuleName: "RuleName", }, confirmText: "Are you sure you want to disable this rule?", + condition: (row) => row.State === "Enabled", }, /* Uncomment and add additional actions if required by future specs { @@ -35,8 +38,7 @@ const Page = () => { type: "POST", url: "/api/RemoveMalwareFilter", data: { - TenantFilter: "tenant.defaultDomainName", - RuleName: "row.RuleName", + RuleName: "RuleName", }, confirmText: "Are you sure you want to delete this rule?", }, diff --git a/src/pages/email/reports/safeattachments-filters/index.js b/src/pages/email/reports/safeattachments-filters/index.js index b61ac47207bc..ae3d6930785e 100644 --- a/src/pages/email/reports/safeattachments-filters/index.js +++ b/src/pages/email/reports/safeattachments-filters/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Block, Check } from "@mui/icons-material"; const Page = () => { const pageTitle = "List of Safe Attachment Filters"; @@ -9,37 +10,38 @@ const Page = () => { const actions = [ { label: "Enable Rule", - type: "POST", + type: "GET", + icon: , url: "/api/EditSafeAttachmentsFilter", data: { - State: "Enable", - TenantFilter: "tenant.defaultDomainName", // TenantFilter uses default domain name in context - RuleName: "row.RuleName", + State: "!Enable", + RuleName: "RuleName", }, confirmText: "Are you sure you want to enable this rule?", color: "info", + condition: (row) => row.State === "Disabled" }, { label: "Disable Rule", - type: "POST", + type: "GET", + icon: , url: "/api/EditSafeAttachmentsFilter", data: { State: "Disable", - TenantFilter: "tenant.defaultDomainName", // TenantFilter uses default domain name in context - RuleName: "row.RuleName", + RuleName: "RuleName", }, confirmText: "Are you sure you want to disable this rule?", color: "info", + condition: (row) => row.State === "Enabled", }, // Commented out "Delete Rule" action from the original file as it was also commented in legacy code /* { label: "Delete Rule", - type: "POST", + type: "GET", url: "/api/RemoveSafeAttachmentsFilter", data: { - TenantFilter: "tenant.defaultDomainName", - RuleName: "row.RuleName", + RuleName: "RuleName", }, confirmText: "Are you sure you want to delete this rule?", color: "danger", diff --git a/src/pages/email/reports/safelinks-filters/index.js b/src/pages/email/reports/safelinks-filters/index.js index 7d2bf1ad5a37..bee1985d9745 100644 --- a/src/pages/email/reports/safelinks-filters/index.js +++ b/src/pages/email/reports/safelinks-filters/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Block, Check } from "@mui/icons-material"; /* Note: Tenant information is passed directly in apiData instead of using Redux (e.g., useSelector) */ /* Original file included a "Delete Rule" action. If needed, add back by following other action formats. */ @@ -7,74 +8,82 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" /* Removed custom formatters and FontAwesome imports, as table formatting is handled by CippTablePage */ const Page = () => { + const pageTitle = "List of Safe Link Filters"; + const apiUrl = "/api/ListSafeLinksFilters"; + + const actions = [ + { + label: "Enable Rule", + type: "GET", + icon: , + url: "/api/EditSafeLinksFilter", + data: { + State: "Enable", + RuleName: "RuleName", + }, + confirmText: "Are you sure you want to enable this rule?", + color: "info", + condition: (row) => row.State === "Disabled", + }, + { + label: "Disable Rule", + type: "GET", + icon: , + url: "/api/EditSafeLinksFilter", + data: { + State: "Disable", + RuleName: "RuleName", + }, + confirmText: "Are you sure you want to disable this rule?", + color: "info", + condition: (row) => row.State === "Enabled", + }, + /* TODO: implement Delete Rule action + { + label: "Delete Rule", + type: "GET", + url: "/api/EditSafeLinksFilter", + data: { + RuleName: "RuleName", + }, + confirmText: "Are you sure you want to delete this rule?", + color: "danger", + }, + */ + ]; + + const offCanvas = { + extendedInfoFields: ["RuleName", "Name", "State", "WhenCreated", "WhenChanged"], + actions: actions, // Attaching actions to offCanvas per original design + }; + + const simpleColumns = [ + "RuleName", + "Name", + "State", + "Priority", + "RecipientDomainIs", + "EnableSafeLinksForEmail", + "EnableSafeLinksForTeams", + "EnableSafeLinksForOffice", + "TrackClicks", + "ScanUrls", + "EnableForInternalSenders", + "DeliverMessageAfterScan", + "AllowClickThrough", + "DisableUrlRewrite", + "EnableOrganizationBranding", + "WhenCreated", + "WhenChanged", + ]; + return ( ); }; diff --git a/src/pages/email/spamfilter/list-spamfilter/index.js b/src/pages/email/spamfilter/list-spamfilter/index.js index 062f9e71dc87..e3c017d1cdbd 100644 --- a/src/pages/email/spamfilter/list-spamfilter/index.js +++ b/src/pages/email/spamfilter/list-spamfilter/index.js @@ -1,15 +1,19 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { Book, Block, Check } from "@mui/icons-material"; +import { TrashIcon } from "@heroicons/react/24/outline"; import Link from "next/link"; const Page = () => { const pageTitle = "Spam Filters"; + const apiUrl = "/api/ListSpamfilter" const actions = [ { label: "Create template based on rule", type: "POST", + icon: , url: "/api/AddSpamfilterTemplate", dataFunction: (data) => { return { ...data }; @@ -18,32 +22,34 @@ const Page = () => { }, { label: "Enable Rule", - type: "POST", + type: "GET", + icon: , url: "/api/EditSpamfilter", data: { State: "enable", - TenantFilter: "Tenant", name: "Name", }, confirmText: "Are you sure you want to enable this rule?", + condition: (row) => row.ruleState === "Disabled", }, { label: "Disable Rule", - type: "POST", + type: "GET", + icon: , url: "/api/EditSpamfilter", data: { State: "disable", - TenantFilter: "Tenant", name: "Name", }, confirmText: "Are you sure you want to disable this rule?", + condition: (row) => row.ruleState === "Enabled", }, { label: "Delete Rule", - type: "POST", + type: "GET", + icon: , url: "/api/RemoveSpamFilter", data: { - TenantFilter: "Tenant", name: "Name", }, confirmText: "Are you sure you want to delete this rule?", @@ -88,7 +94,7 @@ const Page = () => { return ( Date: Thu, 30 Jan 2025 16:28:54 -0500 Subject: [PATCH 053/231] Update CippApiDialog.jsx --- src/components/CippComponents/CippApiDialog.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/CippComponents/CippApiDialog.jsx b/src/components/CippComponents/CippApiDialog.jsx index 834cb3e958dc..2e37e00f3c4f 100644 --- a/src/components/CippComponents/CippApiDialog.jsx +++ b/src/components/CippComponents/CippApiDialog.jsx @@ -79,8 +79,7 @@ export const CippApiDialog = (props) => { } else { Object.keys(dataObject).forEach((key) => { const value = dataObject[key]; - - if (typeof value === "string" && value.startsWith("!")) { + if (value.startsWith("!")) { newData[key] = value.slice(1); } else if (typeof value === "string") { if (row[value] !== undefined) { From 7e8bdc61e430888ab0b6e3c408c35f25916fc2ee Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 Jan 2025 22:36:51 +0100 Subject: [PATCH 054/231] fix: no idea why lower case works as expected --- src/pages/email/reports/safeattachments-filters/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/email/reports/safeattachments-filters/index.js b/src/pages/email/reports/safeattachments-filters/index.js index ae3d6930785e..11e15a1bdea7 100644 --- a/src/pages/email/reports/safeattachments-filters/index.js +++ b/src/pages/email/reports/safeattachments-filters/index.js @@ -14,7 +14,7 @@ const Page = () => { icon: , url: "/api/EditSafeAttachmentsFilter", data: { - State: "!Enable", + State: "!enable", RuleName: "RuleName", }, confirmText: "Are you sure you want to enable this rule?", From f15e30a196669b192947fa870d685f7611adc2f6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 Jan 2025 16:42:23 -0500 Subject: [PATCH 055/231] Update CippApiDialog.jsx --- src/components/CippComponents/CippApiDialog.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CippComponents/CippApiDialog.jsx b/src/components/CippComponents/CippApiDialog.jsx index 2e37e00f3c4f..bd6348868c8b 100644 --- a/src/components/CippComponents/CippApiDialog.jsx +++ b/src/components/CippComponents/CippApiDialog.jsx @@ -79,7 +79,7 @@ export const CippApiDialog = (props) => { } else { Object.keys(dataObject).forEach((key) => { const value = dataObject[key]; - if (value.startsWith("!")) { + if (typeof value === "string" && value.startsWith("!")) { newData[key] = value.slice(1); } else if (typeof value === "string") { if (row[value] !== undefined) { From 4a812c0d9ecbdffe502ae1df96b92b12d5861999 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 Jan 2025 17:13:43 -0500 Subject: [PATCH 056/231] add missing mailbox actions --- .../email/administration/mailboxes/index.js | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/pages/email/administration/mailboxes/index.js b/src/pages/email/administration/mailboxes/index.js index 81726a1abd14..eea3d264e425 100644 --- a/src/pages/email/administration/mailboxes/index.js +++ b/src/pages/email/administration/mailboxes/index.js @@ -131,6 +131,93 @@ const Page = () => { confirmText: "Are you sure you want to delete this mailbox?", multiPost: false, }, + { + label: "Copy Sent Items to Shared Mailbox", + type: "GET", + url: "/api/ExecCopyForSent", + data: { ID: "UPN" }, + confirmText: "Are you sure you want to enable Copy Sent Items to Shared Mailbox?", + icon: , + condition: (row) => + row.MessageCopyForSentAsEnabled === false && row.recipientTypeDetails === "SharedMailbox", + }, + { + label: "Disable Copy Sent Items to Shared Mailbox", + type: "GET", + url: "/api/ExecCopyForSent", + data: { ID: "UPN", MessageCopyForSentAsEnabled: false }, + confirmText: "Are you sure you want to disable Copy Sent Items to Shared Mailbox?", + icon: , + condition: (row) => + row.MessageCopyForSentAsEnabled === true && row.recipientTypeDetails === "SharedMailbox", + }, + { + label: "Set mailbox locale", + type: "POST", + url: "/api/ExecSetMailboxLocale", + data: { user: "UPN", ProhibitSendQuota: true }, + confirmText: "Enter a locale, e.g. en-US", + icon: , + fields: [ + { + label: "Locale", + name: "locale", + type: "textField", + placeholder: "e.g. en-US", + }, + ], + }, + { + label: "Set Send Quota", + type: "POST", + url: "/api/ExecSetMailboxQuota", + data: { user: "UPN", ProhibitSendQuota: true }, + confirmText: "Enter a quota. e.g. 1000MB, 10GB,1TB", + icon: , + fields: [ + { + label: "Quota", + name: "quota", + type: "textField", + placeholder: "e.g. 1000MB, 10GB,1TB", + }, + ], + }, + { + label: "Set Send and Receive Quota", + type: "POST", + url: "/api/ExecSetMailboxQuota", + data: { + user: "UPN", + ProhibitSendReceiveQuota: true, + }, + confirmText: "Enter a quota. e.g. 1000MB, 10GB,1TB", + icon: , + fields: [ + { + label: "Quota", + name: "quota", + type: "textField", + placeholder: "e.g. 1000MB, 10GB,1TB", + }, + ], + }, + { + label: "Set Quota Warning Level", + type: "POST", + url: "/api/ExecSetMailboxQuota", + data: { user: "UPN", IssueWarningQuota: true }, + confirmText: "Enter a quota. e.g. 1000MB, 10GB,1TB", + icon: , + fields: [ + { + label: "Quota", + name: "quota", + type: "textField", + placeholder: "e.g. 1000MB, 10GB,1TB", + }, + ], + }, ]; // Define off-canvas details From eba21f51540b5567957206000588a974e99bb467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 29 Jan 2025 20:44:15 +0100 Subject: [PATCH 057/231] Add back sync autopilot devices button Add icons More icons Add SharePoint Admin portal and update icons in bulk actions menu update icon property there must be a less ugly way to do this, help Add icons to action buttons across various pages --- src/components/bulk-actions-menu.js | 29 +++++++++++ src/data/portals.json | 34 ++++++------- src/pages/cipp/settings/tenants.js | 7 ++- .../email/administration/contacts/index.js | 8 ++- .../email/administration/mailboxes/index.js | 7 ++- .../tenant-allow-block-lists/index.js | 9 +++- .../resources/management/list-rooms/index.js | 7 ++- .../resources/management/room-lists/index.js | 4 +- .../spamfilter/list-connectionfilter/index.js | 8 ++- .../email/spamfilter/list-spamfilter/index.js | 7 ++- .../email/tools/mailbox-restores/index.js | 10 +++- .../list-connector-templates/index.js | 14 ++++++ .../email/transport/list-connectors/index.js | 12 ++++- src/pages/email/transport/list-rules/index.js | 8 ++- .../email/transport/list-templates/index.js | 7 ++- src/pages/endpoint/MEM/devices/index.js | 20 ++++++++ src/pages/endpoint/applications/list/index.js | 4 +- .../endpoint/applications/queue/index.js | 7 ++- .../endpoint/autopilot/list-devices/index.js | 50 +++++++++++++------ .../endpoint/autopilot/list-profiles/index.js | 7 ++- .../autopilot/list-status-pages/index.js | 7 ++- .../identity/administration/devices/index.js | 8 ++- .../administration/group-templates/index.js | 6 ++- .../identity/administration/groups/index.js | 12 ++--- .../administration/jit-admin/index.js | 3 +- .../administration/risky-users/index.js | 5 +- .../identity/administration/users/index.js | 11 ++-- src/pages/index.js | 1 + .../security/incidents/list-alerts/index.js | 3 ++ .../incidents/list-incidents/index.js | 5 ++ src/pages/teams-share/sharepoint/index.js | 20 +++++++- .../teams-share/teams/business-voice/index.js | 4 ++ .../teams-share/teams/list-team/index.js | 3 +- .../alert-configuration/index.js | 8 ++- .../authentication-methods/index.js | 3 ++ .../tenant/backup/backup-wizard/index.js | 9 +++- .../conditional/deploy-vacation/index.js | 3 +- .../conditional/list-named-locations/index.js | 3 +- .../tenant/conditional/list-policies/index.js | 7 ++- .../tenant/conditional/list-template/index.js | 2 + .../tenant/gdap-management/invites/index.js | 3 +- .../gdap-management/onboarding/index.js | 8 ++- .../gdap-management/role-templates/index.js | 9 ++-- .../tenant/gdap-management/roles/index.js | 12 +++-- .../reports/list-csp-licenses/index.jsx | 4 +- .../tenant/standards/bpa-report/index.js | 4 +- .../standards/domains-analyser/index.js | 12 +++-- .../tenant/standards/list-standards/index.js | 6 +-- 48 files changed, 337 insertions(+), 103 deletions(-) diff --git a/src/components/bulk-actions-menu.js b/src/components/bulk-actions-menu.js index b4ceba4c48bd..fd15898e28a3 100644 --- a/src/components/bulk-actions-menu.js +++ b/src/components/bulk-actions-menu.js @@ -2,6 +2,33 @@ import PropTypes from "prop-types"; import ChevronDownIcon from "@heroicons/react/24/outline/ChevronDownIcon"; import { Button, Link, ListItemText, Menu, MenuItem, SvgIcon } from "@mui/material"; import { usePopover } from "../hooks/use-popover"; +import { FilePresent, Laptop, Mail, Share, Shield, ShieldMoon } from "@mui/icons-material"; +import { GlobeAltIcon, UsersIcon, ServerIcon } from "@heroicons/react/24/outline"; + +function getIconByName(iconName) { + switch (iconName) { + case "GlobeAltIcon": + return ; + case "Mail": + return ; + case "UsersIcon": + return ; + case "FilePresent": + return ; + case "ServerIcon": + return ; + case "Laptop": + return ; + case "Share": + return ; + case "Shield": + return ; + case "ShieldMoon": + return ; + default: + return null; + } +} export const BulkActionsMenu = (props) => { const { buttonName, sx, row, actions = [], ...other } = props; @@ -55,12 +82,14 @@ export const BulkActionsMenu = (props) => { target="_blank" rel="noreferrer" > + {getIconByName(action.icon)} ); } else { return ( + {getIconByName(action.icon)} ); diff --git a/src/data/portals.json b/src/data/portals.json index 130c9f2d11e4..d5fdbd5ebeb0 100644 --- a/src/data/portals.json +++ b/src/data/portals.json @@ -6,7 +6,7 @@ "variable": "customerId", "target": "_blank", "external": true, - "icon": "cog" + "icon": "GlobeAltIcon" }, { "label": "Exchange Portal", @@ -15,7 +15,7 @@ "variable": "defaultDomainName", "target": "_blank", "external": true, - "icon": "mail-bulk" + "icon": "Mail" }, { "label": "Entra Portal", @@ -24,7 +24,7 @@ "variable": "defaultDomainName", "target": "_blank", "external": true, - "icon": "users" + "icon": "UsersIcon" }, { "label": "Teams Portal", @@ -33,7 +33,7 @@ "variable": "defaultDomainName", "target": "_blank", "external": true, - "icon": "comments" + "icon": "FilePresent" }, { "label": "Azure Portal", @@ -42,7 +42,7 @@ "variable": "defaultDomainName", "target": "_blank", "external": true, - "icon": "server" + "icon": "ServerIcon" }, { "label": "Intune Portal", @@ -51,7 +51,16 @@ "variable": "defaultDomainName", "target": "_blank", "external": true, - "icon": "laptop-code" + "icon": "Laptop" + }, + { + "label": "SharePoint Admin", + "name": "SharePoint_Admin", + "url": "https://admin.microsoft.com/Partner/beginclientsession.aspx?CTID=customerId&CSDEST=SharePoint", + "variable": "customerId", + "target": "_blank", + "external": true, + "icon": "Share" }, { "label": "Security Portal", @@ -60,7 +69,7 @@ "variable": "customerId", "target": "_blank", "external": true, - "icon": "shield-alt" + "icon": "Shield" }, { "label": "Compliance Portal", @@ -69,15 +78,6 @@ "variable": "customerId", "target": "_blank", "external": true, - "icon": "shield-alt" - }, - { - "label": "SharePoint Admin", - "name": "SharePoint_Admin", - "url": "https://admin.microsoft.com/Partner/beginclientsession.aspx?CTID=customerId&CSDEST=SharePoint", - "variable": "customerId", - "target": "_blank", - "external": true, - "icon": "book" + "icon": "ShieldMoon" } ] diff --git a/src/pages/cipp/settings/tenants.js b/src/pages/cipp/settings/tenants.js index 3a09b8ff8aa4..529e7c413a18 100644 --- a/src/pages/cipp/settings/tenants.js +++ b/src/pages/cipp/settings/tenants.js @@ -5,7 +5,7 @@ import tabOptions from "./tabOptions"; import { Button, SvgIcon } from "@mui/material"; import { CippApiDialog } from "/src/components/CippComponents/CippApiDialog"; import { useDialog } from "/src/hooks/use-dialog"; -import { Sync } from "@mui/icons-material"; +import { Sync, Block, PlayArrow, RestartAlt, Delete, Add } from "@mui/icons-material"; const Page = () => { const pageTitle = "Tenants - Backend"; @@ -17,6 +17,7 @@ const Page = () => { label: "Exclude Tenants", type: "POST", url: `/api/ExecExcludeTenant?AddExclusion=true`, + icon: , data: { value: "customerId" }, confirmText: "Are you sure you want to exclude these tenants?", multiPost: false, @@ -25,6 +26,7 @@ const Page = () => { label: "Include Tenants", type: "POST", url: `/api/ExecExcludeTenant?RemoveExclusion=true`, + icon: , data: { value: "customerId" }, confirmText: "Are you sure you want to include these tenants?", multiPost: false, @@ -33,6 +35,7 @@ const Page = () => { label: "Refresh CPV Permissions", type: "POST", url: `/api/ExecCPVPermissions`, + icon: , data: { TenantFilter: "customerId" }, confirmText: "Are you sure you want to refresh the CPV permissions for these tenants?", multiPost: false, @@ -41,6 +44,7 @@ const Page = () => { label: "Reset CPV Permissions", type: "POST", url: `/api/ExecCPVPermissions?&ResetSP=true`, + icon: , data: { TenantFilter: "customerId" }, confirmText: "Are you sure you want to reset the CPV permissions for these tenants? (This will delete the Service Principal and re-add it.)", @@ -50,6 +54,7 @@ const Page = () => { label: "Remove Tenant", type: "POST", url: `/api/ExecRemoveTenant`, + icon: , data: { TenantID: "customerId" }, confirmText: "Are you sure you want to remove this tenant?", multiPost: false, diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index a6d7fa23c5fe..ac22d6596579 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -1,6 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; -import { Edit } from "@mui/icons-material"; +import { Edit, PersonAdd } from "@mui/icons-material"; import { Button } from "@mui/material"; import Link from "next/link"; import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; @@ -40,7 +40,11 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/email/administration/mailboxes/index.js b/src/pages/email/administration/mailboxes/index.js index eea3d264e425..90bfc401266e 100644 --- a/src/pages/email/administration/mailboxes/index.js +++ b/src/pages/email/administration/mailboxes/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import Link from "next/link"; import { Button } from "@mui/material"; +import { Add } from "@mui/icons-material"; import { Archive, @@ -269,7 +270,11 @@ const Page = () => { filters={filterList} cardButton={ <> - diff --git a/src/pages/email/administration/tenant-allow-block-lists/index.js b/src/pages/email/administration/tenant-allow-block-lists/index.js index 508d5c67110e..f88d18848767 100644 --- a/src/pages/email/administration/tenant-allow-block-lists/index.js +++ b/src/pages/email/administration/tenant-allow-block-lists/index.js @@ -2,7 +2,8 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; -import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; +import TrashIcon from "@heroicons/react/24/outline/TrashIcon"; +import { PlaylistAdd } from "@mui/icons-material"; const Page = () => { const pageTitle = "Tenant Allow/Block Lists"; @@ -50,7 +51,11 @@ const Page = () => { }} cardButton={ <> - diff --git a/src/pages/email/resources/management/list-rooms/index.js b/src/pages/email/resources/management/list-rooms/index.js index e81e9313ef7a..a3fe7dab1547 100644 --- a/src/pages/email/resources/management/list-rooms/index.js +++ b/src/pages/email/resources/management/list-rooms/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; +import { AddHomeWork } from "@mui/icons-material"; const Page = () => { const pageTitle = "Rooms"; @@ -12,7 +13,11 @@ const Page = () => { apiUrl="/api/ListRooms" simpleColumns={["displayName", "building", "floorNumber", "capacity", "bookingType"]} cardButton={ - } diff --git a/src/pages/email/resources/management/room-lists/index.js b/src/pages/email/resources/management/room-lists/index.js index 11abfc1683cb..6ae175a9ed1f 100644 --- a/src/pages/email/resources/management/room-lists/index.js +++ b/src/pages/email/resources/management/room-lists/index.js @@ -1,15 +1,17 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Visibility } from "@mui/icons-material"; const Page = () => { const pageTitle = "Room Lists"; - const apiUrl = "/api/ListRoomLists" + const apiUrl = "/api/ListRoomLists"; const actions = [ { label: "View included Rooms", link: `/email/resources/management/room-lists/list/view?roomAddress=[emailAddress]`, color: "info", + icon: , }, ]; diff --git a/src/pages/email/spamfilter/list-connectionfilter/index.js b/src/pages/email/spamfilter/list-connectionfilter/index.js index 97e8cd8f963f..02481161dc18 100644 --- a/src/pages/email/spamfilter/list-connectionfilter/index.js +++ b/src/pages/email/spamfilter/list-connectionfilter/index.js @@ -1,7 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; -import { Book } from "@mui/icons-material"; +import { Book, AddModerator } from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -45,7 +45,11 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/email/spamfilter/list-spamfilter/index.js b/src/pages/email/spamfilter/list-spamfilter/index.js index e3c017d1cdbd..55985f5d7316 100644 --- a/src/pages/email/spamfilter/list-spamfilter/index.js +++ b/src/pages/email/spamfilter/list-spamfilter/index.js @@ -4,6 +4,7 @@ import { Button } from "@mui/material"; import { Book, Block, Check } from "@mui/icons-material"; import { TrashIcon } from "@heroicons/react/24/outline"; import Link from "next/link"; +import { RocketLaunch } from "@mui/icons-material"; const Page = () => { const pageTitle = "Spam Filters"; @@ -100,7 +101,11 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/email/tools/mailbox-restores/index.js b/src/pages/email/tools/mailbox-restores/index.js index ffa463800bd5..cedc2e73f0a9 100644 --- a/src/pages/email/tools/mailbox-restores/index.js +++ b/src/pages/email/tools/mailbox-restores/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; +import { RestoreFromTrash, PlayArrow, Pause, Delete } from "@mui/icons-material"; import MailboxRestoreDetails from "../../../../components/CippComponents/MailboxRestoreDetails"; const Page = () => { @@ -12,6 +13,7 @@ const Page = () => { label: "Resume Restore Request", type: "POST", url: "/api/ExecMailboxRestore", + icon: , data: { TenantFilter: "Tenant", Identity: "Identity", @@ -24,6 +26,7 @@ const Page = () => { label: "Suspend Restore Request", type: "POST", url: "/api/ExecMailboxRestore", + icon: , data: { TenantFilter: "Tenant", Identity: "Identity", @@ -36,6 +39,7 @@ const Page = () => { label: "Remove Restore Request", type: "POST", url: "/api/ExecMailboxRestore", + icon: , data: { TenantFilter: "Tenant", Identity: "Identity", @@ -63,7 +67,11 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/email/transport/list-connector-templates/index.js b/src/pages/email/transport/list-connector-templates/index.js index 671c148f21e2..188e87254ab6 100644 --- a/src/pages/email/transport/list-connector-templates/index.js +++ b/src/pages/email/transport/list-connector-templates/index.js @@ -1,4 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import { Button } from "@mui/material"; +import Link from "next/link"; +import { RocketLaunch } from "@mui/icons-material"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { EyeIcon, TrashIcon } from "@heroicons/react/24/outline"; import ConnectorTemplateDetails from "../../../../components/CippComponents/ConnectorTemplateDetails"; @@ -39,6 +42,17 @@ const Page = () => { label: "Add Template", href: "/email/connectors/add-connector-templates", }} + cardButton={ + <> + + + } /> ); }; diff --git a/src/pages/email/transport/list-connectors/index.js b/src/pages/email/transport/list-connectors/index.js index c61b44ad6fa2..477b191fdff5 100644 --- a/src/pages/email/transport/list-connectors/index.js +++ b/src/pages/email/transport/list-connectors/index.js @@ -1,6 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { RocketLaunch, Book, Check, Block, Delete } from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -11,6 +12,7 @@ const Page = () => { label: "Create template based on connector", type: "POST", url: "/api/AddExConnectorTemplate", + icon: , postEntireRow: true, confirmText: "Are you sure you want to create a template based on this connector?", color: "info", @@ -19,6 +21,7 @@ const Page = () => { label: "Enable Connector", type: "POST", url: "/api/EditExConnector", + icon: , data: { State: "Enable", GUID: "Guid", @@ -31,6 +34,7 @@ const Page = () => { label: "Disable Connector", type: "POST", url: "/api/EditExConnector", + icon: , data: { State: "Disable", GUID: "Guid", @@ -43,6 +47,7 @@ const Page = () => { label: "Delete Connector", type: "POST", url: "/api/RemoveExConnector", + icon: , data: { GUID: "Guid", Type: "cippconnectortype", @@ -80,10 +85,15 @@ const Page = () => { titleButton={{ label: "Deploy Connector", href: "/email/connectors/deploy-connector", + startIcon: , // Added icon }} cardButton={ <> - diff --git a/src/pages/email/transport/list-rules/index.js b/src/pages/email/transport/list-rules/index.js index 7312f49794fc..0c6128024c6e 100644 --- a/src/pages/email/transport/list-rules/index.js +++ b/src/pages/email/transport/list-rules/index.js @@ -1,7 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; -import { Book, DoDisturb, Done } from "@mui/icons-material"; +import { Book, DoDisturb, Done, RocketLaunch } from "@mui/icons-material"; import { TrashIcon } from "@heroicons/react/24/outline"; import Link from "next/link"; @@ -88,7 +88,11 @@ const Page = () => { ]} cardButton={ <> - diff --git a/src/pages/email/transport/list-templates/index.js b/src/pages/email/transport/list-templates/index.js index 1bfff7428f93..fb40f8da0e9b 100644 --- a/src/pages/email/transport/list-templates/index.js +++ b/src/pages/email/transport/list-templates/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { EyeIcon, TrashIcon } from "@heroicons/react/24/outline"; import { Button } from "@mui/material"; +import { RocketLaunch } from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -35,7 +36,11 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/endpoint/MEM/devices/index.js b/src/pages/endpoint/MEM/devices/index.js index 4ce9ebcbc46a..0965bb50462f 100644 --- a/src/pages/endpoint/MEM/devices/index.js +++ b/src/pages/endpoint/MEM/devices/index.js @@ -2,6 +2,17 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { useSettings } from "/src/hooks/use-settings"; import { EyeIcon } from "@heroicons/react/24/outline"; +import { + Sync, + RestartAlt, + LocationOn, + Password, + PasswordOutlined, + Key, + Security, + FindInPage, + Shield, +} from "@mui/icons-material"; const Page = () => { const pageTitle = "Devices"; @@ -11,6 +22,7 @@ const Page = () => { { label: "Sync Device", type: "POST", + icon: , url: "/api/ExecDeviceAction", data: { GUID: "id", @@ -21,6 +33,7 @@ const Page = () => { { label: "Reboot Device", type: "POST", + icon: , url: "/api/ExecDeviceAction", data: { GUID: "id", @@ -31,6 +44,7 @@ const Page = () => { { label: "Locate Device", type: "POST", + icon: , url: "/api/ExecDeviceAction", data: { GUID: "id", @@ -41,6 +55,7 @@ const Page = () => { { label: "Retrieve LAPs password", type: "POST", + icon: , url: "/api/ExecGetLocalAdminPassword", data: { GUID: "azureADDeviceId", @@ -50,6 +65,7 @@ const Page = () => { { label: "Rotate Local Admin Password", type: "POST", + icon: , url: "/api/ExecDeviceAction", data: { GUID: "id", @@ -60,6 +76,7 @@ const Page = () => { { label: "Retrieve Bitlocker Keys", type: "POST", + icon: , url: "/api/ExecGetRecoveryKey", data: { GUID: "azureADDeviceId", @@ -69,6 +86,7 @@ const Page = () => { { label: "Windows Defender Full Scan", type: "POST", + icon: , url: "/api/ExecDeviceAction", data: { GUID: "id", @@ -80,6 +98,7 @@ const Page = () => { { label: "Windows Defender Quick Scan", type: "POST", + icon: , url: "/api/ExecDeviceAction", data: { GUID: "id", @@ -91,6 +110,7 @@ const Page = () => { { label: "Update Windows Defender", type: "POST", + icon: , url: "/api/ExecDeviceAction", data: { GUID: "id", diff --git a/src/pages/endpoint/applications/list/index.js b/src/pages/endpoint/applications/list/index.js index 5a3d8eef0cfb..9530d9712981 100644 --- a/src/pages/endpoint/applications/list/index.js +++ b/src/pages/endpoint/applications/list/index.js @@ -1,7 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { GlobeAltIcon, TrashIcon, UserIcon } from "@heroicons/react/24/outline"; -import { LaptopMac } from "@mui/icons-material"; +import { Add, LaptopMac } from "@mui/icons-material"; import { Button } from "@mui/material"; import Link from "next/link"; @@ -95,7 +95,7 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/endpoint/applications/queue/index.js b/src/pages/endpoint/applications/queue/index.js index 0f30341cefcb..3e683b11e8b0 100644 --- a/src/pages/endpoint/applications/queue/index.js +++ b/src/pages/endpoint/applications/queue/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { CheckmarkIcon } from "react-hot-toast"; import { Button } from "@mui/material"; +import { PlayArrow, Add } from "@mui/icons-material"; import Link from "next/link"; import { ApiPostCall } from "../../../../api/ApiCall"; import { CippApiResults } from "../../../../components/CippComponents/CippApiResults"; @@ -40,9 +41,11 @@ const Page = () => { tenantInTitle={false} cardButton={ <> - + - diff --git a/src/pages/endpoint/autopilot/list-devices/index.js b/src/pages/endpoint/autopilot/list-devices/index.js index d924ec33b3d5..038e5b9d8d2a 100644 --- a/src/pages/endpoint/autopilot/list-devices/index.js +++ b/src/pages/endpoint/autopilot/list-devices/index.js @@ -1,11 +1,15 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { CippApiDialog } from "/src/components/CippComponents/CippApiDialog.jsx"; import { Button } from "@mui/material"; -import { PersonAdd, Delete } from "@mui/icons-material"; +import { PersonAdd, Delete, Sync, Add } from "@mui/icons-material"; +import { useDialog } from "../../../../hooks/use-dialog"; import Link from "next/link"; +import { useState } from "react"; const Page = () => { const pageTitle = "Autopilot Devices"; + const createDialog = useDialog(); const actions = [ { @@ -70,20 +74,36 @@ const Page = () => { ]; return ( - - - - } - /> + <> + + + + + } + /> + + ); }; diff --git a/src/pages/endpoint/autopilot/list-profiles/index.js b/src/pages/endpoint/autopilot/list-profiles/index.js index 2e9d5f419aef..e1e3e8375b1a 100644 --- a/src/pages/endpoint/autopilot/list-profiles/index.js +++ b/src/pages/endpoint/autopilot/list-profiles/index.js @@ -3,6 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { EyeIcon } from "@heroicons/react/24/outline"; import { Button } from "@mui/material"; import Link from "next/link"; +import { AccountCircle } from "@mui/icons-material"; import CippJsonView from "../../../../components/CippFormPages/CippJSONView"; const Page = () => { @@ -32,7 +33,11 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/endpoint/autopilot/list-status-pages/index.js b/src/pages/endpoint/autopilot/list-status-pages/index.js index d49f4281b043..fc1525f4cbbb 100644 --- a/src/pages/endpoint/autopilot/list-status-pages/index.js +++ b/src/pages/endpoint/autopilot/list-status-pages/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; +import { PostAdd } from "@mui/icons-material"; const Page = () => { const pageTitle = "Autopilot Status Pages"; @@ -25,7 +26,11 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/identity/administration/devices/index.js b/src/pages/identity/administration/devices/index.js index 456329c33755..0ae68838f469 100644 --- a/src/pages/identity/administration/devices/index.js +++ b/src/pages/identity/administration/devices/index.js @@ -1,7 +1,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Layout as DashboardLayout } from "/src/layouts/index.js"; // had to add an extra path here because I added an extra folder structure. We should switch to absolute pathing so we dont have to deal with relative. import { useSettings } from "/src/hooks/use-settings"; -import { EyeIcon } from "@heroicons/react/24/outline"; +import { Visibility, CheckCircleOutline, Block, VpnKey, DeleteForever } from "@mui/icons-material"; const Page = () => { const pageTitle = "Devices"; @@ -12,7 +12,7 @@ const Page = () => { label: "View in Entra", link: `https://entra.microsoft.com/${tenantFilter}/#view/Microsoft_AAD_Devices/DeviceDetailsMenuBlade/~/Properties/objectId/[id]/deviceId/`, color: "info", - icon: , + icon: , target: "_blank", multiPost: false, external: true, @@ -27,6 +27,7 @@ const Page = () => { }, confirmText: "Are you sure you want to enable this device?", multiPost: false, + icon: , }, { label: "Disable Device", @@ -38,6 +39,7 @@ const Page = () => { }, confirmText: "Are you sure you want to disable this device?", multiPost: false, + icon: , }, { label: "Retrieve BitLocker Keys", @@ -48,6 +50,7 @@ const Page = () => { }, confirmText: "Are you sure you want to retrieve the BitLocker keys?", multiPost: false, + icon: , }, { label: "Delete Device", @@ -59,6 +62,7 @@ const Page = () => { }, confirmText: "Are you sure you want to delete this device?", multiPost: false, + icon: , }, ]; diff --git a/src/pages/identity/administration/group-templates/index.js b/src/pages/identity/administration/group-templates/index.js index 52bb163880a8..69a3a55d6911 100644 --- a/src/pages/identity/administration/group-templates/index.js +++ b/src/pages/identity/administration/group-templates/index.js @@ -1,6 +1,7 @@ import { Button } from "@mui/material"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import { AddBox, RocketLaunch, Delete } from "@mui/icons-material"; import Link from "next/link"; import { CippCodeBlock } from "../../../../components/CippComponents/CippCodeBlock"; @@ -12,6 +13,7 @@ const Page = () => { label: "Delete Template", type: "GET", url: "/api/RemoveGroupTemplate", + icon: , data: { ID: "GUID", }, @@ -31,10 +33,10 @@ const Page = () => { actions={actions} cardButton={ <> - - diff --git a/src/pages/identity/administration/groups/index.js b/src/pages/identity/administration/groups/index.js index 1fb57be03d1e..0c9fc8452887 100644 --- a/src/pages/identity/administration/groups/index.js +++ b/src/pages/identity/administration/groups/index.js @@ -2,8 +2,8 @@ import { Button } from "@mui/material"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Layout as DashboardLayout } from "/src/layouts/index.js"; import Link from "next/link"; -import { EyeIcon, LockClosedIcon, LockOpenIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline"; -import { LockOpen, Visibility, VisibilityOff } from "@mui/icons-material"; +import { TrashIcon } from "@heroicons/react/24/outline"; +import { Visibility, VisibilityOff, GroupAdd, Edit, LockOpen, Lock } from "@mui/icons-material"; const Page = () => { const pageTitle = "Groups"; @@ -13,7 +13,7 @@ const Page = () => { label: "Edit Group", link: "/identity/administration/groups/edit?groupId=[id]", multiPost: false, - icon: , + icon: , color: "success", }, { @@ -49,7 +49,7 @@ const Page = () => { label: "Only allow messages from people inside the organisation", type: "GET", url: "/api/ExecGroupsDeliveryManagement", - icon: , + icon: , data: { TenantFilter: "TenantFilter", ID: "mail", @@ -63,7 +63,7 @@ const Page = () => { { label: "Allow messages from people inside and outside the organisation", type: "GET", - icon: , + icon: , url: "/api/ExecGroupsDeliveryManagement", data: { TenantFilter: "TenantFilter", @@ -106,7 +106,7 @@ const Page = () => { title={pageTitle} cardButton={ <> - diff --git a/src/pages/identity/administration/jit-admin/index.js b/src/pages/identity/administration/jit-admin/index.js index cc90ab853599..e4ad1c00ce46 100644 --- a/src/pages/identity/administration/jit-admin/index.js +++ b/src/pages/identity/administration/jit-admin/index.js @@ -1,6 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import CippTablePage from "/src/components/CippComponents/CippTablePage"; import { Button } from "@mui/material"; +import { AdminPanelSettings } from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -8,7 +9,7 @@ const Page = () => { - diff --git a/src/pages/identity/administration/risky-users/index.js b/src/pages/identity/administration/risky-users/index.js index 759117480d8b..a5327f24d7f3 100644 --- a/src/pages/identity/administration/risky-users/index.js +++ b/src/pages/identity/administration/risky-users/index.js @@ -1,7 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; -import { Clear } from "@mui/icons-material"; -import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { Clear, Search } from "@mui/icons-material"; const Page = () => { const pageTitle = "Risky Users"; @@ -19,7 +18,7 @@ const Page = () => { { label: "Research Compromised Account", type: "GET", - icon: , + icon: , link: "/identity/administration/users/user/bec?userId=[id]", confirmText: "Are you sure you want to research this compromised account?", multiPost: false, diff --git a/src/pages/identity/administration/users/index.js b/src/pages/identity/administration/users/index.js index ec4552915b18..5d646a68fb69 100644 --- a/src/pages/identity/administration/users/index.js +++ b/src/pages/identity/administration/users/index.js @@ -1,6 +1,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { Button } from "@mui/material"; +import { Send, GroupAdd, PersonAdd } from "@mui/icons-material"; import Link from "next/link"; import { useSettings } from "/src/hooks/use-settings.js"; import { CippUserActions } from "/src/components/CippComponents/CippUserActions.jsx"; @@ -53,15 +54,15 @@ const Page = () => { apiUrl="/api/ListGraphRequest" cardButton={ <> - + - - } apiData={{ diff --git a/src/pages/index.js b/src/pages/index.js index 0c60b06fe5a2..c5810877c598 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -167,6 +167,7 @@ const Page = () => { label: portal.label, target: "_blank", link: portal.url.replace(portal.variable, tenantLookup?.[portal.variable]), + icon: portal.icon, })); setPortalMenuItems(menuItems); } diff --git a/src/pages/security/incidents/list-alerts/index.js b/src/pages/security/incidents/list-alerts/index.js index 09e1411d9d3b..4110754efd8d 100644 --- a/src/pages/security/incidents/list-alerts/index.js +++ b/src/pages/security/incidents/list-alerts/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Assignment, Done } from "@mui/icons-material"; const Page = () => { const pageTitle = "Alerts List"; @@ -9,6 +10,7 @@ const Page = () => { { label: "Set status to in progress", type: "POST", + icon: , url: "/api/ExecSetSecurityAlert", data: { TenantFilter: "Tenant", @@ -22,6 +24,7 @@ const Page = () => { { label: "Set status to resolved", type: "POST", + icon: , url: "/api/ExecSetSecurityAlert", data: { TenantFilter: "Tenant", diff --git a/src/pages/security/incidents/list-incidents/index.js b/src/pages/security/incidents/list-incidents/index.js index bebae5e2f983..9737696a1d02 100644 --- a/src/pages/security/incidents/list-incidents/index.js +++ b/src/pages/security/incidents/list-incidents/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { PersonAdd, PlayArrow, Assignment, Done } from "@mui/icons-material"; const Page = () => { const pageTitle = "Incidents List"; @@ -9,6 +10,7 @@ const Page = () => { { label: "Assign to self", type: "POST", + icon: , url: "/api/ExecSetSecurityIncident", data: { TenantFilter: "Tenant", @@ -20,6 +22,7 @@ const Page = () => { { label: "Set status to active", type: "POST", + icon: , url: "/api/ExecSetSecurityIncident", data: { TenantFilter: "Tenant", @@ -32,6 +35,7 @@ const Page = () => { { label: "Set status to in progress", type: "POST", + icon: , url: "/api/ExecSetSecurityIncident", data: { TenantFilter: "Tenant", @@ -44,6 +48,7 @@ const Page = () => { { label: "Set status to resolved", type: "POST", + icon: , url: "/api/ExecSetSecurityIncident", data: { TenantFilter: "Tenant", diff --git a/src/pages/teams-share/sharepoint/index.js b/src/pages/teams-share/sharepoint/index.js index d88d75533e92..5b15705536f9 100644 --- a/src/pages/teams-share/sharepoint/index.js +++ b/src/pages/teams-share/sharepoint/index.js @@ -1,6 +1,14 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { + Add, + AddToPhotos, + PersonAdd, + PersonRemove, + AdminPanelSettings, + NoAccounts, +} from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -10,6 +18,7 @@ const Page = () => { { label: "Add Member", type: "POST", + icon: , url: "/api/ExecSetSharePointMember", data: { groupId: "ownerPrincipalName", @@ -40,6 +49,7 @@ const Page = () => { { label: "Remove Member", type: "POST", + icon: , url: "/api/ExecSetSharePointMember", data: { groupId: "ownerPrincipalName", @@ -70,6 +80,7 @@ const Page = () => { { label: "Add Site Admin", type: "POST", + icon: , url: "/api/ExecSharePointPerms", data: { UPN: "ownerPrincipalName", @@ -99,6 +110,7 @@ const Page = () => { { label: "Remove Site Admin", type: "POST", + icon: , url: "/api/ExecSharePointPerms", data: { UPN: "ownerPrincipalName", @@ -151,10 +163,14 @@ const Page = () => { ]} cardButton={ <> - - diff --git a/src/pages/teams-share/teams/business-voice/index.js b/src/pages/teams-share/teams/business-voice/index.js index 725a2a8a5331..6cef4fd00045 100644 --- a/src/pages/teams-share/teams/business-voice/index.js +++ b/src/pages/teams-share/teams/business-voice/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { PersonAdd, PersonRemove, LocationOn } from "@mui/icons-material"; const Page = () => { const pageTitle = "Teams Business Voice"; @@ -9,6 +10,7 @@ const Page = () => { { label: "Assign User", type: "POST", + icon: , url: "/api/ExecTeamsVoicePhoneNumberAssignment", data: { PhoneNumber: "TelephoneNumber", @@ -34,6 +36,7 @@ const Page = () => { { label: "Unassign User", type: "POST", + icon: , url: "/api/ExecRemoveTeamsVoicePhoneNumberAssignment", data: { PhoneNumber: "TelephoneNumber", @@ -45,6 +48,7 @@ const Page = () => { { label: "Set Emergency Location", type: "POST", + icon: , url: "/api/ExecTeamsVoicePhoneNumberAssignment", data: { PhoneNumber: "TelephoneNumber", diff --git a/src/pages/teams-share/teams/list-team/index.js b/src/pages/teams-share/teams/list-team/index.js index b1a41a9adbb6..fb3580cc2622 100644 --- a/src/pages/teams-share/teams/list-team/index.js +++ b/src/pages/teams-share/teams/list-team/index.js @@ -1,6 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { GroupAdd } from "@mui/icons-material"; import Link from "next/link"; import { Edit } from "@mui/icons-material"; @@ -25,7 +26,7 @@ const Page = () => { simpleColumns={["displayName", "description", "visibility", "mailNickname", "id"]} cardButton={ <> - diff --git a/src/pages/tenant/administration/alert-configuration/index.js b/src/pages/tenant/administration/alert-configuration/index.js index 6b68555d0e66..1544d84c8e39 100644 --- a/src/pages/tenant/administration/alert-configuration/index.js +++ b/src/pages/tenant/administration/alert-configuration/index.js @@ -3,7 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Layout as DashboardLayout } from "/src/layouts/index.js"; // had to add an extra path here because I added an extra folder structure. We should switch to absolute pathing so we dont have to deal with relative. import Link from "next/link"; import { EyeIcon } from "@heroicons/react/24/outline"; -import { CopyAll, Delete } from "@mui/icons-material"; +import { CopyAll, Delete, NotificationAdd } from "@mui/icons-material"; const Page = () => { const pageTitle = "Alerts"; @@ -43,7 +43,11 @@ const Page = () => { apiUrl="/api/ListAlertsQueue" tenantInTitle={false} cardButton={ - } diff --git a/src/pages/tenant/administration/authentication-methods/index.js b/src/pages/tenant/administration/authentication-methods/index.js index 7da41b844058..cd8fc26259c3 100644 --- a/src/pages/tenant/administration/authentication-methods/index.js +++ b/src/pages/tenant/administration/authentication-methods/index.js @@ -1,5 +1,6 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Check, Block } from "@mui/icons-material"; const Page = () => { const pageTitle = "Auth Methods"; @@ -12,6 +13,7 @@ const Page = () => { { label: "Enable Policy", type: "POST", + icon: , url: "/api/SetAuthMethod", data: { state: "enabled", id: "id" }, confirmText: "Are you sure you want to enable this policy?", @@ -20,6 +22,7 @@ const Page = () => { { label: "Disable Policy", type: "POST", + icon: , url: "/api/SetAuthMethod", data: { state: "disabled", id: "id" }, confirmText: "Are you sure you want to disable this policy?", diff --git a/src/pages/tenant/backup/backup-wizard/index.js b/src/pages/tenant/backup/backup-wizard/index.js index a5a5b04b6d62..ef07baf9d842 100644 --- a/src/pages/tenant/backup/backup-wizard/index.js +++ b/src/pages/tenant/backup/backup-wizard/index.js @@ -1,6 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { Restore, Backup } from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -10,10 +11,14 @@ const Page = () => { apiUrl="/api/ListScheduledItems" cardButton={ <> - - diff --git a/src/pages/tenant/conditional/deploy-vacation/index.js b/src/pages/tenant/conditional/deploy-vacation/index.js index ddddd13809c2..ca4092689195 100644 --- a/src/pages/tenant/conditional/deploy-vacation/index.js +++ b/src/pages/tenant/conditional/deploy-vacation/index.js @@ -1,6 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import CippTablePage from "/src/components/CippComponents/CippTablePage"; import { Button } from "@mui/material"; +import { EventAvailable } from "@mui/icons-material"; import Link from "next/link"; const Page = () => { @@ -8,7 +9,7 @@ const Page = () => { - diff --git a/src/pages/tenant/conditional/list-named-locations/index.js b/src/pages/tenant/conditional/list-named-locations/index.js index 2f72a57d5325..834efd07eb32 100644 --- a/src/pages/tenant/conditional/list-named-locations/index.js +++ b/src/pages/tenant/conditional/list-named-locations/index.js @@ -3,6 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Button } from "@mui/material"; import Link from "next/link"; import { MinusIcon, PlusIcon } from "@heroicons/react/24/outline"; +import { LocationOn } from "@mui/icons-material"; const Page = () => { const pageTitle = "Named Locations"; @@ -75,7 +76,7 @@ const Page = () => { offCanvas={offCanvas} cardButton={ <> - diff --git a/src/pages/tenant/conditional/list-policies/index.js b/src/pages/tenant/conditional/list-policies/index.js index 35f77a73f286..df42715f9801 100644 --- a/src/pages/tenant/conditional/list-policies/index.js +++ b/src/pages/tenant/conditional/list-policies/index.js @@ -5,6 +5,7 @@ import { Check as CheckIcon, Delete as DeleteIcon, MenuBook as MenuBookIcon, + AddModerator as AddModeratorIcon, Visibility as VisibilityIcon, } from "@mui/icons-material"; import { Button } from "@mui/material"; @@ -105,7 +106,11 @@ const Page = () => { - diff --git a/src/pages/tenant/conditional/list-template/index.js b/src/pages/tenant/conditional/list-template/index.js index 41a8010d6b50..b45950ba60dc 100644 --- a/src/pages/tenant/conditional/list-template/index.js +++ b/src/pages/tenant/conditional/list-template/index.js @@ -2,6 +2,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import CippJsonView from "../../../../components/CippFormPages/CippJSONView"; +import { Delete } from "@mui/icons-material"; const Page = () => { const pageTitle = "Available Conditional Access Templates"; @@ -11,6 +12,7 @@ const Page = () => { label: "Delete Template", type: "GET", url: "/api/RemoveCATemplate", + icon: , data: { ID: "GUID" }, confirmText: "Do you want to delete the template?", multiPost: false, diff --git a/src/pages/tenant/gdap-management/invites/index.js b/src/pages/tenant/gdap-management/invites/index.js index 7cf52a876857..54670b22330e 100644 --- a/src/pages/tenant/gdap-management/invites/index.js +++ b/src/pages/tenant/gdap-management/invites/index.js @@ -3,6 +3,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import tabOptions from "../tabOptions"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { Add } from "@mui/icons-material"; import Link from "next/link"; const pageTitle = "GDAP Invites"; @@ -13,7 +14,7 @@ const Page = () => { return ( + } diff --git a/src/pages/tenant/gdap-management/onboarding/index.js b/src/pages/tenant/gdap-management/onboarding/index.js index 3835749a7cac..f5f2042f3064 100644 --- a/src/pages/tenant/gdap-management/onboarding/index.js +++ b/src/pages/tenant/gdap-management/onboarding/index.js @@ -4,7 +4,7 @@ import tabOptions from "../tabOptions"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; -import { Cancel, Replay } from "@mui/icons-material"; +import { Cancel, PlayArrow, Replay } from "@mui/icons-material"; const pageTitle = "Tenant Onboarding"; @@ -49,7 +49,11 @@ const Page = () => { tenantInTitle={false} queryKey="ListTenantOnboarding" cardButton={ - } diff --git a/src/pages/tenant/gdap-management/role-templates/index.js b/src/pages/tenant/gdap-management/role-templates/index.js index def2717cc986..3b82189aeb14 100644 --- a/src/pages/tenant/gdap-management/role-templates/index.js +++ b/src/pages/tenant/gdap-management/role-templates/index.js @@ -9,7 +9,7 @@ import { useEffect, useState } from "react"; import { Box, Stack } from "@mui/system"; import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline"; import { CippApiResults } from "../../../../components/CippComponents/CippApiResults"; -import { Edit } from "@mui/icons-material"; +import { Edit, AddBox } from "@mui/icons-material"; const Page = () => { const pageTitle = "GDAP Role Templates"; @@ -42,7 +42,6 @@ const Page = () => { urlFromData: true, relatedQueryKeys: "ListGDAPRoleTemplates", }); - useEffect(() => { if (currentTemplates.isSuccess) { @@ -98,7 +97,11 @@ const Page = () => { tenantInTitle={false} sx={{ flexGrow: 1, pb: 4 }} cardButton={ - } diff --git a/src/pages/tenant/gdap-management/roles/index.js b/src/pages/tenant/gdap-management/roles/index.js index 2de5ad32b096..e97820abaf08 100644 --- a/src/pages/tenant/gdap-management/roles/index.js +++ b/src/pages/tenant/gdap-management/roles/index.js @@ -3,15 +3,15 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import tabOptions from "../tabOptions"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; +import { AdminPanelSettings, Add, Delete } from "@mui/icons-material"; import Link from "next/link"; -import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline"; const pageTitle = "GDAP Role Mappings"; const actions = [ { label: "Add to Template", - icon: , + icon: , type: "POST", url: "/api/ExecGDAPRoleTemplate?Action=Add", confirmText: "Select a template to add the selected role mapping(s) to.", @@ -40,7 +40,7 @@ const actions = [ }, { label: "Delete Mapping", - icon: , + icon: , type: "POST", url: "/api/ExecDeleteGDAPRoleMapping", data: { @@ -64,7 +64,11 @@ const Page = () => { simpleColumns={simpleColumns} tenantInTitle={false} cardButton={ - } diff --git a/src/pages/tenant/reports/list-csp-licenses/index.jsx b/src/pages/tenant/reports/list-csp-licenses/index.jsx index 611d4f5d9b10..9e6264df4c74 100644 --- a/src/pages/tenant/reports/list-csp-licenses/index.jsx +++ b/src/pages/tenant/reports/list-csp-licenses/index.jsx @@ -1,7 +1,7 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { MinusIcon, PlusIcon } from "@heroicons/react/24/outline"; -import { DeleteForever } from "@mui/icons-material"; +import { DeleteForever, ShoppingCart } from "@mui/icons-material"; import { Button } from "@mui/material"; import Link from "next/link"; @@ -93,7 +93,7 @@ const Page = () => { simpleColumns={simpleColumns} cardButton={ <> - diff --git a/src/pages/tenant/standards/bpa-report/index.js b/src/pages/tenant/standards/bpa-report/index.js index 2c786341cd68..50cf80d53b99 100644 --- a/src/pages/tenant/standards/bpa-report/index.js +++ b/src/pages/tenant/standards/bpa-report/index.js @@ -3,7 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Layout as DashboardLayout } from "/src/layouts/index.js"; // had to add an extra path here because I added an extra folder structure. We should switch to absolute pathing so we dont have to deal with relative. import Link from "next/link"; import { EyeIcon } from "@heroicons/react/24/outline"; -import { CopyAll, Delete, Edit } from "@mui/icons-material"; +import { CopyAll, Delete, Edit, AddBox } from "@mui/icons-material"; const Page = () => { const pageTitle = "Best Practice Reports"; @@ -48,7 +48,7 @@ const Page = () => { title={pageTitle} apiUrl="/api/listBPATemplates" cardButton={ - } diff --git a/src/pages/tenant/standards/domains-analyser/index.js b/src/pages/tenant/standards/domains-analyser/index.js index 1a5c2e9b4a68..c90254aab4df 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 } from "@mui/icons-material"; +import { DeleteForever, TravelExplore, Refresh } from "@mui/icons-material"; const Page = () => { const currentTenant = useSettings().currentTenant; @@ -36,11 +36,17 @@ const Page = () => { apiUrl="/api/ListDomainAnalyser" cardButton={ <> - {/* This needs to be replaced with a CippApiDialog. */} - + } prependComponents={} diff --git a/src/pages/tenant/standards/list-standards/index.js b/src/pages/tenant/standards/list-standards/index.js index e041ea9cd23b..2d9b4493d975 100644 --- a/src/pages/tenant/standards/list-standards/index.js +++ b/src/pages/tenant/standards/list-standards/index.js @@ -3,7 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Layout as DashboardLayout } from "/src/layouts/index.js"; // had to add an extra path here because I added an extra folder structure. We should switch to absolute pathing so we dont have to deal with relative. import Link from "next/link"; import { EyeIcon } from "@heroicons/react/24/outline"; -import { CopyAll, Delete, PlayArrow } from "@mui/icons-material"; +import { CopyAll, Delete, PlayArrow, AddBox, Visibility, Edit } from "@mui/icons-material"; import { ApiGetCall, ApiPostCall } from "../../../../api/ApiCall"; import { Grid } from "@mui/system"; import { CippApiResults } from "../../../../components/CippComponents/CippApiResults"; @@ -17,7 +17,7 @@ const Page = () => { label: "Edit Template", //when using a link it must always be the full path /identity/administration/users/[id] for example. link: "/tenant/standards/template?id=[GUID]", - icon: , + icon: , color: "success", target: "_self", }, @@ -105,7 +105,7 @@ const Page = () => { apiUrl="/api/listStandardTemplates" tenantInTitle={false} cardButton={ - } From b0aa77755d3716bbd5fa74f15da702dbdf50eaac Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 Jan 2025 22:16:29 -0500 Subject: [PATCH 058/231] add github logos --- public/assets/integrations/github.png | Bin 0 -> 13001 bytes public/assets/integrations/github_dark.png | Bin 0 -> 31120 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/assets/integrations/github.png create mode 100644 public/assets/integrations/github_dark.png diff --git a/public/assets/integrations/github.png b/public/assets/integrations/github.png new file mode 100644 index 0000000000000000000000000000000000000000..e03d8dd8bcf0d851fe1eb89f93a39de843e5c69c GIT binary patch literal 13001 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 Dq_KSN literal 0 HcmV?d00001 diff --git a/public/assets/integrations/github_dark.png b/public/assets/integrations/github_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..c61ab9d0582e487852d3afdbf22987208123591e GIT binary patch literal 31120 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 Date: Thu, 30 Jan 2025 22:37:26 -0500 Subject: [PATCH 059/231] downgrade node to 20.18.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index af7519d616d5..d4d4aad1955a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "license": "AGPL-3.0", "engines": { - "node": "^20.18.2" + "node": "^20.18.1" }, "repository": { "type": "git", From 1ea3338b4c572482a8d7dc51ed516b67429ed65e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 Jan 2025 22:44:50 -0500 Subject: [PATCH 060/231] cleanup manually specified tenant filters in actions --- .../email/administration/tenant-allow-block-lists/index.js | 1 - src/pages/email/tools/mailbox-restores/index.js | 3 --- src/pages/endpoint/applications/list/index.js | 4 ---- src/pages/identity/administration/groups/index.js | 4 ---- src/pages/security/incidents/list-alerts/index.js | 2 -- src/pages/security/incidents/list-incidents/index.js | 4 ---- 6 files changed, 18 deletions(-) diff --git a/src/pages/email/administration/tenant-allow-block-lists/index.js b/src/pages/email/administration/tenant-allow-block-lists/index.js index 508d5c67110e..e0348868e263 100644 --- a/src/pages/email/administration/tenant-allow-block-lists/index.js +++ b/src/pages/email/administration/tenant-allow-block-lists/index.js @@ -13,7 +13,6 @@ const Page = () => { type: "POST", url: "/api/RemoveTenantAllowBlockList", data: { - TenantFilter: "Tenant", Entries: "Value", ListType: "ListType", }, diff --git a/src/pages/email/tools/mailbox-restores/index.js b/src/pages/email/tools/mailbox-restores/index.js index ffa463800bd5..d9956d0d742b 100644 --- a/src/pages/email/tools/mailbox-restores/index.js +++ b/src/pages/email/tools/mailbox-restores/index.js @@ -13,7 +13,6 @@ const Page = () => { type: "POST", url: "/api/ExecMailboxRestore", data: { - TenantFilter: "Tenant", Identity: "Identity", Action: "Resume", }, @@ -25,7 +24,6 @@ const Page = () => { type: "POST", url: "/api/ExecMailboxRestore", data: { - TenantFilter: "Tenant", Identity: "Identity", Action: "Suspend", }, @@ -37,7 +35,6 @@ const Page = () => { type: "POST", url: "/api/ExecMailboxRestore", data: { - TenantFilter: "Tenant", Identity: "Identity", Action: "Remove", }, diff --git a/src/pages/endpoint/applications/list/index.js b/src/pages/endpoint/applications/list/index.js index 5a3d8eef0cfb..67e16ece37bd 100644 --- a/src/pages/endpoint/applications/list/index.js +++ b/src/pages/endpoint/applications/list/index.js @@ -15,7 +15,6 @@ const Page = () => { url: "/api/ExecAssignApp", data: { AssignTo: "AllUsers", - TenantFilter: "Tenant", ID: "id", }, confirmText: "Are you sure you want to assign this app to all users?", @@ -28,7 +27,6 @@ const Page = () => { url: "/api/ExecAssignApp", data: { AssignTo: "AllDevices", - TenantFilter: "Tenant", ID: "id", }, confirmText: "Are you sure you want to assign this app to all devices?", @@ -41,7 +39,6 @@ const Page = () => { url: "/api/ExecAssignApp", data: { AssignTo: "Both", - TenantFilter: "Tenant", ID: "id", }, confirmText: "Are you sure you want to assign this app to all users and devices?", @@ -53,7 +50,6 @@ const Page = () => { type: "POST", url: "/api/RemoveApp", data: { - TenantFilter: "Tenant", ID: "id", }, confirmText: "Are you sure you want to delete this application?", diff --git a/src/pages/identity/administration/groups/index.js b/src/pages/identity/administration/groups/index.js index 1fb57be03d1e..934526687979 100644 --- a/src/pages/identity/administration/groups/index.js +++ b/src/pages/identity/administration/groups/index.js @@ -22,7 +22,6 @@ const Page = () => { url: "/api/ExecGroupsHideFromGAL", icon: , data: { - TenantFilter: "TenantFilter", ID: "mail", GroupType: "calculatedGroupType", HidefromGAL: true, @@ -37,7 +36,6 @@ const Page = () => { url: "/api/ExecGroupsHideFromGAL", icon: , data: { - TenantFilter: "TenantFilter", ID: "mail", GroupType: "calculatedGroupType", }, @@ -51,7 +49,6 @@ const Page = () => { url: "/api/ExecGroupsDeliveryManagement", icon: , data: { - TenantFilter: "TenantFilter", ID: "mail", GroupType: "calculatedGroupType", OnlyAllowInternal: true, @@ -66,7 +63,6 @@ const Page = () => { icon: , url: "/api/ExecGroupsDeliveryManagement", data: { - TenantFilter: "TenantFilter", ID: "mail", GroupType: "calculatedGroupType", }, diff --git a/src/pages/security/incidents/list-alerts/index.js b/src/pages/security/incidents/list-alerts/index.js index 09e1411d9d3b..837db5087312 100644 --- a/src/pages/security/incidents/list-alerts/index.js +++ b/src/pages/security/incidents/list-alerts/index.js @@ -11,7 +11,6 @@ const Page = () => { type: "POST", url: "/api/ExecSetSecurityAlert", data: { - TenantFilter: "Tenant", GUID: "id", Status: "inProgress", Vendor: "vendorInformation.vendor", @@ -24,7 +23,6 @@ const Page = () => { type: "POST", url: "/api/ExecSetSecurityAlert", data: { - TenantFilter: "Tenant", GUID: "id", Status: "resolved", Vendor: "vendorInformation.vendor", diff --git a/src/pages/security/incidents/list-incidents/index.js b/src/pages/security/incidents/list-incidents/index.js index bebae5e2f983..53ac8ab1ef30 100644 --- a/src/pages/security/incidents/list-incidents/index.js +++ b/src/pages/security/incidents/list-incidents/index.js @@ -11,7 +11,6 @@ const Page = () => { type: "POST", url: "/api/ExecSetSecurityIncident", data: { - TenantFilter: "Tenant", GUID: "id", Assigned: "currentUserId", }, @@ -22,7 +21,6 @@ const Page = () => { type: "POST", url: "/api/ExecSetSecurityIncident", data: { - TenantFilter: "Tenant", GUID: "id", Status: "active", Assigned: "currentAssignedUser", @@ -34,7 +32,6 @@ const Page = () => { type: "POST", url: "/api/ExecSetSecurityIncident", data: { - TenantFilter: "Tenant", GUID: "id", Status: "inProgress", Assigned: "currentAssignedUser", @@ -46,7 +43,6 @@ const Page = () => { type: "POST", url: "/api/ExecSetSecurityIncident", data: { - TenantFilter: "Tenant", GUID: "id", Status: "resolved", Assigned: "currentAssignedUser", From 32cbe0277a43203638631961e22c77d4772f906b Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Fri, 31 Jan 2025 08:48:00 +0000 Subject: [PATCH 061/231] Add Speed Dial component with help, bug report, and feedback actions --- src/pages/_app.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/pages/_app.js b/src/pages/_app.js index 1dd1e6971768..b4ac447e1829 100644 --- a/src/pages/_app.js +++ b/src/pages/_app.js @@ -20,6 +20,12 @@ import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; import TimeAgo from "javascript-time-ago"; import en from "javascript-time-ago/locale/en.json"; +import CippSpeedDial from 'src/components/CippComponents/CippSpeedDial' +import { + Help as HelpIcon, + BugReport as BugReportIcon, + Feedback as FeedbackIcon, +} from '@mui/icons-material' import React from "react"; TimeAgo.addDefaultLocale(en); @@ -84,6 +90,11 @@ const App = (props) => { {getLayout()} + } + position={{ bottom: 16, right: 16 }} + /> {settings?.showDevtools && ( From 205fa4ca188ecb9060b3420a0f9147062ecc97ee Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Fri, 31 Jan 2025 08:50:04 +0000 Subject: [PATCH 062/231] Prettier fix --- src/pages/_app.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pages/_app.js b/src/pages/_app.js index b4ac447e1829..c4884343f139 100644 --- a/src/pages/_app.js +++ b/src/pages/_app.js @@ -20,12 +20,12 @@ import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; import TimeAgo from "javascript-time-ago"; import en from "javascript-time-ago/locale/en.json"; -import CippSpeedDial from 'src/components/CippComponents/CippSpeedDial' +import CippSpeedDial from "src/components/CippComponents/CippSpeedDial"; import { Help as HelpIcon, BugReport as BugReportIcon, Feedback as FeedbackIcon, -} from '@mui/icons-material' +} from "@mui/icons-material"; import React from "react"; TimeAgo.addDefaultLocale(en); @@ -90,11 +90,11 @@ const App = (props) => { {getLayout()} - } - position={{ bottom: 16, right: 16 }} - /> + } + position={{ bottom: 16, right: 16 }} + /> {settings?.showDevtools && ( From 65da8b660e90cc07a0e9dd46890ca5fb917d6ab0 Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Fri, 31 Jan 2025 09:24:13 +0000 Subject: [PATCH 063/231] Tested and works properly on my Dev Env now! --- src/components/CippComponents/CippSpeedDial.jsx | 2 +- src/pages/_app.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/CippComponents/CippSpeedDial.jsx b/src/components/CippComponents/CippSpeedDial.jsx index 805ca4a66fe9..4313ace7a7ef 100644 --- a/src/components/CippComponents/CippSpeedDial.jsx +++ b/src/components/CippComponents/CippSpeedDial.jsx @@ -14,7 +14,7 @@ import { } from "@mui/material"; import { Close as CloseIcon } from "@mui/icons-material"; import { useForm } from "react-hook-form"; -import { CippFormComponent } from "/src/components/CippComponents/CippFormComponent"; +import { CippFormComponent } from "../../components/CippComponents/CippFormComponent"; const CippSpeedDial = ({ actions = [], diff --git a/src/pages/_app.js b/src/pages/_app.js index c4884343f139..b764d3f36c12 100644 --- a/src/pages/_app.js +++ b/src/pages/_app.js @@ -20,7 +20,7 @@ import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; import TimeAgo from "javascript-time-ago"; import en from "javascript-time-ago/locale/en.json"; -import CippSpeedDial from "src/components/CippComponents/CippSpeedDial"; +import CippSpeedDial from "../components/CippComponents/CippSpeedDial"; import { Help as HelpIcon, BugReport as BugReportIcon, From 6c432d3d77631c3cc94d15cd560c2456dd9ff70b Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Fri, 31 Jan 2025 09:26:28 +0000 Subject: [PATCH 064/231] Add onClick handlers to Speed Dial GitHub links --- src/pages/_app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/_app.js b/src/pages/_app.js index b764d3f36c12..271c911a2c5b 100644 --- a/src/pages/_app.js +++ b/src/pages/_app.js @@ -48,12 +48,14 @@ const App = (props) => { icon: , name: "Report Bug", href: "https://github.com/KelvinTegelaar/CIPP/issues/new?template=bug.yml", + onClick: () => window.open("https://github.com/KelvinTegelaar/CIPP/issues/new?template=bug.yml", "_blank") }, { id: "feature-request", icon: , name: "Request Feature", href: "https://github.com/KelvinTegelaar/CIPP/issues/new?template=feature.yml", + onClick: () => window.open("https://github.com/KelvinTegelaar/CIPP/issues/new?template=feature.yml", "_blank") }, ]; From 8830a02a37de356486fe9d12c65ab24cc6eb1911 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 31 Jan 2025 13:30:33 +0100 Subject: [PATCH 065/231] fix reset form issue --- .../CippFormPages/CippAddGroupForm.jsx | 4 ++-- src/components/CippFormPages/CippFormPage.jsx | 3 +-- .../CippStandards/CippStandardsSideBar.jsx | 23 ++++++++++--------- .../administration/group-templates/add.jsx | 1 + 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/components/CippFormPages/CippAddGroupForm.jsx b/src/components/CippFormPages/CippAddGroupForm.jsx index 9745d9858636..49be141db5dd 100644 --- a/src/components/CippFormPages/CippAddGroupForm.jsx +++ b/src/components/CippFormPages/CippAddGroupForm.jsx @@ -51,7 +51,7 @@ const CippAddGroupForm = (props) => { formControl={formControl} name="owners" label="Owners" - multiple={false} + multiple={true} select={"id,userPrincipalName,displayName"} /> @@ -62,7 +62,7 @@ const CippAddGroupForm = (props) => { formControl={formControl} name="members" label="Members" - multiple={false} + multiple={true} select={"id,userPrincipalName,displayName"} /> diff --git a/src/components/CippFormPages/CippFormPage.jsx b/src/components/CippFormPages/CippFormPage.jsx index 585975b073bb..7db1575e9620 100644 --- a/src/components/CippFormPages/CippFormPage.jsx +++ b/src/components/CippFormPages/CippFormPage.jsx @@ -27,7 +27,7 @@ const CippFormPage = (props) => { formControl, postUrl, customDataformatter, - resetForm = true, + resetForm = false, hideBackButton = false, hidePageType = false, hideTitle = false, @@ -36,7 +36,6 @@ const CippFormPage = (props) => { ...other } = props; const router = useRouter(); - //check if there are const postCall = ApiPostCall({ datafromUrl: true, diff --git a/src/components/CippStandards/CippStandardsSideBar.jsx b/src/components/CippStandards/CippStandardsSideBar.jsx index c6a405de636f..2c87c7562fe8 100644 --- a/src/components/CippStandards/CippStandardsSideBar.jsx +++ b/src/components/CippStandards/CippStandardsSideBar.jsx @@ -1,14 +1,5 @@ import PropTypes from "prop-types"; -import { - Card, - CardContent, - CardHeader, - Divider, - formControlLabelClasses, - Stack, - SvgIcon, - Typography, -} from "@mui/material"; +import { Card, CardContent, CardHeader, Divider, Stack, SvgIcon, Typography } from "@mui/material"; import { styled } from "@mui/material/styles"; import { Timeline, @@ -24,7 +15,7 @@ import { ActionListItem } from "/src/components/action-list-item"; import CheckIcon from "@heroicons/react/24/outline/CheckIcon"; import CloseIcon from "@mui/icons-material/Close"; import { useWatch } from "react-hook-form"; -import { useEffect, useState } from "react"; +import { use, useEffect, useState } from "react"; import _ from "lodash"; import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; import { CippFormTenantSelector } from "../CippComponents/CippFormTenantSelector"; @@ -127,6 +118,15 @@ const CippStandardsSideBar = ({ fullWidth /> + + { return ( <> Date: Fri, 31 Jan 2025 14:22:35 +0100 Subject: [PATCH 066/231] feat: readded MDM wipe methods --- src/pages/endpoint/MEM/devices/index.js | 146 ++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 9 deletions(-) diff --git a/src/pages/endpoint/MEM/devices/index.js b/src/pages/endpoint/MEM/devices/index.js index 0965bb50462f..a381de6b12df 100644 --- a/src/pages/endpoint/MEM/devices/index.js +++ b/src/pages/endpoint/MEM/devices/index.js @@ -12,6 +12,9 @@ import { Security, FindInPage, Shield, + Archive, + AutoMode, + Recycling, } from "@mui/icons-material"; const Page = () => { @@ -19,6 +22,15 @@ const Page = () => { const tenantFilter = useSettings().currentTenant; const actions = [ + { + label: "View in InTune", + link: `https://intune.microsoft.com/${tenantFilter}/#view/Microsoft_Intune_Devices/DeviceSettingsMenuBlade/~/overview/mdmDeviceId/[id]`, + color: "info", + icon: , + target: "_blank", + multiPost: false, + external: true, + }, { label: "Sync Device", type: "POST", @@ -116,17 +128,133 @@ const Page = () => { GUID: "id", Action: "windowsDefenderUpdateSignatures", }, - confirmText: - "Are you sure you want to update the Windows Defender signatures for this device?", + confirmText: "Are you sure you want to update the Windows Defender signatures for this device?", }, { - label: "View in InTune", - link: `https://intune.microsoft.com/${tenantFilter}/#view/Microsoft_Intune_Devices/DeviceSettingsMenuBlade/~/overview/mdmDeviceId/[id]`, - color: "info", - icon: , - target: "_blank", - multiPost: false, - external: true, + label: "Generate logs and ship to MEM", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "CreateDeviceLogCollectionRequest", + }, + confirmText: "Are you sure you want to generate logs and ship these to MEM?", + }, + /* + { + label: "Rename device", + type: "POST", + icon: null, + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "setDeviceName", + }, + confirmText: "Enter the new name for the device", + }, + */ + { + label: "Fresh Start (Remove user data)", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "cleanWindowsDevice", + keepUserData: false, + }, + confirmText: "Are you sure you want to Fresh Start this device?", + }, + { + label: "Fresh Start (Do not remove user data)", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "cleanWindowsDevice", + keepUserData: true, + }, + confirmText: "Are you sure you want to Fresh Start this device?", + }, + { + label: "Wipe Device, keep enrollment data", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "cleanWindowsDevice", + keepUserData: false, + keepEnrollmentData: true, + }, + confirmText: "Are you sure you want to wipe this device, and retain enrollment data?", + }, + { + label: "Wipe Device, remove enrollment data", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "cleanWindowsDevice", + keepUserData: false, + keepEnrollmentData: false, + }, + confirmText: "Are you sure you want to wipe this device, and remove enrollment data?", + }, + { + label: "Wipe Device, keep enrollment data, and continue at powerloss", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "cleanWindowsDevice", + keepEnrollmentData: true, + keepUserData: false, + useProtectedWipe: true, + }, + confirmText: "Are you sure you want to wipe this device? This will retain enrollment data. Continuing at powerloss may cause boot issues if wipe is interrupted.", + }, + { + label: "Wipe Device, remove enrollment data, and continue at powerloss", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "cleanWindowsDevice", + keepEnrollmentData: false, + keepUserData: false, + useProtectedWipe: true, + }, + confirmText: "Are you sure you want to wipe this device? This will also remove enrollment data. Continuing at powerloss may cause boot issues if wipe is interrupted.", + }, + { + label: "Autopilot Reset", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "wipe", + keepUserData: "false", + keepEnrollmentData: "true", + }, + confirmText: "Are you sure you want to Autopilot Reset this device?", + }, + { + label: "Retire device", + type: "POST", + icon: , + url: "/api/ExecDeviceAction", + data: { + GUID: "id", + Action: "retire", + }, + confirmText: "Are you sure you want to retire this device?", }, ]; From d6eaf09fef428c52f1565655b4b5548959c19e6e Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Fri, 31 Jan 2025 14:19:04 +0000 Subject: [PATCH 067/231] Add Discord link to Speed Dial component --- public/discord-mark-blue.svg | 1 + src/pages/_app.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 public/discord-mark-blue.svg diff --git a/public/discord-mark-blue.svg b/public/discord-mark-blue.svg new file mode 100644 index 000000000000..4cadbc7f7ed3 --- /dev/null +++ b/public/discord-mark-blue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/pages/_app.js b/src/pages/_app.js index 271c911a2c5b..e520d50c5822 100644 --- a/src/pages/_app.js +++ b/src/pages/_app.js @@ -26,6 +26,8 @@ import { BugReport as BugReportIcon, Feedback as FeedbackIcon, } from "@mui/icons-material"; +import { SvgIcon } from "@mui/material"; +import discordIcon from "../../public/discord-mark-blue.svg"; import React from "react"; TimeAgo.addDefaultLocale(en); @@ -57,6 +59,16 @@ const App = (props) => { href: "https://github.com/KelvinTegelaar/CIPP/issues/new?template=feature.yml", onClick: () => window.open("https://github.com/KelvinTegelaar/CIPP/issues/new?template=feature.yml", "_blank") }, + { + id: "discord", + icon: ( + + + ), + name: "Join the Discord!", + href: "https://discord.gg/cyberdrain", + onClick: () => window.open("https://discord.gg/cyberdrain", "_blank") + }, ]; return ( From 392baf39fcc77bad3da2cdb0893432d94729245f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 31 Jan 2025 17:02:59 -0500 Subject: [PATCH 068/231] fix graph explorer in offcanvas fix scheduler parameters --- .../CippFormPages/CippSchedulerForm.jsx | 3 +- .../CippTable/CippGraphExplorerFilter.js | 72 ++++++++++--------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/components/CippFormPages/CippSchedulerForm.jsx b/src/components/CippFormPages/CippSchedulerForm.jsx index e18e9c57421a..5bc71dd02211 100644 --- a/src/components/CippFormPages/CippSchedulerForm.jsx +++ b/src/components/CippFormPages/CippSchedulerForm.jsx @@ -206,7 +206,8 @@ const CippSchedulerForm = (props) => { formControl={formControl} > - {param.Type === "System.Boolean" ? ( + {param.Type === "System.Boolean" || + param.Type === "System.Management.Automation.SwitchParameter" ? ( { + const endpoint = watchedValues.endpoint; + if (endpoint && endpoint !== currentEndpoint) { + setCurrentEndpoint(endpoint); + } + }, [watchedValues.endpoint]); // API call for available properties const propertyList = ApiGetCall({ url: "/api/ListGraphRequest", - queryKey: `graph-properties-${endpoint}`, + queryKey: `graph-properties-${currentEndpoint}`, data: { - Endpoint: endpoint, + Endpoint: currentEndpoint, ListProperties: true, TenantFilter: tenant, IgnoreErrors: true, @@ -141,16 +149,16 @@ const CippGraphExplorerFilter = ({ }); } setPresetOptions(presetOptionList); - }, [defaultPresets, presetList.isSuccess]); + }, [defaultPresets, presetList.isSuccess, presetList.data]); // Debounced refetch when endpoint, put in in a useEffect dependand on endpoint const debouncedRefetch = useCallback( debounce(() => { - if (endpoint) { + if (currentEndpoint) { propertyList.refetch(); } }, 1000), - [endpoint] // Dependencies that the debounce function depends on + [currentEndpoint] // Dependencies that the debounce function depends on ); useEffect(() => { @@ -159,10 +167,10 @@ const CippGraphExplorerFilter = ({ return () => { debouncedRefetch.cancel(); }; - }, [endpoint, debouncedRefetch]); + }, [currentEndpoint, debouncedRefetch]); const savePresetApi = ApiPostCall({ - relatedQueryKeys: "ListGraphExplorerPresets", + relatedQueryKeys: ["ListGraphExplorerPresets", "ListGraphRequest"], }); // Save preset function @@ -278,13 +286,13 @@ const CippGraphExplorerFilter = ({ }; // Schedule report function const handleScheduleReport = () => { - const formParameters = formControl.getValues(); + const formParameters = watchedValues; const selectString = formParameters.$select ? formParameters.$select?.map((item) => item.value).join(",") : null; //compose the parameters for the form based on what is available - const Parameters = [ + var Parameters = [ { Key: "$select", Value: selectString, @@ -309,32 +317,17 @@ const CippGraphExplorerFilter = ({ Key: "$expand", Value: formParameters.$expand, }, - { - Key: "ReverseTenantLookup", - Value: formParameters.ReverseTenantLookup, - }, - { - Key: "ReverseTenantLookupProperty", - Value: formParameters.ReverseTenantLookupProperty, - }, - { - Key: "NoPagination", - Value: formParameters.NoPagination, - }, - { - Key: "AsApp", - Value: formParameters.AsApp, - }, { Key: "$format", Value: formParameters.$format, }, ]; - Parameters.forEach((param) => { - if (param.Value == null || param.Value === "") { - //delete the index - Parameters.splice(Parameters.indexOf(param), 1); - } + Parameters = Parameters.filter((param) => { + return ( + param.Value != null && + param.Value !== "" && + !(typeof param.Value === "boolean" && param.Value === false) + ); }); const resetParams = { tenantFilter: tenant, @@ -350,6 +343,9 @@ const CippGraphExplorerFilter = ({ Endpoint: formParameters.endpoint, skipCache: true, NoPagination: formParameters.NoPagination, + AsApp: formParameters.AsApp, + ReverseTenantLookup: formParameters.ReverseTenantLookup, + ReverseTenantLookupProperty: formParameters.ReverseTenantLookupProperty, Parameters: Parameters, }, advancedParameters: false, @@ -375,12 +371,14 @@ const CippGraphExplorerFilter = ({ function getPresetProps(values) { var newvals = Object.assign({}, values); + console.log(values); if (newvals?.$select !== undefined && Array.isArray(newvals?.$select)) { newvals.$select = newvals?.$select.map((p) => p.value).join(","); } delete newvals["reportTemplate"]; delete newvals["tenantFilter"]; delete newvals["IsShared"]; + delete newvals["id"]; if (newvals.ReverseTenantLookup === false) { delete newvals.ReverseTenantLookup; } @@ -390,6 +388,9 @@ const CippGraphExplorerFilter = ({ if (newvals.$count === false) { delete newvals.$count; } + if (newvals.AsApp === false) { + delete newvals.AsApp; + } Object.keys(newvals).forEach((key) => { if (values[key] === "" || values[key] === null) { delete newvals[key]; @@ -399,7 +400,7 @@ const CippGraphExplorerFilter = ({ } useEffect(() => { - var values = getPresetProps(formControl.getValues()); + var values = getPresetProps(watchedValues); setOffCanvasContent(() => ( <> @@ -425,7 +426,7 @@ const CippGraphExplorerFilter = ({ )); - }, [editorValues, savePresetApi.isPending, formControl, selectedPresets]); + }, [editorValues, savePresetApi.isPending, formControl, selectedPresets, watchedValues]); const handleImport = () => { setOffCanvasOpen(true); // Open the offCanvas, the content will be updated by useEffect @@ -555,6 +556,7 @@ const CippGraphExplorerFilter = ({ multiple={false} formControl={formControl} options={presetOptions} + isFetching={presetList.isFetching} groupBy={(option) => option.type} renderGroup={(params) => (
  • @@ -594,7 +596,7 @@ const CippGraphExplorerFilter = ({ name="$select" label="Select" formControl={formControl} - isFetching={propertyList.isLoading} + isFetching={propertyList.isFetching} options={ (propertyList.isSuccess && propertyList?.data?.Results?.length > 0 && From f740ad5a73220e10b8acf219da29be84ea55dfd0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 31 Jan 2025 17:10:38 -0500 Subject: [PATCH 069/231] up version --- package.json | 2 +- public/version.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d4d4aad1955a..13dac459bf3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cipp", - "version": "7.0.0", + "version": "7.1.3", "author": "CIPP Contributors", "homepage": "https://cipp.app/", "bugs": { diff --git a/public/version.json b/public/version.json index ef511cf84994..795806e4fd04 100644 --- a/public/version.json +++ b/public/version.json @@ -1,3 +1,3 @@ { - "version": "7.1.2" + "version": "7.1.3" } From 033592c89a95b9aca073a3cb4f07dfa31d70345a Mon Sep 17 00:00:00 2001 From: Esco Date: Sun, 2 Feb 2025 02:29:22 +0100 Subject: [PATCH 070/231] feat: New standard RetentionPolicyTag --- src/data/standards.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 4a7a5527ae36..eddac84ee102 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1412,6 +1412,26 @@ "powershellEquivalent": "Set-HostedOutboundSpamFilterPolicy -AutoForwardingMode 'Off'", "recommendedBy": ["CIS"] }, + { + "name": "standards.RetentionPolicyTag", + "cat": "Exchange Standards", + "tag": ["highimpact"], + "helpText": "Creates a CIPP - Deleted Items retention policy tag that permanently deletes items in the Deleted Items folder after X days.", + "docsDescription": "Creates a CIPP - Deleted Items retention policy tag that permanently deletes items in the Deleted Items folder after X days.", + "addedComponent": [ + { + "type": "number", + "name": "standards.RetentionPolicyTag.AgeLimitForRetention", + "label": "Retention Days", + "required": true + } + ], + "label": "Retention Policy, permanently delete items in Deleted Items after X days", + "impact": "High Impact", + "impactColour": "danger", + "powershellEquivalent": "Set-RetentionPolicyTag", + "recommendedBy": [] + }, { "name": "standards.QuarantineRequestAlert", "cat": "Defender Standards", From 32d9f71655b29c4e0a339fc5aa8c71113f7e6f37 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 3 Feb 2025 15:04:06 +0100 Subject: [PATCH 071/231] fix: make some standards required input --- src/data/standards.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index eddac84ee102..e868f769760c 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -645,6 +645,7 @@ "addedComponent": [ { "type": "autoComplete", + "required": true, "multiple": false, "label": "Who can send invites?", "name": "standards.GuestInvite.allowInvitesFrom", @@ -1871,6 +1872,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "Spam Action", "name": "standards.SpamFilterPolicy.SpamAction", @@ -1887,6 +1889,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "Spam Quarantine Tag", "name": "standards.SpamFilterPolicy.SpamQuarantineTag", @@ -1907,6 +1910,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "High Confidence Spam Action", "name": "standards.SpamFilterPolicy.HighConfidenceSpamAction", @@ -1923,6 +1927,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "High Confidence Spam Quarantine Tag", "name": "standards.SpamFilterPolicy.HighConfidenceSpamQuarantineTag", @@ -1943,6 +1948,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "Bulk Spam Action", "name": "standards.SpamFilterPolicy.BulkSpamAction", @@ -1959,6 +1965,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "Bulk Quarantine Tag", "name": "standards.SpamFilterPolicy.BulkQuarantineTag", @@ -1979,6 +1986,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "Phish Spam Action", "name": "standards.SpamFilterPolicy.PhishSpamAction", @@ -1995,6 +2003,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "Phish Quarantine Tag", "name": "standards.SpamFilterPolicy.PhishQuarantineTag", @@ -2015,6 +2024,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "label": "High Confidence Phish Quarantine Tag", "name": "standards.SpamFilterPolicy.HighConfidencePhishQuarantineTag", @@ -2138,6 +2148,7 @@ "addedComponent": [ { "type": "autoComplete", + "required": true, "multiple": false, "name": "standards.IntuneComplianceSettings.secureByDefault", "label": "Mark devices with no compliance policy as", @@ -2588,6 +2599,7 @@ "addedComponent": [ { "type": "autoComplete", + "required": true, "multiple": false, "name": "standards.TeamsGlobalMeetingPolicy.DesignatedPresenterRoleMode", "label": "Default value of the `Who can present?`", @@ -2617,6 +2629,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "name": "standards.TeamsGlobalMeetingPolicy.MeetingChatEnabledType", "label": "Meeting chat policy", @@ -2708,6 +2721,8 @@ "addedComponent": [ { "type": "autoComplete", + "required": true, + "multiple": false, "name": "standards.TeamsEnrollUser.EnrollUserOverride", "label": "Voice and Face Enrollment", "options": [ @@ -2776,6 +2791,7 @@ }, { "type": "autoComplete", + "required" : true, "multiple": false, "name": "standards.TeamsFederationConfiguration.DomainControl", "label": "Communication Mode", @@ -2844,6 +2860,7 @@ }, { "type": "autoComplete", + "required": true, "multiple": false, "name": "standards.TeamsMessagingPolicy.ReadReceiptsEnabledType", "label": "Read Receipts Enabled Type", From dc9c7c336cec58c5d45e229f89d90c44321d4c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 3 Feb 2025 19:12:04 +0100 Subject: [PATCH 072/231] feat: Add Edit Contact page with form functionality --- .../email/administration/contacts/edit.jsx | 236 ++++++++++++++++++ .../email/administration/contacts/index.js | 8 +- 2 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 src/pages/email/administration/contacts/edit.jsx diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx new file mode 100644 index 000000000000..12846ae3140a --- /dev/null +++ b/src/pages/email/administration/contacts/edit.jsx @@ -0,0 +1,236 @@ +import React, { useEffect } from "react"; +import { useRouter } from "next/router"; +import { Grid, Divider } from "@mui/material"; +import { useForm } from "react-hook-form"; +import { useSelector } from "react-redux"; +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import CippFormPage from "/src/components/CippFormPages/CippFormPage"; +import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; +import { useSettings } from "../../../../hooks/use-settings"; +import { ApiGetCall } from "../../../../api/ApiCall"; + +const EditContact = () => { + const tenantDomain = useSettings().currentTenant; + const router = useRouter(); + const { id } = router.query; + + const contactInfo = ApiGetCall({ + url: `/api/ListContacts?tenantFilter=${tenantDomain}&id=${id}`, + queryKey: `ListContacts-${id}`, + waiting: false, + }); + + useEffect(() => { + if (id) { + contactInfo.refetch(); + } + }, [router.query, id, tenantDomain]); + + const formControl = useForm({ + mode: "onChange", + defaultValues: { + displayName: "", + firstName: "", + lastName: "", + email: "", + hidefromGAL: false, + streetAddress: "", + postalCode: "", + city: "", + country: "", + companyName: "", + mobilePhone: "", + businessPhone: "", + jobTitle: "", + }, + }); + + useEffect(() => { + if (contactInfo.isSuccess && contactInfo.data?.Results?.[0]) { + const contact = contactInfo.data.Results[0]; + formControl.reset({ + displayName: contact.displayName || "", + firstName: contact.firstName || "", + lastName: contact.lastName || "", + email: contact.mail || "", + hidefromGAL: contact.hidefromGAL || false, + streetAddress: contact.streetAddress || "", + postalCode: contact.postalCode || "", + city: contact.city || "", + country: contact.countryOrRegion || "", + companyName: contact.companyName || "", + mobilePhone: contact.mobilePhone || "", + businessPhone: contact.phone || "", + jobTitle: contact.jobTitle || "", + }); + } + }, [contactInfo.isSuccess, contactInfo.data, contactInfo.isFetching]); + + if (contactInfo.isLoading) { + return
    Loading...
    ; + } + + return ( + { + return { + tenantID: tenantDomain, + firstName: values.firstName, + lastName: values.lastName, + displayName: values.displayName, + mail: values.email, + hidefromGAL: values.hidefromGAL, + ContactID: contactInfo.data?.Results?.[0]?.id, + StreetAddress: values.streetAddress, + PostalCode: values.postalCode, + City: values.city, + Country: values.country, + companyName: values.companyName, + MobilePhone: values.mobilePhone, + BusinessPhone: values.businessPhone, + jobTitle: values.jobTitle, + }; + }} + > + + {/* Display Name */} + + + + + {/* First Name and Last Name */} + + + + + + + + + + {/* Email */} + + + + + {/* Hide from GAL */} + + + + + + + {/* Company Information */} + + + + + + + + + + {/* Address Information */} + + + + + + + + + + + + + + + + {/* Phone Numbers */} + + + + + + + + + ); +}; + +EditContact.getLayout = (page) => {page}; + +export default EditContact; diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index ac22d6596579..e08ab4e7d785 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -3,7 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Edit, PersonAdd } from "@mui/icons-material"; import { Button } from "@mui/material"; import Link from "next/link"; -import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; +import TrashIcon from "@heroicons/react/24/outline/TrashIcon"; const Page = () => { const pageTitle = "Contacts"; @@ -20,14 +20,14 @@ const Page = () => { color: "danger", icon: , }, - /* TODO: Implement edit contact { label: "Edit Contact", - link: "/email/administration/edit-contact/[id]", + link: "/email/administration/contacts/edit?id={id}", multiPost: false, + postEntireRow: true, icon: , color: "warning", - },*/ + }, ]; const simpleColumns = ["displayName", "mail", "companyName", "onPremisesSyncEnabled"]; From 5cc4ae46006bbc09917ed9751988fc9db2251daa Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 3 Feb 2025 21:44:40 +0100 Subject: [PATCH 073/231] Tweaks to Start with Windows Terminal and Dev Installation --- Tools/Start-CippDevEmulators.ps1 | 10 ++++++++-- Tools/Start-CippDevInstallation.ps1 | 30 ++++++++++++++--------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Tools/Start-CippDevEmulators.ps1 b/Tools/Start-CippDevEmulators.ps1 index 882579f1bdc4..d171c0a1eaaf 100644 --- a/Tools/Start-CippDevEmulators.ps1 +++ b/Tools/Start-CippDevEmulators.ps1 @@ -1,8 +1,14 @@ -Write-Host 'Starting CIPP Dev Emulators' +Get-Command wt -ErrorAction Stop | Out-Null Get-Process node -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue $Path = (Get-Item $PSScriptRoot).Parent.Parent.FullName -$Process = Read-Host -Prompt 'Start Process Function (y/N)?' +pwsh -file (Join-Path $PSScriptRoot 'Start-CippDevInstallation.ps1') + +Write-Host 'Starting CIPP Dev Emulators' + +if (Test-Path (Join-Path $Path 'CIPP-API-Processor')) { + $Process = Read-Host -Prompt 'Start Process Function (y/N)?' +} if ($Process -eq 'y') { wt --title CIPP`; new-tab --title 'Azurite' -d $Path pwsh -c azurite`; new-tab --title 'FunctionApp' -d $Path\CIPP-API pwsh -c func start`; new-tab --title 'CIPP Frontend' -d $Path\CIPP pwsh -c npm run dev`; new-tab --title 'SWA' -d $Path\CIPP pwsh -c npm run start-swa`; new-tab --title 'CIPP-API-Processor' -d $Path\CIPP-API-Processor pwsh -c func start --port 7072 diff --git a/Tools/Start-CippDevInstallation.ps1 b/Tools/Start-CippDevInstallation.ps1 index fa1de465b2eb..2d00a12c6a26 100644 --- a/Tools/Start-CippDevInstallation.ps1 +++ b/Tools/Start-CippDevInstallation.ps1 @@ -1,32 +1,32 @@ $Path = (Get-Item $PSScriptRoot).Parent.Parent.FullName -if (-not(Get-Command npm)) { - throw 'npm is required to install the CIPP development environment' +if (-not((Get-Command npm -ErrorAction SilentlyContinue) -or (Get-Command yarn -ErrorAction SilentlyContinue))) { + throw 'npm or yarn is required to install the CIPP development environment.' } -if (-not(Get-Command azurite)) { +if (-not(Get-Command yarn -ErrorAction SilentlyContinue)) { + Write-Host 'Installing Yarn' + npm install --global yarn +} + +if (-not(Get-Command azurite -ErrorAction SilentlyContinue)) { Write-Host 'Installing Azurite' - npm install --global 'azurite' + yarn global add 'azurite' } -if (-not(Get-Command swa)) { +if (-not(Get-Command swa -ErrorAction SilentlyContinue)) { Write-Host 'Installing @azure/static-web-apps-cli' - npm install --global '@azure/static-web-apps-cli' + yarn global add '@azure/static-web-apps-cli' } -if (-not(Get-Command func)) { +if (-not(Get-Command func -ErrorAction SilentlyContinue)) { Write-Host 'Installing Azure Functions Core Tools' - npm install --global 'azure-functions-core-tools@4' --unsafe-perms true -} - -if (-not(Get-Command yarn)) { - Write-Host 'Installing Yarn' - npm install --global yarn + yarn global add 'azure-functions-core-tools@4' } -if (-not(yarn list --global --pattern 'next' | Select-String -Pattern 'next')) { +if (-not(yarn global list | Select-String -Pattern 'next')) { Write-Host 'Installing Next.js' - yarn install --global next --network-timeout 500000 + yarn global add 'next' } yarn install --cwd (Join-Path $Path "CIPP") --network-timeout 500000 From 3f7e051e2126c7a703ca7360d4325871e4871ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 3 Feb 2025 23:42:15 +0100 Subject: [PATCH 074/231] move up --- .../email/administration/contacts/index.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index e08ab4e7d785..8d512604501f 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -9,6 +9,15 @@ const Page = () => { const pageTitle = "Contacts"; const actions = [ + , + { + label: "Edit Contact", + link: "/email/administration/contacts/edit?id=[id]", + multiPost: false, + postEntireRow: true, + icon: , + color: "warning", + }, { label: "Remove Contact", type: "GET", @@ -20,14 +29,6 @@ const Page = () => { color: "danger", icon: , }, - { - label: "Edit Contact", - link: "/email/administration/contacts/edit?id={id}", - multiPost: false, - postEntireRow: true, - icon: , - color: "warning", - }, ]; const simpleColumns = ["displayName", "mail", "companyName", "onPremisesSyncEnabled"]; From fa7eda9bb3837ef78c789cb1382935bfe1fa57ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 4 Feb 2025 01:29:44 +0100 Subject: [PATCH 075/231] make it actually work --- .../email/administration/contacts/edit.jsx | 52 +++++++++++-------- .../email/administration/contacts/index.js | 6 ++- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx index 12846ae3140a..56bf1e557f6e 100644 --- a/src/pages/email/administration/contacts/edit.jsx +++ b/src/pages/email/administration/contacts/edit.jsx @@ -46,21 +46,29 @@ const EditContact = () => { }); useEffect(() => { - if (contactInfo.isSuccess && contactInfo.data?.Results?.[0]) { - const contact = contactInfo.data.Results[0]; + if (contactInfo.isSuccess && contactInfo.data?.[0]) { + const contact = contactInfo.data[0]; + // Get the address info from the first address entry + const address = contact.addresses?.[0] || {}; + + // Find phone numbers by type + const phones = contact.phones || []; + const mobilePhone = phones.find((p) => p.type === "mobile")?.number; + const businessPhone = phones.find((p) => p.type === "business")?.number; + formControl.reset({ displayName: contact.displayName || "", - firstName: contact.firstName || "", - lastName: contact.lastName || "", + firstName: contact.givenName || "", + lastName: contact.surname || "", email: contact.mail || "", hidefromGAL: contact.hidefromGAL || false, - streetAddress: contact.streetAddress || "", - postalCode: contact.postalCode || "", - city: contact.city || "", - country: contact.countryOrRegion || "", + streetAddress: address.street || "", + postalCode: address.postalCode || "", + city: address.city || "", + country: address.countryOrRegion || "", companyName: contact.companyName || "", - mobilePhone: contact.mobilePhone || "", - businessPhone: contact.phone || "", + mobilePhone: mobilePhone || "", + businessPhone: businessPhone || "", jobTitle: contact.jobTitle || "", }); } @@ -74,26 +82,28 @@ const EditContact = () => { { return { tenantID: tenantDomain, - firstName: values.firstName, - lastName: values.lastName, - displayName: values.displayName, - mail: values.email, + ContactID: contactInfo.data?.[0]?.id, + DisplayName: values.displayName, hidefromGAL: values.hidefromGAL, - ContactID: contactInfo.data?.Results?.[0]?.id, + email: values.email, + FirstName: values.firstName, + LastName: values.lastName, + Title: values.jobTitle, StreetAddress: values.streetAddress, PostalCode: values.postalCode, City: values.city, - Country: values.country, - companyName: values.companyName, - MobilePhone: values.mobilePhone, - BusinessPhone: values.businessPhone, - jobTitle: values.jobTitle, + CountryOrRegion: values.country, + Company: values.companyName, + mobilePhone: values.mobilePhone, + phone: values.businessPhone, }; }} > diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index 8d512604501f..9d75996d8652 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -9,7 +9,6 @@ const Page = () => { const pageTitle = "Contacts"; const actions = [ - , { label: "Edit Contact", link: "/email/administration/contacts/edit?id=[id]", @@ -17,6 +16,7 @@ const Page = () => { postEntireRow: true, icon: , color: "warning", + condition: (row) => !row.onPremisesSyncEnabled, }, { label: "Remove Contact", @@ -25,9 +25,11 @@ const Page = () => { data: { GUID: "id", }, - confirmText: "Are you sure you want to delete this contact?", + confirmText: + "Are you sure you want to delete this contact? Remember this will not work if the contact is AD Synced.", color: "danger", icon: , + condition: (row) => !row.onPremisesSyncEnabled, }, ]; From d185ae1feba6e492b38d62da84eb201ee2508c7d Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Feb 2025 21:23:57 -0500 Subject: [PATCH 076/231] fix tenant mapping and buttons --- .../CippIntegrationTenantMapping.jsx | 60 +++++++++---------- src/pages/cipp/integrations/configure.js | 5 +- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/components/CippIntegrations/CippIntegrationTenantMapping.jsx b/src/components/CippIntegrations/CippIntegrationTenantMapping.jsx index 8f1ecc67ec5c..6bc3e95caea6 100644 --- a/src/components/CippIntegrations/CippIntegrationTenantMapping.jsx +++ b/src/components/CippIntegrations/CippIntegrationTenantMapping.jsx @@ -95,37 +95,37 @@ const CippIntegrationSettings = ({ children }) => { }; const handleAutoMap = () => { - const newTableData = []; - tenantList.data?.pages[0]?.forEach((tenant) => { - const matchingCompany = mappings.data.Companies.find( - (company) => company.name === tenant.displayName - ); - if ( - Array.isArray(tableData) && - tableData?.find((item) => item.TenantId === tenant.customerId) - ) - return; - if (matchingCompany) { - newTableData.push({ - TenantId: tenant.customerId, - Tenant: tenant.displayName, - IntegrationName: matchingCompany.name, - IntegrationId: matchingCompany.value, - }); - } - }); - if (Array.isArray(tableData)) { - setTableData([...tableData, ...newTableData]); - } else { - setTableData(newTableData); - } - if (extension.autoMapSyncApi) { - automapPostCall.mutate({ - url: `/api/ExecExtensionMapping?AutoMapping=${router.query.id}`, - queryKey: `IntegrationTenantMapping-${router.query.id}`, + const newTableData = []; + tenantList.data?.pages[0]?.forEach((tenant) => { + const matchingCompany = mappings.data.Companies.find( + (company) => company.name === tenant.displayName + ); + if ( + Array.isArray(tableData) && + tableData?.find((item) => item.TenantId === tenant.customerId) + ) + return; + if (matchingCompany) { + newTableData.push({ + TenantId: tenant.customerId, + Tenant: tenant.displayName, + IntegrationName: matchingCompany.name, + IntegrationId: matchingCompany.value, }); } - }; + }); + if (Array.isArray(tableData)) { + setTableData([...tableData, ...newTableData]); + } else { + setTableData(newTableData); + } + if (extension.autoMapSyncApi) { + automapPostCall.mutate({ + url: `/api/ExecExtensionMapping?AutoMapping=${router.query.id}`, + queryKey: `IntegrationTenantMapping-${router.query.id}`, + }); + } + }; const actions = [ { @@ -140,7 +140,7 @@ const CippIntegrationSettings = ({ children }) => { useEffect(() => { if (mappings.isSuccess) { - setTableData(mappings.data.Mappings); + setTableData(mappings.data.Mappings ?? []); } }, [mappings.isSuccess]); diff --git a/src/pages/cipp/integrations/configure.js b/src/pages/cipp/integrations/configure.js index 62bc4990350b..e45bf0fd4489 100644 --- a/src/pages/cipp/integrations/configure.js +++ b/src/pages/cipp/integrations/configure.js @@ -174,10 +174,9 @@ const Page = () => { ))} )} - - - + + From 8e4c7f5140c9ac941fd1cb2ab8d2ac19385794f6 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Feb 2025 10:01:09 +0100 Subject: [PATCH 077/231] api data key --- src/pages/security/incidents/list-alerts/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/security/incidents/list-alerts/index.js b/src/pages/security/incidents/list-alerts/index.js index 00748c78552c..444459c102ec 100644 --- a/src/pages/security/incidents/list-alerts/index.js +++ b/src/pages/security/incidents/list-alerts/index.js @@ -62,6 +62,7 @@ const Page = () => { Date: Tue, 4 Feb 2025 10:03:22 +0100 Subject: [PATCH 078/231] api datakey --- src/pages/security/incidents/list-incidents/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/security/incidents/list-incidents/index.js b/src/pages/security/incidents/list-incidents/index.js index ec9860e7e96f..213d760ff575 100644 --- a/src/pages/security/incidents/list-incidents/index.js +++ b/src/pages/security/incidents/list-incidents/index.js @@ -83,7 +83,7 @@ const Page = () => { Date: Tue, 4 Feb 2025 11:02:40 +0100 Subject: [PATCH 079/231] fixes default attributess --- src/pages/identity/administration/users/add.jsx | 1 + src/pages/identity/administration/users/user/edit.jsx | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/src/pages/identity/administration/users/add.jsx b/src/pages/identity/administration/users/add.jsx index 5d15605280e7..61e9e1dc2025 100644 --- a/src/pages/identity/administration/users/add.jsx +++ b/src/pages/identity/administration/users/add.jsx @@ -36,6 +36,7 @@ const Page = () => { newFields.usageLocation = { label: usageLocation, value: usageLocation }; } newFields.tenantFilter = userSettingsDefaults.currentTenant; + formControl.reset(newFields); } }, [formValues]); diff --git a/src/pages/identity/administration/users/user/edit.jsx b/src/pages/identity/administration/users/user/edit.jsx index 539ed69d1d98..17e60e4a4f1b 100644 --- a/src/pages/identity/administration/users/user/edit.jsx +++ b/src/pages/identity/administration/users/user/edit.jsx @@ -34,8 +34,17 @@ const Page = () => { useEffect(() => { if (userRequest.isSuccess) { const user = userRequest.data?.[0]; + //if we have userSettingsDefaults.userAttributes set, grab the .label from each userSsettingsDefaults, then set defaultAttributes.${label}.value to user.${label} + let defaultAttributes = {}; + if (userSettingsDefaults.userAttributes) { + userSettingsDefaults.userAttributes.forEach((attribute) => { + defaultAttributes[attribute.label] = { Value: user?.[attribute.label] }; + }); + } + console.log(defaultAttributes); formControl.reset({ ...user, + defaultAttributes: defaultAttributes, tenantFilter: userSettingsDefaults.currentTenant, licenses: user.assignedLicenses.map((license) => ({ label: getCippLicenseTranslation([license]), From 54f0fdebbef53c7dc8fe6a895199c07cabd9fe60 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 4 Feb 2025 11:08:38 +0100 Subject: [PATCH 080/231] auto username and default attributes --- src/components/CippFormPages/CippAddEditUser.jsx | 11 +++++++++++ src/pages/identity/administration/users/add.jsx | 2 +- src/pages/identity/administration/users/user/edit.jsx | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/CippFormPages/CippAddEditUser.jsx b/src/components/CippFormPages/CippAddEditUser.jsx index 991ade01854a..f772ae0e8e0e 100644 --- a/src/components/CippFormPages/CippAddEditUser.jsx +++ b/src/components/CippFormPages/CippAddEditUser.jsx @@ -8,6 +8,8 @@ import { CippFormLicenseSelector } from "/src/components/CippComponents/CippForm import Grid from "@mui/material/Grid"; import { ApiGetCall } from "../../api/ApiCall"; import { useSettings } from "../../hooks/use-settings"; +import { useWatch } from "react-hook-form"; +import { useEffect } from "react"; const CippAddEditUser = (props) => { const { formControl, userSettingsDefaults, formType = "add" } = props; @@ -16,6 +18,15 @@ const CippAddEditUser = (props) => { url: "/api/ListExtensionsConfig", queryKey: "ListExtensionsConfig", }); + + const watcher = useWatch({ control: formControl.control }); + useEffect(() => { + //if watch.firstname changes, and watch.lastname changes, set displayname to firstname + lastname + if (watcher.givenName && watcher.surname && formType === "add") { + formControl.setValue("displayName", `${watcher.givenName} ${watcher.surname}`); + } + }, [watcher.givenName, watcher.surname]); + return ( diff --git a/src/pages/identity/administration/users/add.jsx b/src/pages/identity/administration/users/add.jsx index 61e9e1dc2025..6db4b2a4bbf6 100644 --- a/src/pages/identity/administration/users/add.jsx +++ b/src/pages/identity/administration/users/add.jsx @@ -11,7 +11,7 @@ const Page = () => { const userSettingsDefaults = useSettings(); const formControl = useForm({ - mode: "onChange", + mode: "onBlur", defaultValues: { tenantFilter: userSettingsDefaults.currentTenant, usageLocation: userSettingsDefaults.usageLocation, diff --git a/src/pages/identity/administration/users/user/edit.jsx b/src/pages/identity/administration/users/user/edit.jsx index 17e60e4a4f1b..76998a10094b 100644 --- a/src/pages/identity/administration/users/user/edit.jsx +++ b/src/pages/identity/administration/users/user/edit.jsx @@ -25,7 +25,7 @@ const Page = () => { }); const formControl = useForm({ - mode: "onChange", + mode: "onBlur", defaultValues: { tenantFilter: userSettingsDefaults.currentTenant, }, From b0e222da1efa5c9b5cfc0916395461dff75c171d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 4 Feb 2025 17:14:12 +0100 Subject: [PATCH 081/231] Country selector --- src/pages/email/administration/contacts/edit.jsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx index 56bf1e557f6e..4981c10fe029 100644 --- a/src/pages/email/administration/contacts/edit.jsx +++ b/src/pages/email/administration/contacts/edit.jsx @@ -8,6 +8,7 @@ import CippFormPage from "/src/components/CippFormPages/CippFormPage"; import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; import { useSettings } from "../../../../hooks/use-settings"; import { ApiGetCall } from "../../../../api/ApiCall"; +import countryList from "/src/data/countryList.json"; const EditContact = () => { const tenantDomain = useSettings().currentTenant; @@ -65,7 +66,9 @@ const EditContact = () => { streetAddress: address.street || "", postalCode: address.postalCode || "", city: address.city || "", - country: address.countryOrRegion || "", + country: address.countryOrRegion + ? countryList.find((c) => c.Name === address.countryOrRegion)?.Code || "" + : "", companyName: contact.companyName || "", mobilePhone: mobilePhone || "", businessPhone: businessPhone || "", @@ -100,7 +103,7 @@ const EditContact = () => { StreetAddress: values.streetAddress, PostalCode: values.postalCode, City: values.city, - CountryOrRegion: values.country, + CountryOrRegion: values.country?.value || values.country, Company: values.companyName, mobilePhone: values.mobilePhone, phone: values.businessPhone, @@ -210,9 +213,14 @@ const EditContact = () => { ({ + label: Name, + value: Code, + }))} formControl={formControl} /> From 7e2c987dad5d51cbb85dad04f22b5d5be0e93f47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 4 Feb 2025 18:06:05 +0100 Subject: [PATCH 082/231] fix: Update label for GAL visibility and disable creatable option for country selection --- src/pages/email/administration/contacts/edit.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx index 4981c10fe029..87e9febc70f9 100644 --- a/src/pages/email/administration/contacts/edit.jsx +++ b/src/pages/email/administration/contacts/edit.jsx @@ -163,7 +163,7 @@ const EditContact = () => { @@ -217,6 +217,7 @@ const EditContact = () => { label="Country" name="country" multiple={false} + creatable={false} options={countryList.map(({ Code, Name }) => ({ label: Name, value: Code, From 0a600445889677169c9742baaaa14d8a3bf12da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 3 Feb 2025 19:12:04 +0100 Subject: [PATCH 083/231] feat: Add Edit Contact page with form functionality --- .../email/administration/contacts/edit.jsx | 236 ++++++++++++++++++ .../email/administration/contacts/index.js | 8 +- 2 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 src/pages/email/administration/contacts/edit.jsx diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx new file mode 100644 index 000000000000..12846ae3140a --- /dev/null +++ b/src/pages/email/administration/contacts/edit.jsx @@ -0,0 +1,236 @@ +import React, { useEffect } from "react"; +import { useRouter } from "next/router"; +import { Grid, Divider } from "@mui/material"; +import { useForm } from "react-hook-form"; +import { useSelector } from "react-redux"; +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import CippFormPage from "/src/components/CippFormPages/CippFormPage"; +import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; +import { useSettings } from "../../../../hooks/use-settings"; +import { ApiGetCall } from "../../../../api/ApiCall"; + +const EditContact = () => { + const tenantDomain = useSettings().currentTenant; + const router = useRouter(); + const { id } = router.query; + + const contactInfo = ApiGetCall({ + url: `/api/ListContacts?tenantFilter=${tenantDomain}&id=${id}`, + queryKey: `ListContacts-${id}`, + waiting: false, + }); + + useEffect(() => { + if (id) { + contactInfo.refetch(); + } + }, [router.query, id, tenantDomain]); + + const formControl = useForm({ + mode: "onChange", + defaultValues: { + displayName: "", + firstName: "", + lastName: "", + email: "", + hidefromGAL: false, + streetAddress: "", + postalCode: "", + city: "", + country: "", + companyName: "", + mobilePhone: "", + businessPhone: "", + jobTitle: "", + }, + }); + + useEffect(() => { + if (contactInfo.isSuccess && contactInfo.data?.Results?.[0]) { + const contact = contactInfo.data.Results[0]; + formControl.reset({ + displayName: contact.displayName || "", + firstName: contact.firstName || "", + lastName: contact.lastName || "", + email: contact.mail || "", + hidefromGAL: contact.hidefromGAL || false, + streetAddress: contact.streetAddress || "", + postalCode: contact.postalCode || "", + city: contact.city || "", + country: contact.countryOrRegion || "", + companyName: contact.companyName || "", + mobilePhone: contact.mobilePhone || "", + businessPhone: contact.phone || "", + jobTitle: contact.jobTitle || "", + }); + } + }, [contactInfo.isSuccess, contactInfo.data, contactInfo.isFetching]); + + if (contactInfo.isLoading) { + return
    Loading...
    ; + } + + return ( + { + return { + tenantID: tenantDomain, + firstName: values.firstName, + lastName: values.lastName, + displayName: values.displayName, + mail: values.email, + hidefromGAL: values.hidefromGAL, + ContactID: contactInfo.data?.Results?.[0]?.id, + StreetAddress: values.streetAddress, + PostalCode: values.postalCode, + City: values.city, + Country: values.country, + companyName: values.companyName, + MobilePhone: values.mobilePhone, + BusinessPhone: values.businessPhone, + jobTitle: values.jobTitle, + }; + }} + > + + {/* Display Name */} + + + + + {/* First Name and Last Name */} + + + + + + + + + + {/* Email */} + + + + + {/* Hide from GAL */} + + + + + + + {/* Company Information */} + + + + + + + + + + {/* Address Information */} + + + + + + + + + + + + + + + + {/* Phone Numbers */} + + + + + + + + + ); +}; + +EditContact.getLayout = (page) => {page}; + +export default EditContact; diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index ac22d6596579..e08ab4e7d785 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -3,7 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Edit, PersonAdd } from "@mui/icons-material"; import { Button } from "@mui/material"; import Link from "next/link"; -import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; +import TrashIcon from "@heroicons/react/24/outline/TrashIcon"; const Page = () => { const pageTitle = "Contacts"; @@ -20,14 +20,14 @@ const Page = () => { color: "danger", icon: , }, - /* TODO: Implement edit contact { label: "Edit Contact", - link: "/email/administration/edit-contact/[id]", + link: "/email/administration/contacts/edit?id={id}", multiPost: false, + postEntireRow: true, icon: , color: "warning", - },*/ + }, ]; const simpleColumns = ["displayName", "mail", "companyName", "onPremisesSyncEnabled"]; From e6ad713b6ab85d7569a8f370606b49feaf107592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 3 Feb 2025 23:42:15 +0100 Subject: [PATCH 084/231] move up --- .../email/administration/contacts/index.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index e08ab4e7d785..8d512604501f 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -9,6 +9,15 @@ const Page = () => { const pageTitle = "Contacts"; const actions = [ + , + { + label: "Edit Contact", + link: "/email/administration/contacts/edit?id=[id]", + multiPost: false, + postEntireRow: true, + icon: , + color: "warning", + }, { label: "Remove Contact", type: "GET", @@ -20,14 +29,6 @@ const Page = () => { color: "danger", icon: , }, - { - label: "Edit Contact", - link: "/email/administration/contacts/edit?id={id}", - multiPost: false, - postEntireRow: true, - icon: , - color: "warning", - }, ]; const simpleColumns = ["displayName", "mail", "companyName", "onPremisesSyncEnabled"]; From b74a81f33318afac9c7e65a067f1d38c0a7b6ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 4 Feb 2025 01:29:44 +0100 Subject: [PATCH 085/231] make it actually work --- .../email/administration/contacts/edit.jsx | 52 +++++++++++-------- .../email/administration/contacts/index.js | 6 ++- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx index 12846ae3140a..56bf1e557f6e 100644 --- a/src/pages/email/administration/contacts/edit.jsx +++ b/src/pages/email/administration/contacts/edit.jsx @@ -46,21 +46,29 @@ const EditContact = () => { }); useEffect(() => { - if (contactInfo.isSuccess && contactInfo.data?.Results?.[0]) { - const contact = contactInfo.data.Results[0]; + if (contactInfo.isSuccess && contactInfo.data?.[0]) { + const contact = contactInfo.data[0]; + // Get the address info from the first address entry + const address = contact.addresses?.[0] || {}; + + // Find phone numbers by type + const phones = contact.phones || []; + const mobilePhone = phones.find((p) => p.type === "mobile")?.number; + const businessPhone = phones.find((p) => p.type === "business")?.number; + formControl.reset({ displayName: contact.displayName || "", - firstName: contact.firstName || "", - lastName: contact.lastName || "", + firstName: contact.givenName || "", + lastName: contact.surname || "", email: contact.mail || "", hidefromGAL: contact.hidefromGAL || false, - streetAddress: contact.streetAddress || "", - postalCode: contact.postalCode || "", - city: contact.city || "", - country: contact.countryOrRegion || "", + streetAddress: address.street || "", + postalCode: address.postalCode || "", + city: address.city || "", + country: address.countryOrRegion || "", companyName: contact.companyName || "", - mobilePhone: contact.mobilePhone || "", - businessPhone: contact.phone || "", + mobilePhone: mobilePhone || "", + businessPhone: businessPhone || "", jobTitle: contact.jobTitle || "", }); } @@ -74,26 +82,28 @@ const EditContact = () => { { return { tenantID: tenantDomain, - firstName: values.firstName, - lastName: values.lastName, - displayName: values.displayName, - mail: values.email, + ContactID: contactInfo.data?.[0]?.id, + DisplayName: values.displayName, hidefromGAL: values.hidefromGAL, - ContactID: contactInfo.data?.Results?.[0]?.id, + email: values.email, + FirstName: values.firstName, + LastName: values.lastName, + Title: values.jobTitle, StreetAddress: values.streetAddress, PostalCode: values.postalCode, City: values.city, - Country: values.country, - companyName: values.companyName, - MobilePhone: values.mobilePhone, - BusinessPhone: values.businessPhone, - jobTitle: values.jobTitle, + CountryOrRegion: values.country, + Company: values.companyName, + mobilePhone: values.mobilePhone, + phone: values.businessPhone, }; }} > diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index 8d512604501f..9d75996d8652 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -9,7 +9,6 @@ const Page = () => { const pageTitle = "Contacts"; const actions = [ - , { label: "Edit Contact", link: "/email/administration/contacts/edit?id=[id]", @@ -17,6 +16,7 @@ const Page = () => { postEntireRow: true, icon: , color: "warning", + condition: (row) => !row.onPremisesSyncEnabled, }, { label: "Remove Contact", @@ -25,9 +25,11 @@ const Page = () => { data: { GUID: "id", }, - confirmText: "Are you sure you want to delete this contact?", + confirmText: + "Are you sure you want to delete this contact? Remember this will not work if the contact is AD Synced.", color: "danger", icon: , + condition: (row) => !row.onPremisesSyncEnabled, }, ]; From 852fafa1618b8fde4478c8a3e9430295b1827244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 4 Feb 2025 17:14:12 +0100 Subject: [PATCH 086/231] Country selector --- src/pages/email/administration/contacts/edit.jsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx index 56bf1e557f6e..4981c10fe029 100644 --- a/src/pages/email/administration/contacts/edit.jsx +++ b/src/pages/email/administration/contacts/edit.jsx @@ -8,6 +8,7 @@ import CippFormPage from "/src/components/CippFormPages/CippFormPage"; import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; import { useSettings } from "../../../../hooks/use-settings"; import { ApiGetCall } from "../../../../api/ApiCall"; +import countryList from "/src/data/countryList.json"; const EditContact = () => { const tenantDomain = useSettings().currentTenant; @@ -65,7 +66,9 @@ const EditContact = () => { streetAddress: address.street || "", postalCode: address.postalCode || "", city: address.city || "", - country: address.countryOrRegion || "", + country: address.countryOrRegion + ? countryList.find((c) => c.Name === address.countryOrRegion)?.Code || "" + : "", companyName: contact.companyName || "", mobilePhone: mobilePhone || "", businessPhone: businessPhone || "", @@ -100,7 +103,7 @@ const EditContact = () => { StreetAddress: values.streetAddress, PostalCode: values.postalCode, City: values.city, - CountryOrRegion: values.country, + CountryOrRegion: values.country?.value || values.country, Company: values.companyName, mobilePhone: values.mobilePhone, phone: values.businessPhone, @@ -210,9 +213,14 @@ const EditContact = () => {
    ({ + label: Name, + value: Code, + }))} formControl={formControl} /> From fa301687464b8b402b6cc0da73a2f8e27d19c45a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 4 Feb 2025 18:06:05 +0100 Subject: [PATCH 087/231] fix: Update label for GAL visibility and disable creatable option for country selection --- src/pages/email/administration/contacts/edit.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx index 4981c10fe029..87e9febc70f9 100644 --- a/src/pages/email/administration/contacts/edit.jsx +++ b/src/pages/email/administration/contacts/edit.jsx @@ -163,7 +163,7 @@ const EditContact = () => { @@ -217,6 +217,7 @@ const EditContact = () => { label="Country" name="country" multiple={false} + creatable={false} options={countryList.map(({ Code, Name }) => ({ label: Name, value: Code, From f2bd99e2ffc68547b0742b094a596e5dfe7df137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 3 Feb 2025 19:12:04 +0100 Subject: [PATCH 088/231] feat: Add Edit Contact page with form functionality --- .../email/administration/contacts/edit.jsx | 255 ++++++++++++++++++ .../email/administration/contacts/index.js | 23 +- 2 files changed, 268 insertions(+), 10 deletions(-) create mode 100644 src/pages/email/administration/contacts/edit.jsx diff --git a/src/pages/email/administration/contacts/edit.jsx b/src/pages/email/administration/contacts/edit.jsx new file mode 100644 index 000000000000..87e9febc70f9 --- /dev/null +++ b/src/pages/email/administration/contacts/edit.jsx @@ -0,0 +1,255 @@ +import React, { useEffect } from "react"; +import { useRouter } from "next/router"; +import { Grid, Divider } from "@mui/material"; +import { useForm } from "react-hook-form"; +import { useSelector } from "react-redux"; +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import CippFormPage from "/src/components/CippFormPages/CippFormPage"; +import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; +import { useSettings } from "../../../../hooks/use-settings"; +import { ApiGetCall } from "../../../../api/ApiCall"; +import countryList from "/src/data/countryList.json"; + +const EditContact = () => { + const tenantDomain = useSettings().currentTenant; + const router = useRouter(); + const { id } = router.query; + + const contactInfo = ApiGetCall({ + url: `/api/ListContacts?tenantFilter=${tenantDomain}&id=${id}`, + queryKey: `ListContacts-${id}`, + waiting: false, + }); + + useEffect(() => { + if (id) { + contactInfo.refetch(); + } + }, [router.query, id, tenantDomain]); + + const formControl = useForm({ + mode: "onChange", + defaultValues: { + displayName: "", + firstName: "", + lastName: "", + email: "", + hidefromGAL: false, + streetAddress: "", + postalCode: "", + city: "", + country: "", + companyName: "", + mobilePhone: "", + businessPhone: "", + jobTitle: "", + }, + }); + + useEffect(() => { + if (contactInfo.isSuccess && contactInfo.data?.[0]) { + const contact = contactInfo.data[0]; + // Get the address info from the first address entry + const address = contact.addresses?.[0] || {}; + + // Find phone numbers by type + const phones = contact.phones || []; + const mobilePhone = phones.find((p) => p.type === "mobile")?.number; + const businessPhone = phones.find((p) => p.type === "business")?.number; + + formControl.reset({ + displayName: contact.displayName || "", + firstName: contact.givenName || "", + lastName: contact.surname || "", + email: contact.mail || "", + hidefromGAL: contact.hidefromGAL || false, + streetAddress: address.street || "", + postalCode: address.postalCode || "", + city: address.city || "", + country: address.countryOrRegion + ? countryList.find((c) => c.Name === address.countryOrRegion)?.Code || "" + : "", + companyName: contact.companyName || "", + mobilePhone: mobilePhone || "", + businessPhone: businessPhone || "", + jobTitle: contact.jobTitle || "", + }); + } + }, [contactInfo.isSuccess, contactInfo.data, contactInfo.isFetching]); + + if (contactInfo.isLoading) { + return
    Loading...
    ; + } + + return ( + { + return { + tenantID: tenantDomain, + ContactID: contactInfo.data?.[0]?.id, + DisplayName: values.displayName, + hidefromGAL: values.hidefromGAL, + email: values.email, + FirstName: values.firstName, + LastName: values.lastName, + Title: values.jobTitle, + StreetAddress: values.streetAddress, + PostalCode: values.postalCode, + City: values.city, + CountryOrRegion: values.country?.value || values.country, + Company: values.companyName, + mobilePhone: values.mobilePhone, + phone: values.businessPhone, + }; + }} + > + + {/* Display Name */} + + + + + {/* First Name and Last Name */} + + + + + + + + + + {/* Email */} + + + + + {/* Hide from GAL */} + + + + + + + {/* Company Information */} + + + + + + + + + + {/* Address Information */} + + + + + + + + + + + ({ + label: Name, + value: Code, + }))} + formControl={formControl} + /> + + + + + {/* Phone Numbers */} + + + + + + + + + ); +}; + +EditContact.getLayout = (page) => {page}; + +export default EditContact; diff --git a/src/pages/email/administration/contacts/index.js b/src/pages/email/administration/contacts/index.js index ac22d6596579..9d75996d8652 100644 --- a/src/pages/email/administration/contacts/index.js +++ b/src/pages/email/administration/contacts/index.js @@ -3,12 +3,21 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Edit, PersonAdd } from "@mui/icons-material"; import { Button } from "@mui/material"; import Link from "next/link"; -import TrashIcon from '@heroicons/react/24/outline/TrashIcon'; +import TrashIcon from "@heroicons/react/24/outline/TrashIcon"; const Page = () => { const pageTitle = "Contacts"; const actions = [ + { + label: "Edit Contact", + link: "/email/administration/contacts/edit?id=[id]", + multiPost: false, + postEntireRow: true, + icon: , + color: "warning", + condition: (row) => !row.onPremisesSyncEnabled, + }, { label: "Remove Contact", type: "GET", @@ -16,18 +25,12 @@ const Page = () => { data: { GUID: "id", }, - confirmText: "Are you sure you want to delete this contact?", + confirmText: + "Are you sure you want to delete this contact? Remember this will not work if the contact is AD Synced.", color: "danger", icon: , + condition: (row) => !row.onPremisesSyncEnabled, }, - /* TODO: Implement edit contact - { - label: "Edit Contact", - link: "/email/administration/edit-contact/[id]", - multiPost: false, - icon: , - color: "warning", - },*/ ]; const simpleColumns = ["displayName", "mail", "companyName", "onPremisesSyncEnabled"]; From e378097e14962207fd7179f5231392669d9b9c21 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 4 Feb 2025 13:56:41 -0500 Subject: [PATCH 089/231] add sam wizard form validation --- .../CippWizard/CIPPDeploymentStep.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/components/CippWizard/CIPPDeploymentStep.js b/src/components/CippWizard/CIPPDeploymentStep.js index d0b17d45f13c..c5166f6fbe3e 100644 --- a/src/components/CippWizard/CIPPDeploymentStep.js +++ b/src/components/CippWizard/CIPPDeploymentStep.js @@ -284,6 +284,13 @@ export const CippDeploymentStep = (props) => { name="TenantID" label="Tenant ID" placeholder="Enter the Tenant ID. Leave blank to retain previous key." + validators={{ + validate: (value) => { + const guidRegex = + /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/; + return value === "" || guidRegex.test(value) || "Invalid Tenant ID"; + }, + }} /> { name="ApplicationID" label="Application ID" placeholder="Enter the Application ID. Leave blank to retain previous key." + validators={{ + validate: (value) => { + const guidRegex = + /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/; + return value === "" || guidRegex.test(value) || "Invalid Application ID"; + }, + }} /> { name="ApplicationSecret" label="Application Secret" placeholder="Enter the application secret. Leave blank to retain previous key." + validators={{ + validate: (value) => { + const secretRegex = /^(?![0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)[0-9a-zA-Z]{40}$/; + return value === "" || secretRegex.test(value) || "This should be the secret value, not the secret ID"; + }, + }} /> { name="RefreshToken" label="Refresh Token" placeholder="Enter the refresh token. Leave blank to retain previous key." + validators={{ + validate: (value) => { + const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/; + return value === "" || jwtRegex.test(value) || "Invalid Refresh Token"; + } + }} /> )} From 0bcf8944d54009e89de000f8bb2f16043de85c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 4 Feb 2025 21:22:09 +0100 Subject: [PATCH 090/231] add conditional --- src/pages/email/transport/list-connectors/index.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pages/email/transport/list-connectors/index.js b/src/pages/email/transport/list-connectors/index.js index 477b191fdff5..c77da7d7ece4 100644 --- a/src/pages/email/transport/list-connectors/index.js +++ b/src/pages/email/transport/list-connectors/index.js @@ -22,6 +22,7 @@ const Page = () => { type: "POST", url: "/api/EditExConnector", icon: , + condition: (row) => !row.Enabled, data: { State: "Enable", GUID: "Guid", @@ -35,6 +36,7 @@ const Page = () => { type: "POST", url: "/api/EditExConnector", icon: , + condition: (row) => row.Enabled, data: { State: "Disable", GUID: "Guid", @@ -82,11 +84,6 @@ const Page = () => { actions={actions} offCanvas={offCanvas} simpleColumns={simpleColumns} - titleButton={{ - label: "Deploy Connector", - href: "/email/connectors/deploy-connector", - startIcon: , // Added icon - }} cardButton={ <> + <> + + {!/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test( + appId.data.applicationId + ) && ( + + The Application ID is not valid. Please return to the first page of the SAM wizard and use the Manual . + + )} + } > @@ -314,8 +328,13 @@ export const CippDeploymentStep = (props) => { placeholder="Enter the application secret. Leave blank to retain previous key." validators={{ validate: (value) => { - const secretRegex = /^(?![0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)[0-9a-zA-Z]{40}$/; - return value === "" || secretRegex.test(value) || "This should be the secret value, not the secret ID"; + const secretRegex = + /^(?![0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$)[0-9a-zA-Z]{40}$/; + return ( + value === "" || + secretRegex.test(value) || + "This should be the secret value, not the secret ID" + ); }, }} /> @@ -329,7 +348,7 @@ export const CippDeploymentStep = (props) => { validate: (value) => { const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/; return value === "" || jwtRegex.test(value) || "Invalid Refresh Token"; - } + }, }} /> From 50f6adaea27c974031dee0e6c2d5a70c2139cc63 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 4 Feb 2025 22:32:25 -0500 Subject: [PATCH 094/231] feat: CIPP-API Integration v2 Update extension configuration for cippapi Add new CippApiClientManagement component to handle multiple App registrations with different permissions New formatters for API client details Adding ability to pass row values to CippApiDialog with setDefaultValues flag on action --- .../CippComponents/CippApiDialog.jsx | 34 ++ .../CippComponents/CippTranslations.jsx | 1 + .../CippApiClientManagement.jsx | 348 ++++++++++++++++++ src/data/Extensions.json | 50 ++- src/pages/cipp/integrations/configure.js | 16 +- src/pages/cipp/integrations/index.js | 4 +- src/utils/get-cipp-formatting.js | 4 + 7 files changed, 434 insertions(+), 23 deletions(-) create mode 100644 src/components/CippIntegrations/CippApiClientManagement.jsx diff --git a/src/components/CippComponents/CippApiDialog.jsx b/src/components/CippComponents/CippApiDialog.jsx index bd6348868c8b..99c5bcc455c9 100644 --- a/src/components/CippComponents/CippApiDialog.jsx +++ b/src/components/CippComponents/CippApiDialog.jsx @@ -207,6 +207,40 @@ export const CippApiDialog = (props) => { const onSubmit = (data) => handleActionClick(row, api, data); const selectedType = api.type === "POST" ? actionPostRequest : actionGetRequest; + if (api?.setDefaultValues) { + fields.map((field) => { + if ( + ((typeof row[field.name] === "string" && field.type === "textField") || + (typeof row[field.name] === "boolean" && field.type === "switch")) && + row[field.name] !== undefined && + row[field.name] !== null && + row[field.name] !== "" + ) { + formHook.setValue(field.name, row[field.name]); + } else if (Array.isArray(row[field.name]) && field.type === "autoComplete") { + var values = []; + row[field.name].map((element) => { + values.push({ + label: element, + value: element, + }); + }); + formHook.setValue(field.name, values); + } else if ( + field.type === "autoComplete" && + row[field.name] !== undefined && + row[field.name] !== null && + row[field.name] !== "" && + typeof row[field.name] === "string" + ) { + formHook.setValue(field.name, { + label: row[field.name], + value: row[field.name], + }); + } + }); + } + // Handling link navigation if (api.link) { const getNestedValue = (obj, path) => { diff --git a/src/components/CippComponents/CippTranslations.jsx b/src/components/CippComponents/CippTranslations.jsx index 0876bded5bd2..7761362d09ed 100644 --- a/src/components/CippComponents/CippTranslations.jsx +++ b/src/components/CippComponents/CippTranslations.jsx @@ -44,4 +44,5 @@ export const CippTranslations = { "commitmentTerm.renewalConfiguration.renewalDate": "Renewal Date", storageUsedInBytes: "Storage Used", prohibitSendReceiveQuotaInBytes: "Quota", + ClientId: "Client ID", }; diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx new file mode 100644 index 000000000000..df348b460aec --- /dev/null +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -0,0 +1,348 @@ +import { Button, Stack, SvgIcon, Menu, MenuItem, ListItemText } from "@mui/material"; +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import { ApiGetCall, ApiPostCall } from "/src/api/ApiCall"; +import { CippDataTable } from "../CippTable/CippDataTable"; +import { + ChevronDownIcon, + ClipboardDocumentIcon, + PencilIcon, + PlusSmallIcon, + TrashIcon, +} from "@heroicons/react/24/outline"; +import { CippApiResults } from "../CippComponents/CippApiResults"; +import { CippApiDialog } from "../CippComponents/CippApiDialog"; +import { Create, Key, Save } from "@mui/icons-material"; +import { CippPropertyListCard } from "../CippCards/CippPropertyListCard"; +import { CippCopyToClipBoard } from "../CippComponents/CippCopyToClipboard"; + +const CippApiClientManagement = () => { + const [openAddClientDialog, setOpenAddClientDialog] = useState(false); + const [openAddExistingAppDialog, setOpenAddExistingAppDialog] = useState(false); + const [menuAnchorEl, setMenuAnchorEl] = useState(null); + + const formControl = useForm({ + mode: "onChange", + }); + + const postCall = ApiPostCall({ + datafromUrl: true, + relatedQueryKeys: ["ApiClients", "AzureConfiguration"], + }); + + const azureConfig = ApiGetCall({ + url: "/api/ExecApiClient", + data: { Action: "GetAzureConfiguration" }, + queryKey: "AzureConfiguration", + }); + + const handleMenuOpen = (event) => { + setMenuAnchorEl(event.currentTarget); + }; + + const handleMenuClose = () => { + setMenuAnchorEl(null); + }; + + const handleSaveToAzure = () => { + postCall.mutate({ + url: `/api/ExecApiClient?action=SaveToAzure`, + data: {}, + }); + handleMenuClose(); + }; + + const actions = [ + { + label: "Edit", + icon: ( + + + + ), + confirmText: "Update the API client settings:", + hideBulk: true, + setDefaultValues: true, + fields: [ + { + type: "autoComplete", + name: "Role", + multiple: false, + creatable: false, + placeholder: "Select Role", + api: { + url: "/api/ListCustomRole", + queryKey: "CustomRoleList", + labelField: "RowKey", + valueField: "RowKey", + }, + }, + { + type: "autoComplete", + name: "IpRange", + multiple: true, + freeSolo: true, + creatable: true, + options: [], + placeholder: "Enter IP Range (Single hosts or CIDR notation)", + }, + { + type: "switch", + name: "Enabled", + label: "Enable this client", + }, + ], + type: "POST", + url: "/api/ExecApiClient", + data: { + Action: "AddUpdate", + ClientId: "ClientId", + }, + relatedQueryKeys: ["ApiClients"], + }, + { + label: "Reset Application Secret", + icon: , + confirmText: "Are you sure you want to reset the application secret?", + type: "POST", + url: "/api/ExecApiClient", + data: { + Action: "ResetSecret", + ClientId: "ClientId", + }, + }, + { + label: "Copy API Scope", + icon: , + noConfirm: true, + customFunction: (row, action, formData) => { + var scope = `api://${row.ClientId}/.default`; + navigator.clipboard.writeText(scope); + }, + }, + { + label: "Delete Client", + icon: , + confirmText: "Are you sure you want to delete this client?", + type: "POST", + url: "/api/ExecApiClient", + data: { + Action: "Delete", + ClientId: "ClientId", + }, + fields: [ + { + type: "switch", + name: "RemoveAppReg", + label: "Remove App Registration", + }, + ], + relatedQueryKeys: ["ApiClients"], + }, + ]; + + return ( + <> + + + ) : ( + "Not Available" + ), + }, + { + label: "Token URL", + value: azureConfig.data?.Results?.TenantID ? ( + + ) : ( + "Not Available" + ), + }, + ]} + layout="dual" + showDivider={false} + isFetching={azureConfig.isFetching} + /> + + + + { + handleMenuClose(); + setOpenAddClientDialog(true); + }} + > + + + + Create New Client + + { + handleMenuClose(); + setOpenAddExistingAppDialog(true); + }} + > + + + + Add Existing Client + + + + + + Save to Azure + + + + } + /> + + + + setOpenAddClientDialog(false), + }} + title="Add Client" + fields={[ + { + type: "textField", + name: "AppName", + placeholder: "Enter App Name", + formControl: formControl, + }, + { + type: "autoComplete", + name: "Role", + multiple: false, + creatable: false, + placeholder: "Select Role", + api: { + url: "/api/ListCustomRole", + queryKey: "CustomRoleList", + labelField: "RowKey", + valueField: "RowKey", + }, + }, + { + type: "autoComplete", + name: "IpRange", + multiple: true, + freeSolo: true, + creatable: true, + options: [], + placeholder: "Enter IP Range (Single hosts or CIDR notation)", + }, + { + type: "switch", + name: "Enabled", + label: "Enable this client", + }, + ]} + api={{ + type: "POST", + url: "/api/ExecApiClient", + data: { Action: "AddUpdate" }, + relatedQueryKeys: [`ApiClients`], + }} + /> + setOpenAddExistingAppDialog(false), + }} + title="Add Existing App" + fields={[ + { + type: "autoComplete", + name: "ClientId", + placeholder: "Select Existing App", + api: { + type: "GET", + url: "/api/ExecApiClient", + data: { Action: "ListAvailable" }, + queryKey: `AvailableApiApps`, + dataKey: "Results", + labelField: (app) => `${app.displayName} (${app.appId})`, + valueField: "appId", + addedField: { + displayName: "displayName", + createdDateTime: "createdDateTime", + }, + }, + creatable: false, + multiple: false, + }, + { + type: "autoComplete", + name: "Role", + multiple: false, + creatable: false, + placeholder: "Select Role", + api: { + url: "/api/ListCustomRole", + queryKey: "CustomRoleList", + labelField: "RowKey", + valueField: "RowKey", + }, + }, + { + type: "autoComplete", + name: "IpRange", + multiple: true, + freeSolo: true, + creatable: true, + options: [], + placeholder: "Enter IP Range(s)", + }, + { + type: "switch", + name: "Enabled", + label: "Enable this client", + }, + ]} + api={{ + type: "POST", + url: "/api/ExecApiClient", + data: { Action: "!AddUpdate" }, + relatedQueryKeys: [`ApiClients`], + }} + /> + + ); +}; + +export default CippApiClientManagement; diff --git a/src/data/Extensions.json b/src/data/Extensions.json index 0110e7d63729..e81d25cf3468 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -7,19 +7,12 @@ "logo": "/assets/integrations/cipp-api.png", "forceSyncButton": false, "hideTestButton": true, - "disableWhenhosted": true, - "description": "Enable the CIPP API to access CIPP data outside of CIPP using a RESTful API.", - "helpText": "This integration allows you to enable CIPP-API access outside of CIPP. Requires Global Administrator permissions inside your tenant for activation of the API. The API credentials will only be shown once.", - "SettingOptions": [ - { - "type": "switch", - "name": "cippapi.ResetPassword", - "label": "Reset application secret - this will invalidate all existing API tokens" - }, + "description": "The CIPP API allows you to access CIPP data outside of CIPP using a RESTful API.", + "helpText": "This integration allows you to enable CIPP-API access outside of CIPP. This is useful for integrations with other systems or custom scripts.", + "links": [ { - "type": "switch", - "name": "cippapi.Enabled", - "label": "Enable Integration" + "name": "CIPP API Documentation", + "url": "https://docs.cipp.app/api-documentation/setup-and-authentication" } ], "mappingRequired": false @@ -76,7 +69,7 @@ "name": "Sherweb.AllowedCustomRoles", "label": "Select custom roles that are allowed to purchase licenses", "api": { - "url": "/api/ExecCustomRole", + "url": "/api/ListCustomRole", "queryKey": "CustomRoles", "labelField": "RowKey", "valueField": "RowKey" @@ -463,5 +456,36 @@ } ], "mappingRequired": false + }, + { + "name": "GitHub", + "id": "GitHub", + "type": "DevOps", + "cat": "Source Control", + "logo": "/assets/integrations/github.png", + "logoDark": "/assets/integrations/github_dark.png", + "description": "Enable the GitHub integration to manage your repositories from CIPP.", + "helpText": "This integration allows you to manage your GitHub repositories from CIPP. Requires a GitHub Fine Grained Personal Access Token (PAT).", + "links": [ + { + "name": "GitHub Token", + "url": "https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token" + } + ], + "SettingOptions": [ + { + "type": "password", + "name": "GitHub.APIKey", + "label": "GitHub Fine Grained Personal Access Token", + "placeholder": "Enter your GitHub PAT", + "required": true + }, + { + "type": "switch", + "name": "GitHub.Enabled", + "label": "Enable Integration" + } + ], + "mappingRequired": false } ] diff --git a/src/pages/cipp/integrations/configure.js b/src/pages/cipp/integrations/configure.js index e45bf0fd4489..1995566ddd38 100644 --- a/src/pages/cipp/integrations/configure.js +++ b/src/pages/cipp/integrations/configure.js @@ -15,6 +15,7 @@ import CippPageCard from "../../../components/CippCards/CippPageCard"; import CippIntegrationTenantMapping from "../../../components/CippIntegrations/CippIntegrationTenantMapping"; import CippIntegrationFieldMapping from "../../../components/CippIntegrations/CippIntegrationFieldMapping"; import { CippCardTabPanel } from "../../../components/CippComponents/CippCardTabPanel"; +import CippApiClientManagement from "../../../components/CippIntegrations/CippApiClientManagement"; function tabProps(index) { return { @@ -77,7 +78,7 @@ const Page = () => { defaultValues: integrations?.data, }); - const extension = extensions.find((extension) => extension.id === router.query.id); + const extension = extensions.find((extension) => extension.id === router.query.id) || {}; var logo = extension?.logo; if (preferredTheme === "dark" && extension?.logoDark) { @@ -185,12 +186,16 @@ const Page = () => { {extension?.mappingRequired && } {extension?.fieldMapping && } - {extension?.id === "cippapi" && }
    - + {extension?.id === "cippapi" ? ( + + ) : ( + + )} + {extension?.mappingRequired && ( @@ -201,11 +206,6 @@ const Page = () => { )} - {extension?.id === "cippapi" && ( - - API Client component to go here - - )} )} diff --git a/src/pages/cipp/integrations/index.js b/src/pages/cipp/integrations/index.js index 241ced5c4792..4bf582e23432 100644 --- a/src/pages/cipp/integrations/index.js +++ b/src/pages/cipp/integrations/index.js @@ -56,11 +56,11 @@ const Page = () => { } var integrationConfig = integrations?.data?.[extension.id]; - var isEnabled = integrationConfig?.Enabled; + var isEnabled = integrationConfig?.Enabled || extension.id === "cippapi"; var status = "Unconfigured"; if (integrationConfig && !isEnabled) { status = "Disabled"; - } else if (integrationConfig && isEnabled) { + } else if ((integrationConfig && isEnabled) || extension.id === "cippapi") { status = "Enabled"; } diff --git a/src/utils/get-cipp-formatting.js b/src/utils/get-cipp-formatting.js index 73c65b8dbdad..2feaacacf94d 100644 --- a/src/utils/get-cipp-formatting.js +++ b/src/utils/get-cipp-formatting.js @@ -219,6 +219,10 @@ export const getCippFormatting = (data, cellName, type, canReceive) => { } } + if (cellName === "ClientId") { + return isText ? data : ; + } + if (cellName === "excludedTenants") { //check if data is an array. if (Array.isArray(data)) { From a4377ef9e471efda97df1ed437491ef8719d62c9 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 4 Feb 2025 23:03:41 -0500 Subject: [PATCH 095/231] Update CippApiClientManagement.jsx --- src/components/CippIntegrations/CippApiClientManagement.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index df348b460aec..1a2635f40535 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -242,7 +242,6 @@ const CippApiClientManagement = () => { type: "textField", name: "AppName", placeholder: "Enter App Name", - formControl: formControl, }, { type: "autoComplete", From 0584d61e90b27337ecf89272fde58306a37f2ed1 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Feb 2025 00:06:32 -0500 Subject: [PATCH 096/231] move actions add refresh config button --- .../CippApiClientManagement.jsx | 83 ++++++++++--------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index 1a2635f40535..01e174c64e46 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -12,7 +12,7 @@ import { } from "@heroicons/react/24/outline"; import { CippApiResults } from "../CippComponents/CippApiResults"; import { CippApiDialog } from "../CippComponents/CippApiDialog"; -import { Create, Key, Save } from "@mui/icons-material"; +import { Create, Key, Save, Sync } from "@mui/icons-material"; import { CippPropertyListCard } from "../CippCards/CippPropertyListCard"; import { CippCopyToClipBoard } from "../CippComponents/CippCopyToClipboard"; @@ -146,43 +146,7 @@ const CippApiClientManagement = () => { - ) : ( - "Not Available" - ), - }, - { - label: "Token URL", - value: azureConfig.data?.Results?.TenantID ? ( - - ) : ( - "Not Available" - ), - }, - ]} - layout="dual" - showDivider={false} - isFetching={azureConfig.isFetching} - /> - + + +
  • + + ); +}; + +Page.getLayout = (page) => {page}; +export default Page; \ No newline at end of file From 1779fbaec58144902cbbf7abeb0ce162efd6568f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 6 Feb 2025 15:09:45 -0500 Subject: [PATCH 104/231] extension updates fix api results for new object format prevent error fields from being selected in CippAutocomplete add halo ticket type selection --- .../CippComponents/CippApiResults.jsx | 63 ++++++++++--------- .../CippComponents/CippAutocomplete.jsx | 14 ++++- src/data/Extensions.json | 53 +++++++++++++--- 3 files changed, 90 insertions(+), 40 deletions(-) diff --git a/src/components/CippComponents/CippApiResults.jsx b/src/components/CippComponents/CippApiResults.jsx index b1fee51f09de..3ef597b2ddb1 100644 --- a/src/components/CippComponents/CippApiResults.jsx +++ b/src/components/CippComponents/CippApiResults.jsx @@ -52,40 +52,47 @@ const extractAllResults = (data) => { return; } - const ignoreKeys = ["metadata", "Metadata"]; - - if (typeof obj === "object") { - Object.keys(obj).forEach((key) => { - const value = obj[key]; - if (ignoreKeys.includes(key)) return; - if (["Results", "Result", "results", "result"].includes(key)) { - if (Array.isArray(value)) { - value.forEach((valItem) => { - const processed = processResultItem(valItem); + if (obj?.resultText) { + const processed = processResultItem(obj); + if (processed) { + results.push(processed); + } + } else { + const ignoreKeys = ["metadata", "Metadata"]; + + if (typeof obj === "object") { + Object.keys(obj).forEach((key) => { + const value = obj[key]; + if (ignoreKeys.includes(key)) return; + if (["Results", "Result", "results", "result"].includes(key)) { + if (Array.isArray(value)) { + value.forEach((valItem) => { + const processed = processResultItem(valItem); + if (processed) { + results.push(processed); + } else { + extractFrom(valItem); + } + }); + } else if (typeof value === "object") { + const processed = processResultItem(value); if (processed) { results.push(processed); } else { - extractFrom(valItem); + extractFrom(value); } - }); - } else if (typeof value === "object") { - const processed = processResultItem(value); - if (processed) { - results.push(processed); - } else { - extractFrom(value); + } else if (typeof value === "string") { + results.push({ + text: value, + copyField: value, + severity: getSeverity(value), + }); } - } else if (typeof value === "string") { - results.push({ - text: value, - copyField: value, - severity: getSeverity(value), - }); + } else { + extractFrom(value); } - } else { - extractFrom(value); - } - }); + }); + } } }; diff --git a/src/components/CippComponents/CippAutocomplete.jsx b/src/components/CippComponents/CippAutocomplete.jsx index 0cb207b835dc..1742ab9c17f2 100644 --- a/src/components/CippComponents/CippAutocomplete.jsx +++ b/src/components/CippComponents/CippAutocomplete.jsx @@ -1,5 +1,11 @@ import { ArrowDropDown } from "@mui/icons-material"; -import { Autocomplete, CircularProgress, createFilterOptions, TextField, IconButton } from "@mui/material"; +import { + Autocomplete, + CircularProgress, + createFilterOptions, + TextField, + IconButton, +} from "@mui/material"; import { useEffect, useState } from "react"; import { useSettings } from "../../hooks/use-settings"; import { getCippError } from "../../utils/get-cipp-error"; @@ -189,7 +195,9 @@ export const CippAutoComplete = (props) => { } return item; }); - newValue = newValue.filter((item) => item.value && item.value.trim() !== "" && item.value !== "error"); + newValue = newValue.filter( + (item) => item.value && item.value !== "" && item.value !== "error" && item.value !== -1 + ); } else { if (newValue?.manual || !newValue?.label) { newValue = { @@ -200,7 +208,7 @@ export const CippAutoComplete = (props) => { onCreateOption(newValue, newValue?.addedFields); } } - if (!newValue?.value || !newValue.value.trim() || newValue.value === "error") { + if (!newValue?.value || newValue.value === "error") { newValue = null; } } diff --git a/src/data/Extensions.json b/src/data/Extensions.json index e81d25cf3468..9fe08b00eb57 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -156,15 +156,25 @@ "type": "textField", "name": "HaloPSA.Tenant", "label": "HaloPSA Tenant", - "placeholder": "Enter your HaloPSA Tenant (Leave blank if self-hosted", + "placeholder": "Enter your HaloPSA Tenant (Leave blank if self-hosted)", "required": true }, { - "type": "textField", + "type": "autoComplete", "name": "HaloPSA.TicketType", - "label": "HaloPSA Ticket Type ID", - "placeholder": "Enter your HaloPSA ticket type to use for CIPP Tickets. Leave blank for default.", - "required": true + "label": "Select your HaloPSA Ticket Type, leave blank for default.", + "multiple": false, + "api": { + "url": "/api/ExecExtensionMapping", + "data": { + "List": "HaloPSAFields" + }, + "queryKey": "HaloTicketTypes", + "dataKey": "TicketTypes", + "labelField": "name", + "valueField": "id", + "showRefresh": true + } }, { "type": "textField", @@ -344,6 +354,11 @@ "name": "PWPush.Enabled", "label": "Enable Integration - Replace passwords with PWPush links" }, + { + "type": "switch", + "name": "PWPush.PWPushPro", + "label": "PWPush Pro/Premium account" + }, { "type": "textField", "name": "PWPush.BaseUrl", @@ -354,7 +369,7 @@ "type": "textField", "name": "PWPush.EmailAddress", "label": "PWPush email address", - "placeholder": "Enter your email address for PWPush. (optional)" + "placeholder": "Enter your email address for PWPush. (Free/Self-Hosted only)" }, { "type": "password", @@ -363,10 +378,25 @@ "placeholder": "Enter your PWPush API Key. (optional)" }, { - "type": "switch", - "name": "PWPush.RetrievalStep", - "label": "Click to retrieve password (recommended)" + "type": "autoComplete", + "name": "PWPush.AccountId", + "label": "Select your PWPush Account for branding (Pro/Premium only)", + "multiple": false, + "api": { + "url": "/api/ExecExtensionMapping?List=PWPushFields", + "queryKey": "PWPushAccounts", + "dataKey": "Accounts", + "labelField": "name", + "valueField": "id", + "showRefresh": true + }, + "condition": { + "field": "PWPush.PWPushPro", + "compareType": "is", + "compareValue": true + } }, + { "type": "number", "name": "PWPush.ExpireAfterDays", @@ -379,6 +409,11 @@ "label": "Expiration after views", "placeholder": "Expiration after views. (optional)" }, + { + "type": "switch", + "name": "PWPush.RetrievalStep", + "label": "Click to retrieve password (recommended)" + }, { "type": "switch", "name": "PWPush.DeletableByViewer", From 97afe05be71926dfe980f141814589ab80e1b190 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 6 Feb 2025 23:05:53 +0100 Subject: [PATCH 105/231] template repo --- src/pages/tools/templatelib/index.jsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/pages/tools/templatelib/index.jsx b/src/pages/tools/templatelib/index.jsx index 2b46fde8cb9e..060ad05d7630 100644 --- a/src/pages/tools/templatelib/index.jsx +++ b/src/pages/tools/templatelib/index.jsx @@ -35,7 +35,7 @@ const TemplateLibrary = () => { Command: { value: `New-CIPPTemplateRun` }, Parameters: { TemplateSettings: { ...values } }, ScheduledTime: unixTime, - Recurrence: { value: "4h" }, + Recurrence: { value: values.tenantFilter?.value ? "4h" : "7d" }, }; }; @@ -160,6 +160,18 @@ const TemplateLibrary = () => { label="Create Group Templates" formControl={formControl} /> + + From 782fa768eccdc307c9725dbf98ee5988feb4f17f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 6 Feb 2025 17:09:41 -0500 Subject: [PATCH 106/231] Update CippApiClientManagement.jsx --- .../CippApiClientManagement.jsx | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index 01e174c64e46..067cae539a05 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -1,7 +1,8 @@ -import { Button, Stack, SvgIcon, Menu, MenuItem, ListItemText } from "@mui/material"; +import { Button, Stack, SvgIcon, Menu, MenuItem, ListItemText, Alert } from "@mui/material"; import { useState } from "react"; +import isEqual from "lodash/isEqual"; import { useForm } from "react-hook-form"; -import { ApiGetCall, ApiPostCall } from "/src/api/ApiCall"; +import { ApiGetCall, ApiGetCallWithPagination, ApiPostCall } from "/src/api/ApiCall"; import { CippDataTable } from "../CippTable/CippDataTable"; import { ChevronDownIcon, @@ -15,6 +16,7 @@ import { CippApiDialog } from "../CippComponents/CippApiDialog"; import { Create, Key, Save, Sync } from "@mui/icons-material"; import { CippPropertyListCard } from "../CippCards/CippPropertyListCard"; import { CippCopyToClipBoard } from "../CippComponents/CippCopyToClipboard"; +import { Box } from "@mui/system"; const CippApiClientManagement = () => { const [openAddClientDialog, setOpenAddClientDialog] = useState(false); @@ -36,6 +38,12 @@ const CippApiClientManagement = () => { queryKey: "AzureConfiguration", }); + const apiClients = ApiGetCallWithPagination({ + url: "/api/ExecApiClient", + data: { Action: "List" }, + queryKey: "ApiClients", + }); + const handleMenuOpen = (event) => { setMenuAnchorEl(event.currentTarget); }; @@ -223,7 +231,27 @@ const CippApiClientManagement = () => { showDivider={false} isFetching={azureConfig.isFetching} /> - + {azureConfig.isSuccess && Array.isArray(azureConfig.data?.Results?.ClientIDs) && ( + <> + {!isEqual( + apiClients.data?.pages?.[0]?.Results?.filter((c) => c.Enabled) + .map((c) => c.ClientId) + .sort(), + azureConfig.data?.Results?.ClientIDs?.sort() + ) && ( + + + You have unsaved changes. Click Actions > Save Azure Configuration to update + the allowed API Clients. + + + )} + + )} + {} + + + { simpleColumns={["Enabled", "AppName", "ClientId", "Role", "IPRange"]} queryKey={`ApiClients`} /> -
    Date: Fri, 7 Feb 2025 00:44:10 +0100 Subject: [PATCH 107/231] minor updates --- src/pages/tools/templatelib/index.jsx | 68 +++++++++++++++------------ 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/src/pages/tools/templatelib/index.jsx b/src/pages/tools/templatelib/index.jsx index 060ad05d7630..85c50646bc50 100644 --- a/src/pages/tools/templatelib/index.jsx +++ b/src/pages/tools/templatelib/index.jsx @@ -108,38 +108,44 @@ const TemplateLibrary = () => { + + + Conditional Access + + - - Conditional Access - - - - - Intune - - - - + + Intune + + + + + Date: Thu, 6 Feb 2025 22:53:59 -0500 Subject: [PATCH 108/231] Update CippApiClientManagement.jsx --- src/components/CippIntegrations/CippApiClientManagement.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index 067cae539a05..69afd6808109 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -231,7 +231,7 @@ const CippApiClientManagement = () => { showDivider={false} isFetching={azureConfig.isFetching} /> - {azureConfig.isSuccess && Array.isArray(azureConfig.data?.Results?.ClientIDs) && ( + {azureConfig.isSuccess && azureConfig.data?.Results?.ClientIDs && ( <> {!isEqual( apiClients.data?.pages?.[0]?.Results?.filter((c) => c.Enabled) @@ -249,7 +249,7 @@ const CippApiClientManagement = () => { )} {} - + Date: Thu, 6 Feb 2025 23:15:33 -0500 Subject: [PATCH 109/231] fix geo ip lookup actions --- src/pages/tenant/tools/geoiplookup/index.js | 42 +++++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/pages/tenant/tools/geoiplookup/index.js b/src/pages/tenant/tools/geoiplookup/index.js index c1d68fa0b041..df8c10702556 100644 --- a/src/pages/tenant/tools/geoiplookup/index.js +++ b/src/pages/tenant/tools/geoiplookup/index.js @@ -3,7 +3,7 @@ import { Grid, Stack } from "@mui/system"; import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { useForm, useWatch } from "react-hook-form"; import CippButtonCard from "../../../../components/CippCards/CippButtonCard"; -import { Delete, Search } from "@mui/icons-material"; +import { Add, Delete, Search } from "@mui/icons-material"; import CippFormComponent from "../../../../components/CippComponents/CippFormComponent"; import { ApiPostCall } from "../../../../api/ApiCall"; import { getCippValidator } from "../../../../utils/get-cipp-validator"; @@ -26,15 +26,33 @@ const Page = () => { customFunction: (row) => setIpAddress(row.RowKey), noConfirm: true, icon: , + hideBulk: true, + }, + { + label: "Add to Whitelist", + url: `/api/ExecAddTrustedIP`, + type: "POST", + data: { + IP: "RowKey", + State: "!Trusted", + }, + icon: , + confirmText: "Are you sure you want to add this IP to the whitelist?", + multiPost: false, + condition: (row) => row.state !== "Trusted", }, { label: "Remove from Whitelist", - customFunction: (row) => - addGeoIP.mutate({ - url: `/api/ExecAddTrustedIP?IP=${row.RowKey}&TenantFilter=${currentTenant}&State=NotTrusted`, - }), + url: `/api/ExecAddTrustedIP`, + type: "POST", + data: { + IP: "RowKey", + State: "!NotTrusted", + }, icon: , confirmText: "Are you sure you want to remove this IP from the whitelist?", + multiPost: false, + condition: (row) => row.state !== "NotTrusted", }, ]; @@ -44,13 +62,23 @@ const Page = () => { const handleAddToWhitelist = () => { addGeoIP.mutate({ - url: `/api/ExecAddTrustedIP?IP=${ip}&TenantFilter=${currentTenant}&State=Trusted`, + url: `/api/ExecAddTrustedIP`, + data: { + IP: ip, + State: "Trusted", + tenantFilter: currentTenant, + } }); }; const handleRemoveFromWhitelist = () => { addGeoIP.mutate({ - url: `/api/ExecAddTrustedIP?IP=${ip}&TenantFilter=${currentTenant}&State=NotTrusted`, + url: `/api/ExecAddTrustedIP`, + data: { + IP: ip, + State: "NotTrusted", + tenantFilter: currentTenant, + } }); }; From bb53d631f1f847e63010245483a5b6a2953dd9d0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 6 Feb 2025 23:51:33 -0500 Subject: [PATCH 110/231] Update CippApiClientManagement.jsx --- src/components/CippIntegrations/CippApiClientManagement.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index 69afd6808109..73d218360df0 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -118,6 +118,7 @@ const CippApiClientManagement = () => { Action: "ResetSecret", ClientId: "ClientId", }, + hideBulk: true, }, { label: "Copy API Scope", @@ -127,6 +128,7 @@ const CippApiClientManagement = () => { var scope = `api://${row.ClientId}/.default`; navigator.clipboard.writeText(scope); }, + hideBulk: true, }, { label: "Delete Client", @@ -146,6 +148,7 @@ const CippApiClientManagement = () => { }, ], relatedQueryKeys: ["ApiClients"], + multiPost: false, }, ]; From 0504105783c05bac9f61f04632bc569573f22a6a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 00:07:38 -0500 Subject: [PATCH 111/231] Update CippApiClientManagement.jsx --- src/components/CippIntegrations/CippApiClientManagement.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index 73d218360df0..09acfbd9e4f0 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -193,7 +193,10 @@ const CippApiClientManagement = () => { Add Existing Client - azureConfig.refetch()}> + { + azureConfig.refetch(); + handleMenuClose(); + }}> From 183ce29e84b9512f593be8c9927fc4f40b73e03a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 01:00:21 -0500 Subject: [PATCH 112/231] ui tweaks --- .../CippApiClientManagement.jsx | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index 09acfbd9e4f0..b85bd8e907a1 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -193,10 +193,12 @@ const CippApiClientManagement = () => { Add Existing Client - { - azureConfig.refetch(); - handleMenuClose(); - }}> + { + azureConfig.refetch(); + handleMenuClose(); + }} + > @@ -212,7 +214,10 @@ const CippApiClientManagement = () => { } propertyItems={[ - { label: "API Auth Enabled", value: azureConfig.data?.Results?.Enabled }, + { + label: "Microsoft Authentication Enabled", + value: azureConfig.data?.Results?.Enabled, + }, { label: "API Url", value: azureConfig.data?.Results?.ApiUrl ? ( @@ -232,6 +237,14 @@ const CippApiClientManagement = () => { "Not Available" ), }, + { + label: "Tenant ID", + value: azureConfig.data?.Results?.TenantID ? ( + + ) : ( + "Not Available" + ), + }, ]} layout="dual" showDivider={false} @@ -254,7 +267,14 @@ const CippApiClientManagement = () => { )} )} - {} + {azureConfig.isSuccess && azureConfig.data?.Results?.Enabled === false && ( + + + Microsoft Authentication is disabled. Configure API Clients and click Actions > + Save Azure Configuration. + + + )} From be74657432a663ae52364ff6ffe2f9cbb107d00a Mon Sep 17 00:00:00 2001 From: Esco Date: Fri, 7 Feb 2025 10:18:29 +0100 Subject: [PATCH 113/231] feat: added View in Entra button to user page --- .../identity/administration/users/user/bec.jsx | 17 ++++++++++++++++- .../users/user/conditional-access.jsx | 17 ++++++++++++++++- .../administration/users/user/edit.jsx | 18 +++++++++++++++++- .../administration/users/user/exchange.jsx | 17 ++++++++++++++++- .../administration/users/user/index.jsx | 17 ++++++++++++++++- 5 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/pages/identity/administration/users/user/bec.jsx b/src/pages/identity/administration/users/user/bec.jsx index 74c8364c4ddb..5e29d93cc09b 100644 --- a/src/pages/identity/administration/users/user/bec.jsx +++ b/src/pages/identity/administration/users/user/bec.jsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import { ApiGetCall } from "/src/api/ApiCall"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { CheckCircle, Download, Mail, Fingerprint } from "@mui/icons-material"; +import { CheckCircle, Download, Mail, Fingerprint, Launch } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import ReactTimeAgo from "react-time-ago"; @@ -160,6 +160,21 @@ const Page = () => { ), }, + { + icon: , + text: ( + + ), + }, ] : []; diff --git a/src/pages/identity/administration/users/user/conditional-access.jsx b/src/pages/identity/administration/users/user/conditional-access.jsx index 5d85ae736cff..d11ba05bc1ba 100644 --- a/src/pages/identity/administration/users/user/conditional-access.jsx +++ b/src/pages/identity/administration/users/user/conditional-access.jsx @@ -4,7 +4,7 @@ import { useSettings } from "/src/hooks/use-settings"; import { useRouter } from "next/router"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { Mail, Forward, Fingerprint } from "@mui/icons-material"; +import { Mail, Forward, Fingerprint, Launch } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import ReactTimeAgo from "react-time-ago"; @@ -53,6 +53,21 @@ const Page = () => { ), }, + { + icon: , + text: ( + + ), + }, ] : []; diff --git a/src/pages/identity/administration/users/user/edit.jsx b/src/pages/identity/administration/users/user/edit.jsx index 76998a10094b..2d793752dfd9 100644 --- a/src/pages/identity/administration/users/user/edit.jsx +++ b/src/pages/identity/administration/users/user/edit.jsx @@ -9,11 +9,12 @@ import { useEffect } from "react"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import { getCippLicenseTranslation } from "/src/utils/get-cipp-license-translation"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { Mail, Fingerprint } from "@mui/icons-material"; +import { Mail, Fingerprint, Launch } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import { CippCopyToClipBoard } from "../../../../../components/CippComponents/CippCopyToClipboard"; import { CippTimeAgo } from "../../../../../components/CippComponents/CippTimeAgo"; +import { Button } from "@mui/material"; const Page = () => { const userSettingsDefaults = useSettings(); const router = useRouter(); @@ -76,6 +77,21 @@ const Page = () => { ), }, + { + icon: , + text: ( + + ), + }, ] : []; diff --git a/src/pages/identity/administration/users/user/exchange.jsx b/src/pages/identity/administration/users/user/exchange.jsx index beccf92393e2..9b22c6ec415f 100644 --- a/src/pages/identity/administration/users/user/exchange.jsx +++ b/src/pages/identity/administration/users/user/exchange.jsx @@ -4,7 +4,7 @@ import { useRouter } from "next/router"; import { ApiGetCall } from "/src/api/ApiCall"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { Check, Error, Mail, Fingerprint } from "@mui/icons-material"; +import { Check, Error, Mail, Fingerprint, Launch } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import { CippTimeAgo } from "../../../../../components/CippComponents/CippTimeAgo"; @@ -113,6 +113,21 @@ const Page = () => { ), }, + { + icon: , + text: ( + + ), + }, ] : []; diff --git a/src/pages/identity/administration/users/user/index.jsx b/src/pages/identity/administration/users/user/index.jsx index f7d8937590d5..0d8628fdd9d5 100644 --- a/src/pages/identity/administration/users/user/index.jsx +++ b/src/pages/identity/administration/users/user/index.jsx @@ -4,7 +4,7 @@ import { useRouter } from "next/router"; import { ApiGetCall } from "/src/api/ApiCall"; import CippFormSkeleton from "/src/components/CippFormPages/CippFormSkeleton"; import CalendarIcon from "@heroicons/react/24/outline/CalendarIcon"; -import { AdminPanelSettings, Check, Group, Mail, Fingerprint } from "@mui/icons-material"; +import { AdminPanelSettings, Check, Group, Mail, Fingerprint, Launch } from "@mui/icons-material"; import { HeaderedTabbedLayout } from "../../../../../layouts/HeaderedTabbedLayout"; import tabOptions from "./tabOptions"; import { CippCopyToClipBoard } from "../../../../../components/CippComponents/CippCopyToClipboard"; @@ -134,6 +134,21 @@ const Page = () => { ), }, + { + icon: , + text: ( + + ), + }, ] : []; From 355afec6b361b742959ee62bc63b872de0849d73 Mon Sep 17 00:00:00 2001 From: Esco Date: Fri, 7 Feb 2025 11:54:40 +0100 Subject: [PATCH 114/231] feat: Enterprise Application Links --- .../administration/enterprise-apps/index.js | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/pages/tenant/administration/enterprise-apps/index.js b/src/pages/tenant/administration/enterprise-apps/index.js index 58fa6b2ddf5f..258e09ce23d8 100644 --- a/src/pages/tenant/administration/enterprise-apps/index.js +++ b/src/pages/tenant/administration/enterprise-apps/index.js @@ -1,11 +1,33 @@ // this page is going to need some love for accounting for filters: https://github.com/KelvinTegelaar/CIPP/blob/main/src/views/tenant/administration/ListEnterpriseApps.jsx#L83 import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { Launch } from "@mui/icons-material"; const Page = () => { const pageTitle = "Enterprise Applications"; const apiUrl = "/api/ListGraphRequest"; - const actions = []; + + const actions = [ + { + icon: , + label: "View Application", + link: `https://entra.microsoft.com/[Tenant]/#view/Microsoft_AAD_IAM/ManagedAppMenuBlade/~/Overview/objectId/[id]/appId/[appId]`, + color: "info", + target: "_blank", + multiPost: false, + external: true, + }, + { + icon: , + label: "View App Registration", + link: `https://entra.microsoft.com/[Tenant]/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/[appId]`, + color: "info", + target: "_blank", + multiPost: false, + external: true, + condition: (row) => row.tags.includes("WindowsAzureActiveDirectoryIntegratedApp"), + }, + ]; const offCanvas = { extendedInfoFields: [ @@ -31,7 +53,7 @@ const Page = () => { const apiParams = { Endpoint: "servicePrincipals", $select: - "appId,displayName,createdDateTime,accountEnabled,homepage,publisherName,signInAudience,replyUrls,verifiedPublisher,info,api,appOwnerOrganizationId,tags", + "id,appId,displayName,createdDateTime,accountEnabled,homepage,publisherName,signInAudience,replyUrls,verifiedPublisher,info,api,appOwnerOrganizationId,tags", $count: true, $top: 999, }; From 4e73dd43855100c1bc88fa1908452774146f332a Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 7 Feb 2025 12:54:29 +0100 Subject: [PATCH 115/231] fix cal permissions if folder is empty --- src/components/CippComponents/CippFormCondition.jsx | 3 +++ src/components/CippFormPages/CippExchangeSettingsForm.jsx | 2 +- src/pages/tools/templatelib/index.jsx | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/CippComponents/CippFormCondition.jsx b/src/components/CippComponents/CippFormCondition.jsx index 7d3dfd029b68..f6e3bdd4fdf2 100644 --- a/src/components/CippComponents/CippFormCondition.jsx +++ b/src/components/CippComponents/CippFormCondition.jsx @@ -66,6 +66,9 @@ export const CippFormCondition = (props) => { if (!watcher.includes(compareValue)) { return children; } + //extra elsseif; if the value is undefined or null, return children because it does not contain the compareValue + } else if (watcher === undefined || watcher === null) { + return children; } else if (typeof watcher === "object" && !(compareValue in watcher)) { // Check if object does not contain the key return children; diff --git a/src/components/CippFormPages/CippExchangeSettingsForm.jsx b/src/components/CippFormPages/CippExchangeSettingsForm.jsx index e46b0ab157f6..3f755ca3b804 100644 --- a/src/components/CippFormPages/CippExchangeSettingsForm.jsx +++ b/src/components/CippFormPages/CippExchangeSettingsForm.jsx @@ -257,7 +257,7 @@ const CippExchangeSettingsForm = (props) => { { Conditional Access From 2d921259891c5fbe50087ebe8b2b7caec0bfdb85 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:38:20 +0100 Subject: [PATCH 116/231] text update --- src/pages/onboarding.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/onboarding.js b/src/pages/onboarding.js index ffe3018ddd58..ee61bbe28261 100644 --- a/src/pages/onboarding.js +++ b/src/pages/onboarding.js @@ -24,8 +24,7 @@ const Page = () => { value: "CreateApp", }, { - description: - "I would like to refresh my token or replace the user I've used for my previous token.", + description: "I would like to refresh my token or replace the account I've used.", icon: , label: "Refresh Tokens for existing application ", value: "UpdateTokens", From a7ca562d109ef2d7c72a285bc7c178dca2dad61c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 7 Feb 2025 15:27:28 +0100 Subject: [PATCH 117/231] add standard --- src/data/standards.json | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index cd56b3a69e2f..34db101496e7 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1201,6 +1201,31 @@ "powershellEquivalent": "Get-SharingPolicy | Set-SharingPolicy -Enabled $False", "recommendedBy": ["CIS"] }, + { + "name": "standards.DisableExternalCalendarSharing", + "cat": "Exchange Standards", + "tag": ["lowimpact", "CIS", "exo_individualsharing"], + "helpText": "Disables the ability for users to share their calendar with external users. Only for the default policy, so exclusions can be made if needed.", + "docsDescription": "Disables external calendar sharing for the entire tenant. This is not a widely used feature, and it's therefore unlikely that this will impact users. Only for the default policy, so exclusions can be made if needed by making a new policy and assigning it to users.", + "addedComponent": [], + "label": "Disable external calendar sharing", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Get-SharingPolicy | Set-SharingPolicy -Enabled $False", + "recommendedBy": ["CIS"] + }, + { + "name": "standardsAutoAddProxy", + "cat": "Exchange Standards", + "tag": ["lowimpact", "CIS"], + "helpText": "Automatically adds all available domains as a proxy address.", + "docsDescription": "Automatically finds all available domain names in the tenant, and tries to add proxyaddresses based on the users UPN to each of these.", + "addedComponent": [], + "label": "Automatically deploy proxy addresses", + "impact": "Medium Impact", + "impactColour": "warning", + "powershellEquivalent": "set-mailbox -emailaddresses @{add=$emailaddress}" + }, { "name": "standards.DisableAdditionalStorageProviders", "cat": "Exchange Standards", @@ -1421,10 +1446,10 @@ "docsDescription": "Creates a CIPP - Deleted Items retention policy tag that permanently deletes items in the Deleted Items folder after X days.", "addedComponent": [ { - "type": "number", - "name": "standards.RetentionPolicyTag.AgeLimitForRetention", - "label": "Retention Days", - "required": true + "type": "number", + "name": "standards.RetentionPolicyTag.AgeLimitForRetention", + "label": "Retention Days", + "required": true } ], "label": "Retention Policy, permanently delete items in Deleted Items after X days", @@ -2791,7 +2816,7 @@ }, { "type": "autoComplete", - "required" : true, + "required": true, "multiple": false, "name": "standards.TeamsFederationConfiguration.DomainControl", "label": "Communication Mode", From aa156e959dd7f26c7bd602516d8b7fa6613b5aa8 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 7 Feb 2025 15:46:24 +0100 Subject: [PATCH 118/231] available units update and correct url --- .../CippComponents/CippFormLicenseSelector.jsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/components/CippComponents/CippFormLicenseSelector.jsx b/src/components/CippComponents/CippFormLicenseSelector.jsx index e435c1b467e1..0f8e1a6b867b 100644 --- a/src/components/CippComponents/CippFormLicenseSelector.jsx +++ b/src/components/CippComponents/CippFormLicenseSelector.jsx @@ -24,14 +24,11 @@ export const CippFormLicenseSelector = ({ api={{ addedField: addedField, tenantFilter: userSettingsDefaults.currentTenant ?? undefined, - url: "/api/ListGraphRequest", - dataKey: "Results", + url: "/api/ListLicenses", labelField: (option) => - `${getCippLicenseTranslation([option])} (${ - option.prepaidUnits.enabled - option.consumedUnits - } available)`, + `${getCippLicenseTranslation([option])} (${option?.availableUnits} available)`, valueField: "skuId", - queryKey: `ListLicenses-${userSettingsDefaults.currentTenant ?? undefined}`, + queryKey: `ListLicenses-${userSettingsDefaults?.currentTenant ?? undefined}`, data: { Endpoint: "subscribedSkus", $count: true, From c2477ce6d70329a62cb23680d4a6056fa3a04d28 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 7 Feb 2025 16:40:48 +0100 Subject: [PATCH 119/231] thanks esco --- src/data/standards.json | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/data/standards.json b/src/data/standards.json index 34db101496e7..5f4c8e681986 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -1201,19 +1201,6 @@ "powershellEquivalent": "Get-SharingPolicy | Set-SharingPolicy -Enabled $False", "recommendedBy": ["CIS"] }, - { - "name": "standards.DisableExternalCalendarSharing", - "cat": "Exchange Standards", - "tag": ["lowimpact", "CIS", "exo_individualsharing"], - "helpText": "Disables the ability for users to share their calendar with external users. Only for the default policy, so exclusions can be made if needed.", - "docsDescription": "Disables external calendar sharing for the entire tenant. This is not a widely used feature, and it's therefore unlikely that this will impact users. Only for the default policy, so exclusions can be made if needed by making a new policy and assigning it to users.", - "addedComponent": [], - "label": "Disable external calendar sharing", - "impact": "Low Impact", - "impactColour": "info", - "powershellEquivalent": "Get-SharingPolicy | Set-SharingPolicy -Enabled $False", - "recommendedBy": ["CIS"] - }, { "name": "standardsAutoAddProxy", "cat": "Exchange Standards", From a5d239b8086cd6287244a8dee41cf380e59b5330 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 13:32:41 -0500 Subject: [PATCH 120/231] Community Repos page --- src/pages/tools/community-repos/index.js | 235 +++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/pages/tools/community-repos/index.js diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js new file mode 100644 index 000000000000..04c3e7257037 --- /dev/null +++ b/src/pages/tools/community-repos/index.js @@ -0,0 +1,235 @@ +import { useState } from "react"; +import { Layout as DashboardLayout } from "/src/layouts"; +import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { + Button, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + TextField, + Stack, + Card, + CardContent, + Divider, + Skeleton, + IconButton, + Tooltip, + Typography, + Alert, + Link, +} from "@mui/material"; +import { TrashIcon } from "@heroicons/react/24/outline"; +import { ApiPostCall } from "/src/api/ApiCall"; +import { useForm, FormProvider } from "react-hook-form"; +import { Radio, RadioGroup, FormControlLabel } from "@mui/material"; +import { CippFormCondition } from "/src/components/CippComponents/CippFormCondition"; +import AddIcon from "@mui/icons-material/Add"; +import { Box } from "@mui/system"; +import { Add, OpenInNew } from "@mui/icons-material"; +import { CippApiResults } from "/src/components/CippComponents/CippApiResults"; +import { ApiGetCall } from "../../../api/ApiCall"; +import NextLink from "next/link"; +import CippFormComponent from "../../../components/CippComponents/CippFormComponent"; + +const Page = () => { + const [openSearch, setOpenSearch] = useState(false); + const [results, setResults] = useState([]); + const [repo, setRepo] = useState(""); + const [user, setUser] = useState(""); + + const actions = [ + { + label: "Delete", + type: "POST", + url: "/api/ExecCommunityRepo", + data: { Action: "Delete", Id: "Id" }, + confirmText: "Are you sure you want to delete this repo?", + icon: , + queryKey: "CommunityRepos", + }, + ]; + + const offCanvas = { + extendedInfoFields: ["Owner", "Name", "Description", "URL", "Visibility", "Permissions"], + actions: actions, + }; + + const integrations = ApiGetCall({ + url: "/api/ListExtensionsConfig", + queryKey: "Integrations", + }); + + const searchMutation = ApiPostCall({ + onResult: (resp) => { + setResults(resp?.Results || []); + }, + }); + + const searchForm = useForm({ defaultValues: { searchType: "user", searchTerm: [] } }); + const watchSearchTerm = searchForm.watch("searchTerm"); + + const handleSearch = () => { + const searchTerms = watchSearchTerm.map((t) => t.value) ?? []; + searchMutation.mutate({ + url: "/api/ExecGitHubAction", + data: { + Search: { + Repository: repo ? [repo] : [], + User: user ? [user] : [], + SearchTerm: searchTerms, + Type: "repositories", + }, + }, + }); + }; + + const addMutation = ApiPostCall({ + urlFromData: true, + relatedQueryKeys: ["CommunityRepos"], + }); + + const handleAdd = (repoId) => { + addMutation.mutate({ + url: "/api/ExecCommunityRepo", + data: { Action: "Add", Id: repoId }, + }); + }; + + return ( + <> + + {integrations.isSuccess && !integrations.data?.GitHub?.Enabled && ( + + The community repositories feature requires the GitHub Integration to be enabled. Go + to the{" "} + + GitHub Integration + {" "} + page to enable it. + + )} + + } + apiUrl="/api/ListCommunityRepos" + apiDataKey="Results" + queryKey="CommunityRepos" + actions={actions} + offCanvas={offCanvas} + simpleColumns={["Owner", "Name", "URL", "Visibility", "WriteAccess"]} + cardButton={ + + } + /> + setOpenSearch(false)}> + Add Community Repositories from GitHub + + + + searchForm.setValue("searchType", e.target.value)} + > + } label="User" /> + } label="Repository" /> + + + + setRepo(e.target.value)} + /> + + + setUser(e.target.value)} + /> + + + + + + + + {searchMutation.isPending || + (searchMutation.isSuccess && Search Results)} + {searchMutation.isPending ? ( + + + + ) : ( + results.map((r) => ( + + + + + handleAdd(r.id)}> + + + + + window.open(r.html_url, "_blank")}> + + + + + {r.full_name} + + {r.html_url} + + + + + + )) + )} + + + + + + + + + + + + ); +}; + +Page.getLayout = (page) => {page}; +export default Page; From 01a17ab855945a6506af5486d328350b7d287784 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 14:54:55 -0500 Subject: [PATCH 121/231] control accordion state --- src/components/CippFormPages/CippJSONView.jsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/CippFormPages/CippJSONView.jsx b/src/components/CippFormPages/CippJSONView.jsx index 8fa0d5532484..90ba35c1464c 100644 --- a/src/components/CippFormPages/CippJSONView.jsx +++ b/src/components/CippFormPages/CippJSONView.jsx @@ -76,8 +76,13 @@ const renderListItems = (data, onItemClick) => { }); }; -function CippJsonView({ object = { "No Data Selected": "No Data Selected" }, type }) { +function CippJsonView({ + object = { "No Data Selected": "No Data Selected" }, + type, + defaultOpen = false, +}) { const [viewJson, setViewJson] = useState(false); + const [accordionOpen, setAccordionOpen] = useState(defaultOpen); const [drilldownData, setDrilldownData] = useState([]); const renderIntuneItems = (data) => { @@ -209,7 +214,11 @@ function CippJsonView({ object = { "No Data Selected": "No Data Selected" }, typ }; return ( - + setAccordionOpen(!accordionOpen)} + > } sx={{ display: "flex", alignItems: "center" }} From 1cdfeaa42a2ff5de98d7a64537a60439aef54929 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 14:55:24 -0500 Subject: [PATCH 122/231] update search results dialog --- src/pages/tools/community-repos/index.js | 65 +++++++++++++++--------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js index 04c3e7257037..e02fe77dec2d 100644 --- a/src/pages/tools/community-repos/index.js +++ b/src/pages/tools/community-repos/index.js @@ -48,6 +48,11 @@ const Page = () => { icon: , queryKey: "CommunityRepos", }, + { + label: "View Templates", + link: "/tools/community-repos/repo?name=[FullName]", + icon: , + }, ]; const offCanvas = { @@ -188,30 +193,42 @@ const Page = () => { ) : ( - results.map((r) => ( - - - - - handleAdd(r.id)}> - - - - - window.open(r.html_url, "_blank")}> - - - - - {r.full_name} - - {r.html_url} - - - - - - )) + <> + {results.length === 0 && ( + + No search results found. Refine your query and try again. + + )} + + {results.map((r) => ( + + + + + handleAdd(r.id)}> + + + + + window.open(r.html_url, "_blank")} + > + + + + + {r.full_name} + + {r.html_url} + + + + + + ))} + + )} From 7ec50aa305ee289c2ffa5d7d6326bacc345c0d3a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 14:55:37 -0500 Subject: [PATCH 123/231] add view repository page --- src/pages/tools/community-repos/repo.js | 112 ++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/pages/tools/community-repos/repo.js diff --git a/src/pages/tools/community-repos/repo.js b/src/pages/tools/community-repos/repo.js new file mode 100644 index 000000000000..fec0db2e7078 --- /dev/null +++ b/src/pages/tools/community-repos/repo.js @@ -0,0 +1,112 @@ +import { useRouter } from "next/router"; +import { Layout as DashboardLayout } from "/src/layouts"; +import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; +import { useState, useEffect } from "react"; +import { ApiPostCall } from "/src/api/ApiCall"; +import { + Button, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Box, + Skeleton, + Alert, +} from "@mui/material"; +import { OpenInNew } from "@mui/icons-material"; +import CippJSONView from "/src/components/CippFormPages/CippJSONView"; +import { EyeIcon } from "@heroicons/react/24/outline"; + +const Page = () => { + const router = useRouter(); + const { name } = router.query; + const [openJsonDialog, setOpenJsonDialog] = useState(false); + const [fileResults, setFileResults] = useState([]); + const [jsonContent, setJsonContent] = useState({}); + + const searchMutation = ApiPostCall({ + onResult: (resp) => { + setFileResults(resp?.Results || []); + }, + }); + + const fileMutation = ApiPostCall({ + onResult: (resp) => { + setJsonContent(JSON.parse(resp?.Results?.content || "{}")); + }, + }); + + const handleJsonView = (url) => { + fileMutation.mutate({ + url: "/api/ExecGitHubAction", + data: { + GetFileContents: { + Url: url, + }, + }, + }); + setOpenJsonDialog(true); + }; + + useEffect(() => { + if (name) { + searchMutation.mutate({ + url: "/api/ExecGitHubAction", + data: { + Search: { + Repository: [name], + Type: "code", + Language: "json", + }, + }, + }); + } + }, [name]); + + return ( + <> + handleJsonView(row.url), + noConfirm: true, + icon: , + }, + ]} + /> + setOpenJsonDialog(false)} + > + Template Details + + {fileMutation.isPending ? ( + + + + ) : ( + + )} + + + + + + + ); +}; + +Page.getLayout = (page) => {page}; +export default Page; From ffdb671567bf9a1d0e53cad840845b54c5922acf Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 15:07:03 -0500 Subject: [PATCH 124/231] repo page tweakl --- src/pages/tools/community-repos/repo.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/tools/community-repos/repo.js b/src/pages/tools/community-repos/repo.js index fec0db2e7078..5fd76a9f983f 100644 --- a/src/pages/tools/community-repos/repo.js +++ b/src/pages/tools/community-repos/repo.js @@ -68,7 +68,6 @@ const Page = () => { { customFunction: (row) => handleJsonView(row.url), noConfirm: true, icon: , + hideBulk: true, }, ]} /> @@ -92,7 +92,7 @@ const Page = () => { {fileMutation.isPending ? ( - + ) : ( From 3f58396dad39168e4408decfa28999ca52ad5df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 7 Feb 2025 19:07:04 +0100 Subject: [PATCH 125/231] Add edit page and refactor other pages to fit add actions feat: Improve room mailbox edit page query handling Move around to make more sense --- .../resources/management/list-rooms/edit.jsx | 311 ++++++++++++++++++ .../resources/management/list-rooms/index.js | 56 +++- .../resources/management/room-lists/index.js | 1 + 3 files changed, 366 insertions(+), 2 deletions(-) create mode 100644 src/pages/email/resources/management/list-rooms/edit.jsx diff --git a/src/pages/email/resources/management/list-rooms/edit.jsx b/src/pages/email/resources/management/list-rooms/edit.jsx new file mode 100644 index 000000000000..91e9ecd66b11 --- /dev/null +++ b/src/pages/email/resources/management/list-rooms/edit.jsx @@ -0,0 +1,311 @@ +import React, { useEffect } from "react"; +import { Grid, Divider, Typography } from "@mui/material"; +import { useForm } from "react-hook-form"; +import { Layout as DashboardLayout } from "/src/layouts/index.js"; +import CippFormPage from "/src/components/CippFormPages/CippFormPage"; +import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; +import { useSettings } from "/src/hooks/use-settings"; +import { useRouter } from "next/router"; +import { ApiGetCall } from "/src/api/ApiCall"; +import countryList from "/src/data/countryList.json"; + +const EditRoomMailbox = () => { + const router = useRouter(); + const { roomId } = router.query; + const tenantDomain = useSettings().currentTenant; + const formControl = useForm({ + mode: "onChange", + }); + + const roomInfo = ApiGetCall({ + url: `/api/ListRooms?roomId=${roomId}&tenantFilter=${tenantDomain}`, + queryKey: `Room-${roomId}`, + waiting: false, + }); + + useEffect(() => { + if (roomInfo.isSuccess && roomInfo.data?.[0]) { + const room = roomInfo.data[0]; + formControl.reset({ + // Core Properties + displayName: room.displayName, + hiddenFromAddressListsEnabled: room.hiddenFromAddressListsEnabled, + + // Room Booking Settings + capacity: room.capacity, + + // Location Information + building: room.building, + floor: room.floor, + floorLabel: room.floorLabel, + street: room.street, + city: room.city, + state: room.state, + postalCode: room.postalCode, + countryOrRegion: room.countryOrRegion + ? countryList.find((c) => c.Name === room.countryOrRegion)?.Code || "" + : "", + + // Room Equipment + audioDeviceName: room.audioDeviceName, + videoDeviceName: room.videoDeviceName, + displayDeviceName: room.displayDeviceName, + + // Room Features + isWheelChairAccessible: room.isWheelChairAccessible, + phone: room.phone, + tags: room.tags?.map(tag => ({ label: tag, value: tag })) || [], + }); + } + }, [roomInfo.isSuccess, roomInfo.data]); + + useEffect(() => { + if (roomId) { + roomInfo.refetch(); + } + }, [router.query, roomId, tenantDomain]); + + return ( + ({ + tenantID: tenantDomain, + roomId: roomId, + displayName: values.displayName?.trim(), + hiddenFromAddressListsEnabled: values.hiddenFromAddressListsEnabled, + + // Room Booking Settings + capacity: values.capacity, + + // Location Information + building: values.building?.trim(), + floor: values.floor, + floorLabel: values.floorLabel?.trim(), + street: values.street?.trim(), + city: values.city?.trim(), + state: values.state?.trim(), + postalCode: values.postalCode?.trim(), + countryOrRegion: values.countryOrRegion?.value || values.countryOrRegion, + + // Room Equipment + audioDeviceName: values.audioDeviceName?.trim(), + videoDeviceName: values.videoDeviceName?.trim(), + displayDeviceName: values.displayDeviceName?.trim(), + + // Room Features + isWheelChairAccessible: values.isWheelChairAccessible, + phone: values.phone?.trim(), + tags: values.tags?.map(tag => tag.value), + })} + > + + {/* Core & Booking Settings */} + + + + + + + + + + + + + + + + + + + {/* Location Information */} + + Location Information + + + {/* Building and Floor Info */} + + + + + + + + + + + + + + + + {/* Address Fields */} + + + + + + {/* City and Postal Code */} + + + + + + + + + {/* State and Country */} + + + + + + ({ + label: Name, + value: Code, + }))} + formControl={formControl} + /> + + + + + + + {/* Room Equipment */} + + Room Equipment + + + + + + + + + + + + + + + + + {/* Room Features */} + + Room Features + + + + + + + + + + + + ); +}; + +EditRoomMailbox.getLayout = (page) => {page}; + +export default EditRoomMailbox; \ No newline at end of file diff --git a/src/pages/email/resources/management/list-rooms/index.js b/src/pages/email/resources/management/list-rooms/index.js index a3fe7dab1547..9fc307d60e63 100644 --- a/src/pages/email/resources/management/list-rooms/index.js +++ b/src/pages/email/resources/management/list-rooms/index.js @@ -2,16 +2,68 @@ import { Layout as DashboardLayout } from "/src/layouts/index.js"; import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx"; import { Button } from "@mui/material"; import Link from "next/link"; -import { AddHomeWork } from "@mui/icons-material"; +import { AddHomeWork, Edit, Block, LockOpen } from "@mui/icons-material"; +import { TrashIcon } from "@heroicons/react/24/outline"; const Page = () => { const pageTitle = "Rooms"; + const actions = [ + { + label: "Edit Room", + link: `/email/resources/management/list-rooms/edit?roomId=[id]`, + icon: , + color: "info", + condition: (row) => !row.isDirSynced, + }, + { + label: "Block Sign In", + type: "GET", + icon: , + url: "/api/ExecDisableUser", + data: { ID: "id" }, + confirmText: "Are you sure you want to block the sign-in for this room mailbox?", + multiPost: false, + condition: (row) => !row.accountDisabled && !row.isDirSynced, + }, + { + label: "Unblock Sign In", + type: "GET", + icon: , + url: "/api/ExecDisableUser", + data: { ID: "id", Enable: true }, + confirmText: "Are you sure you want to unblock sign-in for this room mailbox?", + multiPost: false, + condition: (row) => row.accountDisabled && !row.isDirSynced, + }, + { + label: "Delete Room", + type: "GET", + icon: , + url: "/api/RemoveMailbox", + data: { ID: "mail" }, + confirmText: "Are you sure you want to delete this room mailbox?", + multiPost: false, + condition: (row) => !row.isDirSynced, + }, + ]; + return ( { title={pageTitle} apiUrl={apiUrl} actions={actions} + apiDataKey="ListRoomListsResults" offCanvas={offCanvas} simpleColumns={simpleColumns} /> From 7e2061a6aa91370bc12ee010d265a4a2421a7e7c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 15:33:11 -0500 Subject: [PATCH 126/231] tweak community repos --- src/components/CippComponents/CippTranslations.jsx | 1 + src/layouts/config.js | 5 +++++ src/pages/tools/community-repos/index.js | 10 +++++----- src/pages/tools/community-repos/repo.js | 13 +++++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/components/CippComponents/CippTranslations.jsx b/src/components/CippComponents/CippTranslations.jsx index 7761362d09ed..fef71fa8ccb0 100644 --- a/src/components/CippComponents/CippTranslations.jsx +++ b/src/components/CippComponents/CippTranslations.jsx @@ -45,4 +45,5 @@ export const CippTranslations = { storageUsedInBytes: "Storage Used", prohibitSendReceiveQuotaInBytes: "Quota", ClientId: "Client ID", + html_url: "URL", }; diff --git a/src/layouts/config.js b/src/layouts/config.js index b31f11be6088..e7093b9f1883 100644 --- a/src/layouts/config.js +++ b/src/layouts/config.js @@ -441,6 +441,11 @@ export const nativeMenuItems = [ path: "/tools/templatelib", roles: ["editor", "admin", "superadmin"], }, + { + title: "Community Repositories", + path: "/tools/community-repos", + roles: ["editor", "admin", "superadmin"], + }, { title: "Scheduler", path: "/cipp/scheduler", diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js index e02fe77dec2d..d00432586c73 100644 --- a/src/pages/tools/community-repos/index.js +++ b/src/pages/tools/community-repos/index.js @@ -39,6 +39,11 @@ const Page = () => { const [user, setUser] = useState(""); const actions = [ + { + label: "View Templates", + link: "/tools/community-repos/repo?name=[FullName]", + icon: , + }, { label: "Delete", type: "POST", @@ -48,11 +53,6 @@ const Page = () => { icon: , queryKey: "CommunityRepos", }, - { - label: "View Templates", - link: "/tools/community-repos/repo?name=[FullName]", - icon: , - }, ]; const offCanvas = { diff --git a/src/pages/tools/community-repos/repo.js b/src/pages/tools/community-repos/repo.js index 5fd76a9f983f..c15b610b5f3d 100644 --- a/src/pages/tools/community-repos/repo.js +++ b/src/pages/tools/community-repos/repo.js @@ -81,6 +81,19 @@ const Page = () => { hideBulk: true, }, ]} + isFetching={searchMutation.isPending} + refreshFunction={() => + searchMutation.mutate({ + url: "/api/ExecGitHubAction", + data: { + Search: { + Repository: [name], + Type: "code", + Language: "json", + }, + }, + }) + } /> Date: Fri, 7 Feb 2025 23:19:50 +0100 Subject: [PATCH 127/231] FEAT: add alert for Entra ID license over-utilization --- src/data/alerts.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/data/alerts.json b/src/data/alerts.json index 1e2b8bdc0fc8..60d288d7329e 100644 --- a/src/data/alerts.json +++ b/src/data/alerts.json @@ -81,6 +81,15 @@ "label": "Alert on overused licenses", "recommendedRunInterval": "7d" }, + { + "name": "EntraLicenseUtilization", + "label": "Alert on Entra ID P1/P2 license over-utilization", + "recommendedRunInterval": "7d", + "requiresInput": true, + "inputType": "textField", + "inputLabel": "Alert when utilization exceeds % (default: 110)", + "inputName": "EntraLicenseUtilizationThreshold" + }, { "name": "AppSecretExpiry", "label": "Alert on expiring application secrets", From c2bd07042f8b3287752f218b430382722ebae6a6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Feb 2025 23:45:33 -0500 Subject: [PATCH 128/231] Update index.js --- src/pages/tools/community-repos/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js index d00432586c73..8fe3c2b65da1 100644 --- a/src/pages/tools/community-repos/index.js +++ b/src/pages/tools/community-repos/index.js @@ -125,7 +125,7 @@ const Page = () => { queryKey="CommunityRepos" actions={actions} offCanvas={offCanvas} - simpleColumns={["Owner", "Name", "URL", "Visibility", "WriteAccess"]} + simpleColumns={["Name", "Owner", "URL", "Visibility", "WriteAccess"]} cardButton={ + color="muted" + style={{ paddingLeft: 0 }} + size="small" + href={`https://entra.microsoft.com/${userSettingsDefaults.currentTenant}/#view/Microsoft_AAD_UsersAndTenants/UserProfileMenuBlade/~/overview/userId/${userId}`} + target="_blank" + rel="noopener noreferrer" + > + View in Entra + ), }, ] @@ -113,11 +114,13 @@ const Page = () => { > {userRequest.isLoading && } {userRequest.isSuccess && ( - + + + )} From 085f8cc55f616ba9d039f8ba9a127757e8bfa6f7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 8 Feb 2025 18:00:26 -0500 Subject: [PATCH 133/231] disable option creation on tenant selector --- src/components/CippComponents/CippFormTenantSelector.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/CippComponents/CippFormTenantSelector.jsx b/src/components/CippComponents/CippFormTenantSelector.jsx index 032d4d6ad96f..d4e0b6587c76 100644 --- a/src/components/CippComponents/CippFormTenantSelector.jsx +++ b/src/components/CippComponents/CippFormTenantSelector.jsx @@ -38,6 +38,7 @@ export const CippFormTenantSelector = ({ customerId: "customerId", }, }} + creatable={false} multiple={type === "single" ? false : true} disableClearable={disableClearable} validators={validators} From eb903beb377dcbbb7a88b4204075377f90fa8365 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 8 Feb 2025 18:01:07 -0500 Subject: [PATCH 134/231] Scheduler: default to textField values on --- src/components/CippFormPages/CippSchedulerForm.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/CippFormPages/CippSchedulerForm.jsx b/src/components/CippFormPages/CippSchedulerForm.jsx index 5bc71dd02211..b0296ce1f723 100644 --- a/src/components/CippFormPages/CippSchedulerForm.jsx +++ b/src/components/CippFormPages/CippSchedulerForm.jsx @@ -230,7 +230,16 @@ const CippSchedulerForm = (props) => { placeholder={`Enter a value for ${param.Name}`} validators={fieldRequired(param)} /> - ) : null} + ) : ( + + )} ))} From cbd0261f811dec264069dd2ea952eda5ec4ca3dc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 8 Feb 2025 19:52:16 -0500 Subject: [PATCH 135/231] add filters --- src/pages/cipp/scheduler/index.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/pages/cipp/scheduler/index.js b/src/pages/cipp/scheduler/index.js index 18b0d01a89b5..97abcc20b602 100644 --- a/src/pages/cipp/scheduler/index.js +++ b/src/pages/cipp/scheduler/index.js @@ -34,6 +34,29 @@ const Page = () => { }, ]; + const filterList = [ + { + filterName: "Running", + value: [{ id: "TaskState", value: "Running" }], + type: "column", + }, + { + filterName: "Planned", + value: [{ id: "TaskState", value: "Planned" }], + type: "column", + }, + { + filterName: "Failed", + value: [{ id: "TaskState", value: "Failed" }], + type: "column", + }, + { + filterName: "Completed", + value: [{ id: "TaskState", value: "Completed" }], + type: "column", + }, + ]; + const offCanvas = { children: (extendedData) => ( <> @@ -75,6 +98,7 @@ const Page = () => { ]} actions={actions} offCanvas={offCanvas} + filters={filterList} /> ); }; From bde053a3d2729e2967a10d8ed42550612aa42ffc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 8 Feb 2025 20:56:21 -0500 Subject: [PATCH 136/231] scheduler form fixes reduce rerenders on autocompletes remove transition animations memoize components --- .../CippComponents/CippAutocomplete.jsx | 62 ++- .../CippComponents/CippFormComponent.jsx | 24 +- .../CippFormPages/CippSchedulerForm.jsx | 382 ++++++++++-------- 3 files changed, 265 insertions(+), 203 deletions(-) diff --git a/src/components/CippComponents/CippAutocomplete.jsx b/src/components/CippComponents/CippAutocomplete.jsx index 1742ab9c17f2..7ce4c872f45a 100644 --- a/src/components/CippComponents/CippAutocomplete.jsx +++ b/src/components/CippComponents/CippAutocomplete.jsx @@ -6,12 +6,42 @@ import { TextField, IconButton, } from "@mui/material"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useMemo, useCallback } from "react"; import { useSettings } from "../../hooks/use-settings"; import { getCippError } from "../../utils/get-cipp-error"; import { ApiGetCallWithPagination } from "../../api/ApiCall"; import { Sync } from "@mui/icons-material"; import { Stack } from "@mui/system"; +import React from "react"; + +const MemoTextField = React.memo(function MemoTextField({ params, label, ...otherProps }) { + const { InputProps, ...otherParams } = params; + + return ( + + ); +}); export const CippAutoComplete = (props) => { const { @@ -136,6 +166,8 @@ export const CippAutoComplete = (props) => { } }, [api, actionGetRequest.data, actionGetRequest.isSuccess, actionGetRequest.isError]); + const memoizedOptions = useMemo(() => (api ? usedOptions : options), [api, usedOptions, options]); + const rand = Math.random().toString(36).substring(5); return ( @@ -143,7 +175,7 @@ export const CippAutoComplete = (props) => { key={`${defaultValue}-${rand}`} disabled={disabled || actionGetRequest.isFetching || isFetching} popupIcon={ - actionGetRequest.isFetching ? ( + actionGetRequest.isFetching || isFetching ? ( ) : ( @@ -216,24 +248,20 @@ export const CippAutoComplete = (props) => { onChange(newValue, newValue?.addedFields); } }} - options={api ? usedOptions : options} - getOptionLabel={(option) => - option - ? option.label === null - ? "" - : option.label || "Label not found - Are you missing a labelField?" - : "" - } + options={memoizedOptions} + getOptionLabel={useCallback( + (option) => + option + ? option.label === null + ? "" + : option.label || "Label not found - Are you missing a labelField?" + : "", + [] + )} sx={sx} renderInput={(params) => ( - + {api?.url && api?.showRefresh && ( { name={convertedName} control={formControl.control} rules={validators} - render={({ field }) => ( - field.onChange(value.value)} - /> - )} + render={({ field }) => + React.memo( + field.onChange(value.value)} + /> + ) + } /> diff --git a/src/components/CippFormPages/CippSchedulerForm.jsx b/src/components/CippFormPages/CippSchedulerForm.jsx index b0296ce1f723..03579b6cd2e4 100644 --- a/src/components/CippFormPages/CippSchedulerForm.jsx +++ b/src/components/CippFormPages/CippSchedulerForm.jsx @@ -1,5 +1,5 @@ import React from "react"; -import { Box, Button, Grid, Skeleton, SvgIcon, Typography } from "@mui/material"; +import { Box, Button, Divider, Grid, Skeleton, SvgIcon, Typography } from "@mui/material"; import { useWatch } from "react-hook-form"; import CippFormComponent from "/src/components/CippComponents/CippFormComponent"; import { CippFormTenantSelector } from "/src/components/CippComponents/CippFormTenantSelector"; @@ -112,200 +112,232 @@ const CippSchedulerForm = (props) => { commands.isSuccess, ]); + const advancedParameters = useWatch({ control: formControl.control, name: "advancedParameters" }); + + useEffect(() => { + if (advancedParameters === true) { + var schedulerValues = formControl.getValues("parameters"); + Object.keys(schedulerValues).forEach((key) => { + if (schedulerValues[key] === "" || schedulerValues[key] === null) { + delete schedulerValues[key]; + } + }); + const jsonString = JSON.stringify(schedulerValues, null, 2); + formControl.setValue("RawJsonParameters", jsonString); + } + }, [advancedParameters]); + const gridSize = fullWidth ? 12 : 4; // Adjust size based on fullWidth prop return ( - - {(scheduledTaskList.isFetching || tenantList.isLoading || commands.isLoading) && ( - - )} - - - - - - - + <> + + {(scheduledTaskList.isFetching || tenantList.isLoading || commands.isLoading) && ( + + )} + + + - - { - return { - label: command.Function, - value: command.Function, - addedFields: command, - }; - }) || [] - } - validators={{ - validate: (value) => { - if (!value) { - return "Please select a Command"; - } - return true; - }, - }} - /> - - - - - - - - {selectedCommand?.addedFields?.Synopsis && ( - - PowerShell Command: - - {selectedCommand.addedFields.Synopsis} - - + + + + + { + return { + label: command.Function, + value: command.Function, + addedFields: command, + }; + }) || [] + } + validators={{ + validate: (value) => { + if (!value) { + return "Please select a Command"; + } + return true; + }, + }} + /> + + + + + + - )} + {selectedCommand?.addedFields?.Synopsis && ( + + + PowerShell Command: + + {selectedCommand.addedFields.Synopsis} + + + + )} - {selectedCommand?.addedFields?.Parameters?.map((param, idx) => ( + {selectedCommand?.addedFields?.Parameters?.map((param, idx) => ( + + + {param.Type === "System.Boolean" || + param.Type === "System.Management.Automation.SwitchParameter" ? ( + + ) : param.Type === "System.Collections.Hashtable" ? ( + + ) : param.Type?.startsWith("System.String") ? ( + + ) : ( + + )} + + + ))} + + + + + + - - {param.Type === "System.Boolean" || - param.Type === "System.Management.Automation.SwitchParameter" ? ( - - ) : param.Type === "System.Collections.Hashtable" ? ( - - ) : param.Type?.startsWith("System.String") ? ( - - ) : ( - - )} + + getCippValidator(value, "json"), + }} + formControl={formControl} + multiline + rows={4} + placeholder={`Enter a JSON object`} + /> - ))} - - - - getCippValidator(value, "json"), - }} + type="autoComplete" + name="postExecution" + label="Post Execution Actions" formControl={formControl} - multiline - rows={4} - placeholder={`Enter a JSON object`} + multiple + creatable={false} + options={[ + { label: "Webhook", value: "Webhook" }, + { label: "Email", value: "Email" }, + { label: "PSA", value: "PSA" }, + ]} /> - - - - - - + + + - + + ); }; From b1931561f6721d530b4becb5bbc193d9c88ccdc5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 8 Feb 2025 21:21:03 -0500 Subject: [PATCH 137/231] CippApiDialog memoize in CippDatatable disable confirm button after submission add new parameter allowResubmit (default false) --- .../CippComponents/CippApiDialog.jsx | 15 ++++++++++-- src/components/CippTable/CippDataTable.js | 23 +++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/components/CippComponents/CippApiDialog.jsx b/src/components/CippComponents/CippApiDialog.jsx index 99c5bcc455c9..f8f7b00b57e6 100644 --- a/src/components/CippComponents/CippApiDialog.jsx +++ b/src/components/CippComponents/CippApiDialog.jsx @@ -17,11 +17,20 @@ export const CippApiDialog = (props) => { row = {}, relatedQueryKeys, dialogAfterEffect, + allowResubmit = false, ...other } = props; const router = useRouter(); const [addedFieldData, setAddedFieldData] = useState({}); const [partialResults, setPartialResults] = useState([]); + const [isFormSubmitted, setIsFormSubmitted] = useState(false); + + useEffect(() => { + if (createDialog.open) { + setIsFormSubmitted(false); + } + }, [createDialog.open]); + const [getRequestInfo, setGetRequestInfo] = useState({ url: "", waiting: false, @@ -103,6 +112,7 @@ export const CippApiDialog = (props) => { }; const tenantFilter = useSettings().currentTenant; const handleActionClick = (row, action, formData) => { + setIsFormSubmitted(true); if (action.multiPost === undefined) { action.multiPost = false; } @@ -304,9 +314,10 @@ export const CippApiDialog = (props) => { - + {console.log("isFormSubmitted", isFormSubmitted)} diff --git a/src/components/CippTable/CippDataTable.js b/src/components/CippTable/CippDataTable.js index 005678d16998..bd95a9baa393 100644 --- a/src/components/CippTable/CippDataTable.js +++ b/src/components/CippTable/CippDataTable.js @@ -358,16 +358,19 @@ export const CippDataTable = (props) => { customComponent={offCanvas?.customComponent} {...offCanvas} /> - {actionData.ready && ( - - )} + {useMemo(() => { + if (!actionData.ready) return null; + return ( + + ); + }, [actionData.ready, createDialog, actionData.action, actionData.data, queryKey, title])} ); }; From db0e254d89c9ab6012508f51094aedeebd45fb6b Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 8 Feb 2025 21:54:39 -0500 Subject: [PATCH 138/231] fix form state changes on save --- src/components/CippSettings/CippCustomRoles.jsx | 7 ++----- src/pages/cipp/super-admin/function-offloading.js | 2 +- src/pages/cipp/super-admin/tenant-mode.js | 2 +- src/pages/tenant/gdap-management/offboarding.js | 1 + 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/components/CippSettings/CippCustomRoles.jsx b/src/components/CippSettings/CippCustomRoles.jsx index 6387ae339a4f..a71d3f0b7ea2 100644 --- a/src/components/CippSettings/CippCustomRoles.jsx +++ b/src/components/CippSettings/CippCustomRoles.jsx @@ -67,10 +67,7 @@ export const CippCustomRoles = () => { queryKey: "customRoleList", }); - const { - data: { pages = [] } = {}, - isSuccess: tenantsSuccess, - } = ApiGetCallWithPagination({ + const { data: { pages = [] } = {}, isSuccess: tenantsSuccess } = ApiGetCallWithPagination({ url: "/api/ListTenants?AllTenantSelector=true", queryKey: "ListTenants-AllTenantSelector", }); @@ -280,7 +277,7 @@ export const CippCustomRoles = () => { label: role.RowKey, value: role.RowKey, }))} - isLoading={customRoleListFetching} + isFetching={customRoleListFetching} refreshFunction={() => refetchCustomRoleList()} creatable={true} formControl={formControl} diff --git a/src/pages/cipp/super-admin/function-offloading.js b/src/pages/cipp/super-admin/function-offloading.js index 489785fa9274..904c5640f0db 100644 --- a/src/pages/cipp/super-admin/function-offloading.js +++ b/src/pages/cipp/super-admin/function-offloading.js @@ -31,7 +31,7 @@ const Page = () => { OffloadFunctions: execOffloadFunctions.data?.OffloadFunctions, }); } - }, [execOffloadFunctions.isSuccess]); + }, [execOffloadFunctions.isSuccess, execOffloadFunctions.data]); return ( { TenantMode: execPartnerMode.data?.TenantMode, }); } - }, [execPartnerMode.isSuccess]); + }, [execPartnerMode.isSuccess, execPartnerMode.data]); return ( { hideBackButton={true} hidePageType={true} postUrl="/api/ExecOffboardTenant" + resetForm={true} > From 1f046acecc83569c5b0b975b84e3817b3f035033 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sat, 8 Feb 2025 21:56:05 -0500 Subject: [PATCH 139/231] prevent resubmit on cippformpage --- src/components/CippFormPages/CippFormPage.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/CippFormPages/CippFormPage.jsx b/src/components/CippFormPages/CippFormPage.jsx index 7db1575e9620..71b0cf5e7682 100644 --- a/src/components/CippFormPages/CippFormPage.jsx +++ b/src/components/CippFormPages/CippFormPage.jsx @@ -32,6 +32,7 @@ const CippFormPage = (props) => { hidePageType = false, hideTitle = false, hideSubmit = false, + allowResubmit = false, addedButtons, ...other } = props; @@ -42,7 +43,7 @@ const CippFormPage = (props) => { relatedQueryKeys: queryKey, }); - const { isValid } = useFormState({ control: formControl.control }); + const { isValid, isDirty } = useFormState({ control: formControl.control }); useEffect(() => { delete router.query.tenantFilter; @@ -133,7 +134,7 @@ const CippFormPage = (props) => { {addedButtons && addedButtons} - {console.log("isFormSubmitted", isFormSubmitted)} diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index 9f51d6aa0c9a..2dc0d021e1cd 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -89,7 +89,7 @@ const CippApiClientManagement = () => { }, { type: "autoComplete", - name: "IpRange", + name: "IPRange", multiple: true, freeSolo: true, creatable: true, @@ -324,7 +324,7 @@ const CippApiClientManagement = () => { }, { type: "autoComplete", - name: "IpRange", + name: "IPRange", multiple: true, freeSolo: true, creatable: true, @@ -391,7 +391,7 @@ const CippApiClientManagement = () => { }, { type: "autoComplete", - name: "IpRange", + name: "IPRange", multiple: true, freeSolo: true, creatable: true, From 0cf18352d0d99e60e08ef937e3b4e8f4935986e7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 9 Feb 2025 19:49:06 -0500 Subject: [PATCH 151/231] fix skeleton loading for second half --- .../CippCards/CippPropertyListCard.jsx | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/CippCards/CippPropertyListCard.jsx b/src/components/CippCards/CippPropertyListCard.jsx index ff7cdcd92a64..136d77e61635 100644 --- a/src/components/CippCards/CippPropertyListCard.jsx +++ b/src/components/CippCards/CippPropertyListCard.jsx @@ -122,15 +122,25 @@ export const CippPropertyListCard = (props) => { )} - {secondHalf.map((item, index) => ( + {isFetching ? ( } /> - ))} + ) : ( + secondHalf.map((item, index) => ( + + )) + )} )} From 92e0c42aa164bc214a53208b515a801472049b8a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 9 Feb 2025 19:56:09 -0500 Subject: [PATCH 152/231] fix CippApiResults reopen --- src/components/CippComponents/CippApiResults.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/CippComponents/CippApiResults.jsx b/src/components/CippComponents/CippApiResults.jsx index 3ef597b2ddb1..21af58b8cc39 100644 --- a/src/components/CippComponents/CippApiResults.jsx +++ b/src/components/CippComponents/CippApiResults.jsx @@ -1,6 +1,6 @@ -import { Close, ContentCopy } from "@mui/icons-material"; +import { Close } from "@mui/icons-material"; import { Alert, CircularProgress, Collapse, IconButton, Typography } from "@mui/material"; -import { useEffect, useState, useMemo } from "react"; +import { useEffect, useState, useMemo, useCallback } from "react"; import { getCippError } from "../../utils/get-cipp-error"; import { CippCopyToClipBoard } from "./CippCopyToClipboard"; import { Grid } from "@mui/system"; @@ -136,7 +136,7 @@ export const CippApiResults = (props) => { const allResults = useMemo(() => { const apiResults = extractAllResults(correctResultObj); return apiResults; - }, [apiObject]); + }, [correctResultObj]); useEffect(() => { setErrorVisible(!!apiObject.isError); @@ -170,9 +170,9 @@ export const CippApiResults = (props) => { errorsOnly, ]); - const handleCloseResult = (id) => { + const handleCloseResult = useCallback((id) => { setFinalResults((prev) => prev.map((r) => (r.id === id ? { ...r, visible: false } : r))); - }; + }, []); const hasVisibleResults = finalResults.some((r) => r.visible); return ( From d777103586c6ccc00de890db61a81bfa805abd21 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 9 Feb 2025 20:40:21 -0500 Subject: [PATCH 153/231] remove mapped tenants from integration map --- src/components/CippComponents/CippAutocomplete.jsx | 13 +++++++++++-- .../CippComponents/CippFormTenantSelector.jsx | 2 ++ .../CippIntegrationTenantMapping.jsx | 4 +++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/CippComponents/CippAutocomplete.jsx b/src/components/CippComponents/CippAutocomplete.jsx index 6747ae0c896b..6bc938b1bf81 100644 --- a/src/components/CippComponents/CippAutocomplete.jsx +++ b/src/components/CippComponents/CippAutocomplete.jsx @@ -68,6 +68,7 @@ export const CippAutoComplete = (props) => { required = false, isFetching = false, sx, + removeOptions = [], ...other } = props; @@ -172,7 +173,15 @@ export const CippAutoComplete = (props) => { } }, [api, actionGetRequest.data, actionGetRequest.isSuccess, actionGetRequest.isError]); - const memoizedOptions = useMemo(() => (api ? usedOptions : options), [api, usedOptions, options]); + const memoizedOptions = useMemo(() => { + let finalOptions = api ? usedOptions : options; + if (removeOptions && removeOptions.length) { + finalOptions = finalOptions.filter( + (o) => !removeOptions.includes(o.value) + ); + } + return finalOptions; + }, [api, usedOptions, options, removeOptions]); const rand = Math.random().toString(36).substring(5); @@ -201,7 +210,7 @@ export const CippAutoComplete = (props) => { options.some( (option) => params.inputValue === option.value || params.inputValue === option.label ); - + console.log(removeOptions); if (params.inputValue !== "" && creatable && !isExisting) { filtered.push({ label: `Add option: "${params.inputValue}"`, diff --git a/src/components/CippComponents/CippFormTenantSelector.jsx b/src/components/CippComponents/CippFormTenantSelector.jsx index d4e0b6587c76..9a8746e5ea4e 100644 --- a/src/components/CippComponents/CippFormTenantSelector.jsx +++ b/src/components/CippComponents/CippFormTenantSelector.jsx @@ -9,6 +9,7 @@ export const CippFormTenantSelector = ({ valueField = "defaultDomainName", required = true, disableClearable = true, + removeOptions = [], ...other }) => { const validators = () => { @@ -42,6 +43,7 @@ export const CippFormTenantSelector = ({ multiple={type === "single" ? false : true} disableClearable={disableClearable} validators={validators} + removeOptions={removeOptions} {...other} /> ); diff --git a/src/components/CippIntegrations/CippIntegrationTenantMapping.jsx b/src/components/CippIntegrations/CippIntegrationTenantMapping.jsx index 6bc3e95caea6..179f057db2d2 100644 --- a/src/components/CippIntegrations/CippIntegrationTenantMapping.jsx +++ b/src/components/CippIntegrations/CippIntegrationTenantMapping.jsx @@ -85,7 +85,7 @@ const CippIntegrationSettings = ({ children }) => { if (tableData?.find((item) => item.TenantId === selectedTenant.addedFields.customerId)) return; const newRowData = { - TenantId: selectedTenant.addedFields.customerId, + TenantId: selectedTenant.value, Tenant: selectedTenant.label, IntegrationName: selectedCompany.label, IntegrationId: selectedCompany.value, @@ -167,6 +167,8 @@ const CippIntegrationSettings = ({ children }) => { multiple={false} required={false} disableClearable={false} + removeOptions={tableData.map((item) => item.TenantId)} + valueField="customerId" /> From ee8ccebe45c72adde3ce0d9c1638bfd0c329ee61 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 9 Feb 2025 21:14:28 -0500 Subject: [PATCH 154/231] CippApiDialog add variable replace in confirmText --- .../CippComponents/CippApiDialog.jsx | 31 ++++++++++++++----- .../CippApiClientManagement.jsx | 6 ++-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/components/CippComponents/CippApiDialog.jsx b/src/components/CippComponents/CippApiDialog.jsx index 0b5811578679..dc75f5b54781 100644 --- a/src/components/CippComponents/CippApiDialog.jsx +++ b/src/components/CippComponents/CippApiDialog.jsx @@ -268,14 +268,14 @@ export const CippApiDialog = (props) => { } }, [createDialog.open, api?.setDefaultValues]); + const getNestedValue = (obj, path) => { + return path + .split(".") + .reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : undefined), obj); + }; + // Handling link navigation if (api.link) { - const getNestedValue = (obj, path) => { - return path - .split(".") - .reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : undefined), obj); - }; - const linkWithRowData = api.link.replace(/\[([^\]]+)\]/g, (_, key) => { return getNestedValue(row, key) || `[${key}]`; }); @@ -300,12 +300,29 @@ export const CippApiDialog = (props) => { setPartialResults([]); }; + var confirmText; + console.log(row); + if (typeof api?.confirmText === "string" && !Array.isArray(row)) { + confirmText = api.confirmText.replace(/\[([^\]]+)\]/g, (_, key) => { + return getNestedValue(row, key) || `[${key}]`; + }); + } else if (Array.isArray(row) && row.length > 1) { + confirmText = api.confirmText.replace(/\[([^\]]+)\]/g, "the selected rows"); + } else if (Array.isArray(row) && row.length === 1) { + console.log("single row in array"); + confirmText = api.confirmText.replace(/\[([^\]]+)\]/g, (_, key) => { + return getNestedValue(row[0], key) || `[${key}]`; + }); + } else { + confirmText = api.confirmText; + } + return (
    {title} - {api.confirmText} + {confirmText} diff --git a/src/components/CippIntegrations/CippApiClientManagement.jsx b/src/components/CippIntegrations/CippApiClientManagement.jsx index 2dc0d021e1cd..71b60116dd50 100644 --- a/src/components/CippIntegrations/CippApiClientManagement.jsx +++ b/src/components/CippIntegrations/CippApiClientManagement.jsx @@ -68,7 +68,7 @@ const CippApiClientManagement = () => { ), - confirmText: "Update the API client settings:", + confirmText: "Update the API client settings for [AppName]?", hideBulk: true, setDefaultValues: true, fields: [ @@ -114,7 +114,7 @@ const CippApiClientManagement = () => { { label: "Reset Application Secret", icon: , - confirmText: "Are you sure you want to reset the application secret?", + confirmText: "Are you sure you want to reset the application secret for [AppName]?", type: "POST", url: "/api/ExecApiClient", data: { @@ -136,7 +136,7 @@ const CippApiClientManagement = () => { { label: "Delete Client", icon: , - confirmText: "Are you sure you want to delete this client?", + confirmText: "Are you sure you want to delete [AppName]?", type: "POST", url: "/api/ExecApiClient", data: { From dc07d6d32b679313043578e3a4cc50bb60d53383 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 9 Feb 2025 21:44:17 -0500 Subject: [PATCH 155/231] clear search query on close dialog --- src/pages/tenant/standards/template.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/tenant/standards/template.jsx b/src/pages/tenant/standards/template.jsx index 2a5934014bc6..e9319bd742b8 100644 --- a/src/pages/tenant/standards/template.jsx +++ b/src/pages/tenant/standards/template.jsx @@ -74,7 +74,10 @@ const Page = () => { }, {}); const handleOpenDialog = () => setDialogOpen(true); - const handleCloseDialog = () => setDialogOpen(false); + const handleCloseDialog = () => { + setDialogOpen(false); + setSearchQuery(""); + }; const filterStandards = (standardsList) => standardsList.filter( From 11fd2bbf072ade0354f5823415657d3b04c363b3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 9 Feb 2025 21:58:53 -0500 Subject: [PATCH 156/231] scroll standards and keep search box at the top --- .../CippComponents/CippApiDialog.jsx | 1 - .../CippStandards/CippStandardDialog.jsx | 31 +++++++------------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/components/CippComponents/CippApiDialog.jsx b/src/components/CippComponents/CippApiDialog.jsx index dc75f5b54781..653c69541dca 100644 --- a/src/components/CippComponents/CippApiDialog.jsx +++ b/src/components/CippComponents/CippApiDialog.jsx @@ -301,7 +301,6 @@ export const CippApiDialog = (props) => { }; var confirmText; - console.log(row); if (typeof api?.confirmText === "string" && !Array.isArray(row)) { confirmText = api.confirmText.replace(/\[([^\]]+)\]/g, (_, key) => { return getNestedValue(row, key) || `[${key}]`; diff --git a/src/components/CippStandards/CippStandardDialog.jsx b/src/components/CippStandards/CippStandardDialog.jsx index d2b94853e6ee..69b014d723e4 100644 --- a/src/components/CippStandards/CippStandardDialog.jsx +++ b/src/components/CippStandards/CippStandardDialog.jsx @@ -48,21 +48,25 @@ const CippStandardDialog = ({ ); return ( - + }} + > Select a Standard to Add handleSearchQueryChange(e.target.value.toLowerCase())} /> - + {Object.keys(categories).every( (category) => filterStandards(categories[category]).length === 0 ) ? ( @@ -101,12 +105,7 @@ const CippStandardDialog = ({ Category: - + {standard.tag?.filter((tag) => !tag.toLowerCase().includes("impact")).length > 0 && ( <> @@ -147,11 +146,7 @@ const CippStandardDialog = ({ Recommended By: - + {standard.recommendedBy.join(", ")} @@ -172,9 +167,7 @@ const CippStandardDialog = ({ control={ - handleToggleSingleStandard(standard.name) - } + onChange={() => handleToggleSingleStandard(standard.name)} /> } label="Add this standard to the template" From 95514f81572b6b4ea157c0f2472bd104dfff5fe1 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 9 Feb 2025 23:19:15 -0500 Subject: [PATCH 157/231] fix securescore add actionLink handler to Remediate fix text decoration on links in html --- .../administration/securescore/index.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/pages/tenant/administration/securescore/index.js b/src/pages/tenant/administration/securescore/index.js index 432b4946e82f..b84506ca01c7 100644 --- a/src/pages/tenant/administration/securescore/index.js +++ b/src/pages/tenant/administration/securescore/index.js @@ -28,6 +28,14 @@ const Page = () => { TimeAgo.addLocale(en); const timeAgo = new TimeAgo("en-US"); + + const openRemediation = (url) => { + if (url.startsWith("https")) { + window.open(url, "_blank"); + } else { + navigate(url); + } + }; return ( { CardButton={ <> - + {secureScoreControl.controlStateUpdates?.length > 0 && ( - + { ))} )} - {apiObject.isSuccess || apiObject.isError ? ( + {(apiObject.isSuccess || apiObject.isError) && !errorsOnly ? ( tableDialog.handleOpen()}> diff --git a/src/components/CippFormPages/CippExchangeSettingsForm.jsx b/src/components/CippFormPages/CippExchangeSettingsForm.jsx index 3f755ca3b804..66d8bb4b6ecb 100644 --- a/src/components/CippFormPages/CippExchangeSettingsForm.jsx +++ b/src/components/CippFormPages/CippExchangeSettingsForm.jsx @@ -515,7 +515,7 @@ const CippExchangeSettingsForm = (props) => { - + {section.formContent} diff --git a/src/components/CippSettings/CippPermissionCheck.jsx b/src/components/CippSettings/CippPermissionCheck.jsx index 5ad0f5d0a502..db0c81c7ad38 100644 --- a/src/components/CippSettings/CippPermissionCheck.jsx +++ b/src/components/CippSettings/CippPermissionCheck.jsx @@ -142,7 +142,7 @@ const CippPermissionCheck = (props) => { {(executeCheck.isSuccess || executeCheck.isLoading) && ( <> {executeCheck.data?.Metadata?.AlertMessage && ( - + - + diff --git a/src/data/Extensions.json b/src/data/Extensions.json index 64c5bb8f59df..ab1dc4c20c95 100644 --- a/src/data/Extensions.json +++ b/src/data/Extensions.json @@ -515,7 +515,7 @@ "logo": "/assets/integrations/github.png", "logoDark": "/assets/integrations/github_dark.png", "description": "Enable the GitHub integration to manage your repositories from CIPP.", - "helpText": "This integration allows you to manage GitHub repositories from CIPP, including the Community Repositorities functionality. Requires a GitHub Personal Access Token (PAT) with a minimum of repo:public_repo permissions. You can create a PAT in your GitHub account settings, see the GitHub Token documentation for more info.", + "helpText": "This integration allows you to manage GitHub repositories from CIPP, including the Community Repositorities functionality. Requires a GitHub Personal Access Token (PAT) with a minimum of repo:public_repo permissions. If you plan on saving your templates to GitHub or accessing private/internal repositories, you will need to grant the whole repo scope. You can create a PAT in your GitHub account settings, see the GitHub Token documentation for more info. If you do not enable the extension, a read-only API will be provided.", "links": [ { "name": "GitHub Token", diff --git a/src/pages/tenant/standards/list-standards/index.js b/src/pages/tenant/standards/list-standards/index.js index 2d9b4493d975..40a215deac87 100644 --- a/src/pages/tenant/standards/list-standards/index.js +++ b/src/pages/tenant/standards/list-standards/index.js @@ -3,7 +3,7 @@ import { CippTablePage } from "/src/components/CippComponents/CippTablePage.jsx" import { Layout as DashboardLayout } from "/src/layouts/index.js"; // had to add an extra path here because I added an extra folder structure. We should switch to absolute pathing so we dont have to deal with relative. import Link from "next/link"; import { EyeIcon } from "@heroicons/react/24/outline"; -import { CopyAll, Delete, PlayArrow, AddBox, Visibility, Edit } from "@mui/icons-material"; +import { CopyAll, Delete, PlayArrow, AddBox, Visibility, Edit, GitHub } from "@mui/icons-material"; import { ApiGetCall, ApiPostCall } from "../../../../api/ApiCall"; import { Grid } from "@mui/system"; import { CippApiResults } from "../../../../components/CippComponents/CippApiResults"; @@ -51,6 +51,37 @@ const Page = () => { confirmText: "Are you sure you want to force a run of this template?", multiPost: false, }, + { + 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, + createable: false, + }, + + ], + confirmText: "Are you sure you want to save this template to the selected repository?", + }, { label: "Delete Template", type: "POST", diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js index 044fe1c8e035..9faebdc1a1f6 100644 --- a/src/pages/tools/community-repos/index.js +++ b/src/pages/tools/community-repos/index.js @@ -39,6 +39,28 @@ const Page = () => { const [repo, setRepo] = useState(""); const [user, setUser] = useState(""); const [org, setOrg] = useState(""); + const [openCreate, setOpenCreate] = useState(false); + const createForm = useForm({ mode: "onChange", defaultValues: { Type: "user" } }); + + const createMutation = ApiPostCall({ + urlFromData: true, + relatedQueryKeys: ["CommunityRepos"], + }); + + const handleCreateRepo = (values) => { + console.log(values); + createMutation.mutate({ + url: "/api/ExecGitHubAction", + data: { + Action: "CreateRepo", + Type: values.type, + Name: values.repoName, + Org: values.orgName?.value, + Description: values.Description, + Private: values.Private, + }, + }); + }; const actions = [ { @@ -63,12 +85,8 @@ const Page = () => { actions: actions, }; - const integrations = ApiGetCall({ - url: "/api/ListExtensionsConfig", - queryKey: "Integrations", - }); - const searchMutation = ApiPostCall({ + urlFromData: true, onResult: (resp) => { setResults(resp?.Results || []); }, @@ -109,20 +127,6 @@ const Page = () => { - {integrations.isSuccess && !integrations.data?.GitHub?.Enabled && ( - - The community repositories feature requires the GitHub Integration to be enabled. Go - to the{" "} - - GitHub Integration - {" "} - page to enable it. - - )} - - } apiUrl="/api/ListCommunityRepos" apiDataKey="Results" queryKey="CommunityRepos" @@ -130,11 +134,90 @@ const Page = () => { offCanvas={offCanvas} simpleColumns={["Name", "Owner", "URL", "Visibility", "WriteAccess"]} cardButton={ - + <> + + + } /> + setOpenCreate(false)}> + Create New Repository + + + { + createForm.setValue("Type", e.target.value); + }} + > + } label="User" /> + } label="Org" /> + + + + + + + + + + + + + + + + + setOpenSearch(false)}> Add Community Repositories from GitHub diff --git a/src/pages/tools/templatelib/index.jsx b/src/pages/tools/templatelib/index.jsx index e05689adf61f..5fa63b3bbf9b 100644 --- a/src/pages/tools/templatelib/index.jsx +++ b/src/pages/tools/templatelib/index.jsx @@ -24,11 +24,6 @@ const TemplateLibrary = () => { }, }); - const integrations = ApiGetCall({ - url: "/api/ListExtensionsConfig", - queryKey: "Integrations", - }); - const templateRepo = useWatch({ control: formControl.control, name: "templateRepo" }); const customDataFormatter = (values) => { @@ -81,17 +76,6 @@ const TemplateLibrary = () => { Enabling this feature will overwrite templates with the same name. - - {integrations.isSuccess && !integrations.data?.GitHub?.Enabled && ( - - The community repositories feature requires the GitHub Integration to be enabled. Go - to the{" "} - - GitHub Integration - {" "} - page to enable it. - - )} @@ -136,7 +120,6 @@ const TemplateLibrary = () => { }} formControl={formControl} multiple={false} - disabled={!integrations.data?.GitHub?.Enabled} /> From 89c860ec50554f0ce591636e20c9585789a6e8a4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 11 Feb 2025 21:10:03 -0500 Subject: [PATCH 190/231] Add Set Upload Branch action Tweak API dialog Tweak API results --- .../CippComponents/CippApiDialog.jsx | 3 ++ .../CippComponents/CippApiResults.jsx | 2 +- src/pages/tools/community-repos/index.js | 44 +++++++++++++++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/components/CippComponents/CippApiDialog.jsx b/src/components/CippComponents/CippApiDialog.jsx index 0a23dc3cb982..d5e15d9bccff 100644 --- a/src/components/CippComponents/CippApiDialog.jsx +++ b/src/components/CippComponents/CippApiDialog.jsx @@ -325,6 +325,9 @@ export const CippApiDialog = (props) => { {fields && fields.map((fieldProps, index) => { + if (fieldProps?.api?.processFieldData) { + fieldProps.api.data = processActionData(fieldProps.api.data, row); + } return ( { ))} )} - {(apiObject.isSuccess || apiObject.isError) && !errorsOnly ? ( + {(apiObject.isSuccess || apiObject.isError) && finalResults.length > 0 ? ( tableDialog.handleOpen()}> diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js index 9faebdc1a1f6..56cfd7a62e30 100644 --- a/src/pages/tools/community-repos/index.js +++ b/src/pages/tools/community-repos/index.js @@ -27,7 +27,7 @@ import { Radio, RadioGroup, FormControlLabel } from "@mui/material"; import { CippFormCondition } from "/src/components/CippComponents/CippFormCondition"; import AddIcon from "@mui/icons-material/Add"; import { Box } from "@mui/system"; -import { Add, OpenInNew } from "@mui/icons-material"; +import { Add, ForkLeft, OpenInNew } from "@mui/icons-material"; import { CippApiResults } from "/src/components/CippComponents/CippApiResults"; import { ApiGetCall } from "../../../api/ApiCall"; import NextLink from "next/link"; @@ -78,10 +78,48 @@ const Page = () => { multiPost: false, queryKey: "CommunityRepos", }, + { + label: "Set Upload Branch", + type: "POST", + url: "/api/ExecCommunityRepo", + data: { Action: "SetBranch", Id: "Id" }, + icon: , + fields: [ + { + type: "select", + name: "Branch", + label: "Branch", + api: { + url: "/api/ExecGitHubAction", + type: "GET", + data: { + Action: "GetBranches", + FullName: "FullName", + }, + dataKey: "Results", + labelField: "name", + valueField: "name", + processFieldData: true, + }, + }, + ], + hideBulk: true, + confirmText: "Are you sure you want to set the branch for this repository?", + condition: (row) => row.WriteAccess === true, + }, ]; const offCanvas = { - extendedInfoFields: ["Owner", "Name", "Description", "URL", "Visibility", "Permissions"], + extendedInfoFields: [ + "Owner", + "Name", + "Description", + "URL", + "Visibility", + "DefaultBranch", + "UploadBranch", + "Permissions", + ], actions: actions, }; @@ -132,7 +170,7 @@ const Page = () => { queryKey="CommunityRepos" actions={actions} offCanvas={offCanvas} - simpleColumns={["Name", "Owner", "URL", "Visibility", "WriteAccess"]} + simpleColumns={["Name", "Owner", "URL", "Visibility", "WriteAccess", "UploadBranch"]} cardButton={ <> - From be8595eafdfcf6cbfdf01054df0eee09db6f45c5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Feb 2025 14:49:34 -0500 Subject: [PATCH 197/231] UI tweaks --- src/pages/tools/community-repos/index.js | 315 +++++++++++++---------- 1 file changed, 173 insertions(+), 142 deletions(-) diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js index 34a5bd9b8510..433f1559cdd6 100644 --- a/src/pages/tools/community-repos/index.js +++ b/src/pages/tools/community-repos/index.js @@ -18,15 +18,16 @@ import { Typography, Alert, Chip, + SvgIcon, } from "@mui/material"; -import { TrashIcon } from "@heroicons/react/24/outline"; +import { MagnifyingGlassIcon, TrashIcon } from "@heroicons/react/24/outline"; import { ApiPostCall } from "/src/api/ApiCall"; import { useForm, FormProvider } from "react-hook-form"; import { Radio, RadioGroup, FormControlLabel } from "@mui/material"; import { CippFormCondition } from "/src/components/CippComponents/CippFormCondition"; import AddIcon from "@mui/icons-material/Add"; import { Box } from "@mui/system"; -import { Add, ForkLeft, OpenInNew } from "@mui/icons-material"; +import { Add, AddBox, ForkLeft, OpenInNew } from "@mui/icons-material"; import { CippApiResults } from "/src/components/CippComponents/CippApiResults"; import CippFormComponent from "../../../components/CippComponents/CippFormComponent"; import { ApiGetCall } from "../../../api/ApiCall"; @@ -176,15 +177,22 @@ const Page = () => { simpleColumns={["Name", "Owner", "URL", "Visibility", "WriteAccess", "UploadBranch"]} cardButton={ <> - } @@ -226,6 +234,10 @@ const Page = () => { valueField: "login", }} multiple={false} + required={true} + validators={{ + required: { value: true, message: "Organization is required" }, + }} /> { name="repoName" label="Repository Name" formControl={createForm} + required={true} /> { setOpenSearch(false)}> Add Community Repositories from GitHub - - - searchForm.setValue("searchType", e.target.value)} + + searchForm.setValue("searchType", e.target.value)} + > + } label="User" /> + } label="Org" /> + } label="Repository" /> + + + - } label="User" /> - } label="Org" /> - } label="Repository" /> - - - setRepo(e.target.value)} + required={true} + /> + + + setUser(e.target.value)} + required={true} + /> + + - setRepo(e.target.value)} - /> - - + + + setOrg(e.target.value)} + required={true} + /> + - setUser(e.target.value)} - /> + freeSolo + fullWidth + options={[]} + label="Search Terms" + /> + + + - - - - setOrg(e.target.value)} - /> - - + {searchMutation.isPending || + (searchMutation.isSuccess && ( + + + Search Results - - - - {searchMutation.isPending || - (searchMutation.isSuccess && Search Results)} - {searchMutation.isPending ? ( - - - - ) : ( - <> - {searchMutation.isSuccess && results.length === 0 && ( + ))} + {searchMutation.isPending ? ( + <> + + + Searching... + + + + + + + + + + + + ) : ( + <> + {(searchMutation.isSuccess && results.length === 0) || + (searchMutation.isError && ( No search results found. Refine your query and try again. - )} - - {results.map((r) => ( - - - - - handleAdd(r.id)}> - - - - - window.open(r.html_url, "_blank")} - > - - - - - - - {r.full_name} - - - - - {r.html_url} + ))} + + {results.map((r) => ( + + + + + handleAdd(r.id)}> + + + + + window.open(r.html_url, "_blank")} + > + + + + + + + {r.full_name} + - - - - ))} - - - )} - - - - + + {r.html_url} + + + + + + ))} + + + )} + + + @@ -445,10 +446,18 @@ const Page = () => { - - From 211e37943e23c6190378a3842c1104a48fbc17b5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Feb 2025 17:01:35 -0500 Subject: [PATCH 199/231] Update index.js --- src/pages/tools/community-repos/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js index f0fb433cab70..6fb4a0137fa6 100644 --- a/src/pages/tools/community-repos/index.js +++ b/src/pages/tools/community-repos/index.js @@ -52,7 +52,6 @@ const Page = () => { }); const handleCreateRepo = (values) => { - console.log(values); createMutation.mutate({ url: "/api/ExecGitHubAction", data: { @@ -265,13 +264,14 @@ const Page = () => { @@ -386,7 +386,7 @@ const Page = () => { No search results found. Refine your query and try again. ))} - + {results.map((r) => ( From 8e622cf7e796d986dec79a0bcb536d58dbf9cc94 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Feb 2025 17:20:19 -0500 Subject: [PATCH 200/231] add import template button --- src/pages/tools/community-repos/repo.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/pages/tools/community-repos/repo.js b/src/pages/tools/community-repos/repo.js index 7b4772561f1d..37d0e9f0c6ca 100644 --- a/src/pages/tools/community-repos/repo.js +++ b/src/pages/tools/community-repos/repo.js @@ -17,6 +17,7 @@ import CippJSONView from "/src/components/CippFormPages/CippJSONView"; import { EyeIcon } from "@heroicons/react/24/outline"; import { CippAutoComplete } from "/src/components/CippComponents/CippAutocomplete"; import React from "react"; +import { CloudDownload } from "@mui/icons-material"; const Page = () => { const router = useRouter(); @@ -202,6 +203,19 @@ const Page = () => { icon: , hideBulk: true, }, + { + label: "Import Template", + url: "/api/ExecCommunityRepo", + icon: , + type: "POST", + data: { + Action: "ImportTemplate", + FullName: selectedRepo, + Path: "path", + Branch: selectedBranch, + }, + confirmText: "Are you sure you want to import [path]?", + }, ]} isFetching={fileTreeQuery.isFetching} refreshFunction={() => fetchFileTree(selectedBranch)} From 7ce94e72b86924f45a467c0f6bc78c5bca60f744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 12 Feb 2025 23:25:33 +0100 Subject: [PATCH 201/231] fix casing --- src/components/CippFormPages/CippAddGroupForm.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CippFormPages/CippAddGroupForm.jsx b/src/components/CippFormPages/CippAddGroupForm.jsx index 49be141db5dd..daac5f7aef7f 100644 --- a/src/components/CippFormPages/CippAddGroupForm.jsx +++ b/src/components/CippFormPages/CippAddGroupForm.jsx @@ -76,7 +76,7 @@ const CippAddGroupForm = (props) => { { label: "Security Group", value: "generic" }, { label: "Microsoft 365 Group", value: "m365" }, { label: "Dynamic Group", value: "dynamic" }, - { label: "Dynamic Distribution Group", value: "dynamicdistribution" }, + { label: "Dynamic Distribution Group", value: "dynamicDistribution" }, { label: "Distribution List", value: "distribution" }, { label: "Mail Enabled Security Group", value: "security" }, ]} From 21168314014ae3321acc2f60d6049a458e26940a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Feb 2025 18:03:56 -0500 Subject: [PATCH 202/231] json view tweak --- src/components/CippFormPages/CippJSONView.jsx | 2 +- src/pages/tools/community-repos/repo.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/CippFormPages/CippJSONView.jsx b/src/components/CippFormPages/CippJSONView.jsx index 5abb73e8ee37..e90fc8732c13 100644 --- a/src/components/CippFormPages/CippJSONView.jsx +++ b/src/components/CippFormPages/CippJSONView.jsx @@ -235,7 +235,7 @@ function CippJsonView({ {viewJson ? : } {viewJson ? ( - + ) : ( {drilldownData.slice(0, 4).map((data, index) => ( diff --git a/src/pages/tools/community-repos/repo.js b/src/pages/tools/community-repos/repo.js index 37d0e9f0c6ca..8b93c7dae27e 100644 --- a/src/pages/tools/community-repos/repo.js +++ b/src/pages/tools/community-repos/repo.js @@ -230,7 +230,7 @@ const Page = () => { {fileQuery.isPending ? ( - + ) : ( From bb2209a96759f48625f25b5944b7705546ea99a2 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 13 Feb 2025 00:42:16 +0100 Subject: [PATCH 203/231] fixes escos whining --- src/pages/identity/administration/groups/index.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/pages/identity/administration/groups/index.js b/src/pages/identity/administration/groups/index.js index 7915d4656404..03d36a08a198 100644 --- a/src/pages/identity/administration/groups/index.js +++ b/src/pages/identity/administration/groups/index.js @@ -107,17 +107,7 @@ const Page = () => { } - apiUrl="/api/ListGraphRequest" - apiData={{ - Endpoint: "groups", - $select: - "id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,grouptypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName,assignedLicenses", - $count: true, - $orderby: "displayName", - $top: 999, - manualPagination: true, - }} - apiDataKey="Results" + apiUrl="/api/ListGroups" actions={actions} offCanvas={offCanvas} simpleColumns={[ From a5f454525fa29d3f6abe01dc9f7fd3b06f938844 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Feb 2025 18:46:02 -0500 Subject: [PATCH 204/231] up version --- public/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/version.json b/public/version.json index 795806e4fd04..7ffa464d8338 100644 --- a/public/version.json +++ b/public/version.json @@ -1,3 +1,3 @@ { - "version": "7.1.3" + "version": "7.2.0" } From ec49fb71caa9d607a0b35d86e9ec0e89345d1ebd Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Feb 2025 20:03:11 -0500 Subject: [PATCH 205/231] github null safety --- public/version.json | 2 +- .../email/spamfilter/list-connectionfilter-templates/index.js | 2 +- src/pages/email/spamfilter/list-templates/index.js | 2 +- src/pages/email/transport/list-connector-templates/index.js | 2 +- src/pages/email/transport/list-templates/index.js | 2 +- src/pages/endpoint/MEM/list-templates/index.js | 2 +- src/pages/identity/administration/group-templates/index.js | 2 +- src/pages/tenant/conditional/list-template/index.js | 2 +- src/pages/tenant/standards/bpa-report/index.js | 2 +- src/pages/tenant/standards/list-standards/index.js | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/public/version.json b/public/version.json index 7ffa464d8338..9e50dd4377c9 100644 --- a/public/version.json +++ b/public/version.json @@ -1,3 +1,3 @@ { - "version": "7.2.0" + "version": "7.2.1" } diff --git a/src/pages/email/spamfilter/list-connectionfilter-templates/index.js b/src/pages/email/spamfilter/list-connectionfilter-templates/index.js index 9eeb2638a408..ca0ced2e75ea 100644 --- a/src/pages/email/spamfilter/list-connectionfilter-templates/index.js +++ b/src/pages/email/spamfilter/list-connectionfilter-templates/index.js @@ -53,7 +53,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", diff --git a/src/pages/email/spamfilter/list-templates/index.js b/src/pages/email/spamfilter/list-templates/index.js index ce86b031198c..ad1e87195129 100644 --- a/src/pages/email/spamfilter/list-templates/index.js +++ b/src/pages/email/spamfilter/list-templates/index.js @@ -53,7 +53,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", diff --git a/src/pages/email/transport/list-connector-templates/index.js b/src/pages/email/transport/list-connector-templates/index.js index 567eac960f94..7f35e6629322 100644 --- a/src/pages/email/transport/list-connector-templates/index.js +++ b/src/pages/email/transport/list-connector-templates/index.js @@ -57,7 +57,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", diff --git a/src/pages/email/transport/list-templates/index.js b/src/pages/email/transport/list-templates/index.js index 5e9e8d12e90e..58340c19ff38 100644 --- a/src/pages/email/transport/list-templates/index.js +++ b/src/pages/email/transport/list-templates/index.js @@ -55,7 +55,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", diff --git a/src/pages/endpoint/MEM/list-templates/index.js b/src/pages/endpoint/MEM/list-templates/index.js index 9a1dfc6e3264..d87b2243c259 100644 --- a/src/pages/endpoint/MEM/list-templates/index.js +++ b/src/pages/endpoint/MEM/list-templates/index.js @@ -77,7 +77,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", diff --git a/src/pages/identity/administration/group-templates/index.js b/src/pages/identity/administration/group-templates/index.js index d1d047594a89..497f3ce71b6c 100644 --- a/src/pages/identity/administration/group-templates/index.js +++ b/src/pages/identity/administration/group-templates/index.js @@ -55,7 +55,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", diff --git a/src/pages/tenant/conditional/list-template/index.js b/src/pages/tenant/conditional/list-template/index.js index fbfb20795f40..8db07cbdca14 100644 --- a/src/pages/tenant/conditional/list-template/index.js +++ b/src/pages/tenant/conditional/list-template/index.js @@ -54,7 +54,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", diff --git a/src/pages/tenant/standards/bpa-report/index.js b/src/pages/tenant/standards/bpa-report/index.js index 1bb4a6cca89b..d80e5eb5ae1c 100644 --- a/src/pages/tenant/standards/bpa-report/index.js +++ b/src/pages/tenant/standards/bpa-report/index.js @@ -77,7 +77,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", diff --git a/src/pages/tenant/standards/list-standards/index.js b/src/pages/tenant/standards/list-standards/index.js index 023e58df5071..6dcc15daeb7f 100644 --- a/src/pages/tenant/standards/list-standards/index.js +++ b/src/pages/tenant/standards/list-standards/index.js @@ -95,7 +95,7 @@ const Page = () => { }, ], confirmText: "Are you sure you want to save this template to the selected repository?", - condition: () => integrations.isSuccess && integrations?.data?.GitHub.Enabled, + condition: () => integrations.isSuccess && integrations?.data?.GitHub?.Enabled, }, { label: "Delete Template", From a279d8b96dc57515c33636ace6f26abd0545a6d5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Feb 2025 20:23:35 -0500 Subject: [PATCH 206/231] null safety sam wizard --- .../CippWizard/CIPPDeploymentStep.js | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/CippWizard/CIPPDeploymentStep.js b/src/components/CippWizard/CIPPDeploymentStep.js index 5ebc0ecf67fd..90a0840fc16e 100644 --- a/src/components/CippWizard/CIPPDeploymentStep.js +++ b/src/components/CippWizard/CIPPDeploymentStep.js @@ -16,7 +16,7 @@ import { CippWizardStepButtons } from "./CippWizardStepButtons"; import { ApiGetCall } from "../../api/ApiCall"; import CippButtonCard from "../CippCards/CippButtonCard"; import { CippCopyToClipBoard } from "../CippComponents/CippCopyToClipboard"; -import { CheckCircle } from "@mui/icons-material"; +import { CheckCircle, Sync } from "@mui/icons-material"; import CippPermissionCheck from "../CippSettings/CippPermissionCheck"; import { useQueryClient } from "@tanstack/react-query"; import { CippApiResults } from "../CippComponents/CippApiResults"; @@ -43,7 +43,7 @@ export const CippDeploymentStep = (props) => { const appId = ApiGetCall({ url: `/api/ExecListAppId`, queryKey: `ExecListAppId`, - waiting: values.selectedOption !== "UpdateTokens" ? false : true, + waiting: true, }); useEffect(() => { if ( @@ -260,19 +260,29 @@ export const CippDeploymentStep = (props) => { disabled={ appId.isLoading || !/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test( - appId.data.applicationId + appId?.data?.applicationId ) } - onClick={() => openPopup(appId.data.refreshUrl)} + onClick={() => openPopup(appId?.data?.refreshUrl)} color="primary" > Refresh Graph Token + {!/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test( - appId.data.applicationId + appId?.data?.applicationId ) && ( - The Application ID is not valid. Please return to the first page of the SAM wizard and use the Manual . + The Application ID is not valid. Please return to the first page of the SAM + wizard and use the Manual . )} From 4d7dea81d96294539be6e9d8e09015e5936d7cad Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Feb 2025 20:39:38 -0500 Subject: [PATCH 207/231] Update CIPPDeploymentStep.js --- src/components/CippWizard/CIPPDeploymentStep.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/CippWizard/CIPPDeploymentStep.js b/src/components/CippWizard/CIPPDeploymentStep.js index 90a0840fc16e..3ba090c1a75e 100644 --- a/src/components/CippWizard/CIPPDeploymentStep.js +++ b/src/components/CippWizard/CIPPDeploymentStep.js @@ -16,7 +16,7 @@ import { CippWizardStepButtons } from "./CippWizardStepButtons"; import { ApiGetCall } from "../../api/ApiCall"; import CippButtonCard from "../CippCards/CippButtonCard"; import { CippCopyToClipBoard } from "../CippComponents/CippCopyToClipboard"; -import { CheckCircle, Sync } from "@mui/icons-material"; +import { CheckCircle, OpenInNew, Sync } from "@mui/icons-material"; import CippPermissionCheck from "../CippSettings/CippPermissionCheck"; import { useQueryClient } from "@tanstack/react-query"; import { CippApiResults } from "../CippComponents/CippApiResults"; @@ -265,12 +265,15 @@ export const CippDeploymentStep = (props) => { } onClick={() => openPopup(appId?.data?.refreshUrl)} color="primary" + startIcon={ + + } > Refresh Graph Token