Merge pull request #714 from theseyi/compliance-dataset-field-split

updates notification confirm dialog. splits dataset field level quest…
This commit is contained in:
Seyi Adebajo 2017-08-30 10:23:42 -07:00 committed by GitHub
commit 364af9c4b9
8 changed files with 221 additions and 61 deletions

View File

@ -142,13 +142,63 @@ export default Component.extend({
* Flag indicating that the component is in edit mode
* @type {String}
*/
isEditing: false,
isEditing: computed('isNewComplianceInfo', 'isEditingDatasetClassification', 'isEditingCompliancePolicy', function() {
const { isNewComplianceInfo, isEditingDatasetClassification, isEditingCompliancePolicy } = getProperties(
this,
'isNewComplianceInfo',
'isEditingDatasetClassification',
'isEditingCompliancePolicy'
);
return isNewComplianceInfo || isEditingDatasetClassification || isEditingCompliancePolicy;
}),
/**
* Convenience flag indicating the policy is not currently being edited
* @type {Ember.computed}
* @return {boolean}
*/
isReadOnly: computed.not('isEditing'),
/**
* Flag indicating that the component is currently saving / attempting to save the privacy policy
* @type {String}
*/
isSaving: false,
/**
* Determines if the the compliance policy update form should be shown
* @type {Ember.computed}
* @return {boolean}
*/
isShowingComplianceEditMode: computed('isNewComplianceInfo', 'isEditingCompliancePolicy', function() {
const { isNewComplianceInfo, isEditingCompliancePolicy, isEditingDatasetClassification } = getProperties(
this,
'isNewComplianceInfo',
'isEditingCompliancePolicy',
'isEditingDatasetClassification'
);
return (isNewComplianceInfo || isEditingCompliancePolicy) && !isEditingDatasetClassification;
}),
/**
* Proxy to the check if the dataset classification form is being edited and should be shown
* @type {Ember.computed}
* @return {boolean}
*/
isShowingDatasetClassificationEditMode: computed.bool('isEditingDatasetClassification'),
datasetComplianceSteps: computed('isEditingCompliancePolicy', 'isEditingDatasetClassification', function() {
const { isEditingCompliancePolicy, isEditingDatasetClassification } = getProperties(
this,
'isEditingCompliancePolicy',
'isEditingDatasetClassification'
);
return [isEditingCompliancePolicy, isEditingDatasetClassification].map((_step, index) => ({
done: !index ? !!isEditingDatasetClassification : false
}));
}),
/**
* Reference to the application notifications Service
* @type {Ember.Service}
@ -156,9 +206,7 @@ export default Component.extend({
notifications: service(),
didReceiveAttrs() {
this._super(...arguments);
// If a compliance policy does not exist for this dataset, place it in edit mode by default
set(this, 'isEditing', get(this, 'isNewComplianceInfo'));
this._super(...Array.from(arguments));
// Perform validation step on the received component attributes
this.validateAttrs();
},
@ -593,7 +641,7 @@ export default Component.extend({
{ formatted: [], unformatted: [] }
);
const actions = {};
const dialogActions = {};
let isConfirmed = true;
let unformattedComplianceEntities = [];
@ -608,8 +656,8 @@ export default Component.extend({
const confirmHandler = (function() {
return new Promise((resolve, reject) => {
actions['didConfirm'] = () => resolve();
actions['didDismiss'] = () => reject();
dialogActions['didConfirm'] = () => resolve();
dialogActions['didDismiss'] = () => reject();
});
})();
@ -620,7 +668,7 @@ export default Component.extend({
`There are ${unformatted.length} non-ID fields that have no field format specified. ` +
`Are you sure they don't contain any of the following PII?\n\n` +
`Name, Email, Phone, Address, Location, IP Address, Payment Info, Password, National ID, Device ID etc.`,
dialogActions: actions
dialogActions: dialogActions
});
try {
@ -683,10 +731,24 @@ export default Component.extend({
/**
* Sets each datasetClassification value as false
*/
markDatasetAsNotContainingMemberData() {
const willMarkAllAsNo = confirm(
'Are you sure that any this dataset does not contain any of the listed types of member data'
);
async markDatasetAsNotContainingMemberData() {
const dialogActions = {};
const confirmMarkAllHandler = new Promise((resolve, reject) => {
dialogActions.didDismiss = () => reject();
dialogActions.didConfirm = () => resolve();
});
let willMarkAllAsNo = true;
get(this, 'notifications').notify('confirm', {
content: 'Are you sure that any this dataset does not contain any of the listed types of member data',
dialogActions
});
try {
await confirmMarkAllHandler;
} catch (e) {
willMarkAllAsNo = false;
}
return (
willMarkAllAsNo &&
@ -708,10 +770,24 @@ export default Component.extend({
},
/**
* Handle the user intent to place this compliance component in edit mode
* Handler for setting the compliance policy into edit mode and rendering
*/
onEdit() {
set(this, 'isEditing', true);
onEditCompliancePolicy() {
setProperties(this, { isEditingCompliancePolicy: true, isEditingDatasetClassification: false });
},
/**
* Handler for setting the dataset classification into edit mode and rendering into DOM
*/
async onEditDatasetClassification() {
const isConfirmed = await this.confirmUnformattedFields();
// If user provides confirmation for unformatted fields or there are none,
// then validate fields against expectations
// otherwise inform user of validation exception
if (isConfirmed) {
setProperties(this, { isEditingCompliancePolicy: false, isEditingDatasetClassification: true });
}
},
/**
@ -847,29 +923,22 @@ export default Component.extend({
*/
async saveCompliance() {
const setSaveFlag = (flag = false) => set(this, 'isSaving', flag);
// If fields are confirmed as unique we can proceed with saving compliance entities
const saveConfirmed = await this.confirmUnformattedFields();
// If user provides confirmation for unformatted fields or there are none,
// then validate fields against expectations
// otherwise inform user of validation exception
if (saveConfirmed) {
try {
const isSaving = true;
const onSave = get(this, 'onSave');
setSaveFlag(isSaving);
await this.validateFields();
try {
const isSaving = true;
const onSave = get(this, 'onSave');
setSaveFlag(isSaving);
await this.validateFields();
return await this.whenRequestCompletes(onSave(), { isSaving });
} catch (e) {
// Flag this dataset's data as problematic
if (e instanceof Error && e.message === complianceDataException) {
set(this, '_hasBadData', true);
window.scrollTo(0, 0);
}
} finally {
setSaveFlag();
return await this.whenRequestCompletes(onSave(), { isSaving });
} catch (e) {
// Flag this dataset's data as problematic
if (e instanceof Error && e.message === complianceDataException) {
set(this, '_hasBadData', true);
window.scrollTo(0, 0);
}
} finally {
setSaveFlag();
}
},

View File

@ -2,3 +2,4 @@
@import "compliance-prompts";
@import "compliance-table";
@import "compliance-auto-suggester-action";
@import "dataset-compliance-step";

View File

@ -8,4 +8,8 @@
&__notification-column {
width: 5%
}
&__classification-column {
width: 17%;
}
}

View File

@ -0,0 +1,51 @@
/// Specifies the width x height for the circle
$dataset-compliance-step-circle-size: 30px;
/// Specifies the base color for the step indicator
$dataset-compliance-step-color-base: set-color(grey, mid);
/// Specifies the completion color for the step indicator
$dataset-compliance-step-color-complete: set-color(blue, blue5);
/// Defines rules for the dataset compliance step indicator
/// A circle containing the step number, with a separating dash between successive steps
.dataset-compliance-step {
display: inline-flex;
justify-content: center;
align-items: center;
font-weight: fw(normal, 4);
height: $dataset-compliance-step-circle-size;
width: $dataset-compliance-step-circle-size;
color: $dataset-compliance-step-color-base;
background-color: set-color(white, base);
border: 2px solid $dataset-compliance-step-color-base;
border-radius: 50%;
&--complete {
color: transparent;
border-color: $dataset-compliance-step-color-complete;
&::after {
content: '\f00c';
font-family: $font-awesome-stack;
color: $dataset-compliance-step-color-complete;
margin-left: -5px;
}
}
& + & {
margin-left: item-spacing(5);
overflow: visible;
&::before {
content: "";
width: 16px;
margin-left: -28px;
border: 1px solid $dataset-compliance-step-color-base;
position: absolute;
}
}
}
/// Sets the styles for a wrapping container
.dataset-compliance-step-container {
margin: item-spacing(4) 0;
}

View File

@ -15,7 +15,7 @@
&__header,
&__content,
&__footer {
padding: item-spacing(2 4);
padding: item-spacing(4 4);
}
&__header {
@ -24,6 +24,9 @@
&__heading-text {
margin-top: 0;
font-weight:fw(normal, 4);
font-size: 24px;
color: set-color(grey, dark);
}
&__footer {

View File

@ -14,30 +14,45 @@
{{else}}
<section class="action-bar">
{{#if isEditing}}
{{#if _message}}
<div class="alert alert-{{_alertType}} post-action-notification action-footer-notification" role="alert">
{{_message}}
</div>
{{/if}}
<div class="container action-bar__content">
<button
class="nacho-button nacho-button--large-inverse action-bar__item"
title={{unless isDatasetFullyClassified
"Ensure you have provided a yes/no value for all dataset tags"
"Save"}}
disabled={{isSavingDisabled}}
{{action "saveCompliance"}}>
Save
</button>
{{#if isShowingComplianceEditMode}}
<button
class="nacho-button nacho-button--large-inverse action-bar__item"
title="Next"
{{action "onEditDatasetClassification"}}>
Next
</button>
{{/if}}
<button class="nacho-button nacho-button--large action-bar__item"
{{action "resetCompliance"}}>
<i class="fa fa-times" title="Cancel">
</i>
Cancel
</button>
{{#if isShowingDatasetClassificationEditMode}}
<button
class="nacho-button nacho-button--large-inverse action-bar__item"
title={{unless isDatasetFullyClassified
"Ensure you have provided a yes/no value for all dataset tags"
"Save"}}
disabled={{isSavingDisabled}}
{{action "saveCompliance"}}>
Save
</button>
<button
class="nacho-button--large nacho-button--secondary action-bar__item"
title="Back"
{{action "onEditCompliancePolicy"}}>
Back
</button>
{{#if _message}}
<div class="alert alert-{{_alertType}} post-action-notification action-footer-notification" role="alert">
{{_message}}
</div>
{{/if}}
</div>
{{/if}}
</section>
{{/if}}
@ -52,8 +67,9 @@
</div>
{{#unless isEditing}}
<button
{{action "onEdit"}}
{{action "onEditCompliancePolicy"}}
class="nacho-button--large nacho-button--secondary secondary-actions__action">
Edit
</button>
@ -65,16 +81,27 @@
Download compliance metadata
</button>
{{/unless}}
{{/unless}}
</div>
{{#if (and isEditing (not _hasBadData))}}
{{#if isEditing}}
<div class="dataset-compliance-step-container">
{{partial "datasets/dataset-compliance/-dataset-compliance-step-indicator"}}
</div>
{{/if}}
{{#if (and isShowingComplianceEditMode (not _hasBadData))}}
{{json-upload receiveJsonFile=(action "onComplianceJsonUpload") class="secondary-actions__action"}}
{{/if}}
{{partial "datasets/dataset-compliance/dataset-classification"}}
{{#if (or isReadOnly isShowingDatasetClassificationEditMode)}}
{{partial "datasets/dataset-compliance/dataset-classification"}}
{{/if}}
{{partial "datasets/dataset-compliance/dataset-compliance-entities"}}
{{#if (or isReadOnly isShowingComplianceEditMode)}}
{{partial "datasets/dataset-compliance/dataset-compliance-entities"}}
{{/if}}
</div>
{{yield}}

View File

@ -39,7 +39,7 @@
value="{{table.searchTerm}}"
oninput={{action table.filterDidChange value="target.value"}}>
{{#if hasRecentSuggestions}}
{{#if (and hasRecentSuggestions (not isNewComplianceInfo))}}
<span class="dataset-compliance-fields__has-suggestions">
{{complianceSuggestion.complianceSuggestions.length}} fields to be reviewed
</span>
@ -79,7 +79,7 @@
</sup>
</a>
{{/head.column}}
{{#head.column class="nacho-table-cell-wrapped"}}
{{#head.column class="nacho-table-cell-wrapped dataset-compliance-fields__classification-column"}}
Security Classification
<sup>
<span

View File

@ -0,0 +1,5 @@
{{#each datasetComplianceSteps as |step index|}}
<span class="dataset-compliance-step dataset-compliance-step--{{if step.done "complete" "incomplete"}}">
{{inc index}}
</span>
{{/each}}