diff --git a/.github/workflows/dependency-pr.yml b/.github/workflows/dependency-pr.yml index 460684895..fa22181bb 100644 --- a/.github/workflows/dependency-pr.yml +++ b/.github/workflows/dependency-pr.yml @@ -18,12 +18,12 @@ jobs: name: Synchronize version steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 ref: develop - name: Setup NodeJS - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: 14 - name: Globally update npm diff --git a/.github/workflows/gh-packages.yml b/.github/workflows/gh-packages.yml index 6c5e43264..03a83ae17 100644 --- a/.github/workflows/gh-packages.yml +++ b/.github/workflows/gh-packages.yml @@ -16,11 +16,11 @@ jobs: packages: write steps: - name: Delete previous oscal-react-library version - uses: actions/delete-package-versions@v2.0.1 + uses: actions/delete-package-versions@v2 with: package-name: oscal-react-library - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup NodeJS uses: actions/setup-node@v3 with: diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 06405c832..451b50f19 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup NodeJS uses: actions/setup-node@v3 with: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index c174ba144..f5eb27674 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup NodeJS @@ -59,7 +59,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup NodeJS diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 083618484..ffd0ff9b6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: steps: # Check out develop branch - name: Checkout Code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: develop diff --git a/example/package-lock.json b/example/package-lock.json index afb5ab7a5..6ca124ed7 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -1,12 +1,12 @@ { "name": "@EasyDynamics/oscal-viewer", - "version": "0.3.0", + "version": "0.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@EasyDynamics/oscal-viewer", - "version": "0.3.0", + "version": "0.4.0", "dependencies": { "@EasyDynamics/oscal-react-library": "file:..", "@testing-library/jest-dom": "file:../node_modules/@testing-library/jest-dom", @@ -26,13 +26,14 @@ }, "..": { "name": "@EasyDynamics/oscal-react-library", - "version": "0.3.0", + "version": "0.4.0", "license": "MIT", "dependencies": { "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.60", "@material-ui/styles": "^4.11.4", + "@monaco-editor/react": "^4.3.1", "@testing-library/dom": "^8.11.3", "@testing-library/jest-dom": "^5.16.2", "@testing-library/react": "^12.1.3", @@ -40,8 +41,9 @@ "prop-types": "^15.8.0", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-router-dom": "^6.2.1", + "react-router-dom": "^6.2.2", "react-scripts": "^5.0.0", + "react-split": "^2.0.14", "web-vitals": "^2.1.2" }, "devDependencies": { @@ -35050,6 +35052,7 @@ "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.60", "@material-ui/styles": "^4.11.4", + "@monaco-editor/react": "^4.3.1", "@storybook/addon-actions": "^6.4.19", "@storybook/addon-docs": "^6.4.19", "@storybook/addon-essentials": "^6.4.19", @@ -35083,8 +35086,9 @@ "prop-types": "^15.8.0", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-router-dom": "^6.2.1", + "react-router-dom": "^6.2.2", "react-scripts": "^5.0.0", + "react-split": "^2.0.14", "web-vitals": "^2.1.2", "webpack": "^5.69.1" }, diff --git a/example/package.json b/example/package.json index 4695c4dbc..c3e698442 100644 --- a/example/package.json +++ b/example/package.json @@ -1,7 +1,7 @@ { "name": "@EasyDynamics/oscal-viewer", "homepage": ".", - "version": "0.3.0", + "version": "0.4.0", "private": "true", "repository": { "type": "git", diff --git a/example/src/App.js b/example/src/App.js index af1813056..94170a774 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -181,7 +181,7 @@ function App() { Profile Viewer - + = 0.21.0 < 1" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.3.1.tgz", + "integrity": "sha512-f+0BK1PP/W5I50hHHmwf11+Ea92E5H1VZXs+wvKplWUWOfyMa1VVwqkJrXjRvbcqHL+XdIGYWhWNdi4McEvnZg==", + "dependencies": { + "@monaco-editor/loader": "^1.2.0", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -26348,6 +26375,12 @@ "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=", "dev": true }, + "node_modules/monaco-editor": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.32.1.tgz", + "integrity": "sha512-LUt2wsUvQmEi2tfTOK+tjAPvt7eQ+K5C4rZPr6SeuyzjAuAHrIvlUloTcOiGjZW3fn3a/jFQCONrEJbNOaCqbA==", + "peer": true + }, "node_modules/move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -29460,9 +29493,9 @@ } }, "node_modules/react-router": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz", - "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.2.tgz", + "integrity": "sha512-/MbxyLzd7Q7amp4gDOGaYvXwhEojkJD5BtExkuKmj39VEE0m3l/zipf6h2WIB2jyAO0lI6NGETh4RDcktRm4AQ==", "dependencies": { "history": "^5.2.0" }, @@ -29471,12 +29504,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz", - "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.2.tgz", + "integrity": "sha512-AtYEsAST7bDD4dLSQHDnk/qxWLJdad5t1HFa1qJyUrCeGgEuCSw0VB/27ARbF9Fi/W5598ujvJOm3ujUCVzuYQ==", "dependencies": { "history": "^5.2.0", - "react-router": "6.2.1" + "react-router": "6.2.2" }, "peerDependencies": { "react": ">=16.8", @@ -31122,6 +31155,18 @@ "throttle-debounce": "^3.0.1" } }, + "node_modules/react-split": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/react-split/-/react-split-2.0.14.tgz", + "integrity": "sha512-bKWydgMgaKTg/2JGQnaJPg51T6dmumTWZppFgEbbY0Fbme0F5TuatAScCLaqommbGQQf/ZT1zaejuPDriscISA==", + "dependencies": { + "prop-types": "^15.5.7", + "split.js": "^1.6.0" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-syntax-highlighter": { "version": "13.5.3", "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz", @@ -33613,6 +33658,11 @@ "node": ">=0.10.0" } }, + "node_modules/split.js": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/split.js/-/split.js-1.6.5.tgz", + "integrity": "sha512-mPTnGCiS/RiuTNsVhCm9De9cCAUsrNFFviRbADdKiiV+Kk8HKp/0fWu7Kr8pi3/yBmsqLFHuXGT9UUZ+CNLwFw==" + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -33659,6 +33709,11 @@ "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz", "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==" }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" + }, "node_modules/state-toggle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", @@ -40094,6 +40149,23 @@ "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", "dev": true }, + "@monaco-editor/loader": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.2.0.tgz", + "integrity": "sha512-cJVCG/T/KxXgzYnjKqyAgsKDbH9mGLjcXxN6AmwumBwa2rVFkwvGcUj1RJtD0ko4XqLqJxwqsN/Z/KURB5f1OQ==", + "requires": { + "state-local": "^1.0.6" + } + }, + "@monaco-editor/react": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.3.1.tgz", + "integrity": "sha512-f+0BK1PP/W5I50hHHmwf11+Ea92E5H1VZXs+wvKplWUWOfyMa1VVwqkJrXjRvbcqHL+XdIGYWhWNdi4McEvnZg==", + "requires": { + "@monaco-editor/loader": "^1.2.0", + "prop-types": "^15.7.2" + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -57327,6 +57399,12 @@ "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=", "dev": true }, + "monaco-editor": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.32.1.tgz", + "integrity": "sha512-LUt2wsUvQmEi2tfTOK+tjAPvt7eQ+K5C4rZPr6SeuyzjAuAHrIvlUloTcOiGjZW3fn3a/jFQCONrEJbNOaCqbA==", + "peer": true + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -59767,20 +59845,20 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, "react-router": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz", - "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.2.tgz", + "integrity": "sha512-/MbxyLzd7Q7amp4gDOGaYvXwhEojkJD5BtExkuKmj39VEE0m3l/zipf6h2WIB2jyAO0lI6NGETh4RDcktRm4AQ==", "requires": { "history": "^5.2.0" } }, "react-router-dom": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz", - "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.2.tgz", + "integrity": "sha512-AtYEsAST7bDD4dLSQHDnk/qxWLJdad5t1HFa1qJyUrCeGgEuCSw0VB/27ARbF9Fi/W5598ujvJOm3ujUCVzuYQ==", "requires": { "history": "^5.2.0", - "react-router": "6.2.1" + "react-router": "6.2.2" } }, "react-scripts": { @@ -60799,6 +60877,15 @@ "throttle-debounce": "^3.0.1" } }, + "react-split": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/react-split/-/react-split-2.0.14.tgz", + "integrity": "sha512-bKWydgMgaKTg/2JGQnaJPg51T6dmumTWZppFgEbbY0Fbme0F5TuatAScCLaqommbGQQf/ZT1zaejuPDriscISA==", + "requires": { + "prop-types": "^15.5.7", + "split.js": "^1.6.0" + } + }, "react-syntax-highlighter": { "version": "13.5.3", "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz", @@ -62773,6 +62860,11 @@ "extend-shallow": "^3.0.0" } }, + "split.js": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/split.js/-/split.js-1.6.5.tgz", + "integrity": "sha512-mPTnGCiS/RiuTNsVhCm9De9cCAUsrNFFviRbADdKiiV+Kk8HKp/0fWu7Kr8pi3/yBmsqLFHuXGT9UUZ+CNLwFw==" + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -62812,6 +62904,11 @@ "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz", "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==" }, + "state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" + }, "state-toggle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", diff --git a/package.json b/package.json index c9f195242..ef36c5267 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@EasyDynamics/oscal-react-library", - "version": "0.3.0", + "version": "0.4.0", "author": "EasyDynamics", "license": "MIT", "repository": { @@ -21,6 +21,7 @@ "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.60", "@material-ui/styles": "^4.11.4", + "@monaco-editor/react": "^4.3.1", "@testing-library/dom": "^8.11.3", "@testing-library/jest-dom": "^5.16.2", "@testing-library/react": "^12.1.3", @@ -28,8 +29,9 @@ "prop-types": "^15.8.0", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-router-dom": "^6.2.1", + "react-router-dom": "^6.2.2", "react-scripts": "^5.0.0", + "react-split": "^2.0.14", "web-vitals": "^2.1.2" }, "scripts": { diff --git a/src/components/OSCALCatalog.js b/src/components/OSCALCatalog.js index 367f35d9f..ebfa70f62 100644 --- a/src/components/OSCALCatalog.js +++ b/src/components/OSCALCatalog.js @@ -1,22 +1,13 @@ import React from "react"; -import { makeStyles } from "@material-ui/core/styles"; import List from "@material-ui/core/List"; import ListSubheader from "@material-ui/core/ListSubheader"; +import { useLoaderStyles } from "./OSCALLoaderStyles"; import OSCALMetadata from "./OSCALMetadata"; import OSCALCatalogGroup from "./OSCALCatalogGroup"; import OSCALBackMatter from "./OSCALBackMatter"; -const useStyles = makeStyles((theme) => ({ - paper: { - marginTop: theme.spacing(2), - display: "flex", - flexDirection: "column", - }, -})); - export default function OSCALCatalog(props) { - const classes = useStyles(); - + const classes = useLoaderStyles(); props.onResolutionComplete(); return ( diff --git a/src/components/OSCALComponentDefinition.js b/src/components/OSCALComponentDefinition.js index 2ecba6173..9029803b4 100644 --- a/src/components/OSCALComponentDefinition.js +++ b/src/components/OSCALComponentDefinition.js @@ -1,26 +1,18 @@ import React, { useState, useEffect } from "react"; -import { makeStyles } from "@material-ui/core/styles"; import OSCALMetadata from "./OSCALMetadata"; import OSCALComponentDefinitionControlImplementation from "./OSCALComponentDefinitionControlImplementation"; import OSCALComponentResolveSources from "./oscal-utils/OSCALComponentResolver"; import OSCALComponentDefinitionComponent from "./OSCALComponentDefinitionComponent"; import OSCALBackMatter from "./OSCALBackMatter"; import OSCALProfileCatalogInheritance from "./OSCALProfileCatalogInheritance"; - -const useStyles = makeStyles((theme) => ({ - paper: { - marginTop: theme.spacing(2), - display: "flex", - flexDirection: "column", - }, -})); +import { useLoaderStyles } from "./OSCALLoaderStyles"; export default function OSCALComponentDefinition(props) { const [error, setError] = useState(null); const [isLoaded, setIsLoaded] = useState(false); const [inheritedProfilesAndCatalogs, setInheritedProfilesAndCatalogs] = useState({}); - const classes = useStyles(); + const classes = useLoaderStyles(); useEffect(() => { OSCALComponentResolveSources( diff --git a/src/components/OSCALJsonEditor.js b/src/components/OSCALJsonEditor.js new file mode 100644 index 000000000..f7b2b478d --- /dev/null +++ b/src/components/OSCALJsonEditor.js @@ -0,0 +1,96 @@ +import React, { useRef } from "react"; +import Button from "@material-ui/core/Button"; +import Editor from "@monaco-editor/react"; +import { Grid, makeStyles, Typography } from "@material-ui/core"; +import SaveIcon from "@material-ui/icons/Save"; +import CancelIcon from "@material-ui/icons/Cancel"; + +export default function OSCALJsonEditor(props) { + const useStyles = makeStyles((theme) => ({ + grid: { + paddingRight: theme.spacing(1), + top: theme.spacing(1), + position: "sticky", + overflow: "hidden", + }, + buttonGrid: { + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + }, + editor: { + width: "100%", + }, + })); + const classes = useStyles(); + const editorRef = useRef(props.editorRef); + + const editorOptions = { + minimap: { + enabled: false, + }, + scrollbar: { + verticalHasArrows: true, + }, + tabSize: 2, + }; + + return ( + + + JSON Editor + + + { + editorRef.current = editor; + }} + value={props.value} + defaultLanguage="json" + /> + + + + + + + + + + + + + ); +} diff --git a/src/components/OSCALJsonEditor.test.js b/src/components/OSCALJsonEditor.test.js new file mode 100644 index 000000000..cd5863b28 --- /dev/null +++ b/src/components/OSCALJsonEditor.test.js @@ -0,0 +1,131 @@ +import { React } from "react"; +import { + act, + render, + screen, + waitFor, + fireEvent, + within, +} from "@testing-library/react"; +import OSCALJsonEditor from "./OSCALJsonEditor"; + +const oscalData = { + "component-definition": { + metadata: { + title: "Test Component Definition", + version: "20200723", + "last-modified": "2021-06-08T13:57:28.355446-04:00", + parties: [ + { + type: "organization", + uuid: "ee47836c-877c-4007-bbf3-c9d9bd805a9a", + name: "Test Vendor", + }, + ], + "oscal-version": "1.0.0", + }, + }, +}; +oscalData.oscalSource = JSON.stringify(oscalData, null, "\t"); + +jest.mock( + "@monaco-editor/react", + () => + function Editor(props) { + const fragment = ( +