mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-01 19:25:56 +00:00
Merge pull request #932 from theseyi/master
depends on platforms api to provide supportedPurgePolicies for each p…
This commit is contained in:
commit
23e449983e
@ -1,69 +1,111 @@
|
||||
import Component from '@ember/component';
|
||||
import { get, set } from '@ember/object';
|
||||
import { run, next } from '@ember/runloop';
|
||||
import { task } from 'ember-concurrency';
|
||||
import {
|
||||
baseCommentEditorOptions,
|
||||
DatasetPlatform,
|
||||
exemptPolicy,
|
||||
getSupportedPurgePolicies,
|
||||
isExempt,
|
||||
missingPolicyText,
|
||||
PurgePolicy,
|
||||
purgePolicyProps
|
||||
} from 'wherehows-web/constants';
|
||||
import noop from 'wherehows-web/utils/noop';
|
||||
import { IComplianceInfo } from 'wherehows-web/typings/api/datasets/compliance';
|
||||
import { IDataPlatform } from 'wherehows-web/typings/api/list/platforms';
|
||||
import { readPlatforms } from 'wherehows-web/utils/api/list/platforms';
|
||||
|
||||
export default Component.extend({
|
||||
export default class PurgePolicyComponent extends Component {
|
||||
/**
|
||||
* Reference to the purge exempt policy
|
||||
* @type {string}
|
||||
* @type {PurgePolicy}
|
||||
*/
|
||||
exemptPolicy,
|
||||
exemptPolicy = exemptPolicy;
|
||||
|
||||
/**
|
||||
* Reference to the informational text if the dataset does not have a saved purge policy
|
||||
* @type {string}
|
||||
*/
|
||||
missingPolicyText,
|
||||
missingPolicyText = missingPolicyText;
|
||||
|
||||
/**
|
||||
* Reference to client options for each purge policy
|
||||
* @type {PurgePolicyProperties}
|
||||
*/
|
||||
purgePolicyProps,
|
||||
purgePolicyProps = purgePolicyProps;
|
||||
|
||||
/**
|
||||
* The list of supported purge policies for the related platform
|
||||
* @type {Array<PurgePolicy>}
|
||||
* @memberof PurgePolicyComponent
|
||||
*/
|
||||
supportedPurgePolicies: Array<PurgePolicy> = [];
|
||||
|
||||
/**
|
||||
* The dataset's platform
|
||||
* @type {DatasetPlatform}
|
||||
* @memberof PurgePolicyComponent
|
||||
*/
|
||||
platform: null,
|
||||
platform: DatasetPlatform;
|
||||
|
||||
/**
|
||||
* The currently save policy for the dataset purge
|
||||
* @type {PurgePolicy}
|
||||
* @memberof PurgePolicyComponent
|
||||
*/
|
||||
purgePolicy: <PurgePolicy>'',
|
||||
purgePolicy: PurgePolicy;
|
||||
|
||||
requestExemptionReason: false,
|
||||
/**
|
||||
* Flag indication that policy has a request exemption reason
|
||||
* @type {boolean}
|
||||
*/
|
||||
requestExemptionReason = false;
|
||||
|
||||
/**
|
||||
* An options hash for the purge exempt reason text editor
|
||||
* @type {}
|
||||
* @memberof PurgePolicyComponent
|
||||
*/
|
||||
editorOptions: {
|
||||
editorOptions = {
|
||||
...baseCommentEditorOptions,
|
||||
placeholder: {
|
||||
text: 'Please provide an explanation for why this dataset is marked "Purge Exempt" status',
|
||||
hideOnClick: false
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Action to handle policy change, by default a no-op function
|
||||
* @type {Function}
|
||||
* @type {(purgePolicy: PurgePolicy) => IComplianceInfo['complianceType'] | null}
|
||||
* @memberof PurgePolicyComponent
|
||||
*/
|
||||
onPolicyChange: noop,
|
||||
onPolicyChange: (purgePolicy: PurgePolicy) => IComplianceInfo['complianceType'] | null;
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
this.checkExemption(get(this, 'purgePolicy'));
|
||||
},
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
get(this, 'getPlatformPolicies').perform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to retrieve platform policies for and set supported policies for the current platform
|
||||
* @memberof PurgePolicyComponent
|
||||
*/
|
||||
getPlatformPolicies = task(function*(
|
||||
this: PurgePolicyComponent
|
||||
): IterableIterator<Array<PurgePolicy> | Promise<Array<IDataPlatform>>> {
|
||||
const platform = get(this, 'platform');
|
||||
|
||||
if (platform) {
|
||||
const supportedPurgePolicies = getSupportedPurgePolicies(platform, yield readPlatforms());
|
||||
|
||||
yield set(this, 'supportedPurgePolicies', supportedPurgePolicies);
|
||||
}
|
||||
}).restartable();
|
||||
|
||||
/**
|
||||
* Checks that the selected purge policy is exempt, if so, set the
|
||||
@ -79,7 +121,7 @@ export default Component.extend({
|
||||
// this allows us to ensure that editor it visible after the set above has been performed
|
||||
run(() => next(this, 'focusEditor'));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies cursor / document focus to the purge note text editor
|
||||
@ -90,16 +132,16 @@ export default Component.extend({
|
||||
if (exemptionReasonElement) {
|
||||
exemptionReasonElement.focus();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
actions: {
|
||||
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) {
|
||||
onChange(this: PurgePolicyComponent, _name: string, purgePolicy: PurgePolicy) {
|
||||
return get(this, 'onPolicyChange')(purgePolicy);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { DatasetPlatform } from 'wherehows-web/constants/datasets/platform';
|
||||
import { IDataPlatform } from 'wherehows-web/typings/api/list/platforms';
|
||||
|
||||
/**
|
||||
* Available values for the purge policy
|
||||
@ -17,7 +17,6 @@ enum PurgePolicy {
|
||||
*/
|
||||
type PurgePolicyProperties = {
|
||||
[K in PurgePolicy]: {
|
||||
platforms: Array<DatasetPlatform>;
|
||||
desc: string;
|
||||
displayAs: string;
|
||||
}
|
||||
@ -29,40 +28,43 @@ type PurgePolicyProperties = {
|
||||
*/
|
||||
const purgePolicyProps: PurgePolicyProperties = {
|
||||
AUTO_PURGE: {
|
||||
platforms: [DatasetPlatform.Teradata, DatasetPlatform.Espresso, DatasetPlatform.HDFS],
|
||||
desc:
|
||||
'Choose this option only if it’s acceptable to have the centralized system purge this dataset based on the provided metadata (e.g. member ID, seat ID etc).',
|
||||
displayAs: 'Auto Purge'
|
||||
},
|
||||
MANUAL_PURGE: {
|
||||
platforms: [
|
||||
DatasetPlatform.MySql,
|
||||
DatasetPlatform.Espresso,
|
||||
DatasetPlatform.Teradata,
|
||||
DatasetPlatform.Oracle,
|
||||
DatasetPlatform.HDFS
|
||||
],
|
||||
desc: 'Choose this option only if you or your team have implemented a custom mechanism to purge this dataset.',
|
||||
displayAs: 'Manual Purge'
|
||||
},
|
||||
LIMITED_RETENTION: {
|
||||
platforms: [DatasetPlatform.Kafka, DatasetPlatform.Teradata, DatasetPlatform.HDFS],
|
||||
desc:
|
||||
'Choose this option only if you rely on the data platform’s default limited retention mechanism to purge your data.',
|
||||
displayAs: 'Auto Limited Retention'
|
||||
},
|
||||
MANUAL_LIMITED_RETENTION: {
|
||||
platforms: [DatasetPlatform.Espresso, DatasetPlatform.Oracle, DatasetPlatform.MySql],
|
||||
desc: 'Choose this option only if you have a well established process to ensure limited data retention.',
|
||||
displayAs: 'Manual Limited Retention'
|
||||
},
|
||||
PURGE_EXEMPTED: {
|
||||
platforms: Object.keys(DatasetPlatform).map((k: keyof typeof DatasetPlatform) => DatasetPlatform[k]),
|
||||
desc: 'Choose this option only if the dataset is explicitly exempted from purging',
|
||||
displayAs: 'Purge Exempt'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the purge policy for a given platform from the list of DatasetPlatforms
|
||||
* @param {IDataPlatform.name} platformName the name of the dataset platform
|
||||
* @param {Array<IDataPlatform>} [platforms=[]] the list of objects with IDataPlatform interface
|
||||
* @returns {Array<PurgePolicy>}
|
||||
*/
|
||||
const getSupportedPurgePolicies = (
|
||||
platformName: IDataPlatform['name'],
|
||||
platforms: Array<IDataPlatform> = []
|
||||
): Array<PurgePolicy> => {
|
||||
const platform = platforms.findBy('name', platformName);
|
||||
return platform ? platform.supportedPurgePolicies : [];
|
||||
};
|
||||
|
||||
/**
|
||||
* A cache for the exempt policy
|
||||
* @type {PurgePolicy}
|
||||
@ -81,4 +83,4 @@ const isExempt = (policy: PurgePolicy) => policy === PurgePolicy.PurgeExempt;
|
||||
*/
|
||||
const missingPolicyText = 'This dataset does not have a current compliance purge policy.';
|
||||
|
||||
export { PurgePolicy, purgePolicyProps, isExempt, exemptPolicy, missingPolicyText };
|
||||
export { PurgePolicy, purgePolicyProps, isExempt, exemptPolicy, missingPolicyText, getSupportedPurgePolicies };
|
||||
|
||||
@ -3,17 +3,17 @@
|
||||
* @enum {string}
|
||||
*/
|
||||
enum DatasetPlatform {
|
||||
Kafka = 'KAFKA',
|
||||
Espresso = 'ESPRESSO',
|
||||
Oracle = 'ORACLE',
|
||||
MySql = 'MYSQL',
|
||||
Teradata = 'TERADATA',
|
||||
HDFS = 'HDFS',
|
||||
Ambry = 'AMBRY',
|
||||
Couchbase = 'COUCHBASE',
|
||||
Voldemort = 'VOLDEMORT',
|
||||
Venice = 'VENICE',
|
||||
Hive = 'HIVE'
|
||||
Kafka = 'kafka',
|
||||
Espresso = 'espresso',
|
||||
Oracle = 'oracle',
|
||||
MySql = 'mysql',
|
||||
Teradata = 'teradata',
|
||||
HDFS = 'hdfs',
|
||||
Ambry = 'ambry',
|
||||
Couchbase = 'couchbase',
|
||||
Voldemort = 'voldemort',
|
||||
Venice = 'venice',
|
||||
Hive = 'hive'
|
||||
}
|
||||
|
||||
export { DatasetPlatform };
|
||||
|
||||
@ -18,4 +18,8 @@
|
||||
@include pill(set-color(red, maroonflush), set-color(white, base));
|
||||
}
|
||||
}
|
||||
|
||||
&__retry-platforms {
|
||||
@include flex-column-center;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,40 +9,65 @@
|
||||
<ul class="purge-policy-list">
|
||||
{{#if isEditable}}
|
||||
|
||||
{{#each-in purgePolicyProps as |purgeType prop|}}
|
||||
<li
|
||||
class="purge-policy-list__item {{unless (contains (uppercase platform) prop.platforms)
|
||||
'purge-policy-list__item--disabled'}}">
|
||||
{{#if getPlatformPolicies.isRunning}}
|
||||
{{pendulum-ellipsis-animation}}
|
||||
{{/if}}
|
||||
|
||||
{{#radio-button-composer
|
||||
name="dataset-purge-policy"
|
||||
value=(if (contains (uppercase platform) prop.platforms) purgeType null)
|
||||
disabled=(if (contains (uppercase platform) prop.platforms) false true)
|
||||
groupValue=(readonly purgePolicy)
|
||||
changed=(action "onChange")
|
||||
}}
|
||||
{{prop.displayAs}}
|
||||
{{/radio-button-composer}}
|
||||
{{#if getPlatformPolicies.last.isError}}
|
||||
{{!--todo: swap out with error-state component--}}
|
||||
{{empty-state
|
||||
heading="Purge Policies not available"
|
||||
subHead="Could not find supported purge policies for this platform"
|
||||
}}
|
||||
|
||||
{{#unless (contains (uppercase platform) prop.platforms)}}
|
||||
<p class="purge-policy-list__availability">
|
||||
Purge policy not available for <span class="purge-policy-list__platform--unavailable">
|
||||
{{lowercase platform}}</span>
|
||||
</p>
|
||||
{{/unless}}
|
||||
<div class="purge-policy-list__retry-platforms">
|
||||
<button
|
||||
class="nacho-button nacho-button--large-inverse"
|
||||
onclick={{perform getPlatformPolicies}}>
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p>{{prop.desc}}</p>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and requestExemptionReason (eq purgeType exemptPolicy))}}
|
||||
{{#if getPlatformPolicies.last.isSuccessful}}
|
||||
|
||||
{{medium-content-editable
|
||||
value=purgeNote
|
||||
options=editorOptions
|
||||
class="comment-new__content"}}
|
||||
{{#each-in purgePolicyProps as |purgeType prop|}}
|
||||
<li
|
||||
class="purge-policy-list__item {{unless (contains purgeType supportedPurgePolicies)
|
||||
'purge-policy-list__item--disabled'}}">
|
||||
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each-in}}
|
||||
{{#radio-button-composer
|
||||
name="dataset-purge-policy"
|
||||
value=(if (contains purgeType supportedPurgePolicies) purgeType null)
|
||||
disabled=(if (contains purgeType supportedPurgePolicies) false true)
|
||||
groupValue=(readonly purgePolicy)
|
||||
changed=(action "onChange")
|
||||
}}
|
||||
{{prop.displayAs}}
|
||||
{{/radio-button-composer}}
|
||||
|
||||
{{#unless (contains purgeType supportedPurgePolicies)}}
|
||||
<p class="purge-policy-list__availability">
|
||||
Purge policy not available for <span class="purge-policy-list__platform--unavailable">
|
||||
{{platform}}</span>
|
||||
</p>
|
||||
{{/unless}}
|
||||
|
||||
<p>{{prop.desc}}</p>
|
||||
|
||||
{{#if (and requestExemptionReason (eq purgeType exemptPolicy))}}
|
||||
|
||||
{{medium-content-editable
|
||||
value=purgeNote
|
||||
options=editorOptions
|
||||
class="comment-new__content"}}
|
||||
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each-in}}
|
||||
|
||||
{{/if}}
|
||||
|
||||
{{else}}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import { ApiStatus } from 'wherehows-web/utils/api/shared';
|
||||
*/
|
||||
export interface IDataPlatform {
|
||||
// Policies supported for this dataset
|
||||
supportedPolicies: Array<PurgePolicy>;
|
||||
supportedPurgePolicies: Array<PurgePolicy>;
|
||||
// the type of the dataset platform with the given name e.g. DISTRIBUTED_FILE_SYSTEM, RELATIONAL_DB
|
||||
type: string;
|
||||
// the name of the dataset platform
|
||||
|
||||
@ -67,7 +67,7 @@ declare module 'ember-concurrency' {
|
||||
cancelAll(): void;
|
||||
};
|
||||
|
||||
export function task<T, A>(generatorFn: (a: A) => Iterator<T>): Task<T, (a: A) => TaskInstance<T>>;
|
||||
export function task<T, A>(generatorFn: (a: A) => Iterator<T>): Task<T, (a?: A) => TaskInstance<T>>;
|
||||
|
||||
export function task<T, A1, A2>(
|
||||
generatorFn: (a1: A1, a2: A2) => Iterator<T>
|
||||
|
||||
75
wherehows-web/mirage/fixtures/list-platforms.ts
Normal file
75
wherehows-web/mirage/fixtures/list-platforms.ts
Normal file
@ -0,0 +1,75 @@
|
||||
export default [
|
||||
{
|
||||
supportedPurgePolicies: ['AUTO_PURGE', 'MANUAL_PURGE', 'MANUAL_LIMITED_RETENTION', 'PURGE_EXEMPTED'],
|
||||
type: 'DISTRIBUTED_KEY_VALUE_STORE',
|
||||
name: 'espresso'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: [
|
||||
'AUTO_PURGE',
|
||||
'MANUAL_PURGE',
|
||||
'LIMITED_RETENTION',
|
||||
'MANUAL_LIMITED_RETENTION',
|
||||
'PURGE_EXEMPTED'
|
||||
],
|
||||
type: 'DISTRIBUTED_FILE_SYSTEM',
|
||||
name: 'hdfs'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: [
|
||||
'AUTO_PURGE',
|
||||
'MANUAL_PURGE',
|
||||
'LIMITED_RETENTION',
|
||||
'MANUAL_LIMITED_RETENTION',
|
||||
'PURGE_EXEMPTED'
|
||||
],
|
||||
type: 'DISTRIBUTED_FILE_SYSTEM',
|
||||
name: 'hive'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: ['LIMITED_RETENTION'],
|
||||
type: 'DISTRIBUTED_MESSAGE_BROKER',
|
||||
name: 'kafka'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: ['MANUAL_PURGE', 'MANUAL_LIMITED_RETENTION', 'PURGE_EXEMPTED'],
|
||||
type: 'RELATIONAL_DB',
|
||||
name: 'mysql'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: ['MANUAL_PURGE', 'MANUAL_LIMITED_RETENTION', 'PURGE_EXEMPTED'],
|
||||
type: 'RELATIONAL_DB',
|
||||
name: 'oracle'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: [
|
||||
'AUTO_PURGE',
|
||||
'MANUAL_PURGE',
|
||||
'LIMITED_RETENTION',
|
||||
'MANUAL_LIMITED_RETENTION',
|
||||
'PURGE_EXEMPTED'
|
||||
],
|
||||
type: 'RELATIONAL_DB',
|
||||
name: 'teradata'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: ['MANUAL_LIMITED_RETENTION', 'PURGE_EXEMPTED'],
|
||||
type: 'DISTRIBUTED_KEY_VALUE_STORE',
|
||||
name: 'venice'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: ['MANUAL_LIMITED_RETENTION', 'PURGE_EXEMPTED'],
|
||||
type: 'DISTRIBUTED_KEY_VALUE_STORE',
|
||||
name: 'voldemort'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: ['MANUAL_PURGE', 'MANUAL_LIMITED_RETENTION', 'PURGE_EXEMPTED'],
|
||||
type: 'DISTRIBUTED_KEY_VALUE_STORE',
|
||||
name: 'couchbase'
|
||||
},
|
||||
{
|
||||
supportedPurgePolicies: ['MANUAL_PURGE', 'MANUAL_LIMITED_RETENTION', 'PURGE_EXEMPTED'],
|
||||
type: 'DISTRIBUTED_OBJECT_STORE',
|
||||
name: 'ambry'
|
||||
}
|
||||
];
|
||||
@ -1,5 +1,6 @@
|
||||
const fixtures = ['dataset-nodes', 'metric-metrics', 'user-entities', 'compliance-data-types', 'list-platforms'];
|
||||
|
||||
export default function(server) {
|
||||
const fixtures = ['dataset-nodes', 'metric-metrics', 'user-entities', 'compliance-data-types'];
|
||||
server.loadFixtures(...fixtures);
|
||||
server.create('config');
|
||||
server.createList('owner', 6);
|
||||
|
||||
@ -1,10 +1,23 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { triggerEvent } from 'ember-native-dom-helpers';
|
||||
import { missingPolicyText, purgePolicyProps, exemptPolicy } from 'wherehows-web/constants';
|
||||
import { triggerEvent, waitUntil, find } from 'ember-native-dom-helpers';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { missingPolicyText, purgePolicyProps, exemptPolicy, PurgePolicy } from 'wherehows-web/constants';
|
||||
import { DatasetPlatform } from 'wherehows-web/constants/datasets/platform';
|
||||
import platforms from 'wherehows-web/mirage/fixtures/list-platforms';
|
||||
import { ApiStatus } from 'wherehows-web/utils/api';
|
||||
|
||||
moduleForComponent('purge-policy', 'Integration | Component | purge policy', {
|
||||
integration: true
|
||||
integration: true,
|
||||
|
||||
beforeEach() {
|
||||
this.server = sinon.createFakeServer();
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
this.server.restore();
|
||||
}
|
||||
});
|
||||
|
||||
const policyList = '.purge-policy-list';
|
||||
@ -59,17 +72,25 @@ test('it renders a user message if the purge policy is not set and is in readonl
|
||||
);
|
||||
});
|
||||
|
||||
test('it indicates the currently selected purge policy', function(assert) {
|
||||
test('it indicates the currently selected purge policy', async function(assert) {
|
||||
assert.expect(1);
|
||||
const selectedPolicy = policyTypes[1];
|
||||
const platform = purgePolicyProps[selectedPolicy].platforms[0];
|
||||
const selectedPolicy = PurgePolicy.ManualPurge;
|
||||
const platform = DatasetPlatform.MySql;
|
||||
|
||||
this.set('isEditable', true);
|
||||
this.set('platform', platform);
|
||||
this.set('purgePolicy', selectedPolicy);
|
||||
|
||||
this.render(hbs`{{purge-policy isEditable=isEditable purgePolicy=purgePolicy platform=platform}}`);
|
||||
this.server.respondWith('GET', '/api/v1/list/platforms', [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({ status: ApiStatus.OK, platforms })
|
||||
]);
|
||||
|
||||
this.render(hbs`{{purge-policy isEditable=isEditable purgePolicy=purgePolicy platform=platform}}`);
|
||||
this.server.respond();
|
||||
|
||||
await waitUntil(() => find(`${policyList} [type=radio][value=${selectedPolicy}]`));
|
||||
assert.ok(
|
||||
document.querySelector(`${policyList} [type=radio][value=${selectedPolicy}]`).checked,
|
||||
`${selectedPolicy} radio is checked`
|
||||
@ -83,7 +104,7 @@ test('it focuses the comment element for exempt policy', function(assert) {
|
||||
assert.equal(++focusMethodCount, 1, 'focusEditor action is invoked');
|
||||
};
|
||||
let selectedPolicy = exemptPolicy;
|
||||
let platform = purgePolicyProps[selectedPolicy].platforms[0];
|
||||
let platform = DatasetPlatform.MySql;
|
||||
let focusMethodCount = 0;
|
||||
|
||||
this.setProperties({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user