mirror of
https://github.com/datahub-project/datahub.git
synced 2025-09-27 01:55:17 +00:00
implements feature to override the retention policy on a child dataset independent of the upstream policies
This commit is contained in:
parent
30926ecb48
commit
c726f136a1
@ -1,55 +1,205 @@
|
|||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import { task } from 'ember-concurrency';
|
import { task, TaskInstance } from 'ember-concurrency';
|
||||||
import { get, setProperties } from '@ember/object';
|
import { get, set, computed, setProperties, getProperties } from '@ember/object';
|
||||||
|
import ComputedProperty from '@ember/object/computed';
|
||||||
|
import { inject } from '@ember/service';
|
||||||
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||||
import { readDatasetByUrn } from 'wherehows-web/utils/api/datasets/dataset';
|
|
||||||
import { assert } from '@ember/debug';
|
import { assert } from '@ember/debug';
|
||||||
|
import { readUpstreamDatasetsByUrn } from 'wherehows-web/utils/api/datasets/lineage';
|
||||||
|
import { IUpstreamWithComplianceMetadata } from 'wherehows-web/typings/app/datasets/lineage';
|
||||||
|
import { datasetsWithComplianceMetadata } from 'wherehows-web/constants/datasets/lineage';
|
||||||
|
import { arraySome } from 'wherehows-web/utils/array';
|
||||||
|
import { IDatasetRetention, IGetDatasetRetentionResponse } from 'wherehows-web/typings/api/datasets/retention';
|
||||||
|
import { readDatasetRetentionByUrn, saveDatasetRetentionByUrn } from 'wherehows-web/utils/api/datasets/retention';
|
||||||
|
import { readPlatforms } from 'wherehows-web/utils/api/list/platforms';
|
||||||
|
import { getSupportedPurgePolicies, PurgePolicy } from 'wherehows-web/constants';
|
||||||
|
import { IDataPlatform } from 'wherehows-web/typings/api/list/platforms';
|
||||||
|
import { action } from '@ember-decorators/object';
|
||||||
|
import { retentionObjectFactory } from 'wherehows-web/constants/datasets/retention';
|
||||||
|
import Notifications, { NotificationEvent } from 'wherehows-web/services/notifications';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aliases the yieldable values for the container task
|
||||||
|
* @alias {IterableIterator<TaskInstance<TaskInstance<Promise<IDatasetView[]>> | Promise<IUpstreamWithComplianceMetadata[]>> | TaskInstance<Promise<IDataPlatform[]>> | TaskInstance<Promise<IGetDatasetRetentionResponse | null>>>}
|
||||||
|
*/
|
||||||
|
type ContainerYieldableResult = IterableIterator<
|
||||||
|
| TaskInstance<TaskInstance<Promise<IDatasetView[]>> | Promise<IUpstreamWithComplianceMetadata[]>>
|
||||||
|
| TaskInstance<Promise<IDataPlatform[]>>
|
||||||
|
| TaskInstance<Promise<IGetDatasetRetentionResponse | null>>
|
||||||
|
>;
|
||||||
|
|
||||||
export default class UpstreamDatasetContainer extends Component {
|
export default class UpstreamDatasetContainer extends Component {
|
||||||
/**
|
/**
|
||||||
* urn for the parent dataset
|
* References the application notifications service
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
* @type {ComputedProperty<Notifications>}
|
||||||
|
*/
|
||||||
|
notifications = <ComputedProperty<Notifications>>inject();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* urn for the child dataset
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof UpstreamDatasetContainer
|
* @memberof UpstreamDatasetContainer
|
||||||
*/
|
*/
|
||||||
upstreamUrn: string;
|
urn: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the upstream dataset
|
* The plaform this dataset is stored on
|
||||||
* @type {IDatasetView.nativeName}
|
* @type {IDatasetView.platform}
|
||||||
* @memberof UpstreamDatasetContainer
|
* @memberof UpstreamDatasetContainer
|
||||||
*/
|
*/
|
||||||
nativeName: IDatasetView['nativeName'];
|
platform: IDatasetView['platform'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A description of the upstream dataset
|
* The list of supported purge policies for the related platform
|
||||||
* @type {IDatasetView.description}
|
* @type {Array<PurgePolicy>}
|
||||||
* @memberof UpstreamDatasetContainer
|
* @memberof UpstreamDatasetContainer
|
||||||
*/
|
*/
|
||||||
description: IDatasetView['description'];
|
supportedPurgePolicies: Array<PurgePolicy> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of upstream datasets for the related urn
|
||||||
|
* @type {Array<IDatasetView>}
|
||||||
|
*/
|
||||||
|
upstreamDatasets: Array<IDatasetView> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of metadata properties for upstream datasets
|
||||||
|
* @type {Array<IUpstreamWithComplianceMetadata>}
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
upstreamsMetadata: Array<IUpstreamWithComplianceMetadata> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retention policy for the dataset with set urn
|
||||||
|
* @type {IDatasetRetention}
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
retention: IDatasetRetention;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
|
||||||
assert('A valid upstreamUrn must be provided on instantiation', typeof this.upstreamUrn === 'string');
|
assert(`A valid child urn must be provided on instantiation, got ${this.urn}`, !!this.urn);
|
||||||
|
assert(`A valid dataset platform must be provided on instantiation, got ${this.platform}`, !!this.platform);
|
||||||
|
this.retention = retentionObjectFactory(this.urn);
|
||||||
}
|
}
|
||||||
|
|
||||||
didUpdateAttrs() {
|
didUpdateAttrs() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
get(this, 'getUpstreamPropertiesTask').perform();
|
get(this, 'getContainerDataTask').perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
get(this, 'getUpstreamPropertiesTask').perform();
|
get(this, 'getContainerDataTask').perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task to get properties for the upstream dataset
|
* Flags if any of the upstream datasets has an incomplete compliance policy
|
||||||
* @type {Task<Promise<IDatasetView>>, (a?: {} | undefined) => TaskInstance<Promise<IDatasetView>>>}
|
* @type ComputedProperty<boolean>
|
||||||
* @memberof UpstreamDatasetContainer
|
* @memberof UpstreamDatasetContainer
|
||||||
*/
|
*/
|
||||||
getUpstreamPropertiesTask = task(function*(this: UpstreamDatasetContainer): IterableIterator<Promise<IDatasetView>> {
|
hasIncompleteUpstream = computed('upstreamsMetadata.[]', function(this: UpstreamDatasetContainer): boolean {
|
||||||
const { nativeName, description }: IDatasetView = yield readDatasetByUrn(get(this, 'upstreamUrn'));
|
const upstreamsMetadata = get(this, 'upstreamsMetadata');
|
||||||
setProperties(this, { nativeName, description });
|
const upstreamIsIncomplete = ({ hasCompliance }: IUpstreamWithComplianceMetadata): boolean => !hasCompliance;
|
||||||
|
|
||||||
|
return arraySome(upstreamIsIncomplete)(upstreamsMetadata);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs tasks related to container data instantiation
|
||||||
|
* @type {Task<ContainerYieldableResult>}
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
getContainerDataTask = task(function*(this: UpstreamDatasetContainer): ContainerYieldableResult {
|
||||||
|
yield get(this, 'getUpstreamMetadataTask').perform();
|
||||||
|
yield get(this, 'getPlatformPoliciesTask').perform();
|
||||||
|
yield get(this, 'getRetentionTask').perform();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task to get properties for the upstream dataset
|
||||||
|
* @type {Task<Promise<Array<IDatasetView>>>, (a?: {} | undefined) => TaskInstance<Promise<Array<IDatasetView>>>>}
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
getUpstreamDatasetsTask = task(function*(
|
||||||
|
this: UpstreamDatasetContainer
|
||||||
|
): IterableIterator<Promise<Array<IDatasetView>>> {
|
||||||
|
const upstreamDatasets: Array<IDatasetView> = yield readUpstreamDatasetsByUrn(get(this, 'urn'));
|
||||||
|
return set(this, 'upstreamDatasets', upstreamDatasets);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task to get and set upstream metadata for upstream datasets
|
||||||
|
* @type {Task<TaskInstance<Promise<Array<IDatasetView>>> | Promise<Array<IUpstreamWithComplianceMetadata>>>}
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
getUpstreamMetadataTask = task(function*(
|
||||||
|
this: UpstreamDatasetContainer
|
||||||
|
): IterableIterator<TaskInstance<Promise<Array<IDatasetView>>> | Promise<Array<IUpstreamWithComplianceMetadata>>> {
|
||||||
|
const upstreamDatasets: Array<IDatasetView> = yield get(this, 'getUpstreamDatasetsTask').perform();
|
||||||
|
const upstreamMetadataPromises = datasetsWithComplianceMetadata(upstreamDatasets);
|
||||||
|
const upstreamsMetadata: Array<IUpstreamWithComplianceMetadata> = yield Promise.all(upstreamMetadataPromises);
|
||||||
|
|
||||||
|
set(this, 'upstreamsMetadata', upstreamsMetadata);
|
||||||
|
}).restartable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task to retrieve platform policies and set supported policies for the current platform
|
||||||
|
* @type {Task<Promise<Array<IDataPlatform>>, () => TaskInstance<Promise<Array<IDataPlatform>>>>}
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
getPlatformPoliciesTask = task(function*(
|
||||||
|
this: UpstreamDatasetContainer
|
||||||
|
): IterableIterator<Promise<Array<IDataPlatform>>> {
|
||||||
|
const platform = get(this, 'platform');
|
||||||
|
|
||||||
|
if (platform) {
|
||||||
|
set(this, 'supportedPurgePolicies', getSupportedPurgePolicies(platform, yield readPlatforms()));
|
||||||
|
}
|
||||||
|
}).restartable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task to get the retention policy for the related child dataset
|
||||||
|
* @type {Task<Promise<IGetDatasetRetentionResponse | null>, () => TaskInstance<Promise<IGetDatasetRetentionResponse | null>>>}
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
getRetentionTask = task(function*(
|
||||||
|
this: UpstreamDatasetContainer
|
||||||
|
): IterableIterator<Promise<IGetDatasetRetentionResponse | null>> {
|
||||||
|
const retentionResponse: IGetDatasetRetentionResponse | null = yield readDatasetRetentionByUrn(get(this, 'urn'));
|
||||||
|
const retention =
|
||||||
|
retentionResponse !== null ? retentionResponse.retentionPolicy : retentionObjectFactory(get(this, 'urn'));
|
||||||
|
|
||||||
|
setProperties(get(this, 'retention'), retention);
|
||||||
|
}).restartable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task to update the dataset's retention policy with the user entered changes
|
||||||
|
* @type {Task<Promise<IDatasetRetention>, () => TaskInstance<Promise<IDatasetRetention>>>}
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
saveRetentionTask = task(function*(this: UpstreamDatasetContainer): IterableIterator<Promise<IDatasetRetention>> {
|
||||||
|
const {
|
||||||
|
retention,
|
||||||
|
notifications: { notify }
|
||||||
|
} = getProperties(this, ['retention', 'notifications']);
|
||||||
|
|
||||||
|
setProperties(retention, yield saveDatasetRetentionByUrn(get(this, 'urn'), retention));
|
||||||
|
|
||||||
|
notify(NotificationEvent.success, {
|
||||||
|
content: 'Successfully updated retention policy for dataset'
|
||||||
|
});
|
||||||
|
}).drop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles user action to change the dataset retention policy purgeType
|
||||||
|
* @param {PurgePolicy} purgePolicy
|
||||||
|
* @memberof UpstreamDatasetContainer
|
||||||
|
*/
|
||||||
|
@action
|
||||||
|
onRetentionPolicyChange(purgePolicy: PurgePolicy) {
|
||||||
|
set(get(this, 'retention'), 'purgeType', purgePolicy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,25 @@
|
|||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
import { set } from '@ember/object';
|
||||||
|
import { action } from '@ember-decorators/object';
|
||||||
|
|
||||||
export default class UpstreamDataset extends Component {
|
export default class UpstreamDataset extends Component {
|
||||||
tagName = 'section';
|
tagName = 'section';
|
||||||
|
|
||||||
classNames = ['upstream-dataset-banner'];
|
classNames = ['upstream-dataset-banner'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating the component is in view only mode and not editable
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof UpstreamDataset
|
||||||
|
*/
|
||||||
|
isReadOnly: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action handler to set component in edit mode
|
||||||
|
* @memberof UpstreamDataset
|
||||||
|
*/
|
||||||
|
@action
|
||||||
|
onEdit() {
|
||||||
|
set(this, 'isReadOnly', false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import {
|
|||||||
DatasetPlatform,
|
DatasetPlatform,
|
||||||
exemptPolicy,
|
exemptPolicy,
|
||||||
isExempt,
|
isExempt,
|
||||||
missingPolicyText,
|
|
||||||
PurgePolicy,
|
PurgePolicy,
|
||||||
purgePolicyProps
|
purgePolicyProps
|
||||||
} from 'wherehows-web/constants';
|
} from 'wherehows-web/constants';
|
||||||
@ -24,7 +23,7 @@ export default class PurgePolicyComponent extends Component {
|
|||||||
* Reference to the informational text if the dataset does not have a saved purge policy
|
* Reference to the informational text if the dataset does not have a saved purge policy
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
missingPolicyText = missingPolicyText;
|
missingPolicyText: string = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to client options for each purge policy
|
* Reference to client options for each purge policy
|
||||||
|
@ -82,10 +82,4 @@ const exemptPolicy = PurgePolicy.PurgeExempt;
|
|||||||
*/
|
*/
|
||||||
const isExempt = (policy: PurgePolicy) => policy === PurgePolicy.PurgeExempt;
|
const isExempt = (policy: PurgePolicy) => policy === PurgePolicy.PurgeExempt;
|
||||||
|
|
||||||
/**
|
export { PurgePolicy, purgePolicyProps, isExempt, exemptPolicy, getSupportedPurgePolicies };
|
||||||
* User informational text for datasets without a purge policy
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const missingPolicyText = 'This dataset does not have a current compliance purge policy.';
|
|
||||||
|
|
||||||
export { PurgePolicy, purgePolicyProps, isExempt, exemptPolicy, missingPolicyText, getSupportedPurgePolicies };
|
|
||||||
|
32
wherehows-web/app/constants/datasets/lineage.ts
Normal file
32
wherehows-web/app/constants/datasets/lineage.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||||
|
import { IReadComplianceResult, readDatasetComplianceByUrn } from 'wherehows-web/utils/api/datasets/compliance';
|
||||||
|
import { IUpstreamWithComplianceMetadata } from 'wherehows-web/typings/app/datasets/lineage';
|
||||||
|
import { arrayMap } from 'wherehows-web/utils/array';
|
||||||
|
import { encodeUrn } from 'wherehows-web/utils/validators/urn';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a dataset urn/uri, other props with a property indicating if the dataset compliance policy exists
|
||||||
|
* @param {(Pick<IDatasetView, 'uri' | 'nativeName'>)} {
|
||||||
|
* uri,
|
||||||
|
* nativeName
|
||||||
|
* }
|
||||||
|
* @returns {Promise<IUpstreamWithComplianceMetadata>}
|
||||||
|
*/
|
||||||
|
const datasetWithComplianceMetadata = async ({
|
||||||
|
uri,
|
||||||
|
nativeName
|
||||||
|
}: Pick<IDatasetView, 'uri' | 'nativeName'>): Promise<IUpstreamWithComplianceMetadata> => {
|
||||||
|
const { isNewComplianceInfo }: IReadComplianceResult = await readDatasetComplianceByUrn(encodeUrn(uri));
|
||||||
|
return { urn: uri, hasCompliance: !isNewComplianceInfo, nativeName };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a list of datasets and maps into a list of IUpstreamWithComplianceMetadata objects
|
||||||
|
* @param {Array<IDatasetView>} datasets
|
||||||
|
* @returns {Array<Promise<IUpstreamWithComplianceMetadata>>}
|
||||||
|
*/
|
||||||
|
const datasetsWithComplianceMetadata = (
|
||||||
|
datasets: Array<IDatasetView>
|
||||||
|
): Array<Promise<IUpstreamWithComplianceMetadata>> => arrayMap(datasetWithComplianceMetadata)(datasets);
|
||||||
|
|
||||||
|
export { datasetsWithComplianceMetadata };
|
14
wherehows-web/app/constants/datasets/retention.ts
Normal file
14
wherehows-web/app/constants/datasets/retention.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { IDatasetRetention } from 'wherehows-web/typings/api/datasets/retention';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 'News' a IDatasetRetention instance with the provided dataset urn
|
||||||
|
* @param {string} urn
|
||||||
|
* @returns {IDatasetRetention}
|
||||||
|
*/
|
||||||
|
const retentionObjectFactory = (urn: string): IDatasetRetention => ({
|
||||||
|
datasetUrn: urn,
|
||||||
|
purgeNote: '',
|
||||||
|
purgeType: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
export { retentionObjectFactory };
|
@ -32,3 +32,4 @@
|
|||||||
@import 'nacho/nacho-breadcrumbs';
|
@import 'nacho/nacho-breadcrumbs';
|
||||||
@import 'nacho/nacho-uploader';
|
@import 'nacho/nacho-uploader';
|
||||||
@import 'nacho/nacho-container';
|
@import 'nacho/nacho-container';
|
||||||
|
@import 'nacho/nacho-divider';
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
&__item {
|
&__item {
|
||||||
@include nacho-container;
|
@include nacho-container;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
margin-bottom: item-spacing(4);
|
|
||||||
|
|
||||||
&--disabled {
|
&--disabled {
|
||||||
color: set-color(grey, mid);
|
color: set-color(grey, mid);
|
||||||
|
@ -86,7 +86,8 @@
|
|||||||
padding: 9px $item-spacing-2 11px;
|
padding: 9px $item-spacing-2 11px;
|
||||||
margin-left: $item-spacing-5;
|
margin-left: $item-spacing-5;
|
||||||
&:first-child {
|
&:first-child {
|
||||||
margin-left: $item-spacing-4;
|
margin-left: 0;
|
||||||
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The underline will exist on all tabs, but be transparent
|
// The underline will exist on all tabs, but be transparent
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
.nacho-divider {
|
||||||
|
margin: item-spacing(5 0);
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
@ -1,9 +1,4 @@
|
|||||||
.upstream-dataset-banner {
|
.upstream-dataset-banner {
|
||||||
@include nacho-container;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.upstream-dataset-banner__description {
|
.upstream-dataset-banner__description {
|
||||||
height: item-spacing(7);
|
height: item-spacing(7);
|
||||||
@ -28,3 +23,51 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.upstream-dataset {
|
||||||
|
@include nacho-container;
|
||||||
|
padding: item-spacing(2 5);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__compliance-status {
|
||||||
|
&__complete {
|
||||||
|
color: get-color(green5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__incomplete {
|
||||||
|
color: get-color(orange5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__upstream-link {
|
||||||
|
margin-left: item-spacing(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__upstream-link-chevron {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.downstream-purge-policy-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: item-spacing(6 0 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.downstream-purge-policy {
|
||||||
|
&__no-policy {
|
||||||
|
@include nacho-container;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__edit {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&--label {
|
||||||
|
margin-right: item-spacing(4);
|
||||||
|
font-weight: fw(normal, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -164,10 +164,23 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if getPlatformPoliciesTask.last.isSuccessful}}
|
{{#if getPlatformPoliciesTask.last.isSuccessful}}
|
||||||
|
<section class="metadata-prompt">
|
||||||
|
<header class="metadata-prompt__header">
|
||||||
|
<p>
|
||||||
|
Compliance Purge Policy
|
||||||
|
|
||||||
|
{{more-info
|
||||||
|
link="http://go/gdpr/deletions/purgePolicies"
|
||||||
|
tooltip="Click for more information Purge Policies"
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
</section>
|
||||||
|
|
||||||
{{purge-policy
|
{{purge-policy
|
||||||
isEditable=(not isReadOnly)
|
isEditable=(not isReadOnly)
|
||||||
platform=platform
|
platform=platform
|
||||||
|
missingPolicyText="This dataset does not have a current compliance purge policy."
|
||||||
supportedPurgePolicies=supportedPurgePolicies
|
supportedPurgePolicies=supportedPurgePolicies
|
||||||
purgeNote=complianceInfo.compliancePurgeNote
|
purgeNote=complianceInfo.compliancePurgeNote
|
||||||
purgePolicy=(readonly complianceInfo.complianceType)
|
purgePolicy=(readonly complianceInfo.complianceType)
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
|
|
||||||
{{#if complianceInfo.fromUpstream}}
|
{{#if complianceInfo.fromUpstream}}
|
||||||
|
|
||||||
{{datasets/containers/upstream-dataset upstreamUrn=complianceInfo.datasetUrn}}
|
{{datasets/containers/upstream-dataset
|
||||||
|
urn=urn
|
||||||
|
platform=platform
|
||||||
|
}}
|
||||||
|
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
{{#if getUpstreamPropertiesTask.isRunning}}
|
{{#if getUpstreamMetadataTask.isRunning}}
|
||||||
|
|
||||||
{{pendulum-ellipsis-animation}}
|
{{pendulum-ellipsis-animation}}
|
||||||
|
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
||||||
{{datasets/upstream-dataset
|
{{datasets/upstream-dataset
|
||||||
nativeName=nativeName
|
upstreamsMetadata=upstreamsMetadata
|
||||||
description=description
|
platform=platform
|
||||||
upstreamUrn=upstreamUrn
|
retention=retention
|
||||||
|
hasIncompleteUpstream=hasIncompleteUpstream
|
||||||
|
supportedPurgePolicies=supportedPurgePolicies
|
||||||
|
saveRetentionTask=saveRetentionTask
|
||||||
|
onChange=(action "onRetentionPolicyChange")
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -1,32 +1,101 @@
|
|||||||
<section class="upstream-dataset-banner__content">
|
<section class="upstream-dataset-banner__content">
|
||||||
<div class="upstream-dataset-banner__informational">
|
<h3>Compliance Info</h3>
|
||||||
<i class="fa fa-info-circle fa-2x"></i>
|
<p>
|
||||||
|
Compliance Policy on this dataset is inherited from it's parent dataset(s). To make modifications on the purge
|
||||||
|
<br>
|
||||||
|
policy on this page, please complete the Compliance Metadata on all of the parent datasets.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class="upstream-dataset-banner__informational__text">
|
<hr class="nacho-divider">
|
||||||
Compliance Policy on this dataset is inherited from a parent dataset.
|
|
||||||
<br>
|
<h4>Parent Dataset</h4>
|
||||||
To make modifications, please update the Compliance on the parent dataset.
|
|
||||||
<br>
|
{{#each upstreamsMetadata as |parent|}}
|
||||||
</p>
|
<div class="upstream-dataset">
|
||||||
</div>
|
<span class="upstream-dataset__compliance-status">
|
||||||
|
{{tooltip-on-element
|
||||||
|
text=(if parent.hasCompliance "Compliance completed for parent dataset" "Please complete the Compliance on this parent dataset")
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{#if parent.hasCompliance}}
|
||||||
|
{{fa-icon "check" class="upstream-dataset__compliance-status__complete"}}
|
||||||
|
{{else}}
|
||||||
|
{{fa-icon "exclamation" class="upstream-dataset__compliance-status__incomplete"}}
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{{#link-to
|
||||||
|
"datasets.dataset"
|
||||||
|
"urn"
|
||||||
|
(query-params urn=parent.urn)
|
||||||
|
class="upstream-dataset__upstream-link"
|
||||||
|
}}
|
||||||
|
<strong>{{parent.nativeName}}</strong>
|
||||||
|
{{/link-to}}
|
||||||
|
|
||||||
|
{{#link-to
|
||||||
|
"datasets.dataset"
|
||||||
|
"urn"
|
||||||
|
(query-params urn=parent.urn)
|
||||||
|
class="upstream-dataset__upstream-link-chevron"
|
||||||
|
}}
|
||||||
|
<i class="glyphicon glyphicon-menu-right" aria-label="Navigate to upstream dataset"></i>
|
||||||
|
{{/link-to}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
<header class="downstream-purge-policy-header">
|
||||||
|
<h4>Compliance Purge Policy</h4>
|
||||||
|
<div class="downstream-purge-policy__edit">
|
||||||
|
{{#unless hasIncompleteUpstream}}
|
||||||
|
<label for="downstream-purge-edit" class="downstream-purge-policy__edit--label">
|
||||||
|
Modifying this will not affect the purge policy on the parent dataset
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{{#if isReadOnly}}
|
||||||
|
<button
|
||||||
|
class="nacho-button nacho-button--large"
|
||||||
|
id="downstream-purge-edit"
|
||||||
|
onclick={{action "onEdit"}}>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
{{else}}
|
||||||
|
<button
|
||||||
|
class="nacho-button nacho-button--large"
|
||||||
|
disabled={{not retention.purgeType}}
|
||||||
|
onclick={{perform saveRetentionTask}}>
|
||||||
|
|
||||||
|
{{#if saveRetentionTask.isRunning}}
|
||||||
|
{{pendulum-ellipsis-animation}}
|
||||||
|
{{else}}
|
||||||
|
Save
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
{{/unless}}
|
||||||
|
</div>
|
||||||
|
|
||||||
<header class="upstream-dataset-banner__title">
|
|
||||||
Parent Dataset Name:
|
|
||||||
{{#link-to
|
|
||||||
"datasets.dataset"
|
|
||||||
"urn"
|
|
||||||
(query-params urn=upstreamUrn)
|
|
||||||
}}
|
|
||||||
<strong>{{nativeName}}</strong>
|
|
||||||
{{/link-to}}
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{{#if description}}
|
<div class="downstream-purge-policy">
|
||||||
|
{{#if hasIncompleteUpstream}}
|
||||||
|
<p class="downstream-purge-policy__no-policy">
|
||||||
|
This dataset does not have a current compliance purge policy. To update, please complete the Compliance Metadata
|
||||||
|
on the parent dataset(s).
|
||||||
|
</p>
|
||||||
|
{{else}}
|
||||||
|
|
||||||
<p class="upstream-dataset-banner__description">
|
{{purge-policy
|
||||||
Parent Dataset Description:
|
isEditable=(not isReadOnly)
|
||||||
<strong>{{description}}</strong>
|
platform=platform
|
||||||
</p>
|
supportedPurgePolicies=supportedPurgePolicies
|
||||||
|
purgeNote=retention.purgeNote
|
||||||
{{/if}}
|
purgePolicy=(readonly retention.purgeType)
|
||||||
|
missingPolicyText="This dataset does not have a current compliance purge policy"
|
||||||
|
onPolicyChange=onChange
|
||||||
|
}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -1,16 +1,3 @@
|
|||||||
<section class="metadata-prompt">
|
|
||||||
<header class="metadata-prompt__header">
|
|
||||||
<p>
|
|
||||||
Compliance Purge Policy
|
|
||||||
|
|
||||||
{{more-info
|
|
||||||
link="http://go/gdpr/deletions/purgePolicies"
|
|
||||||
tooltip="Click for more information Purge Policies"
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<ul class="purge-policy-list">
|
<ul class="purge-policy-list">
|
||||||
{{#if isEditable}}
|
{{#if isEditable}}
|
||||||
|
|
||||||
@ -51,17 +38,16 @@
|
|||||||
|
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
||||||
{{#if purgePolicy}}
|
<li class="purge-policy-list__item">
|
||||||
<li class="purge-policy-list__item">
|
{{#if purgePolicy}}
|
||||||
<strong>
|
<strong>
|
||||||
{{get (get purgePolicyProps purgePolicy) "displayAs"}}
|
{{get (get purgePolicyProps purgePolicy) "displayAs"}}
|
||||||
</strong>
|
</strong>
|
||||||
</li>
|
{{else}}
|
||||||
{{else}}
|
|
||||||
|
|
||||||
<p>{{missingPolicyText}}</p>
|
{{missingPolicyText}}
|
||||||
<sub>To update, click edit and follow the steps</sub>
|
|
||||||
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</ul>
|
</ul>
|
||||||
|
31
wherehows-web/app/typings/api/datasets/retention.d.ts
vendored
Normal file
31
wherehows-web/app/typings/api/datasets/retention.d.ts
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { IComplianceInfo } from 'wherehows-web/typings/api/datasets/compliance';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the interface for a dataset retention policy
|
||||||
|
*
|
||||||
|
* @interface IDatasetRetention
|
||||||
|
*/
|
||||||
|
interface IDatasetRetention {
|
||||||
|
// Unused attribute for the id of the dataset, use datasetUrn instead
|
||||||
|
datasetId?: number | null;
|
||||||
|
// Urn string identifying the dataset that owns this policy
|
||||||
|
datasetUrn: string;
|
||||||
|
// Purge Policy for the dataset
|
||||||
|
purgeType: IComplianceInfo['complianceType'];
|
||||||
|
// User entered purge notation for a dataset with a purge exempt policy
|
||||||
|
purgeNote: IComplianceInfo['compliancePurgeNote'];
|
||||||
|
// Who modified this retention policy
|
||||||
|
modifiedBy?: string;
|
||||||
|
// When this policy was last modified
|
||||||
|
modifiedTime?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desribes the return type for requests to the endpoint returning the dataset retention policy
|
||||||
|
* @interface IGetDatasetRetentionResponse
|
||||||
|
*/
|
||||||
|
interface IGetDatasetRetentionResponse {
|
||||||
|
retentionPolicy: IDatasetRetention;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { IDatasetRetention, IGetDatasetRetentionResponse };
|
14
wherehows-web/app/typings/app/datasets/lineage.d.ts
vendored
Normal file
14
wherehows-web/app/typings/app/datasets/lineage.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the interface for the attributes used by the app to render the upstream datasets for a child
|
||||||
|
* dataset
|
||||||
|
* @interface IUpstreamWithComplianceMetadata
|
||||||
|
*/
|
||||||
|
interface IUpstreamWithComplianceMetadata {
|
||||||
|
urn: IDatasetView['uri'];
|
||||||
|
nativeName: IDatasetView['nativeName'];
|
||||||
|
hasCompliance: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { IUpstreamWithComplianceMetadata };
|
20
wherehows-web/app/utils/api/datasets/lineage.ts
Normal file
20
wherehows-web/app/utils/api/datasets/lineage.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { getJSON } from 'wherehows-web/utils/api/fetcher';
|
||||||
|
import { datasetUrlByUrn } from 'wherehows-web/utils/api/datasets/shared';
|
||||||
|
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the url for a datasets upstreams
|
||||||
|
* @param {string} urn the urn for the child dataset
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
const datasetUpstreamUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/upstreams`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the list of upstream datasets for a dataset by urn
|
||||||
|
* @param {string} urn urn for the child dataset
|
||||||
|
* @return {Promise<Array<IDatasetView>>}
|
||||||
|
*/
|
||||||
|
const readUpstreamDatasetsByUrn = (urn: string): Promise<Array<IDatasetView>> =>
|
||||||
|
getJSON<Array<IDatasetView>>({ url: datasetUpstreamUrlByUrn(urn) });
|
||||||
|
|
||||||
|
export { readUpstreamDatasetsByUrn };
|
39
wherehows-web/app/utils/api/datasets/retention.ts
Normal file
39
wherehows-web/app/utils/api/datasets/retention.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { getJSON, postJSON } from 'wherehows-web/utils/api/fetcher';
|
||||||
|
import { datasetUrlByUrn } from 'wherehows-web/utils/api/datasets/shared';
|
||||||
|
import { IDatasetRetention, IGetDatasetRetentionResponse } from 'wherehows-web/typings/api/datasets/retention';
|
||||||
|
import { notFoundApiError } from 'wherehows-web/utils/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the url for a datasets retention policy
|
||||||
|
* @param {string} urn the urn for the dataset
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
const datasetRetentionUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/retention`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the list of retention policy for a dataset by urn
|
||||||
|
* @param {string} urn urn for the dataset
|
||||||
|
* @return {Promise<Array<IDatasetView>>}
|
||||||
|
*/
|
||||||
|
const readDatasetRetentionByUrn = async (urn: string): Promise<IGetDatasetRetentionResponse | null> => {
|
||||||
|
try {
|
||||||
|
return await getJSON<IGetDatasetRetentionResponse>({ url: datasetRetentionUrlByUrn(urn) });
|
||||||
|
} catch (e) {
|
||||||
|
if (notFoundApiError(e)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists the dataset retention policy remotely
|
||||||
|
* @param {string} urn the urn of the dataset to save
|
||||||
|
* @param {IDatasetRetention} retention the dataset retention policy to updae
|
||||||
|
* @return {Promise<IDatasetRetention>}
|
||||||
|
*/
|
||||||
|
const saveDatasetRetentionByUrn = (urn: string, retention: IDatasetRetention): Promise<IDatasetRetention> =>
|
||||||
|
postJSON<IDatasetRetention>({ url: datasetRetentionUrlByUrn(urn), data: retention });
|
||||||
|
|
||||||
|
export { readDatasetRetentionByUrn, saveDatasetRetentionByUrn };
|
Loading…
x
Reference in New Issue
Block a user