Skip to content

Commit a4ae0c5

Browse files
feat(myopencre): add initial MyOpenCRE page and CSV template download (#661)
* feat(myopencre): add initial MyOpenCRE page and CSV template download * fix(header): add MyOpenCRE link and resolve navigation conflict
1 parent 0dfec60 commit a4ae0c5

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

application/frontend/src/pages/MyOpenCRE/MyOpenCRE.scss

Whitespace-only changes.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
import { Button, Container, Header } from 'semantic-ui-react';
3+
4+
import { useEnvironment } from '../../hooks';
5+
6+
export const MyOpenCRE = () => {
7+
const { apiUrl } = useEnvironment();
8+
9+
const downloadTemplate = () => {
10+
const headers = ['standard_name', 'standard_section', 'cre_id', 'notes'];
11+
12+
const csvContent = headers.join(',') + '\n';
13+
14+
const blob = new Blob([csvContent], {
15+
type: 'text/csv;charset=utf-8;',
16+
});
17+
18+
const url = URL.createObjectURL(blob);
19+
const link = document.createElement('a');
20+
21+
link.href = url;
22+
link.setAttribute('download', 'myopencre_mapping_template.csv');
23+
document.body.appendChild(link);
24+
link.click();
25+
document.body.removeChild(link);
26+
};
27+
28+
return (
29+
<Container style={{ marginTop: '3rem' }}>
30+
<Header as="h1">MyOpenCRE</Header>
31+
32+
<p>
33+
MyOpenCRE allows you to map your own security standard (e.g. SOC2) to OpenCRE Common Requirements
34+
using a CSV spreadsheet.
35+
</p>
36+
37+
<p>
38+
Start by downloading the mapping template below, fill it with your standard’s controls, and map them
39+
to CRE IDs.
40+
</p>
41+
42+
<Button primary onClick={downloadTemplate}>
43+
Download Mapping Template (CSV)
44+
</Button>
45+
</Container>
46+
);
47+
};

application/frontend/src/routes.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { ExplorerCircles } from './pages/Explorer/visuals/circles/circles';
2121
import { ExplorerForceGraph } from './pages/Explorer/visuals/force-graph/forceGraph';
2222
import { GapAnalysis } from './pages/GapAnalysis/GapAnalysis';
2323
import { MembershipRequired } from './pages/MembershipRequired/MembershipRequired';
24+
import { MyOpenCRE } from './pages/MyOpenCRE/MyOpenCRE';
2425
import { SearchName } from './pages/Search/SearchName';
2526
import { StandardSection } from './pages/Standard/StandardSection';
2627

@@ -31,6 +32,12 @@ export interface IRoute {
3132
}
3233

3334
export const ROUTES: IRoute[] = [
35+
{
36+
path: '/myopencre',
37+
component: MyOpenCRE,
38+
showFilter: false,
39+
},
40+
3441
{
3542
path: INDEX,
3643
component: SearchPage,

application/frontend/src/scaffolding/Header/Header.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Button } from 'semantic-ui-react';
88

99
import { ClearFilterButton } from '../../components/FilterButton/FilterButton';
1010
import { useLocationFromOutsideRoute } from '../../hooks/useLocationFromOutsideRoute';
11+
import { MyOpenCRE } from '../../pages/MyOpenCRE/MyOpenCRE';
1112
import { SearchBar } from '../../pages/Search/components/SearchBar';
1213

1314
export const Header = () => {
@@ -68,6 +69,10 @@ export const Header = () => {
6869
<NavLink to="/explorer" className="nav-link" activeClassName="nav-link--active">
6970
Explorer
7071
</NavLink>
72+
73+
<NavLink to="/myopencre" className="nav-link" activeClassName="nav-link--active">
74+
MyOpenCRE
75+
</NavLink>
7176
</div>
7277

7378
<div>
@@ -186,6 +191,15 @@ export const Header = () => {
186191
>
187192
Explorer
188193
</NavLink>
194+
195+
<NavLink
196+
to="/myopencre"
197+
className="nav-link"
198+
activeClassName="nav-link--active"
199+
onClick={closeMobileMenu}
200+
>
201+
MyOpenCRE
202+
</NavLink>
189203
</div>
190204

191205
<div className="mobile-auth">

0 commit comments

Comments
 (0)