mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-16 20:48:35 +00:00
Merge pull request #1029 from theseyi/resolved-ownership
resolved ownership
This commit is contained in:
commit
701824cc2a
@ -1,12 +1,12 @@
|
|||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import { get, set, getProperties } from '@ember/object';
|
import { get, set, getProperties, setProperties } from '@ember/object';
|
||||||
import ComputedProperty from '@ember/object/computed';
|
import ComputedProperty from '@ember/object/computed';
|
||||||
import { inject } from '@ember/service';
|
import { inject } from '@ember/service';
|
||||||
import { task, TaskInstance } from 'ember-concurrency';
|
import { task, TaskInstance } from 'ember-concurrency';
|
||||||
import { action } from 'ember-decorators/object';
|
import { action } from 'ember-decorators/object';
|
||||||
import Notifications from 'wherehows-web/services/notifications';
|
import Notifications from 'wherehows-web/services/notifications';
|
||||||
import { NotificationEvent } from 'wherehows-web/services/notifications';
|
import { NotificationEvent } from 'wherehows-web/services/notifications';
|
||||||
import { IOwner } from 'wherehows-web/typings/api/datasets/owners';
|
import { IOwner, IOwnerResponse } from 'wherehows-web/typings/api/datasets/owners';
|
||||||
import {
|
import {
|
||||||
OwnerType,
|
OwnerType,
|
||||||
readDatasetOwnersByUrn,
|
readDatasetOwnersByUrn,
|
||||||
@ -39,6 +39,18 @@ export default class DatasetOwnershipContainer extends Component {
|
|||||||
*/
|
*/
|
||||||
notifications: ComputedProperty<Notifications> = inject();
|
notifications: ComputedProperty<Notifications> = inject();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicates that a ownership metadata is inherited from an upstream dataset
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
fromUpstream = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to the upstream dataset
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
upstreamUrn: string;
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
get(this, 'getContainerDataTask').perform();
|
get(this, 'getContainerDataTask').perform();
|
||||||
}
|
}
|
||||||
@ -59,12 +71,12 @@ export default class DatasetOwnershipContainer extends Component {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the owners for this dataset
|
* Reads the owners for this dataset
|
||||||
* @type {Task<Promise<Array<IOwner>>, (a?: any) => TaskInstance<Promise<Array<IOwner>>>>}
|
* @type {Task<Promise<Array<IOwner>>, (a?: any) => TaskInstance<Promise<IOwnerResponse>>>}
|
||||||
*/
|
*/
|
||||||
getDatasetOwnersTask = task(function*(this: DatasetOwnershipContainer): IterableIterator<Promise<Array<IOwner>>> {
|
getDatasetOwnersTask = task(function*(this: DatasetOwnershipContainer): IterableIterator<Promise<IOwnerResponse>> {
|
||||||
const owners = yield readDatasetOwnersByUrn(get(this, 'urn'));
|
const { owners, fromUpstream, datasetUrn } = yield readDatasetOwnersByUrn(get(this, 'urn'));
|
||||||
|
|
||||||
set(this, 'owners', owners);
|
setProperties(this, { owners, fromUpstream, upstreamUrn: datasetUrn });
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,48 @@
|
|||||||
|
import Component from '@ember/component';
|
||||||
|
import { task } from 'ember-concurrency';
|
||||||
|
import { get, set } from '@ember/object';
|
||||||
|
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||||
|
import { assert } from '@ember/debug';
|
||||||
|
import { readDatasetByUrn } from 'wherehows-web/utils/api/datasets/dataset';
|
||||||
|
|
||||||
|
export default class UpstreamOwners extends Component {
|
||||||
|
/**
|
||||||
|
* urn for the parent dataset
|
||||||
|
* @type {string}
|
||||||
|
* @memberof UpstreamOwners
|
||||||
|
*/
|
||||||
|
upstreamUrn: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the upstream dataset
|
||||||
|
* @type {IDatasetView.nativeName}
|
||||||
|
* @memberof UpstreamOwners
|
||||||
|
*/
|
||||||
|
nativeName: IDatasetView['nativeName'];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
|
||||||
|
assert('A valid upstreamUrn must be provided on instantiation', typeof this.upstreamUrn === 'string');
|
||||||
|
}
|
||||||
|
|
||||||
|
didUpdateAttrs() {
|
||||||
|
this._super(...arguments);
|
||||||
|
get(this, 'getUpstreamPropertiesTask').perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
didInsertElement() {
|
||||||
|
this._super(...arguments);
|
||||||
|
get(this, 'getUpstreamPropertiesTask').perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task to get properties for the upstream dataset
|
||||||
|
* @type {Task<Promise<IDatasetView>>, (a?: {} | undefined) => TaskInstance<Promise<IDatasetView>>>}
|
||||||
|
* @memberof UpstreamOwners
|
||||||
|
*/
|
||||||
|
getUpstreamPropertiesTask = task(function*(this: UpstreamOwners): IterableIterator<Promise<IDatasetView>> {
|
||||||
|
const { nativeName }: IDatasetView = yield readDatasetByUrn(get(this, 'upstreamUrn'));
|
||||||
|
set(this, 'nativeName', nativeName);
|
||||||
|
});
|
||||||
|
}
|
||||||
7
wherehows-web/app/components/datasets/upstream-owners.ts
Normal file
7
wherehows-web/app/components/datasets/upstream-owners.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default class extends Component {
|
||||||
|
tagName = 'section';
|
||||||
|
|
||||||
|
classNames = ['upstream-owners-banner'];
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@ import { inject } from '@ember/service';
|
|||||||
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
|
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
|
||||||
import { featureEntryPoints } from 'wherehows-web/constants/application';
|
import { featureEntryPoints } from 'wherehows-web/constants/application';
|
||||||
|
|
||||||
const { browse, scriptFinder, schemaHistory, idpc } = featureEntryPoints;
|
const { browse, scriptFinder, schemaHistory } = featureEntryPoints;
|
||||||
|
|
||||||
export default Route.extend(AuthenticatedRouteMixin, {
|
export default Route.extend(AuthenticatedRouteMixin, {
|
||||||
/**
|
/**
|
||||||
@ -26,7 +26,7 @@ export default Route.extend(AuthenticatedRouteMixin, {
|
|||||||
|
|
||||||
model() {
|
model() {
|
||||||
// Static list of content for the index route featureCard links
|
// Static list of content for the index route featureCard links
|
||||||
return [browse, scriptFinder, schemaHistory, idpc];
|
return [browse, scriptFinder, schemaHistory];
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Perform post model operations
|
* Perform post model operations
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
@import 'dataset-acl-access/all';
|
@import 'dataset-acl-access/all';
|
||||||
@import 'ivy-tabs/all';
|
@import 'ivy-tabs/all';
|
||||||
@import 'upstream-dataset/all';
|
@import 'upstream-dataset/all';
|
||||||
|
@import 'upstream-owners/all';
|
||||||
|
|
||||||
@import 'nacho/nacho-button';
|
@import 'nacho/nacho-button';
|
||||||
@import 'nacho/nacho-global-search';
|
@import 'nacho/nacho-global-search';
|
||||||
|
|||||||
@ -30,5 +30,5 @@ $feature-card-image-size: 50px !default;
|
|||||||
|
|
||||||
/// Wrap cards in containers with 1:1 ar
|
/// Wrap cards in containers with 1:1 ar
|
||||||
.feature-container {
|
.feature-container {
|
||||||
@include aspect-ratio(1, 1);
|
@include aspect-ratio(1, 0.5);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
@import 'upstream-owners';
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
.upstream-owners-banner {
|
||||||
|
@include nacho-container;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__informational {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
margin: 0;
|
||||||
|
padding: item-spacing(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,11 +24,19 @@
|
|||||||
|
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
||||||
{{dataset-authors
|
{{#if fromUpstream}}
|
||||||
owners=owners
|
|
||||||
ownerTypes=ownerTypes
|
{{datasets/containers/upstream-owners upstreamUrn=upstreamUrn}}
|
||||||
save=(action "saveOwnerChanges")
|
|
||||||
}}
|
{{else}}
|
||||||
|
|
||||||
|
{{dataset-authors
|
||||||
|
owners=owners
|
||||||
|
ownerTypes=ownerTypes
|
||||||
|
save=(action "saveOwnerChanges")
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
{{#if getUpstreamPropertiesTask.isRunning}}
|
||||||
|
|
||||||
|
{{pendulum-ellipsis-animation}}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
|
||||||
|
{{datasets/upstream-owners
|
||||||
|
nativeName=nativeName
|
||||||
|
upstreamUrn=upstreamUrn
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
<section class="upstream-owners-banner__content">
|
||||||
|
<div class="upstream-owners-banner__informational">
|
||||||
|
<i class="fa fa-info-circle fa-2x"></i>
|
||||||
|
|
||||||
|
<p class="upstream-owners-banner__informational__text">
|
||||||
|
Ownership metadata for this dataset is inherited from a parent dataset.
|
||||||
|
<br>
|
||||||
|
To make modifications, please update the Ownership on the parent dataset.
|
||||||
|
<br>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<header class="upstream-owners-banner__title">
|
||||||
|
Parent Dataset Name:
|
||||||
|
{{#link-to
|
||||||
|
"datasets.dataset"
|
||||||
|
upstreamUrn
|
||||||
|
}}
|
||||||
|
<strong>{{nativeName}}</strong>
|
||||||
|
{{/link-to}}
|
||||||
|
</header>
|
||||||
|
</section>
|
||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{#each model as |featureCard|}}
|
{{#each model as |featureCard|}}
|
||||||
<div class="col-md-3">
|
<div class="col-md-4">
|
||||||
<div class="feature-container">
|
<div class="feature-container">
|
||||||
<article class="feature-card">
|
<article class="feature-card">
|
||||||
{{#link-to featureCard.route}}
|
{{#link-to featureCard.route}}
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
<ul class="dropdown-menu" role="menu">
|
<ul class="dropdown-menu" role="menu">
|
||||||
{{#nav-link 'scripts' tagName="li"}}Script Finder{{/nav-link}}
|
{{#nav-link 'scripts' tagName="li"}}Script Finder{{/nav-link}}
|
||||||
{{#nav-link 'schemahistory' tagName="li"}}Schema History{{/nav-link}}
|
{{#nav-link 'schemahistory' tagName="li"}}Schema History{{/nav-link}}
|
||||||
{{#nav-link 'idpc' tagName="li"}}IDPC{{/nav-link}}
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|||||||
@ -94,15 +94,17 @@ const ownersWithModifiedTimeAsDate = arrayMap(ownerWithModifiedTimeAsDate);
|
|||||||
* @param {string} urn
|
* @param {string} urn
|
||||||
* @return {Promise<Array<IOwner>>}
|
* @return {Promise<Array<IOwner>>}
|
||||||
*/
|
*/
|
||||||
const readDatasetOwnersByUrn = async (urn: string): Promise<Array<IOwner>> => {
|
const readDatasetOwnersByUrn = async (urn: string): Promise<IOwnerResponse> => {
|
||||||
let owners: Array<IOwner> = [];
|
let owners: Array<IOwner> = [],
|
||||||
|
fromUpstream = false,
|
||||||
|
datasetUrn = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
({ owners = [] } = await getJSON<Pick<IOwnerResponse, 'owners'>>({ url: datasetOwnersUrlByUrn(urn) }));
|
({ owners = [], fromUpstream, datasetUrn } = await getJSON<IOwnerResponse>({ url: datasetOwnersUrlByUrn(urn) }));
|
||||||
return ownersWithModifiedTimeAsDate(owners);
|
return { owners: ownersWithModifiedTimeAsDate(owners), fromUpstream, datasetUrn };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (notFoundApiError(e)) {
|
if (notFoundApiError(e)) {
|
||||||
return owners;
|
return { owners, fromUpstream, datasetUrn };
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
import { moduleForComponent, test } from 'ember-qunit';
|
||||||
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
import { hdfsUrn } from 'wherehows-web/mirage/fixtures/urn';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import { waitUntil, find } from 'ember-native-dom-helpers';
|
||||||
|
|
||||||
|
moduleForComponent(
|
||||||
|
'datasets/containers/upstream-owners',
|
||||||
|
'Integration | Component | datasets/containers/upstream owners',
|
||||||
|
{
|
||||||
|
integration: true,
|
||||||
|
|
||||||
|
beforeEach() {
|
||||||
|
this.server = sinon.createFakeServer();
|
||||||
|
this.server.respondImmediately = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
afterEach() {
|
||||||
|
this.server.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
test('it renders', async function(assert) {
|
||||||
|
const titleElementQuery = '.upstream-owners-banner__title strong';
|
||||||
|
const nativeName = 'A nativeName';
|
||||||
|
|
||||||
|
this.set('upstreamUrn', hdfsUrn);
|
||||||
|
this.server.respondWith(/\/api\/v2\/datasets.*/, async function(xhr) {
|
||||||
|
xhr.respond(
|
||||||
|
200,
|
||||||
|
{ 'Content-Type': 'application/json' },
|
||||||
|
JSON.stringify({
|
||||||
|
dataset: {
|
||||||
|
nativeName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.render(hbs`{{datasets/containers/upstream-owners upstreamUrn=upstreamUrn}}`);
|
||||||
|
|
||||||
|
await waitUntil(() => find(titleElementQuery));
|
||||||
|
|
||||||
|
assert.equal(find(titleElementQuery).textContent.trim(), nativeName);
|
||||||
|
});
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { moduleForComponent, test } from 'ember-qunit';
|
||||||
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
import { hdfsUrn, nonHdfsUrn } from 'wherehows-web/mirage/fixtures/urn';
|
||||||
|
|
||||||
|
moduleForComponent('datasets/upstream-owners', 'Integration | Component | datasets/upstream owners', {
|
||||||
|
integration: true
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders', function(assert) {
|
||||||
|
this.render(hbs`{{datasets/upstream-owners}}`);
|
||||||
|
|
||||||
|
assert.ok(document.querySelector('.upstream-owners-banner'), 'renders upstream-dataset as expected');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rendering nativeName', function(assert) {
|
||||||
|
const titleElementQuery = '.upstream-owners-banner__title strong';
|
||||||
|
const nativeName = 'Upstream Dataset';
|
||||||
|
|
||||||
|
this.set('nativeName', nativeName);
|
||||||
|
|
||||||
|
this.render(hbs`{{datasets/upstream-owners nativeName=nativeName}}`);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
document
|
||||||
|
.querySelector(titleElementQuery)
|
||||||
|
.textContent.trim()
|
||||||
|
.includes(nativeName),
|
||||||
|
'it renders upstream ownership properties'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('link to upstream dataset', function(assert) {
|
||||||
|
this.set('upstreamUrn', hdfsUrn);
|
||||||
|
|
||||||
|
this.render(hbs`{{datasets/upstream-owners upstreamUrn=upstreamUrn}}`);
|
||||||
|
|
||||||
|
assert.ok(document.querySelector('.upstream-owners-banner a'), 'it creates a link to the upstream dataset');
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user