diff --git a/application/frontend/src/pages/MyOpenCRE/MyOpenCRE.scss b/application/frontend/src/pages/MyOpenCRE/MyOpenCRE.scss new file mode 100644 index 00000000..e69de29b diff --git a/application/frontend/src/pages/MyOpenCRE/MyOpenCRE.tsx b/application/frontend/src/pages/MyOpenCRE/MyOpenCRE.tsx new file mode 100644 index 00000000..4a3de6a2 --- /dev/null +++ b/application/frontend/src/pages/MyOpenCRE/MyOpenCRE.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { Button, Container, Header } from 'semantic-ui-react'; + +import { useEnvironment } from '../../hooks'; + +export const MyOpenCRE = () => { + const { apiUrl } = useEnvironment(); + + const downloadTemplate = () => { + const headers = ['standard_name', 'standard_section', 'cre_id', 'notes']; + + const csvContent = headers.join(',') + '\n'; + + const blob = new Blob([csvContent], { + type: 'text/csv;charset=utf-8;', + }); + + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + + link.href = url; + link.setAttribute('download', 'myopencre_mapping_template.csv'); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }; + + return ( + +
MyOpenCRE
+ +

+ MyOpenCRE allows you to map your own security standard (e.g. SOC2) to OpenCRE Common Requirements + using a CSV spreadsheet. +

+ +

+ Start by downloading the mapping template below, fill it with your standard’s controls, and map them + to CRE IDs. +

+ + +
+ ); +}; diff --git a/application/frontend/src/routes.tsx b/application/frontend/src/routes.tsx index da9c507e..5d18ba09 100644 --- a/application/frontend/src/routes.tsx +++ b/application/frontend/src/routes.tsx @@ -21,6 +21,7 @@ import { ExplorerCircles } from './pages/Explorer/visuals/circles/circles'; import { ExplorerForceGraph } from './pages/Explorer/visuals/force-graph/forceGraph'; import { GapAnalysis } from './pages/GapAnalysis/GapAnalysis'; import { MembershipRequired } from './pages/MembershipRequired/MembershipRequired'; +import { MyOpenCRE } from './pages/MyOpenCRE/MyOpenCRE'; import { SearchName } from './pages/Search/SearchName'; import { StandardSection } from './pages/Standard/StandardSection'; @@ -31,6 +32,12 @@ export interface IRoute { } export const ROUTES: IRoute[] = [ + { + path: '/myopencre', + component: MyOpenCRE, + showFilter: false, + }, + { path: INDEX, component: SearchPage, diff --git a/application/frontend/src/scaffolding/Header/Header.tsx b/application/frontend/src/scaffolding/Header/Header.tsx index 9e653b42..1b36dd72 100644 --- a/application/frontend/src/scaffolding/Header/Header.tsx +++ b/application/frontend/src/scaffolding/Header/Header.tsx @@ -8,6 +8,7 @@ import { Button } from 'semantic-ui-react'; import { ClearFilterButton } from '../../components/FilterButton/FilterButton'; import { useLocationFromOutsideRoute } from '../../hooks/useLocationFromOutsideRoute'; +import { MyOpenCRE } from '../../pages/MyOpenCRE/MyOpenCRE'; import { SearchBar } from '../../pages/Search/components/SearchBar'; export const Header = () => { @@ -68,6 +69,10 @@ export const Header = () => { Explorer + + + MyOpenCRE +
@@ -186,6 +191,15 @@ export const Header = () => { > Explorer + + + MyOpenCRE +