From 2a56d473bc757de0d1129a2dbb216eacb77b7c0c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Feb 2025 22:58:20 -0500 Subject: [PATCH 1/5] repo browser page --- src/pages/tools/community-repos/repo.js | 171 +++++++++++++++++++----- 1 file changed, 136 insertions(+), 35 deletions(-) diff --git a/src/pages/tools/community-repos/repo.js b/src/pages/tools/community-repos/repo.js index c15b610b5f3d..060915cb2cf5 100644 --- a/src/pages/tools/community-repos/repo.js +++ b/src/pages/tools/community-repos/repo.js @@ -2,7 +2,7 @@ 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 { ApiPostCall, ApiGetCall } from "/src/api/ApiCall"; import { Button, Dialog, @@ -11,11 +11,12 @@ import { DialogActions, Box, Skeleton, - Alert, } from "@mui/material"; -import { OpenInNew } from "@mui/icons-material"; +import { Grid } from "@mui/system"; 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"; const Page = () => { const router = useRouter(); @@ -23,55 +24,166 @@ const Page = () => { const [openJsonDialog, setOpenJsonDialog] = useState(false); const [fileResults, setFileResults] = useState([]); const [jsonContent, setJsonContent] = useState({}); + const [branches, setBranches] = useState([]); + const [selectedBranch, setSelectedBranch] = useState(""); + const [selectedRepo, setSelectedRepo] = useState(name); const searchMutation = ApiPostCall({ onResult: (resp) => { + if (resp?.Results === null || resp?.Results?.[0] === null) return; setFileResults(resp?.Results || []); }, }); - const fileMutation = ApiPostCall({ + const fileQuery = ApiPostCall({ onResult: (resp) => { setJsonContent(JSON.parse(resp?.Results?.content || "{}")); }, }); + const branchQuery = ApiGetCall({ + url: "/api/ExecGitHubAction", + data: { + Action: "GetBranches", + FullName: selectedRepo, + }, + onResult: (resp) => { + const branchList = resp?.Results || []; + setBranches(branchList); + if (branchList.length === 1) { + setSelectedBranch(branchList[0].name); + fetchFileTree(branchList[0].name); + } + const mainBranch = branchList.find((branch) => ["main", "master"].includes(branch.name)); + if (mainBranch) { + setSelectedBranch(mainBranch.name); + fetchFileTree(mainBranch.name); + } + }, + queryKey: `${selectedRepo}-branches`, + waiting: selectedRepo !== "", + }); + + const fileTreeQuery = ApiGetCall({ + url: "/api/ExecGitHubAction", + data: { + Action: "GetFileTree", + FullName: selectedRepo, + Branch: selectedBranch, + }, + onResult: (resp) => { + setFileResults(resp?.Results || []); + }, + queryKey: `${selectedRepo}-${selectedBranch}-filetree`, + waiting: selectedRepo !== "" && selectedBranch !== "", + }); + + const fetchFileTree = (branch) => { + if (selectedRepo !== "" && branch !== "") { + if (!fileTreeQuery.waiting) { + fileTreeQuery.waiting = true; + } + fileTreeQuery.refetch(); + } + }; + const handleJsonView = (url) => { - fileMutation.mutate({ + fileQuery.mutate({ url: "/api/ExecGitHubAction", data: { - GetFileContents: { - Url: url, - }, + Action: "GetFileContents", + Url: url, }, }); setOpenJsonDialog(true); }; useEffect(() => { - if (name) { - searchMutation.mutate({ - url: "/api/ExecGitHubAction", - data: { - Search: { - Repository: [name], - Type: "code", - Language: "json", - }, + if (selectedRepo) { + branchQuery.refetch(); + } + }, [selectedRepo]); + + useEffect(() => { + if (selectedBranch) { + fetchFileTree(selectedBranch); + } + }, [selectedBranch]); + + const updateQueryParams = (newRepo) => { + const query = { ...router.query }; + if (query.name !== newRepo) { + query.name = newRepo; + router.replace( + { + pathname: router.pathname, + query: query, }, - }); + undefined, + { shallow: true } + ); } - }, [name]); + }; + + const MemoizedCippAutoComplete = React.memo((props) => { + return ; + }); return ( <> + + { + if (newValue.value === selectedRepo) return; + setSelectedRepo(newValue.value); + updateQueryParams(newValue.value); + }} + api={{ + url: "/api/ListCommunityRepos", + queryKey: "CommunityRepos", + dataKey: "Results", + valueField: "FullName", + labelField: "FullName", + }} + multiple={false} + label="Select Repository" + placeholder="Select Repository" + disableClearable + /> + + + setSelectedBranch(newValue.value)} + options={branches.map((branch) => ({ label: branch.name, value: branch.name }))} + multiple={false} + label="Select Branch" + placeholder="Select Branch" + disableClearable + isFetching={branchQuery.isPending} + /> + + + } data={fileResults} apiDataKey="Results" queryKey="JsonTemplates" - simpleColumns={["name", "html_url"]} + simpleColumns={["path", "html_url"]} actions={[ { label: "View Template", @@ -81,19 +193,8 @@ const Page = () => { hideBulk: true, }, ]} - isFetching={searchMutation.isPending} - refreshFunction={() => - searchMutation.mutate({ - url: "/api/ExecGitHubAction", - data: { - Search: { - Repository: [name], - Type: "code", - Language: "json", - }, - }, - }) - } + isFetching={fileTreeQuery.isFetching} + refreshFunction={() => fetchFileTree(selectedBranch)} /> { > Template Details - {fileMutation.isPending ? ( + {fileQuery.isPending ? ( From 7a3e6d64f56d1f4187e0f9bb5fbf763bd8927fe3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Feb 2025 23:29:34 -0500 Subject: [PATCH 2/5] add branch selection to template library --- src/pages/tools/templatelib/index.jsx | 41 ++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/pages/tools/templatelib/index.jsx b/src/pages/tools/templatelib/index.jsx index fbe16255ecc8..186495a9e949 100644 --- a/src/pages/tools/templatelib/index.jsx +++ b/src/pages/tools/templatelib/index.jsx @@ -1,6 +1,6 @@ import React from "react"; import { Grid, Divider, Typography, CircularProgress, Alert, Chip } from "@mui/material"; -import { useForm } from "react-hook-form"; +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"; @@ -22,6 +22,8 @@ const TemplateLibrary = () => { }, }); + const templateRepo = useWatch({ control: formControl.control, name: "templateRepo" }); + const customDataFormatter = (values) => { const startDate = new Date(); startDate.setHours(0, 0, 0, 0); @@ -108,6 +110,31 @@ const TemplateLibrary = () => { + {templateRepo?.value && ( + + + Repository Branch + + + + )} { compareValue={"CIPP"} > - Conditional Access + + Conditional Access + { - Intune + + Intune + { compareValue={"CIPP-"} > - Template Repository files + + Template Repository files + Date: Mon, 10 Feb 2025 23:34:22 -0500 Subject: [PATCH 3/5] template library add extension check add branch selection --- src/pages/tools/templatelib/index.jsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/pages/tools/templatelib/index.jsx b/src/pages/tools/templatelib/index.jsx index 186495a9e949..2f4ce00db21e 100644 --- a/src/pages/tools/templatelib/index.jsx +++ b/src/pages/tools/templatelib/index.jsx @@ -8,6 +8,7 @@ import { useSettings } from "/src/hooks/use-settings"; import { CippFormTenantSelector } from "../../../components/CippComponents/CippFormTenantSelector"; import { Box } from "@mui/system"; import { CippFormCondition } from "../../../components/CippComponents/CippFormCondition"; +import { ApiGetCall } from "/src/api/ApiCall"; const TemplateLibrary = () => { const currentTenant = useSettings().currentTenant; @@ -22,6 +23,12 @@ const TemplateLibrary = () => { }, }); + + const integrations = ApiGetCall({ + url: "/api/ListExtensionsConfig", + queryKey: "Integrations", + }); + const templateRepo = useWatch({ control: formControl.control, name: "templateRepo" }); const customDataFormatter = (values) => { @@ -65,6 +72,17 @@ 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. + + )} @@ -105,6 +123,7 @@ const TemplateLibrary = () => { }} formControl={formControl} multiple={false} + disabled={!integrations.data?.GitHub?.Enabled} /> From e3423d3520c76631eca3763939a28f90c3116bab Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Feb 2025 23:43:09 -0500 Subject: [PATCH 4/5] add alert for github integration fix alignment --- src/pages/tools/templatelib/index.jsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pages/tools/templatelib/index.jsx b/src/pages/tools/templatelib/index.jsx index 2f4ce00db21e..6b17c943374d 100644 --- a/src/pages/tools/templatelib/index.jsx +++ b/src/pages/tools/templatelib/index.jsx @@ -1,5 +1,5 @@ import React from "react"; -import { Grid, Divider, Typography, CircularProgress, Alert, Chip } from "@mui/material"; +import { Grid, Divider, Typography, CircularProgress, Alert, Chip, Link } 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"; @@ -9,6 +9,7 @@ import { CippFormTenantSelector } from "../../../components/CippComponents/CippF import { Box } from "@mui/system"; import { CippFormCondition } from "../../../components/CippComponents/CippFormCondition"; import { ApiGetCall } from "/src/api/ApiCall"; +import NextLink from "next/link"; const TemplateLibrary = () => { const currentTenant = useSettings().currentTenant; @@ -23,7 +24,6 @@ const TemplateLibrary = () => { }, }); - const integrations = ApiGetCall({ url: "/api/ListExtensionsConfig", queryKey: "Integrations", @@ -85,13 +85,14 @@ const TemplateLibrary = () => { )} - + @@ -128,7 +129,7 @@ const TemplateLibrary = () => { - + {templateRepo?.value && ( From b8957baa112b29573bb7386df97da763a7cf8c8b Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Feb 2025 23:44:02 -0500 Subject: [PATCH 5/5] Update index.jsx --- src/pages/tools/templatelib/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/tools/templatelib/index.jsx b/src/pages/tools/templatelib/index.jsx index 6b17c943374d..a58adc3e0453 100644 --- a/src/pages/tools/templatelib/index.jsx +++ b/src/pages/tools/templatelib/index.jsx @@ -52,7 +52,7 @@ const TemplateLibrary = () => {