implements purge policy feature. constants for platforms and purge types. adds styles for feature. implements ui logic for selecting purge based on platform availability.

This commit is contained in:
Seyi Adebajo 2017-10-19 18:17:16 -07:00
parent 1f3fb8b30f
commit 64c442b938
13 changed files with 283 additions and 15 deletions

View File

@ -1,5 +1,6 @@
import Ember from 'ember';
import isTrackingHeaderField from 'wherehows-web/utils/validators/tracking-headers';
import { getPlatformFromUrn } from 'wherehows-web/utils/validators/urn';
import {
classifiers,
datasetClassifiers,
@ -189,6 +190,15 @@ export default Component.extend({
return get(this, 'isNewComplianceInfo') ? 'showAll' : 'showReview';
}),
/**
* Extracts the dataset platform from the dataset urn
* @type {Ember.ComputedProperty}
* @return {string | void}
*/
datasetPlatform: computed('complianceInfo.datasetUrn', function() {
return getPlatformFromUrn(get(this, 'complianceInfo.datasetUrn'));
}),
/**
* Reference to the application notifications Service
* @type {Ember.Service}
@ -723,6 +733,26 @@ export default Component.extend({
return sourceDatasetClassification;
},
/**
* Display a modal dialog requesting that the user check affirm that the purge type is exempt
* @return {Promise<void>}
*/
showPurgeExemptionWarning() {
const dialogActions = {};
get(this, 'notifications').notify('confirm', {
header: 'Confirm purge exemption',
content:
'By choosing this option you understand that either Legal or HSEC may contact you to verify the purge exemption',
dialogActions
});
return new Promise((resolve, reject) => {
dialogActions['didConfirm'] = () => resolve();
dialogActions['didDismiss'] = () => reject();
});
},
actions: {
/**
* Sets each datasetClassification value as false
@ -957,6 +987,15 @@ export default Component.extend({
return set(this.getDatasetClassificationRef(), classifier, value);
},
/**
* Updates the complianceType on the compliance policy
* @param {PurgePolicy} purgePolicy
*/
onDatasetPurgePolicyChange(purgePolicy) {
// directly set the complianceType to the updated value
return set(this, 'complianceInfo.complianceType', purgePolicy);
},
/**
* If all validity checks are passed, invoke onSave action on controller
*/

View File

@ -0,0 +1,80 @@
import Ember from 'ember';
import { baseCommentEditorOptions, PurgePolicy, purgePolicyProps } from 'wherehows-web/constants';
import noop from 'wherehows-web/utils/noop';
const { Component, get, set } = Ember;
/**
* A cache for the exempt policy
* @type {PurgePolicy}
*/
const exemptPolicy = PurgePolicy.PurgeExempt;
/**
* Checks that a purge policy is exempt
* @param {PurgePolicy} policy the policy to check
*/
const isExempt = (policy: PurgePolicy) => policy === exemptPolicy;
export default Component.extend({
tagName: 'ul',
classNames: ['purge-policy-list'],
exemptPolicy,
purgePolicyProps,
/**
* The dataset's platform
*/
platform: null,
/**
* The currently save policy for the dataset purge
*/
purgePolicy: null,
/**
* An options hash for the purge exempt reason text editor
* @type {}
*/
editorOptions: {
...baseCommentEditorOptions,
placeholder: {
text: 'Please provide an explanation for why this dataset is marked "Purge Exempt" status'
}
},
/**
* Action to handle policy change, by default a no-op function
* @type {Function}
*/
onPolicyChange: noop,
didReceiveAttrs() {
this._super(...arguments);
this.checkExemption(get(this, 'purgePolicy'));
},
/**
* Checks that the selected purge policy is exempt, if so, set the
* flag to request the exemption to true
* @param {PurgePolicy} purgePolicy
*/
checkExemption(purgePolicy: PurgePolicy) {
const exemptionReasonRequested = isExempt(purgePolicy);
set(this, 'requestExemptionReason', exemptionReasonRequested);
},
actions: {
/**
* Handles the change to the currently selected purge policy
* @param {string} _name unused name for the radio group
* @param {PurgePolicy} purgePolicy the selected purge policy
*/
onChange(_name: string, purgePolicy: PurgePolicy) {
return get(this, 'onPolicyChange')(purgePolicy);
}
}
});

View File

@ -0,0 +1,14 @@
/**
* The known/supported list of dataset platforms
* @enum {string}
*/
enum DatasetPlatform {
Kafka = 'KAFKA',
Espresso = 'ESPRESSO',
Oracle = 'ORACLE',
MySql = 'MYSQL',
Teradata = 'TERADATA',
HDFS = 'HDFS'
}
export { DatasetPlatform };

View File

@ -0,0 +1,62 @@
import { DatasetPlatform } from 'wherehows-web/constants/dataset-platforms';
/**
* Available values for the purge policy
* @enum {string}
*/
enum PurgePolicy {
AutoPurge = 'AUTO_PURGE',
ManualPurge = 'MANUAL_PURGE',
AutoLimitedRetention = 'AUTO_LIMITED_RETENTION',
ManualLimitedRetention = 'MANUAL_LIMITED_RETENTION',
PurgeExempt = 'PURGE_EXEMPT'
}
/**
* Index signature for purge policy properties
*/
type PurgePolicyProperties = {
[K in PurgePolicy]: {
platforms: Array<DatasetPlatform>;
desc: string;
displayAs: string;
}
};
/**
* Client options for each purge policy
* Lists, the available platforms, a descriptions field and a user friendly name for the purge key
*/
const purgePolicyProps: PurgePolicyProperties = {
AUTO_PURGE: {
platforms: [DatasetPlatform.Teradata, DatasetPlatform.Espresso, DatasetPlatform.HDFS],
desc: 'A centralized system will automatically purge this dataset based on the provided metadata.',
displayAs: 'Auto Purge'
},
MANUAL_PURGE: {
platforms: [DatasetPlatform.MySql, DatasetPlatform.Espresso, DatasetPlatform.Teradata, DatasetPlatform.HDFS],
desc: '',
displayAs: 'Manual Purge'
},
AUTO_LIMITED_RETENTION: {
platforms: [DatasetPlatform.Kafka, DatasetPlatform.Teradata, DatasetPlatform.HDFS],
desc:
'The data platform enforces limited retention. Only choose this option if your dataset ' +
"complies with the platform's limited retention policy.",
displayAs: 'Auto Limited Retention'
},
MANUAL_LIMITED_RETENTION: {
platforms: [DatasetPlatform.Espresso, DatasetPlatform.Oracle, DatasetPlatform.MySql],
desc: '',
displayAs: 'Manual Limited Retention'
},
PURGE_EXEMPT: {
platforms: Object.keys(DatasetPlatform).map((k: keyof typeof DatasetPlatform) => DatasetPlatform[k]),
desc:
'The dataset is exempted from purging due to legal or financial requirements.' +
" Only choose this option if you've received an explicit exemption from legal.",
displayAs: 'Purge Exempt'
}
};
export { PurgePolicy, purgePolicyProps };

View File

@ -3,3 +3,5 @@ export * from 'wherehows-web/constants/dataset-classification';
export * from 'wherehows-web/constants/dataset-compliance';
export * from 'wherehows-web/constants/application';
export * from 'wherehows-web/constants/dataset-comments';
export * from 'wherehows-web/constants/dataset-purge-policy';
export * from 'wherehows-web/constants/dataset-platforms';

View File

@ -44,11 +44,7 @@
$breakpoint-query: map-get($breakpoints, $breakpoint);
@if $breakpoint-query {
$query: if(
type-of($breakpoint-query) == 'string',
unquote($breakpoint-query),
inspect($breakpoint-query)
);
$query: if(type-of($breakpoint-query) == 'string', unquote($breakpoint-query), inspect($breakpoint-query));
@media #{$query} {
@content;
@ -84,6 +80,34 @@
overflow-y: auto;
}
/// Proxy for AD container styles
@mixin nacho-container {
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
background-color: set-color(white, base);
background-clip: padding-box;
border-radius: 2px;
padding: item-spacing(4);
transition: box-shadow 83ms;
}
/// Applies rules to render an element with a pill shape
/// @param {Color} $bg-color the background color for the pill
/// @param {Color} $color font/text color
/// @param {Color} $border-color=$bg-color the color to apply to the pill border
///@example - Usage
/// .foo {
/// @include pill(get-color(gray1), get-color(gray6));
/// }
@mixin pill($bg-color, $color, $border-color: $bg-color) {
border-radius: 32px;
background-color: $bg-color;
border: 1px solid $border-color;
color: $color;
display: inline-block;
line-height: item-spacing(3);
padding: 1px 10px;
}
/// Temp implementation before Auto Prefixer is installed
/// @link https://github.com/postcss/autoprefixer
@ -99,7 +123,6 @@
#{$property}: $value;
}
/// Maintains the aspect ratio for a wrapped element
/// @param {Number} $width number value for the container's width ratio
/// @param {Number} $height number value for the container's with ratio
@ -107,7 +130,7 @@
position: relative;
&::before {
content: "";
content: '';
display: block;
width: 100%;
padding-top: ($height / $width) * 100%;

View File

@ -11,6 +11,7 @@
@import 'dataset-comments/all';
@import 'comments/all';
@import 'empty-state/all';
@import 'dataset-purge-policy/all';
@import 'nacho/nacho-button';
@import 'nacho/nacho-global-search';

View File

@ -0,0 +1 @@
@import 'purge-policy-list';

View File

@ -0,0 +1,21 @@
.purge-policy-list {
margin: 0;
padding: 0;
&__item {
@include nacho-container;
list-style-type: none;
margin-bottom: item-spacing(4);
&--disabled {
color: set-color(grey, mid);
background-color: set-color(grey, light);
}
}
&__platform {
&--unavailable {
@include pill(set-color(red, maroonflush), set-color(white, base));
}
}
}

View File

@ -102,6 +102,15 @@
{{#if (or isReadOnly isShowingComplianceEditMode)}}
{{partial "datasets/dataset-compliance/dataset-compliance-entities"}}
{{/if}}
{{#if isShowingCompliancePurgePolicy}}
{{purge-policy
platform=datasetPlatform
purgeNote=complianceInfo.compliancePurgeNote
purgePolicy=(readonly complianceInfo.complianceType)
onPolicyChange=(action "onDatasetPurgePolicyChange")
}}
{{/if}}
</div>
{{yield}}

View File

@ -13,12 +13,9 @@ const createInitialComplianceInfo = datasetId => ({
datasetId,
// default to first item in compliance types list
complianceType: 'AUTO_PURGE',
compliancePurgeNote: '',
complianceEntities: [],
fieldClassification: {},
datasetClassification: {},
geographicAffinity: { affinity: '' },
recordOwnerType: '',
retentionPolicy: { retentionType: '' }
datasetClassification: {}
});
/**

View File

@ -0,0 +1,4 @@
/**
* exports a noop that can be used in place of Ember.K which is currently deprecated.
*/
export default () => {};

View File

@ -14,8 +14,23 @@ const specialFlowUrnRegex = /(?:\?urn=)([a-z0-9_\-/{}\s]+)/i;
/**
* Asserts that a provided string matches the urn pattern above
* @param {String} candidateUrn the string to test on
* @param {string} candidateUrn the string to test on
*/
export default (candidateUrn: string) => urnRegex.test(String(candidateUrn));
const isUrn = (candidateUrn: string) => urnRegex.test(String(candidateUrn));
export { urnRegex, specialFlowUrnRegex };
/**
* Extracts the platform string from the candidate urn string
* @param {string} candidateUrn the urn string with leading platform identifier
* @returns {string | void}
*/
const getPlatformFromUrn = (candidateUrn: string) => {
const matches = urnRegex.exec(candidateUrn);
if (matches) {
const [, platform] = matches;
return platform.toUpperCase();
}
};
export default isUrn;
export { urnRegex, specialFlowUrnRegex, getPlatformFromUrn };