mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-24 08:28:12 +00:00
Merge pull request #1345 from cptran777/remove-compliance-wizard
Remove compliance tab editing wizard in favor of individual handlers
This commit is contained in:
commit
05a1b6eb0a
@ -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,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
};
|
||||
|
||||
@ -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}}
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
{{yield}}
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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'));
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user