Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
gillespi314 committed Nov 22, 2024
1 parent 57d640d commit ef18576
Show file tree
Hide file tree
Showing 28 changed files with 1,227 additions and 6 deletions.
1 change: 1 addition & 0 deletions frontend/components/FileUploader/FileUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type ISupportedGraphicNames = Extract<
| "file-p7m"
| "file-pem"
| "file-vpp"
| "file-crt"
>;

interface IFileUploaderProps {
Expand Down
71 changes: 71 additions & 0 deletions frontend/components/graphics/FileCrt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from "react";

const FileCrt = () => {
return (
<svg
width="34"
height="40"
viewBox="0 0 34 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_5318_4000)">
<path
d="M29.3333 39.7505H4.66667C3.33198 39.7505 2.25 38.6685 2.25 37.3338V2.66716C2.25 1.33247 3.33198 0.250488 4.66667 0.250488H24.2288C24.8697 0.250488 25.4844 0.505101 25.9376 0.958313L31.0422 6.06288C31.4954 6.5161 31.75 7.13078 31.75 7.77172V37.3338C31.75 38.6685 30.668 39.7505 29.3333 39.7505Z"
fill="white"
stroke="#192147"
strokeWidth="0.5"
/>
<path
d="M23.5 0.500488H24.3335L24.8335 7.00049L31.5 7.50049V8.50049H25.5C24.3954 8.50049 23.5 7.60506 23.5 6.50049V0.500488Z"
fill="#C5C7D1"
/>
<path
d="M24.5 0.333984V6.00065C24.5 6.73703 25.097 7.33398 25.8333 7.33398H31.8333"
stroke="#192147"
strokeWidth="0.5"
/>
<path
d="M2.5 20H27.5C28.6046 20 29.5 20.8954 29.5 22V35C29.5 36.1046 28.6046 37 27.5 37H2.5V20Z"
fill="#C5C7D1"
/>
<rect
x="0.25"
y="18.25"
width="27.7"
height="16.35"
rx="1.75"
fill="#515774"
/>
<rect
x="0.25"
y="18.25"
width="27.7"
height="16.35"
rx="1.75"
stroke="#192147"
strokeWidth="0.5"
/>
<path
d="M20.4527 24.4947V25.7859H17.1859V24.4947H20.4527ZM17.8186 23.3068H19.6005V27.8582C19.6005 27.9271 19.6123 27.9852 19.636 28.0325C19.6597 28.0777 19.6962 28.1122 19.7457 28.1358C19.7952 28.1574 19.8587 28.1681 19.9362 28.1681C19.99 28.1681 20.0524 28.1617 20.1234 28.1487C20.1966 28.1358 20.2504 28.1251 20.2848 28.1165L20.543 29.3689C20.4634 29.3926 20.3494 29.4216 20.2009 29.4561C20.0545 29.4905 19.8802 29.5131 19.6779 29.5239C19.2691 29.5454 18.9258 29.5034 18.6482 29.398C18.3706 29.2904 18.1619 29.1214 18.022 28.8912C17.8821 28.6609 17.8143 28.3726 17.8186 28.0261V23.3068Z"
fill="white"
/>
<path
d="M13.3503 29.4528V24.4947H15.0805V25.4372H15.1322C15.2225 25.0886 15.3656 24.8336 15.5615 24.6722C15.7595 24.5108 15.9908 24.4301 16.2555 24.4301C16.333 24.4301 16.4094 24.4366 16.4847 24.4495C16.5622 24.4602 16.6364 24.4764 16.7074 24.4979V26.0183C16.6192 25.9881 16.5105 25.9656 16.3814 25.9505C16.2523 25.9354 16.1414 25.9279 16.0489 25.9279C15.8746 25.9279 15.7175 25.9677 15.5776 26.0473C15.4399 26.1248 15.3312 26.2345 15.2516 26.3766C15.172 26.5165 15.1322 26.6811 15.1322 26.8705V29.4528H13.3503Z"
fill="white"
/>
<path
d="M10.2264 29.5432C9.68843 29.5432 9.2279 29.4367 8.84485 29.2237C8.4618 29.0085 8.16805 28.7093 7.96361 28.3263C7.75917 27.9411 7.65695 27.4945 7.65695 26.9867C7.65695 26.4788 7.75917 26.0333 7.96361 25.6503C8.16805 25.2651 8.4618 24.966 8.84485 24.7529C9.2279 24.5377 9.68843 24.4301 10.2264 24.4301C10.7128 24.4301 11.1335 24.5183 11.4886 24.6948C11.8458 24.8691 12.1223 25.1166 12.3182 25.4372C12.514 25.7557 12.613 26.1302 12.6151 26.5606H10.9624C10.9387 26.3002 10.8634 26.1022 10.7364 25.9666C10.6116 25.8289 10.4502 25.76 10.2523 25.76C10.0973 25.76 9.96173 25.8052 9.84552 25.8956C9.72932 25.9838 9.63893 26.1183 9.57437 26.2991C9.50981 26.4777 9.47753 26.7026 9.47753 26.9738C9.47753 27.2449 9.50981 27.4709 9.57437 27.6516C9.63893 27.8302 9.72932 27.9647 9.84552 28.0551C9.96173 28.1434 10.0973 28.1875 10.2523 28.1875C10.3835 28.1875 10.4997 28.1574 10.6009 28.0971C10.702 28.0347 10.7838 27.9443 10.8462 27.8259C10.9108 27.7054 10.9495 27.5591 10.9624 27.3869H12.6151C12.6087 27.8238 12.5086 28.2047 12.3149 28.5296C12.1213 28.8524 11.8469 29.1021 11.4918 29.2785C11.1389 29.455 10.7171 29.5432 10.2264 29.5432Z"
fill="white"
/>
</g>
<defs>
<clipPath id="clip0_5318_4000">
<rect width="34" height="40" fill="white" />
</clipPath>
</defs>
</svg>
);
};

export default FileCrt;
2 changes: 2 additions & 0 deletions frontend/components/graphics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import FilePkg from "./FilePkg";
import FileP7m from "./FileP7m";
import FilePem from "./FilePem";
import FileVpp from "./FileVpp";
import FileCrt from "./FileCrt";
import EmptyHosts from "./EmptyHosts";
import EmptyTeams from "./EmptyTeams";
import EmptyPacks from "./EmptyPacks";
Expand Down Expand Up @@ -48,6 +49,7 @@ export const GRAPHIC_MAP = {
"file-p7m": FileP7m,
"file-pem": FilePem,
"file-vpp": FileVpp,
"file-crt": FileCrt,
// Other graphics
"collecting-results": CollectingResults,
"data-error": DataError,
Expand Down
9 changes: 9 additions & 0 deletions frontend/interfaces/pki.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type IPkiTemplate = {
profile_id: number;
name: string;
common_name: string;
san: string;
seat_id: string;
};

export type IPkiConfig = { name: string; templates: IPkiTemplate[] };
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import IdpSection from "./components/IdpSection";
import EulaSection from "./components/EulaSection";
import EndUserMigrationSection from "./components/EndUserMigrationSection";
import ScepSection from "./components/ScepSection/ScepSection";
import PkiSection from "./components/PkiSection/PkiSection";

const baseClass = "mdm-settings";

Expand Down Expand Up @@ -133,6 +134,11 @@ const MdmSettings = ({ router }: IMdmSettingsProps) => {
isVppOn={!noVppTokenUploaded}
isPremiumTier={!!isPremiumTier}
/>
<PkiSection
router={router}
isPremiumTier={!!isPremiumTier}
isPkiOn={!noScepCredentials}
/>
<ScepSection
router={router}
isScepOn={!noScepCredentials}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import React, { useCallback, useContext, useRef, useState } from "react";
import { noop } from "lodash";

import { useQuery } from "react-query";
import { InjectedRouter } from "react-router";

import { AxiosError } from "axios";

import PATHS from "router/paths";

import { AppContext } from "context/app";

import { IPkiConfig } from "interfaces/pki";

import BackLink from "components/BackLink";
import Button from "components/buttons/Button";
import DataError from "components/DataError";
import MainContent from "components/MainContent";
import Spinner from "components/Spinner";
import PremiumFeatureMessage from "components/PremiumFeatureMessage";
import TurnOnMdmMessage from "components/TurnOnMdmMessage";

import AddPkiModal from "./components/AddPkiModal";
import DeletePkiModal from "./components/DeletePkiModal";
import EditTemplateModal from "./components/EditTemplateModal";
import PkiTable from "./components/PkiTable";

const baseClass = "pki-page";

interface IAddPkiMessageProps {
onAddPki: () => void;
}

const AddPkiMessage = ({ onAddPki }: IAddPkiMessageProps) => {
return (
<div className={`${baseClass}__add-message`}>
<h2>Add your PKI</h2>
<p>Help your end users connect to Wi-Fi</p>
<Button variant="brand" onClick={onAddPki}>
Add PKI
</Button>
</div>
);
};

const PkiPage = ({ router }: { router: InjectedRouter }) => {
const { config, isPremiumTier } = useContext(AppContext);

const [showDeleteModal, setShowDeleteModal] = useState(false);
const [showAddPkiModal, setShowAddPkiModal] = useState(false);
const [showEditTemplateModal, setShowEditTemplateModal] = useState(false);

const selectedPki = useRef<IPkiConfig | null>(null);

const {
data: pkiConfigs,
error: errorPkiConfigs,
isLoading,
isRefetching,
refetch,
} = useQuery<IPkiConfig[], AxiosError>(
["pkiConfigs"],
() =>
Promise.resolve([
{
name: "test_config",
templates: [
{
profile_id: 1,
name: "test",
common_name: "test",
san: "test",
seat_id: "test",
},
],
},
]),
{
refetchOnWindowFocus: false,
retry: (tries, error) =>
error.status !== 404 && error.status !== 400 && tries <= 3,
enabled: isPremiumTier,
}
);

const onAdd = () => {
setShowAddPkiModal(true);
};

const onAdded = () => {
refetch();
setShowAddPkiModal(false);
};

const onEditTemplate = (pkiConfig: IPkiConfig) => {
selectedPki.current = pkiConfig;
setShowEditTemplateModal(true);
};

const onCancelEditTemplate = useCallback(() => {
selectedPki.current = null;
setShowEditTemplateModal(false);
}, []);

const onEditedTemplate = useCallback(() => {
selectedPki.current = null;
refetch();
setShowEditTemplateModal(false);
}, [refetch]);

const onDelete = (pkiConfig: IPkiConfig) => {
selectedPki.current = pkiConfig;
setShowDeleteModal(true);
};

const onCancelDelete = useCallback(() => {
selectedPki.current = null;
setShowDeleteModal(false);
}, []);

const onDeleted = useCallback(() => {
selectedPki.current = null;
refetch();
setShowDeleteModal(false);
}, [refetch]);

if (isLoading || isRefetching) {
return <Spinner />;
}

const showDataError = errorPkiConfigs && errorPkiConfigs.status !== 404;

const renderContent = () => {
if (!isPremiumTier) {
return <PremiumFeatureMessage />;
}

if (!config?.mdm.enabled_and_configured) {
return (
<TurnOnMdmMessage
router={router}
header="Turn on Apple MDM"
info="To add your ABM and enable automatic enrollment for macOS, iOS, and
iPadOS hosts, first turn on Apple MDM."
/>
);
}

if (isLoading) {
return <Spinner />;
}

// TODO: error UI
if (showDataError) {
return (
<div>
<DataError />
</div>
);
}

if (!pkiConfigs?.length) {
return <AddPkiMessage onAddPki={onAdd} />;
}

return (
<>
<p>To help your end users connect to Wi-Fi, you can add your PKI.</p>
<PkiTable
data={pkiConfigs}
onEdit={onEditTemplate}
onDelete={onDelete}
/>
</>
);
};

return (
<MainContent className={baseClass}>
<>
<BackLink
text="Back to MDM"
path={PATHS.ADMIN_INTEGRATIONS_MDM}
className={`${baseClass}__back-to-mdm`}
/>
<div className={`${baseClass}__page-content`}>
<div className={`${baseClass}__page-header-section`}>
<h1>Public key infrastructure (PKI)</h1>
{isPremiumTier &&
pkiConfigs?.length !== 0 &&
!!config?.mdm.enabled_and_configured && (
<Button variant="brand" onClick={onAdd}>
Add PKI
</Button>
)}
</div>
<>{renderContent()}</>
</div>
</>
{showAddPkiModal && (
<AddPkiModal
onAdded={onAdded}
onCancel={() => setShowAddPkiModal(false)}
/>
)}
{showDeleteModal && selectedPki.current && (
<DeletePkiModal
pkiConfig={selectedPki.current}
onCancel={onCancelDelete}
onDeleted={onDeleted}
/>
)}
{showEditTemplateModal && selectedPki.current && (
<EditTemplateModal
pkiConfig={selectedPki.current}
onCancel={onCancelEditTemplate}
onSuccess={onEditedTemplate}
/>
)}
</MainContent>
);
};

export default PkiPage;
Loading

0 comments on commit ef18576

Please sign in to comment.