Skip to content
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

Security UI Fixes #233

Merged
merged 8 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions app/src/components/security/SecuritiesDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,7 @@ const SecuritiesDialog = (props: ISecuritiesDialogProps) => {
dialogContext.setSnackbar({
snackbarMessage: (
<Typography variant="body2" component="div">
{ApplySecurityRulesI18N.applySecuritySuccess(
patch.stagedForApply.length,
patch.stagedForRemove.length,
props.submissionFeatureIds.length
)}
{ApplySecurityRulesI18N.applySecuritySuccess(props.submissionFeatureIds.length)}
</Typography>
),
open: true
Expand All @@ -61,7 +57,7 @@ const SecuritiesDialog = (props: ISecuritiesDialogProps) => {
return (
<EditDialog<IPatchFeatureSecurityRules>
isLoading={isLoading}
dialogTitle={hasSecurity ? 'Edit Security Reasons' : ' Add Security Reasons'}
dialogTitle={hasSecurity ? 'Edit Security' : ' Add Security'}
open={props.open}
dialogSaveButtonLabel="APPLY"
onCancel={props.onClose}
Expand Down
13 changes: 10 additions & 3 deletions app/src/components/security/SecurityRuleActionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@
variant="outlined"
sx={{
display: 'flex',
px: 2,
py: 1.5,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
p: 2,
background: grey[100]
}}>
<SecurityRuleCard {...rest} />
Expand All @@ -30,7 +29,15 @@
<Icon path={mdiClose} size={1} />
</IconButton>
) : (
<Button variant={props.action === 'remove' ? 'contained' : 'outlined'} color="error" onClick={() => onRemove()}>
<Button
variant={props.action === 'remove' ? 'contained' : 'outlined'}
color="error"
sx={{
width: '6rem',
fontWeight: 700,
letterSpacing: '0.02rem'
}}
onClick={() => onRemove()}>

Check warning on line 40 in app/src/components/security/SecurityRuleActionCard.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleActionCard.tsx#L40

Added line #L40 was not covered by tests
Remove
</Button>
)}
Expand Down
67 changes: 34 additions & 33 deletions app/src/components/security/SecurityRuleCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Box, Typography } from '@mui/material';
import { Stack } from '@mui/system';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';

export interface ISecurityRuleCardProps {
key?: string | number;
Expand All @@ -11,46 +11,47 @@

const SecurityRuleCard = (props: ISecurityRuleCardProps) => {
return (
<Box>
<Typography variant="body2" color="textSecondary">
<Stack gap={0.75} mt={-0.25}>
<Typography variant="body2" component="div" color="textSecondary" textTransform="uppercase">
{props.category}
</Typography>
<Typography
variant="body1"
fontWeight={700}
gutterBottom
sx={{
display: '-webkit-box',
WebkitLineClamp: '2',
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
textOverflow: 'ellipsis'
}}>
{props.title}
</Typography>
<Typography
variant="body2"
color="textSecondary"
sx={{
display: '-webkit-box',
maxWidth: '92ch',
WebkitLineClamp: '2',
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
textOverflow: 'ellipsis'
}}>
{props.description}
</Typography>
<Stack>
<Typography
variant="body1"
fontWeight={700}
sx={{
display: '-webkit-box',
WebkitLineClamp: '2',
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
textOverflow: 'ellipsis'
}}>
{props.title}
</Typography>
<Typography
variant="body1"
color="textSecondary"
sx={{
display: '-webkit-box',
maxWidth: '92ch',
WebkitLineClamp: '2',
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
textOverflow: 'ellipsis'
}}>
{props.description}
</Typography>
</Stack>
{props.featureMembers && props.featureMembers?.length && (
<Stack component="ul" mt={1} pl={0} mb={0} display="flex" flexDirection="row" gap={2}>
<Stack component="ul" flexDirection="row" gap={2} mt={0.75} mb={0} p={0}>
{props.featureMembers.map((featureMember) => (
<Typography variant="body2" color="textSecondary" sx={{ display: 'block' }} component="li">
<Typography component="li" variant="body2" color="textSecondary" fontWeight={700} sx={{ display: 'block' }}>

Check warning on line 48 in app/src/components/security/SecurityRuleCard.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleCard.tsx#L48

Added line #L48 was not covered by tests
{featureMember}
</Typography>
))}
</Stack>
)}
</Box>
</Stack>
);
};

Expand Down
233 changes: 113 additions & 120 deletions app/src/components/security/SecurityRuleForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
return ruleGroups;
}, [])
);
}, [initialAppliedSecurityRules, submissionFeatureGroupsDataLoader.data]);

Check warning on line 100 in app/src/components/security/SecurityRuleForm.tsx

View workflow job for this annotation

GitHub Actions / Running Linter and Formatter

React Hook useMemo has missing dependencies: 'allSecurityRules' and 'formikProps.initialValues.submissionFeatureIds'. Either include them or remove the dependency array

const toggleStageApply = (securityRule: ISecurityRuleAndCategory) => {
if (
Expand Down Expand Up @@ -137,95 +137,85 @@

return (
<form onSubmit={formikProps.handleSubmit}>
<Box component="fieldset">
<Typography
variant="body1"
color="textSecondary"
sx={{
maxWidth: '72ch'
}}>
Specify reasons why this information should be secured.
<Box component="fieldset" mt={1}>
<Typography component="legend">Secure Records</Typography>
<Typography variant="body1" color="textSecondary" sx={{ mt: -1, mb: 3 }}>
Secure records by adding one or more security rules.
</Typography>
<Autocomplete
value={null}
id={'autocomplete-security-rule-search'}
data-testid={'autocomplete-security-rule-search'}
filterSelectedOptions
clearOnBlur
loading={submissionContext.allSecurityRulesStaticListDataLoader.isLoading}
noOptionsText="No records found"
options={applyRulesAvailableSortedOptions}
filterOptions={(options, state) => {
const searchFilter = createFilterOptions<ISecurityRuleAndCategory>({

Check warning on line 155 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L155

Added line #L155 was not covered by tests
ignoreCase: true,
matchFrom: 'any',
stringify: (option) => option.name + option.category_name

Check warning on line 158 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L158

Added line #L158 was not covered by tests
});

<Box mt={3}>
<Box mb={2}>
<Typography component="legend">Add Security Rules</Typography>
</Box>
<Autocomplete
value={null}
id={'autocomplete-security-rule-search'}
data-testid={'autocomplete-security-rule-search'}
filterSelectedOptions
clearOnBlur
loading={submissionContext.allSecurityRulesStaticListDataLoader.isLoading}
noOptionsText="No records found"
options={applyRulesAvailableSortedOptions}
filterOptions={(options, state) => {
const searchFilter = createFilterOptions<ISecurityRuleAndCategory>({
ignoreCase: true,
matchFrom: 'any',
stringify: (option) => option.name + option.category_name
});

const selectableOptions = options.filter((securityRule) => {
return !formikProps.values.stagedForApply.some(
(applyingRule) => applyingRule.security_rule_id === securityRule.security_rule_id
);
});

return searchFilter(selectableOptions, state);
}}
getOptionLabel={(option) => option.name}
isOptionEqualToValue={(option, value) => option.security_rule_id === value.security_rule_id}
inputValue={searchText}
onInputChange={(_, value, reason) => {
if (reason === 'reset') {
setSearchText('');
} else {
setSearchText(value);
}
}}
onChange={(_, option) => {
if (option) {
toggleStageApply(option);
}
}}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
placeholder={'Add security reasons'}
fullWidth
InputProps={{
...params.InputProps,
startAdornment: (
<Box mx={1} mt="6px">
<Icon path={mdiMagnify} size={1}></Icon>
</Box>
)
}}
/>
)}
renderOption={(renderProps, renderOption) => {
return (
<ListItem
divider
sx={{
px: 2,
py: '12px !important'
}}
{...renderProps}>
<SecurityRuleCard
title={renderOption.name}
category={renderOption.category_name}
description={renderOption.description}
/>
</ListItem>
const selectableOptions = options.filter((securityRule) => {
return !formikProps.values.stagedForApply.some(
(applyingRule) => applyingRule.security_rule_id === securityRule.security_rule_id

Check warning on line 163 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L161-L163

Added lines #L161 - L163 were not covered by tests
);
}}
/>
</Box>
});

return searchFilter(selectableOptions, state);

Check warning on line 167 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L167

Added line #L167 was not covered by tests
}}
getOptionLabel={(option) => option.name}
isOptionEqualToValue={(option, value) => option.security_rule_id === value.security_rule_id}

Check warning on line 170 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L169-L170

Added lines #L169 - L170 were not covered by tests
inputValue={searchText}
onInputChange={(_, value, reason) => {
if (reason === 'reset') {
setSearchText('');

Check warning on line 174 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L174

Added line #L174 was not covered by tests
} else {
setSearchText(value);

Check warning on line 176 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L176

Added line #L176 was not covered by tests
}
}}
onChange={(_, option) => {
if (option) {
toggleStageApply(option);

Check warning on line 181 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L181

Added line #L181 was not covered by tests
}
}}
renderInput={(params) => (
<TextField

Check warning on line 185 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L185

Added line #L185 was not covered by tests
{...params}
variant="outlined"
placeholder={'Add security rules'}
fullWidth
InputProps={{
...params.InputProps,
startAdornment: (
<Box mx={1} mt="6px">
<Icon path={mdiMagnify} size={1}></Icon>
</Box>
)
}}
/>
)}
renderOption={(renderProps, renderOption) => {
return (

Check warning on line 201 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L201

Added line #L201 was not covered by tests
<ListItem
disablePadding
divider
sx={{
py: '12px !important',
px: 2
}}
{...renderProps}>
<SecurityRuleCard
title={renderOption.name}
category={renderOption.category_name}
description={renderOption.description}
/>
</ListItem>
);
}}
/>
<Stack component={TransitionGroup} gap={1} my={1}>
{formikProps.values.stagedForApply.map((applyingRule) => {
return (
Expand All @@ -241,43 +231,46 @@
);
})}
</Stack>
</Box>
<Box component="fieldset" mt={2}>
<Typography component="legend">Secured Records</Typography>

<Box my={2}>
<Typography component="legend">Manage Existing Security</Typography>
<Typography variant="body2">
These rules have already been applied to one or more of the selected features.
</Typography>
</Box>
<Stack component={TransitionGroup} gap={1}>
{groupedAppliedSecurityRules.map((group: IAppliedSecurityRuleGroup) => {
const cardAction = formikProps.values.stagedForRemove.some(
(removingRule) => removingRule.security_rule_id === group.securityRule.security_rule_id
)
? 'remove'
: 'persist';

return (
<Collapse key={group.securityRule.security_rule_id}>
<SecurityRuleActionCard
action={cardAction}
title={group.securityRule.name}
category={group.securityRule.category_name}
description={group.securityRule.description}
featureMembers={group.appliedFeatureGroups.map(
(featureGroup) =>
`${p(featureGroup.numFeatures, featureGroup.displayName)} (${featureGroup.numFeatures})`
)}
onRemove={() => toggleStageRemove(group.securityRule)}
/>
</Collapse>
);
})}
</Stack>
{hasNoSecuritySelected && (
<Alert severity="error" sx={{ marginTop: 1 }}>
<AlertTitle>Open access to all records</AlertTitle>
All users will have unrestricted access to records that have been included in this submission.
{hasNoSecuritySelected ? (
<Alert severity="error">

Check warning on line 239 in app/src/components/security/SecurityRuleForm.tsx

View workflow job for this annotation

GitHub Actions / Running Linter and Formatter

Delete `·`
<AlertTitle>No security applied</AlertTitle>
All users will have unrestricted access to selected records.
</Alert>
) : (

Check warning on line 243 in app/src/components/security/SecurityRuleForm.tsx

View workflow job for this annotation

GitHub Actions / Running Linter and Formatter

Delete `··`
<>

Check warning on line 244 in app/src/components/security/SecurityRuleForm.tsx

View workflow job for this annotation

GitHub Actions / Running Linter and Formatter

Delete `··`
<Typography variant="body1" color="textSecondary" sx={{ mt: -1 }}>
Some of the selected records have been secured using the following rules.
</Typography>
<Stack component={TransitionGroup} gap={1} mt={3}>
{groupedAppliedSecurityRules.map((group: IAppliedSecurityRuleGroup) => {
const cardAction = formikProps.values.stagedForRemove.some(
(removingRule) => removingRule.security_rule_id === group.securityRule.security_rule_id

Check warning on line 251 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L251

Added line #L251 was not covered by tests
)
? 'remove'
: 'persist';

return (

Check warning on line 256 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L256

Added line #L256 was not covered by tests
<Collapse key={group.securityRule.security_rule_id}>
<SecurityRuleActionCard
action={cardAction}
title={group.securityRule.name}
category={group.securityRule.category_name}
description={group.securityRule.description}
featureMembers={group.appliedFeatureGroups.map(
(featureGroup) =>
`${p(featureGroup.numFeatures, featureGroup.displayName)} (${featureGroup.numFeatures})`

Check warning on line 265 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L265

Added line #L265 was not covered by tests
)}
onRemove={() => toggleStageRemove(group.securityRule)}

Check warning on line 267 in app/src/components/security/SecurityRuleForm.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/security/SecurityRuleForm.tsx#L267

Added line #L267 was not covered by tests
/>
</Collapse>
);
})}
</Stack>
</>

Check warning on line 273 in app/src/components/security/SecurityRuleForm.tsx

View workflow job for this annotation

GitHub Actions / Running Linter and Formatter

Delete `··`
)}
</Box>
</form>
Expand Down
Loading
Loading