Merge pull request #1345 from cptran777/remove-compliance-wizard

Remove compliance tab editing wizard in favor of individual handlers
This commit is contained in:
Charlie Tran 2018-08-29 14:01:51 -07:00 committed by GitHub
commit 05a1b6eb0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 147 additions and 142 deletions

View File

@ -2,6 +2,22 @@ import Application from '@ember/application';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
import { registerDeprecationHandler } from '@ember/debug';
let hasShownDefinePropDeprecation = false;
// Suggestion to keep this here until we are ready to handle the deprecation to use definePRoperty for
// computed properties. Otherwise, console log will actually hang the app
registerDeprecationHandler(function(message, { id }, next) {
if (message.includes('defineProperty')) {
if (!hasShownDefinePropDeprecation) {
next(...arguments);
hasShownDefinePropDeprecation = true;
}
} else {
next(...arguments);
}
});
const App = Application.extend({
Resolver,

View File

@ -37,7 +37,8 @@ import {
editableTags,
lowQualitySuggestionConfidenceThreshold,
TagFilter,
tagSuggestionNeedsReview
tagSuggestionNeedsReview,
ComplianceEdit
} from 'wherehows-web/constants';
import { getTagsSuggestions } from 'wherehows-web/utils/datasets/compliance-suggestions';
import { arrayFilter, arrayMap, compact, isListUnique, iterateArrayAsync } from 'wherehows-web/utils/array';
@ -146,6 +147,29 @@ export default class DatasetCompliance extends Component {
*/
suggestionConfidenceThreshold: number;
/**
* Used in the template to help pass values for the edit target
* @type {ComplianceEdit}
*/
ComplianceEdit = ComplianceEdit;
/**
* The current edit state of the dataset compliance tab. If isEditing is true, then this state is used to
* determine which component we are actually editing
* @type {ComplianceEdit}
* @memberof DatasetCompliance
*/
editTarget: ComplianceEdit;
/**
* Flag determining whether or not we are in an editing state. Triggered by an action connected to the
* user pressing an edit button, set back to false by the cancellation button or successful save of the
* edit
* @type {boolean}
* @memberof DatasetCompliance
*/
isEditing = false;
/**
* Formatted JSON string representing the compliance entities for this dataset
* @type {ComputedProperty<string>}
@ -169,32 +193,13 @@ export default class DatasetCompliance extends Component {
return JSON.stringify(entitiesWithModifiableKeys, null, '\t');
});
/**
* Convenience computed property flag indicates if current edit step is the first step in the wizard flow
* @type {ComputedProperty<boolean>}
* @memberof DatasetCompliance
*/
isInitialEditStep = computed('editStep', 'editSteps.0.name', function(this: DatasetCompliance): boolean {
const { editStep, editSteps } = getProperties(this, ['editStep', 'editSteps']);
const [initialStep] = editSteps;
return editStep.name === initialStep.name;
});
/**
* Indicates if the first step does not need further user review to advance
* @type {ComputedProperty<boolean>}
* @memberof DatasetCompliance
*/
initialStepNeedsReview = computed('isInitialEditStep', 'changeSetReviewWithoutSuggestionCheck', function(
this: DatasetCompliance
): boolean {
const { isInitialEditStep, changeSetReviewWithoutSuggestionCheck } = getProperties(this, [
'isInitialEditStep',
'changeSetReviewWithoutSuggestionCheck'
]);
const { length } = editableTags(changeSetReviewWithoutSuggestionCheck);
return isInitialEditStep && length > 0;
changeSetNeedsReview = computed('changeSetReviewWithoutSuggestionCheck', function(this: DatasetCompliance): boolean {
return editableTags(get(this, 'changeSetReviewWithoutSuggestionCheck')).length > 0;
});
/**
@ -202,14 +207,8 @@ export default class DatasetCompliance extends Component {
* @type {ComputedProperty<boolean>}
* @memberof DatasetCompliance
*/
showAdvancedEditApplyStep = computed('isInitialEditStep', 'showGuidedComplianceEditMode', function(
this: DatasetCompliance
): boolean {
const { isInitialEditStep, showGuidedComplianceEditMode } = getProperties(this, [
'isInitialEditStep',
'showGuidedComplianceEditMode'
]);
return isInitialEditStep && !showGuidedComplianceEditMode;
showAdvancedEditApplyStep = computed('showGuidedComplianceEditMode', function(this: DatasetCompliance): boolean {
return !get(this, 'showGuidedComplianceEditMode');
});
/**
@ -238,7 +237,6 @@ export default class DatasetCompliance extends Component {
* External action to handle manual compliance entity metadata entry
*/
onComplianceJsonUpdate: (jsonString: string) => Promise<void>;
notifyOnChangeSetSuggestions: (hasSuggestions: boolean) => void;
notifyOnChangeSetRequiresReview: (hasChangeSetDrift: boolean) => void;
@ -316,16 +314,6 @@ export default class DatasetCompliance extends Component {
return changeSetReviewCount ? hint : '';
});
/**
* Flag indicating that the component is in edit mode
* @type {ComputedProperty<boolean>}
* @memberof DatasetCompliance
*/
isEditing = computed('editStepIndex', 'complianceInfo.fromUpstream', function(this: DatasetCompliance): boolean {
// initialStepIndex is less than the currently set step index
return get(this, 'editStepIndex') > initialStepIndex;
});
/**
* Convenience flag indicating the policy is not currently being edited
* @type {ComputedProperty<boolean>}
@ -539,11 +527,6 @@ export default class DatasetCompliance extends Component {
didReceiveAttrs(): void {
// Perform validation step on the received component attributes
this.validateAttrs();
// Set the current step to first edit step if compliance policy is new / doesn't exist
if (get(this, 'isNewComplianceInfo')) {
this.updateStep(0);
}
}
didInsertElement(): void {
@ -1106,12 +1089,33 @@ export default class DatasetCompliance extends Component {
}
/**
* Updates the currently active step in the edit sequence
* @param {number} step
* Can be an action triggered by the user or another component action/method to toggle whether we are currently editing
* @param this - explicit this declaration for typescript
* @param isEditing - Whether or not we are entering or exiting the editing mode
* @param editTarget - Which component/section is going into editing mode
*/
updateStep(this: DatasetCompliance, step: number): void {
set(this, 'editStepIndex', step);
get(this, 'updateEditStepTask').perform();
toggleEditing(this: DatasetCompliance, isEditing: boolean = false, editTarget: ComplianceEdit): void {
setProperties(this, { isEditing, editTarget });
}
/**
* Handler that processes actions to be called before the save process
* @param editTarget - The current edit target being saved
*/
async beforeSaveCompliance(editTarget: ComplianceEdit): Promise<void> {
switch (editTarget) {
case ComplianceEdit.CompliancePolicy:
await this.actions.didEditCompliancePolicy.call(this);
break;
case ComplianceEdit.DatasetLevelPolicy:
await this.actions.didEditDatasetLevelCompliancePolicy.call(this);
break;
case ComplianceEdit.PurgePolicy:
await this.actions.didEditPurgePolicy.call(this);
break;
}
}
actions: IDatasetComplianceActions = {
@ -1171,7 +1175,7 @@ export default class DatasetCompliance extends Component {
try {
await get(this, 'onComplianceJsonUpdate')(JSON.stringify(get(this, 'manuallyEnteredComplianceEntities')));
// Proceed to next step if application of entities is successful
this.actions.nextStep.call(this);
this.actions.saveCompliance.call(this);
} catch {
noop();
}
@ -1181,7 +1185,7 @@ export default class DatasetCompliance extends Component {
* Action handles wizard step cancellation
*/
onCancel(this: DatasetCompliance): void {
this.updateStep(initialStepIndex);
this.toggleEditing(false, <any>undefined);
},
/**
@ -1346,24 +1350,6 @@ export default class DatasetCompliance extends Component {
return option;
},
/**
* Progresses 1 step backward in the edit sequence
*/
previousStep(this: DatasetCompliance): void {
const editStepIndex = get(this, 'editStepIndex');
const previousIndex = editStepIndex > 0 ? editStepIndex - 1 : editStepIndex;
this.updateStep(previousIndex);
},
/**
* Progresses 1 step forward in the edit sequence
*/
nextStep(this: DatasetCompliance): void {
const { editStepIndex, editSteps } = getProperties(this, ['editStepIndex', 'editSteps']);
const nextIndex = editStepIndex < editSteps.length - 1 ? editStepIndex + 1 : editStepIndex;
this.updateStep(nextIndex);
},
/**
* Handler applies fields changeSet working copy to compliance policy to be persisted amd validates fields
* @returns {Promise<void>}
@ -1513,16 +1499,19 @@ export default class DatasetCompliance extends Component {
*/
async saveCompliance(this: DatasetCompliance): Promise<void> {
const setSaveFlag = (flag = false): boolean => set(this, 'isSaving', flag);
const editTarget = get(this, 'editTarget');
try {
const isSaving = true;
const onSave = get(this, 'onSave');
setSaveFlag(isSaving);
await this.beforeSaveCompliance(editTarget);
await onSave();
return this.updateStep(-1);
return;
} finally {
setSaveFlag();
this.toggleEditing(false, editTarget);
}
},

View File

@ -0,0 +1,7 @@
import Component from '@ember/component';
export default class DatasetsComplianceSchemaEntities extends Component.extend({
// anything which *must* be merged to prototype here
}) {
// normal class body definition here
}

View File

@ -94,6 +94,18 @@ const complianceSteps = {
}
};
// Should replace compliance steps
/**
* Defines the edit states that the compliance policy component can have. Each one corresponds to a
* different section/component being edited on the compliance tab
*/
enum ComplianceEdit {
CompliancePolicy = 'editCompliancePolicy',
PurgePolicy = 'editPurgePolicy',
DatasetLevelPolicy = 'editDatasetLevelCompliancePolicy',
ExportPolicy = 'editExportPolicy'
}
/**
* Takes a map of dataset options and constructs the relevant compliance edit wizard steps to build the wizard flow
* @param {boolean} [hasSchema=true] flag indicating if the dataset has a schema or otherwise
@ -129,8 +141,8 @@ const editableTags = (entities: Array<IComplianceEntity>): Array<IComplianceEnti
* Strips out the readonly attribute from a list of compliance entities
* @type {(entities: Array<IComplianceEntity>) => Array<IComplianceEntity>}
*/
const removeReadonlyAttr = <(entities: Array<IComplianceEntity>) => Array<IComplianceEntity>>arrayMap(
(entity: IComplianceEntity) => omit(entity, ['readonly'])
const removeReadonlyAttr = <(entities: Array<IComplianceEntity>) => Array<IComplianceEntity>>(
arrayMap((entity: IComplianceEntity) => omit(entity, ['readonly']))
);
/**
@ -667,5 +679,6 @@ export {
tagsWithoutIdentifierType,
tagsForIdentifierField,
singleTagsInChangeSet,
overrideTagReadonly
overrideTagReadonly,
ComplianceEdit
};

View File

@ -21,35 +21,19 @@
{{#if isEditing}}
<div class="container action-bar__content">
{{#if (has-next editStep editSteps)}}
{{#if showAdvancedEditApplyStep}}
{{#if showAdvancedEditApplyStep}}
{{#track-ui-event category=trackableCategory.Compliance action=trackableEvent.Compliance.ManualApply
name=editStep.name as |metrics|}}
<button
class="nacho-button nacho-button--large-inverse action-bar__item"
title="Apply JSON"
onclick={{action metrics.trackOnAction (action "onApplyComplianceJson")}}
disabled={{isManualApplyDisabled}}>
Apply
</button>
{{/track-ui-event}}
{{else}}
{{#track-ui-event category=trackableCategory.Compliance action=trackableEvent.Compliance.Next
name=editStep.name as |metrics|}}
<button
class="nacho-button nacho-button--large-inverse action-bar__item"
title="Next"
onclick={{action metrics.trackOnAction (action "nextStep")}}
disabled={{initialStepNeedsReview}}>
Next
</button>
{{/track-ui-event}}
{{/if}}
{{#track-ui-event category=trackableCategory.Compliance action=trackableEvent.Compliance.ManualApply
name=editStep.name as |metrics|}}
<button
class="nacho-button nacho-button--large-inverse action-bar__item"
title="Apply JSON"
onclick={{action metrics.trackOnAction (action "onApplyComplianceJson")}}
disabled={{isManualApplyDisabled}}>
Apply
</button>
{{/track-ui-event}}
{{else}}
@ -60,26 +44,13 @@
title="{{unless isDatasetFullyClassified
'Ensure you have provided a yes/no value for all dataset tags'
'Save'}}"
onclick={{action metrics.trackOnAction (action "saveCompliance")}} disabled={{isSavingDisabled}}>
onclick={{action metrics.trackOnAction (action "saveCompliance")}} disabled={{and (eq edit ComplianceEdit.CompliancePolicy) changeSetNeedsReview}}>
Save
</button>
{{/track-ui-event}}
{{/if}}
{{#if (has-previous editStep editSteps)}}
{{#track-ui-event category=trackableCategory.Compliance
action=trackableEvent.Compliance.Previous
name=editStep.name as |metrics|}}
<button
class="nacho-button nacho-button--large nacho-button--secondary action-bar__item"
title="Back"
onclick={{action metrics.trackOnAction (action "previousStep")}}>
Back
</button>
{{/track-ui-event}}
{{/if}}
{{#track-ui-event category=trackableCategory.Compliance
action=trackableEvent.Compliance.Cancel as |metrics|}}
@ -106,19 +77,6 @@
{{/if}}
<div class="secondary-actions">
{{#unless isEditing}}
{{#track-ui-event category=trackableCategory.Compliance
action=trackableEvent.Compliance.Edit as |metrics|}}
<button
class="nacho-button nacho-button--large secondary-actions__action"
onclick={{action metrics.trackOnAction (action "nextStep")}}>
Edit
</button>
{{/track-ui-event}}
{{/unless}}
<div class="policy-last-saved">
Last saved:
{{#if isNewComplianceInfo}}
@ -136,17 +94,11 @@
</div>
</div>
{{#if isEditing}}
<div class="dataset-compliance-step-container">
{{partial "datasets/dataset-compliance/dataset-compliance-step-indicator"}}
</div>
{{/if}}
{{#if (or isReadOnly (eq editStep.name editSteps.2.name))}}
{{#if (or isReadOnly (eq editTarget ComplianceEdit.DatasetLevelPolicy))}}
{{partial "datasets/dataset-compliance/dataset-classification"}}
{{/if}}
{{#if (or isReadOnly (eq editStep.name editSteps.1.name))}}
{{#if (or isReadOnly (eq editTarget ComplianceEdit.PurgePolicy))}}
{{#if getPlatformPoliciesTask.isRunning}}
{{pendulum-ellipsis-animation}}
{{/if}}
@ -184,7 +136,7 @@
<div class="compliance-entities-meta__secondary">
<button
class="nacho-button nacho-button--tertiary"
onclick={{action "nextStep"}}>
onclick={{action toggleEditing true ComplianceEdit.PurgePolicy}}>
<i class="fa fa-pencil" aria-label="Edit Compliance Policy"></i>
@ -210,7 +162,7 @@
{{#if schemaless}}
{{#if (or isReadOnly isInitialEditStep)}}
{{#if (or isReadOnly (eq editTarget ComplianceEdit.CompliancePolicy))}}
{{datasets/schemaless-tagging
classificationHelpLink=@wikiLinks.dht
isEditable=(not isReadOnly)
@ -223,7 +175,7 @@
{{else}}
{{#if (or isReadOnly isInitialEditStep)}}
{{#if (or isReadOnly (eq editTarget ComplianceEdit.CompliancePolicy))}}
{{partial "datasets/dataset-compliance/dataset-compliance-entities"}}
{{/if}}

View File

@ -16,7 +16,7 @@
<div class="compliance-entities-meta__secondary">
<button
class="nacho-button nacho-button--tertiary"
onclick={{action "nextStep"}}>
onclick={{action toggleEditing true ComplianceEdit.DatasetLevelPolicy}}>
<i class="fa fa-pencil" aria-label="Edit Compliance Policy"></i>

View File

@ -79,7 +79,7 @@
<div class="compliance-entities-meta__secondary">
<button
class="nacho-button nacho-button--tertiary"
onclick={{action "nextStep"}}>
onclick={{action toggleEditing true ComplianceEdit.CompliancePolicy}}>
<i class="fa fa-pencil" aria-label="Edit Compliance Policy"></i>

View File

@ -0,0 +1,27 @@
import { module, test, skip } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import notificationsStub from 'wherehows-web/tests/stubs/services/notifications';
import { noop } from 'wherehows-web/utils/helpers/functions';
module('Integration | Component | datasets/compliance/schema-entities', function(hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function() {
this.owner.register('service:notifications', notificationsStub);
this.notifications = this.owner.lookup('service:notifications');
this.setProperties({
noop: noop
});
});
// Skipping until development on this actually starts
skip('it renders', async function(assert) {
await render(hbs`{{datasets/compliance/schema-entities
nextStep=noop
notifyOnChangeSetSuggestions=noop
notifyOnComplianceSuggestionFeedback=noop
notifyOnChangeSetRequiresReview=noop}}`);
assert.ok(this.element, 'Renders without errors');
assert.ok(document.querySelector('empty-state'));
});
});