-
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
UX Change; Move Modification icon to the side of control title #52
Conversation
Changed the react components in OSCALControl.js to render the modification component (OSCALControlModification.js) instead of it being rendered at the top of OSCALControlPart.js This satisfies the UX change specified in EGRC-306.
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 resolve conflicts here first, and check with @kkennedy26 on the check for whether or not to display the modification as mentioned in comments.
src/OSCALControl.js
Outdated
@@ -58,6 +59,26 @@ export default function OSCALControl(props) { | |||
} | |||
const classes = useStyles(props); | |||
|
|||
let modificationDisplay; | |||
if (props.modifications) { | |||
// Finds the control-id within alters and matches it with a resolved control |
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 think all of this has been moved into the OSCALControlModification
component and does not need to be duplicated here.
src/OSCALControlModification.js
Outdated
<Tooltip title="Modifications"> | ||
<Badge | ||
anchorOrigin={{ | ||
vertical: "top", | ||
horizontal: "right", | ||
horizontal: "left", |
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 think this should stay to the right.
OSCALControlPart.js renders the modification icon for each control part. Before, this rendered the icon under the title, which was undesirable as referenced in EGRC-306. OSCALControl.js now renders the icon next to the title, and passes in null as the modifications argument to its top-level control part so that the icon is not rendered in OSCALControlPart.js Also, in OSCALControlModification.js the <div> around the icon was removed so that it would render next to the title.
The const topPart variable in OSCALControl.js was out of place and was causing tests to fail. The line was deleted.
src/OSCALControl.js
Outdated
modificationDisplay = ( | ||
<OSCALControlModification | ||
modifications={props.modifications} | ||
controlPartId={props.control.parts[0].id} |
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 think we want to specify a controlPartId at all here.
src/OSCALControl.js
Outdated
control={props.control} | ||
modifications={index !== 0 && props.modifications} |
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.
What is this change trying to do?
src/OSCALControlModification.js
Outdated
@@ -145,7 +145,7 @@ export default function OSCALControlModification(props) { | |||
// Display if alter or controlPartObject is true | |||
if (alter || controlPartObject) { | |||
modificationsDisplay = ( | |||
<div> | |||
<> |
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 don't need a div can we remove the empty <>
element?
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.
Believe that's the only way to have a component without a div around it
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.
@hreineck I was wondering what removing the <div>
does here? I was just looking over it for suggestions and genuinely didn't know.
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.
div adds a divider between the icon and the text it's supposed to be next to, so I removed it to render in line with the text
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.
Would a <span>
accomplish the same thing?
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 tested it locally, and from what I can see it works.
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.
True. Span would be another way of doing it inline. Maybe that would be more descriptive than the empty <>
src/OSCALControlModification.js
Outdated
); | ||
} else { | ||
modificationsDisplay = null; | ||
} | ||
|
||
return <div>{modificationsDisplay}</div>; | ||
return <>{modificationsDisplay}</>; |
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 the empty <>
element here as well?
if (!parameter) { | ||
return; | ||
} | ||
// TODO parse select parameters | ||
return `< ${parameter.label} >`; | ||
} | ||
|
||
replacedProse = props.prose.replace(/\{\{ insert: param, ([0-9a-zA-B-_.]*) \}\}/g, getParameterLabel); | ||
replacedProse = props.prose.replace( |
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.
Were these types of changes from linter complaints?
Moved the call to OSCALControlModification in OSCALControlParts into the typography component of the replaced prose so that it renders next to the control part. Fixed some issues with rendering the top level control modifications: OSCALControl now correctly passes in its own control id when displaying its modifications. Also some minor cleanup in OSCALControlModification.js These changes modify the UX to satisfy EGRC-306.
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 believe places with empty <>
can be replaced with a <span>
. <div>
is a block level element while <span>
is an inline element.
src/OSCALControl.js
Outdated
<OSCALControlModification | ||
modifications={props.modifications} | ||
controlPartId={props.control.id} | ||
control={props.control} |
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 think this now needs to be controlId
?
Changed OSCALModification to distinguish between top-level modifications and control parts. Some profiles do not include a "by-id" field on top-level modifications; added a check to get around this so that only the control title renders the top-level icon.
@@ -78,8 +90,8 @@ export default function OSCALControl(props) { | |||
parameters={props.control.params} | |||
implReqStatements={props.implReqStatements} | |||
componentId={props.componentId} | |||
modifications={props.modifications} | |||
control={props.control} |
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 can be changed to use the id rather than the entire control now. That would also make check in OSCALControlPart
unneeded.
src/OSCALControlModification.js
Outdated
@@ -122,6 +122,7 @@ export default function OSCALControlModification(props) { | |||
if (alter.adds) { | |||
[addsDisplay, len] = getModifications( | |||
props.controlPartId, | |||
props.controlPartId === props.controlId, |
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.
Would it be cleaner to just pass the controlId
? I feel like that would give us more relevant information later on, for things like debugging, than just a bool
. Either way would probably work
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.
You would just push the check to isRelevantId
where we are already doing logic checking similar to that
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.
Yes, this is what I had done as well, see above comment on isRelevantId
.
src/OSCALControlModification.js
Outdated
@@ -137,7 +138,7 @@ export default function OSCALControlModification(props) { | |||
// Display if altered is true | |||
if (modLength) { | |||
modificationsDisplay = ( | |||
<div> | |||
<span> |
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.
Nice!
src/OSCALControlModification.js
Outdated
@@ -61,11 +61,11 @@ const getAlterAddsOrRemovesDisplay = (addsElements, addsLabel) => { | |||
* @param {String} field Field of Add/Remove element to check | |||
* @returns true if element matches controlID | |||
*/ | |||
const isRelevantId = (controlPartId, element, field) => | |||
const isRelevantId = (controlPartId, element, field, isTopLevel) => |
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.
Changing the documentation to show change in parameters might be good to do now rather than figure it out in documentation issue. Same for getModifications
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.
Let's instead send in the controlId
(maybe as the first argument) and a null controlPartId
when calling from a top-level control, and yes, let's update the docs.
src/OSCALControlModification.js
Outdated
@@ -61,11 +61,11 @@ const getAlterAddsOrRemovesDisplay = (addsElements, addsLabel) => { | |||
* @param {String} field Field of Add/Remove element to check | |||
* @returns true if element matches controlID | |||
*/ | |||
const isRelevantId = (controlPartId, element, field) => | |||
const isRelevantId = (controlPartId, element, field, isTopLevel) => |
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.
Let's instead send in the controlId
(maybe as the first argument) and a null controlPartId
when calling from a top-level control, and yes, let's update the docs.
src/OSCALControlModification.js
Outdated
@@ -122,6 +122,7 @@ export default function OSCALControlModification(props) { | |||
if (alter.adds) { | |||
[addsDisplay, len] = getModifications( | |||
props.controlPartId, | |||
props.controlPartId === props.controlId, |
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.
Yes, this is what I had done as well, see above comment on isRelevantId
.
Removed the redundant props passed into OSCALModification from OSCALControl Changed the structure of the isRelevantId function to be more self-describing Updated function docs
@@ -69,7 +80,7 @@ export default function OSCALControl(props) { | |||
className={classes.OSCALControlChildLevelTitle} | |||
> | |||
<span className={classes.OSCALControlId}>{props.control.id}</span>{" "} | |||
{props.control.title} | |||
{props.control.title} {modificationDisplay} |
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.
What happens if (!props.modifications)
above and therefore and modificationDisplay == undefined
? Not reviewing, just asking a React question. Does it just not render this bit?
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 should just not render anything
src/OSCALControlModification.js
Outdated
// TODO: Differences in how NIST and FedRAMP implement adds makes | ||
// this check needed. See if we can clean this up at some point. | ||
// Assumes the difference is that NIST does not have a "control-id" field | ||
!element[field] || element[field] === controlPartId; | ||
// Assumes the difference is that NIST does not have a "by-id" field |
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 doesn't really make that assumption does it? It allows callers to make that assumption? Basically, the old comment was incorrect as well right? Can we remove it?
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 think more accurately there should be a comment where we call this check with"by-id" as an argument
src/OSCALControlModification.js
Outdated
); | ||
} else { | ||
modificationsDisplay = null; | ||
} | ||
|
||
return <div>{modificationsDisplay}</div>; | ||
return modificationsDisplay; |
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.
With the removal of the <div>
you, can now just return directly in the if
above without having to keep this extra mutable var.
if (!modLength) {
return null;
}
return (
<span>...
src/OSCALControlModification.js
Outdated
(!element[field] && controlPartId === controlId) || | ||
element[field] === controlPartId; |
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.
Now I feel guilty for having helped shorten this earlier as the number of variables and conditions begins to grow. I am losing understanding of the implementation here. Could we do something like:
const nistCheck = (controlPartId, controlId, element, field) => ...
const fedrampCheck = (controlPartId, controlId, element, field) => ...
return nistCheck(...) || fedrampCheck(...)
or even just some well-written if
statements with early returns that are well commented.
It sounds like each of them defines things in a certain way. But we talk a lot about how we have to do this check because they're different. And then we lose all sight of how they differ in the implementation. But we also want to do something extensible because if NIST and FedRAMP differ here, then is it possible for Agency C to come along and do it differently 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.
These variations aren't specific to NIST or FedRAMP, just different ways to represent control modifications in the OSCAL spec, so I don't think we want to start naming methods around their implementations.
I'm fine with splitting things out into separate conditionals for better readability if need be though.
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.
So are these the only ways to express the control modifications? Or would there be others? If these two are the only ways we're going to have to do it, then yeah, separate conditionals explaining would make sense. But the surrounding comments right now are very name-focused (NIST & FedRAMP) and not data structure focused (how it relates to the spec) so that was the idea behind using the names.
But I think the fact there's ambiguity there at all with the comments and complexity of the expression is a good indication we should try to clean it up at some point. @hreineck if there's a good way to clean this up during this PR that doesn't creep the scope of what you're actually working on, that'd be cool to see but I want to make sure I am not asking for something beyond what you're already doing.
I would like to see Kyle's reccomendations considered
Edited comments in OSCALControlModification.js to more accurately explain the isRelevantID check, which is needed for different ways to represent control modifications in OSCAL. Cleaned up the modification React component; removed an uncessesary variable.
Thanks @hreineck for the changes! Good stuff! |
Changed the react components in OSCALControl.js to render the modification component (OSCALControlModification.js)
instead of it being rendered at the top of OSCALControlPart.js
This satisfies the UX change specified in EGRC-306.