-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Show profile and catalog inheritance #186
Conversation
Display the tree of inherited profiles and catalogs for any profile json document in the Profile viewer.
Display the tree of inherited profiles and catalogs for any component definition json document in the Component Viewer. Add rule to linting json file that forces the linter to allow the reassignment of function parameters.
Display the tree on inherited profiles and catalogs for any SSP json document in the SSP Viewer. Remove the original document title from being displayed in the inherited profiles and catalogs.
Identify whether an inherited profile or catalog is a profile or catalog, making it easy to identify the document type.
Change the collapse icon to ExpandLess to use an icon more representative of the action taken. Use IconButton in order to give labels to the icons, which is important for testing purposes.
Create tests for the newly added react component to ensure it functions as expected.
Remove subtracting one from the id array so icon ids are the same as the node id.
.eslintrc.json
Outdated
@@ -25,7 +25,8 @@ | |||
"react/prop-types": [0], | |||
"react/destructuring-assignment": [0], | |||
"react/jsx-props-no-spreading": "off", | |||
"prettier/prettier": "error" | |||
"prettier/prettier": "error", | |||
"no-param-reassign": 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love the addition of this. Why don't we just use a different name for the variable inside the function rather than reusing a parameter name? Shadowing variables is always a little iffy.
Remove the no-param-reassign linting rule as we do not want to shadow variables.
Here are some of the other options for the expand/collapse icons. Just wanted to put them here in case anyone thought one of these could be better than the ones currently used. Expand icon: Add, ControlPoint, MoreHoriz, MoreVert, UnfoldMore, ExpandMore Collapse icon: Remove, Unfold Less, ExpandLess, Close, Cancel, HighlightOff, Remove You can easily view these visually here by searching for the above icons in the search box. |
return null; | ||
} | ||
|
||
const generateLabel = (title, type) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be pulled out of renderTree
?
<TreeItem | ||
nodeId={idReassign[0].toString()} | ||
label={generateLabel(node.title, node.type)} | ||
expandIcon={ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just the the defaults on TreeView
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I chose not to because if we use the TreeView
default icon properties, then all icons will have the same value for the aria-label
property. That won't go well for testing purposes so if we want to be able to test the expansion and collapse of the tree, then we can't use the TreeView
defaults. If we don't care about that, then the defaults are fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we don't want to be required to rely on aria labels, instead taking an approach of finding the expected text then the closest button.
As mentioned elsewhere on this PR, we also want the tree to be expanded by default, so I'm not sure will need to test clicking on these at all.
|
||
test("OSCALProfileCatalogInheritance displays nested inherited objects", async () => { | ||
profileCatalogInheritanceRenderer(); | ||
const inheritanceButton = await screen.findByRole( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want all nodes in the tree expanded by default so this may not be needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like it would make sense to at least test the expansion and collapse of the tree to ensure everything works and is displayed as expected in both cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this test can be rewritten once everything is expanded by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, that's fine.
@@ -27,17 +27,19 @@ import getUriFromBackMatterByHref from "./OSCALBackMatterUtils"; | |||
* @see {@link https://pages.nist.gov/OSCAL/documentation/schema/profile-layer/profile/xml-schema/#global_import} | |||
* @see {@link https://pages.nist.gov/OSCAL/documentation/schema/profile-layer/profile/xml-schema/#global_back-matter_h2} | |||
*/ | |||
export default function OSCALResolveProfileOrCatalogUrlControls( | |||
export default async function OSCALResolveProfileOrCatalogUrlControls( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we're introducing asyncs and awaits for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was some issue when I was first doing the task that async
/await
seemed to resolve. It isn't needed I just forgot to remove them from the code.
id[0] += 1; | ||
idReassign[0] += 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not really short on characters here. How about inheritedNodeId
or just nodeId
to give it a more descriptive name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thought here would be to add the UUID of the OSCAL document to the inheritance object, but we also talk about the possibility of using default icons at the TreeView
level, so this ID may not be needed at all.
Add second React component, one for the TreeView that displays the inherited profiles and catalogs, so the defaultExpanded prop of TreeView works as expected, allowing us to see the expanded tree by default and collapse the expanded tree as desired. TreeView has an expanded prop that doesn't require a second React component but that doesn't allow for the collapse of TreeView nodes. Clean up component, testing, and other files to remove code that was not necessary and rename functions and variables to improve readability.
Remove async/await, as they are not needed and do not impact the result.
Test that nested profiles/catalogs will be displayed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Both the Viewer and Storybook are working locally for me.
Just a few small changes/questions.
setInheritedProfilesAndCatalogs( | ||
OSCALComponentResolveSources( | ||
props.componentDefinition, | ||
props.parentUrl, | ||
() => { | ||
setIsLoaded(true); | ||
props.onResolutionComplete(); | ||
}, | ||
(errorReturned) => { | ||
setError(errorReturned); | ||
setIsLoaded(true); | ||
props.onResolutionComplete(); | ||
} | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting a bit convoluted. Instead of having a method that takes in the return of the existing OSCALComponentResolveSources
method, could we have an overall "resolve" wrapper method like the other OSCAL types do?
import ListSubheader from "@material-ui/core/ListSubheader"; | ||
|
||
export default function OSCALProfileCatalogInheritanceTree(props) { | ||
const tree = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the const
necessary? Why not just return
this object?
<ExpandLessIcon /> | ||
</IconButton> | ||
} | ||
defaultExpanded={props.validIds} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just putting this out here - is the ability to actually collapse the tree necessary? If it makes things simpler to have it permanently expanded that could work as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that it's absolutely necessary but if we can allow users to collapse the tree we should provide it as it's something, albeit small, that could improve user experience.
Remove intialization and use of a variable that was not needed. Remove return from a function and instead pass in a function that sets a state variable so a component will rerender.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work!
|
||
export default function OSCALProfileCatalogInheritance(props) { | ||
const classes = useStyles(); | ||
const [validIds, setValidIds] = useState([false, []]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need all of these instances of IDs separately rather than just using the UUID already in the inherited objects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to ensure each nodeId in the tree is unique? We could have the same profile or catalog in different parts of the tree which could cause repeated nodeIds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're setting node IDs and keys we do want them to be unique.
Are we sure we need useState
here?
I'd also recommend changing these to something like expandedIds
everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need useState
so when we set the expanded ids, we re-render the component. If we do not re-render, the tree will not be expanded by default.
|
||
export default function OSCALProfileCatalogInheritance(props) { | ||
const classes = useStyles(); | ||
const [validIds, setValidIds] = useState([false, []]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're setting node IDs and keys we do want them to be unique.
Are we sure we need useState
here?
I'd also recommend changing these to something like expandedIds
everywhere.
Remove the second react component that was created, as it was not needed and we want to avoid creating additional, unnecessary components.
Rename variable to make code more readable.
Relocate call of setInheritedProfilesAndCatalogs to within onSuccess and remove that parameter from util resolver functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two minor rendering changes:
- I think the tree needs more of a left margin. The expand arrow currently bumps up against the card edge.
- The header is sticky rather than scrolling with the page
Create a left margin for the tree so the expand and collapse icons do not brush against the edge. Make the header scroll with the page instead of being sticky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thanks for working through all the changes.
Create a react component,
OSCALProfileCatalogInheritance
, which displays the tree of inherited profiles and catalogs for any Component Definition, Profile, or SSP. This allows us to view that inheritance tree, providing users greater insight into which profiles and catalogs were used in the creation of a given OSCAL document.Additionally created a storybook page for the new component so any developer can view how it looks and functions and potentially reuse it in their code.
closes #161