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 1/9] 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 e7e54fd8f9fa4ab96605187f9b63da08c0b8fd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 7 Feb 2025 23:19:50 +0100 Subject: [PATCH 2/9] 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 d58203cd3af4339c05b10a052c57f8d3f0b24047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sun, 9 Feb 2025 21:37:08 +0100 Subject: [PATCH 3/9] add validation for CSV import form field --- src/components/CippWizard/CippWizardCSVImport.jsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/CippWizard/CippWizardCSVImport.jsx b/src/components/CippWizard/CippWizardCSVImport.jsx index 6f665df4523b..141672f68874 100644 --- a/src/components/CippWizard/CippWizardCSVImport.jsx +++ b/src/components/CippWizard/CippWizardCSVImport.jsx @@ -32,6 +32,11 @@ export const CippWizardCSVImport = (props) => { const [newTableData, setTableData] = useState([]); const [open, setOpen] = useState(false); + // Register form field with validation + formControl.register(name, { + validate: (value) => Array.isArray(value) && value.length > 0, + }); + const handleRemoveItem = (row) => { if (row === undefined) return false; const index = tableData?.findIndex((item) => item === row); @@ -49,7 +54,9 @@ export const CippWizardCSVImport = (props) => { }; useEffect(() => { - formControl.setValue(name, newTableData); + formControl.setValue(name, newTableData, { + shouldValidate: true, + }); }, [newTableData]); const actions = [ From e96891dc756fbd49b67151a87cd6a59341190051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 10 Feb 2025 17:49:11 +0100 Subject: [PATCH 4/9] FEAT: Add clear immutable ID to offboarding wizard --- src/components/CippComponents/CippUserActions.jsx | 2 +- src/components/CippWizard/CippWizardOffboarding.jsx | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/CippComponents/CippUserActions.jsx b/src/components/CippComponents/CippUserActions.jsx index cf30780eb5e8..93e6d991adb6 100644 --- a/src/components/CippComponents/CippUserActions.jsx +++ b/src/components/CippComponents/CippUserActions.jsx @@ -284,7 +284,7 @@ export const CippUserActions = () => { }, { label: "Clear Immutable ID", - type: "GET", + type: "POST", icon: , url: "/api/ExecClrImmId", data: { diff --git a/src/components/CippWizard/CippWizardOffboarding.jsx b/src/components/CippWizard/CippWizardOffboarding.jsx index d61e9365c1e5..6c79070dcd81 100644 --- a/src/components/CippWizard/CippWizardOffboarding.jsx +++ b/src/components/CippWizard/CippWizardOffboarding.jsx @@ -97,6 +97,12 @@ export const CippWizardOffboarding = (props) => { type="switch" formControl={formControl} /> + Date: Mon, 10 Feb 2025 22:18:59 +0100 Subject: [PATCH 5/9] add creatable properties and new AuthMethodsSettings standard --- src/data/standards.json | 84 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/data/standards.json b/src/data/standards.json index 5f4c8e681986..f7a88174afc0 100644 --- a/src/data/standards.json +++ b/src/data/standards.json @@ -59,6 +59,7 @@ { "type": "select", "multiple": false, + "creatable": false, "label": "Select value", "name": "standards.ProfilePhotos.state", "options": [ @@ -225,6 +226,7 @@ { "type": "select", "multiple": false, + "creatable": false, "label": "Select value", "name": "standards.ActivityBasedTimeout.timeout", "options": [ @@ -257,6 +259,64 @@ "powershellEquivalent": "Portal or Graph API", "recommendedBy": ["CIS"] }, + { + "name": "standards.AuthMethodsSettings", + "cat": "Entra (AAD) Standards", + "tag": ["lowimpact"], + "helpText": "Configures the report suspicious activity settings and system credential preferences in the authentication methods policy.", + "docsDescription": "Controls the authentication methods policy settings for reporting suspicious activity and system credential preferences. These settings help enhance the security of authentication in your organization.", + "addedComponent": [ + { + "type": "autoComplete", + "multiple": false, + "creatable": false, + "required": false, + "name": "standards.AuthMethodsSettings.ReportSuspiciousActivity", + "label": "Report Suspicious Activity Settings", + "options": [ + { + "label": "Microsoft managed", + "value": "default" + }, + { + "label": "Enabled", + "value": "enabled" + }, + { + "label": "Disabled", + "value": "disabled" + } + ] + }, + { + "type": "autoComplete", + "multiple": false, + "creatable": false, + "required": false, + "name": "standards.AuthMethodsSettings.SystemCredential", + "label": "System Credential Preferences", + "options": [ + { + "label": "Microsoft managed", + "value": "default" + }, + { + "label": "Enabled", + "value": "enabled" + }, + { + "label": "Disabled", + "value": "disabled" + } + ] + } + ], + "label": "Configure Authentication Methods Policy Settings", + "impact": "Low Impact", + "impactColour": "info", + "powershellEquivalent": "Update-MgBetaPolicyAuthenticationMethodPolicy", + "recommendedBy": [] + }, { "name": "standards.AppDeploy", "cat": "Entra (AAD) Standards", @@ -325,6 +385,7 @@ { "type": "select", "multiple": false, + "creatable": false, "label": "Select value", "name": "standards.PWcompanionAppAllowedState.state", "options": [ @@ -394,6 +455,7 @@ { "type": "select", "multiple": false, + "creatable": false, "label": "Select TAP Lifetime", "name": "standards.TAP.config", "options": [ @@ -436,6 +498,7 @@ { "type": "select", "multiple": false, + "creatable": false, "label": "Select value", "name": "standards.ExternalMFATrusted.state", "options": [ @@ -498,6 +561,7 @@ { "type": "select", "multiple": false, + "creatable": false, "label": "Select value", "name": "standards.NudgeMFA.state", "options": [ @@ -647,6 +711,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "Who can send invites?", "name": "standards.GuestInvite.allowInvitesFrom", "options": [ @@ -1886,6 +1951,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "Spam Action", "name": "standards.SpamFilterPolicy.SpamAction", "options": [ @@ -1903,6 +1969,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "Spam Quarantine Tag", "name": "standards.SpamFilterPolicy.SpamQuarantineTag", "options": [ @@ -1924,6 +1991,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "High Confidence Spam Action", "name": "standards.SpamFilterPolicy.HighConfidenceSpamAction", "options": [ @@ -1941,6 +2009,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "High Confidence Spam Quarantine Tag", "name": "standards.SpamFilterPolicy.HighConfidenceSpamQuarantineTag", "options": [ @@ -1962,6 +2031,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "Bulk Spam Action", "name": "standards.SpamFilterPolicy.BulkSpamAction", "options": [ @@ -1979,6 +2049,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "Bulk Quarantine Tag", "name": "standards.SpamFilterPolicy.BulkQuarantineTag", "options": [ @@ -2000,6 +2071,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "Phish Spam Action", "name": "standards.SpamFilterPolicy.PhishSpamAction", "options": [ @@ -2017,6 +2089,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "Phish Quarantine Tag", "name": "standards.SpamFilterPolicy.PhishQuarantineTag", "options": [ @@ -2038,6 +2111,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "label": "High Confidence Phish Quarantine Tag", "name": "standards.SpamFilterPolicy.HighConfidencePhishQuarantineTag", "options": [ @@ -2162,6 +2236,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "name": "standards.IntuneComplianceSettings.secureByDefault", "label": "Mark devices with no compliance policy as", "options": [ @@ -2397,6 +2472,7 @@ { "type": "autoComplete", "multiple": false, + "creatable": false, "label": "Add Shortcuts To OneDrive button state", "name": "standards.DisableAddShortcutsToOneDrive.state", "options": [ @@ -2426,6 +2502,7 @@ { "type": "autoComplete", "multiple": false, + "creatable": false, "label": "SharePoint Sync Button state", "name": "standards.SPSyncButtonState.state", "options": [ @@ -2613,6 +2690,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "name": "standards.TeamsGlobalMeetingPolicy.DesignatedPresenterRoleMode", "label": "Default value of the `Who can present?`", "options": [ @@ -2643,6 +2721,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "name": "standards.TeamsGlobalMeetingPolicy.MeetingChatEnabledType", "label": "Meeting chat policy", "options": [ @@ -2735,6 +2814,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "name": "standards.TeamsEnrollUser.EnrollUserOverride", "label": "Voice and Face Enrollment", "options": [ @@ -2805,6 +2885,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "name": "standards.TeamsFederationConfiguration.DomainControl", "label": "Communication Mode", "options": [ @@ -2874,6 +2955,7 @@ "type": "autoComplete", "required": true, "multiple": false, + "creatable": false, "name": "standards.TeamsMessagingPolicy.ReadReceiptsEnabledType", "label": "Read Receipts Enabled Type", "options": [ @@ -3023,6 +3105,7 @@ { "type": "autoComplete", "multiple": false, + "creatable": false, "name": "standards.AutopilotProfile.Languages", "label": "Languages", "api": { @@ -3107,6 +3190,7 @@ { "type": "autoComplete", "multiple": false, + "creatable": false, "name": "TemplateList", "label": "Select Intune Template", "api": { From 03536a4ed14374eb0d4dd7acc2a7995aa9e74076 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Feb 2025 17:11:16 -0500 Subject: [PATCH 6/9] fix logout page Remove extra re-renders when not logged in Hide navigation menus --- src/layouts/index.js | 17 ++++++++++++----- src/pages/unauthenticated.js | 32 +++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/layouts/index.js b/src/layouts/index.js index 9538706081fa..33ffc87aa2eb 100644 --- a/src/layouts/index.js +++ b/src/layouts/index.js @@ -84,11 +84,14 @@ export const Layout = (props) => { url: "/.auth/me", queryKey: "authmecipp", }); + const [hideSidebar, setHideSidebar] = useState(false); useEffect(() => { if (currentRole.isSuccess && !currentRole.isFetching) { const userRoles = currentRole.data?.clientPrincipal?.userRoles; if (!userRoles) { + setMenuItems([]); + setHideSidebar(true); return; } const filterItemsByRole = (items) => { @@ -200,15 +203,19 @@ export const Layout = (props) => { return ( <> - - {mdDown && ( - + {hideSidebar === false && ( + <> + + {mdDown && ( + + )} + {!mdDown && } + )} - {!mdDown && } diff --git a/src/pages/unauthenticated.js b/src/pages/unauthenticated.js index ce64a19fa462..6c06e2ca3a80 100644 --- a/src/pages/unauthenticated.js +++ b/src/pages/unauthenticated.js @@ -3,6 +3,7 @@ import Head from "next/head"; import { CippImageCard } from "../components/CippCards/CippImageCard"; import { Layout as DashboardLayout } from "../layouts/index.js"; import { ApiGetCall } from "../api/ApiCall"; +import { useState, useEffect } from "react"; const Page = () => { const orgData = ApiGetCall({ @@ -10,9 +11,16 @@ const Page = () => { queryKey: "me", }); const blockedRoles = ["anonymous", "authenticated"]; - const userRoles = orgData.data?.clientPrincipal?.userRoles.filter( - (role) => !blockedRoles.includes(role) - ); + const [userRoles, setUserRoles] = useState([]); + + useEffect(() => { + if (orgData.isSuccess) { + const roles = orgData.data?.clientPrincipal?.userRoles.filter( + (role) => !blockedRoles.includes(role) + ); + setUserRoles(roles ?? []); + } + }, [orgData, blockedRoles]); return ( <> @@ -36,14 +44,16 @@ const Page = () => { sx={{ height: "100%" }} // Ensure the container takes full height > - 0 ? "Return" : "Login"} - link={userRoles.length > 0 ? "/" : "/.auth/login/aad"} - /> + {orgData.isSuccess && Array.isArray(userRoles) && ( + 0 ? "Return" : "Login"} + link={userRoles.length > 0 ? "/" : "/.auth/login/aad"} + /> + )} From c46ecb7ae2f675a7b7266f9cf2ab3c42b51bd0c8 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Feb 2025 17:19:53 -0500 Subject: [PATCH 7/9] Memoize CippAutocomplete in form components --- .../CippComponents/CippFormComponent.jsx | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/components/CippComponents/CippFormComponent.jsx b/src/components/CippComponents/CippFormComponent.jsx index 28abfd910586..669dd4b2c141 100644 --- a/src/components/CippComponents/CippFormComponent.jsx +++ b/src/components/CippComponents/CippFormComponent.jsx @@ -24,12 +24,17 @@ import { } from "mui-tiptap"; import StarterKit from "@tiptap/starter-kit"; import { CippDataTable } from "../CippTable/CippDataTable"; +import React, { useMemo } from "react"; // Helper function to convert bracket notation to dot notation const convertBracketsToDots = (name) => { return name.replace(/\[(\d+)\]/g, ".$1"); // Replace [0] with .0 }; +const MemoizedCippAutoComplete = React.memo((props) => { + return ; +}); + export const CippFormComponent = (props) => { const { validators, @@ -233,19 +238,17 @@ export const CippFormComponent = (props) => { name={convertedName} control={formControl.control} rules={validators} - render={({ field }) => - React.memo( - field.onChange(value.value)} - /> - ) - } + render={({ field }) => ( + field.onChange(value.value)} + /> + )} /> @@ -263,7 +266,7 @@ export const CippFormComponent = (props) => { control={formControl.control} rules={validators} render={({ field }) => ( - Date: Mon, 10 Feb 2025 18:32:47 -0500 Subject: [PATCH 8/9] community repositories tweaks to extension add new chip formatter for visibility update template library to pull from community repos --- .../CippComponents/CippFormComponent.jsx | 2 +- src/data/Extensions.json | 4 +- src/pages/tools/community-repos/index.js | 59 +++++++++++++++++-- src/pages/tools/templatelib/index.jsx | 26 ++++---- src/utils/get-cipp-formatting.js | 19 ++++++ 5 files changed, 90 insertions(+), 20 deletions(-) diff --git a/src/components/CippComponents/CippFormComponent.jsx b/src/components/CippComponents/CippFormComponent.jsx index 669dd4b2c141..d44f547f94d7 100644 --- a/src/components/CippComponents/CippFormComponent.jsx +++ b/src/components/CippComponents/CippFormComponent.jsx @@ -24,7 +24,7 @@ import { } from "mui-tiptap"; import StarterKit from "@tiptap/starter-kit"; import { CippDataTable } from "../CippTable/CippDataTable"; -import React, { useMemo } from "react"; +import React from "react"; // Helper function to convert bracket notation to dot notation const convertBracketsToDots = (name) => { diff --git a/src/data/Extensions.json b/src/data/Extensions.json index 15ef6a02de3a..64c5bb8f59df 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 your GitHub repositories from CIPP. Requires a GitHub Fine Grained Personal Access Token (PAT).", + "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.", "links": [ { "name": "GitHub Token", @@ -526,7 +526,7 @@ { "type": "password", "name": "GitHub.APIKey", - "label": "GitHub Fine Grained Personal Access Token", + "label": "GitHub Personal Access Token", "placeholder": "Enter your GitHub PAT", "required": true }, diff --git a/src/pages/tools/community-repos/index.js b/src/pages/tools/community-repos/index.js index 8fe3c2b65da1..f862ba2aa028 100644 --- a/src/pages/tools/community-repos/index.js +++ b/src/pages/tools/community-repos/index.js @@ -18,6 +18,7 @@ import { Typography, Alert, Link, + Chip, } from "@mui/material"; import { TrashIcon } from "@heroicons/react/24/outline"; import { ApiPostCall } from "/src/api/ApiCall"; @@ -37,6 +38,7 @@ const Page = () => { const [results, setResults] = useState([]); const [repo, setRepo] = useState(""); const [user, setUser] = useState(""); + const [org, setOrg] = useState(""); const actions = [ { @@ -51,6 +53,7 @@ const Page = () => { data: { Action: "Delete", Id: "Id" }, confirmText: "Are you sure you want to delete this repo?", icon: , + multiPost: false, queryKey: "CommunityRepos", }, ]; @@ -80,8 +83,9 @@ const Page = () => { url: "/api/ExecGitHubAction", data: { Search: { - Repository: repo ? [repo] : [], - User: user ? [user] : [], + Repository: repo ? repo : "", + User: user ? user : "", + Org: org ? org : "", SearchTerm: searchTerms, Type: "repositories", }, @@ -143,6 +147,7 @@ const Page = () => { onChange={(e) => searchForm.setValue("searchType", e.target.value)} > } label="User" /> + } label="Org" /> } label="Repository" /> @@ -182,6 +187,28 @@ const Page = () => { label="Search Terms" /> + + setOrg(e.target.value)} + /> + + @@ -217,8 +244,32 @@ const Page = () => { - - {r.full_name} + + + + {r.full_name} + + + {r.html_url} diff --git a/src/pages/tools/templatelib/index.jsx b/src/pages/tools/templatelib/index.jsx index e654b87f1a8e..fbe16255ecc8 100644 --- a/src/pages/tools/templatelib/index.jsx +++ b/src/pages/tools/templatelib/index.jsx @@ -76,7 +76,11 @@ const TemplateLibrary = () => { > - + @@ -89,18 +93,14 @@ const TemplateLibrary = () => { `${option.Name} (${option.URL})`, + }} formControl={formControl} multiple={false} /> diff --git a/src/utils/get-cipp-formatting.js b/src/utils/get-cipp-formatting.js index 2feaacacf94d..b6b7fa399571 100644 --- a/src/utils/get-cipp-formatting.js +++ b/src/utils/get-cipp-formatting.js @@ -429,6 +429,25 @@ export const getCippFormatting = (data, cellName, type, canReceive) => { ); } + if (cellName === "Visibility") { + const gitHubVisibility = ["public", "private", "internal"]; + if (gitHubVisibility.includes(data)) { + return isText ? ( + data + ) : ( + + ); + } + } + if (cellName === "AutoMapUrl") { return isText ? data : ; } From 7895a4dc47dd6070afc20521e17819ea2bfd1ce6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Feb 2025 19:39:44 -0500 Subject: [PATCH 9/9] Update CippApiResults.jsx --- src/components/CippComponents/CippApiResults.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CippComponents/CippApiResults.jsx b/src/components/CippComponents/CippApiResults.jsx index 21af58b8cc39..0c5807c379ed 100644 --- a/src/components/CippComponents/CippApiResults.jsx +++ b/src/components/CippComponents/CippApiResults.jsx @@ -10,7 +10,7 @@ const extractAllResults = (data) => { const getSeverity = (text) => { if (typeof text !== "string") return "success"; - return /error|failed|exception|not found/i.test(text) ? "error" : "success"; + return /error|failed|exception|not found|invalid_grant/i.test(text) ? "error" : "success"; }; const processResultItem = (item) => {