mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-12 01:11:41 +00:00
implements relationship table component abstraction to show dataset lineage upstream / downstream datasets. adds take function to array functions. extracts lineage functions to utility module for lineage. adds RelationshipType alias for dropdown option
This commit is contained in:
parent
ca5d969dbe
commit
386b065ca6
@ -1,3 +1,141 @@
|
|||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
import { action } from '@ember-decorators/object';
|
||||||
|
import { Relationships, RelationshipType } from 'wherehows-web/typings/api/datasets/relationships';
|
||||||
|
import { computed, get, getProperties, set } from '@ember/object';
|
||||||
|
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||||
|
import { arrayMap, arrayPipe, arrayReduce } from 'wherehows-web/utils/array';
|
||||||
|
import ComputedProperty from '@ember/object/computed';
|
||||||
|
import {
|
||||||
|
allRelationshipType,
|
||||||
|
dedupeType,
|
||||||
|
filterRelationshipsByType,
|
||||||
|
takeNRelationships
|
||||||
|
} from 'wherehows-web/utils/datasets/lineage';
|
||||||
|
|
||||||
export default class DatasetRelationshipTable extends Component {}
|
export default class DatasetRelationshipTable extends Component {
|
||||||
|
/**
|
||||||
|
* The default number of element relationships to render initially
|
||||||
|
* @type {number}
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
truncatedLength = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of dataset relationships
|
||||||
|
* @type {Relationships}
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
relationships: Relationships;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* References the currently selected relationship type, used to filter out relationships
|
||||||
|
* of non matching type
|
||||||
|
* @type {RelationshipType}
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
selectedRelationshipType: RelationshipType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating if all relationships for the selected relationship type should be shown
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
showAllRelationships: boolean = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
|
||||||
|
// set default values for required props
|
||||||
|
this.selectedRelationshipType || set(this, 'selectedRelationshipType', allRelationshipType);
|
||||||
|
this.relationships || set(this, 'relationships', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the list of relationships to be rendered based on the currently set props
|
||||||
|
* for filter values e.g. relationshipType and show all flag
|
||||||
|
* @type {ComputedProperty<Relationships>}
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
filteredRelationships: ComputedProperty<Relationships> = computed(
|
||||||
|
'selectedRelationshipType',
|
||||||
|
'showAllRelationships',
|
||||||
|
function(this: DatasetRelationshipTable): Relationships {
|
||||||
|
const {
|
||||||
|
selectedRelationshipType: { value },
|
||||||
|
relationships,
|
||||||
|
showAllRelationships,
|
||||||
|
truncatedLength: n
|
||||||
|
} = getProperties(this, ['selectedRelationshipType', 'relationships', 'showAllRelationships', 'truncatedLength']);
|
||||||
|
|
||||||
|
return arrayPipe<Relationships>(
|
||||||
|
filterRelationshipsByType(value), // TODO: might need to break out into separate CP, relationshipsOfTypeN for hasMore CP filteredLength parameter
|
||||||
|
takeNRelationships(showAllRelationships, n)
|
||||||
|
)(relationships);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computed flag indicating if the currently rendered list of relationships has more
|
||||||
|
* elements than the current truncation length value
|
||||||
|
* @type {ComputedProperty<boolean>}
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
hasMore = computed(
|
||||||
|
'showAllRelationships',
|
||||||
|
'relationships.length',
|
||||||
|
'truncatedLength',
|
||||||
|
'filteredRelationships.length',
|
||||||
|
function(this: DatasetRelationshipTable): boolean {
|
||||||
|
const {
|
||||||
|
selectedRelationshipType,
|
||||||
|
relationships: { length: totalLength },
|
||||||
|
filteredRelationships: { length: filteredLength },
|
||||||
|
truncatedLength
|
||||||
|
} = getProperties(this, [
|
||||||
|
'selectedRelationshipType',
|
||||||
|
'relationships',
|
||||||
|
'filteredRelationships',
|
||||||
|
'truncatedLength'
|
||||||
|
]);
|
||||||
|
const hasFilter = selectedRelationshipType !== allRelationshipType;
|
||||||
|
|
||||||
|
return hasFilter ? filteredLength > truncatedLength : totalLength > truncatedLength;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a unique list of relationship types found the list of relationship
|
||||||
|
* @type {ComputedProperty<Array<RelationshipType>>}
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
relationshipTypes: ComputedProperty<Array<RelationshipType>> = computed('relationships.[]', function(
|
||||||
|
this: DatasetRelationshipTable
|
||||||
|
): Array<RelationshipType> {
|
||||||
|
const relationships = get(this, 'relationships');
|
||||||
|
const typeOption = ({ nativeType }: IDatasetView): RelationshipType => ({
|
||||||
|
label: nativeType,
|
||||||
|
value: nativeType
|
||||||
|
});
|
||||||
|
|
||||||
|
return [allRelationshipType, ...arrayPipe(arrayMap(typeOption), arrayReduce(dedupeType, []))(relationships)];
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the relationship type selection change
|
||||||
|
* @param {RelationshipType} type
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
@action
|
||||||
|
onTypeSelect(type: RelationshipType): void {
|
||||||
|
set(this, 'selectedRelationshipType', type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the flag to show all available relationships
|
||||||
|
* @memberof DatasetRelationshipTable
|
||||||
|
*/
|
||||||
|
@action
|
||||||
|
onToggleShowMore() {
|
||||||
|
this.toggleProperty('showAllRelationships');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
line-height: item-spacing(4) + 4;
|
line-height: item-spacing(4) + 4;
|
||||||
padding: item-spacing(2);
|
padding: item-spacing(2);
|
||||||
color: get-color(black, 0.6);
|
color: get-color(black, 0.6);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&--selected {
|
&--selected {
|
||||||
border-left: $option-border-width solid get-color(blue7);
|
border-left: $option-border-width solid get-color(blue7);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
{{#dataset-table fields=relationships as |relationTable|}}
|
{{#dataset-table fields=filteredRelationships as |relationTable|}}
|
||||||
{{#relationTable.head as |head|}}
|
{{#relationTable.head as |head|}}
|
||||||
{{#head.column}}Dataset{{/head.column}}
|
{{#head.column}}Dataset{{/head.column}}
|
||||||
{{#head.column}}
|
{{#head.column}}
|
||||||
@ -37,4 +37,24 @@
|
|||||||
{{/body.row}}
|
{{/body.row}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/relationTable.body}}
|
{{/relationTable.body}}
|
||||||
|
|
||||||
|
{{#if hasMore}}
|
||||||
|
{{#relationTable.foot}}
|
||||||
|
<td colspan="4" class="text-center">
|
||||||
|
<button
|
||||||
|
{{action "onToggleShowMore"}}
|
||||||
|
class="nacho-button--large nacho-button--tertiary">
|
||||||
|
{{#if showAllRelationships}}
|
||||||
|
|
||||||
|
See Less <span class="fa fa-caret-up" aria-label="See less relationships"></span>
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
|
||||||
|
See More <span class="fa fa-caret-down" aria-label="See more relationships"></span>
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
{{/relationTable.foot}}
|
||||||
|
{{/if}}
|
||||||
{{/dataset-table}}
|
{{/dataset-table}}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||||
|
import { IDropDownOption } from 'wherehows-web/typings/app/dataset-compliance';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias for a list of IDatasetView instances
|
* Alias for a list of IDatasetView instances
|
||||||
@ -7,4 +8,11 @@ import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
|||||||
*/
|
*/
|
||||||
type Relationships = Array<IDatasetView>;
|
type Relationships = Array<IDatasetView>;
|
||||||
|
|
||||||
export { Relationships };
|
/**
|
||||||
|
* Alias for a drop-down option based on an IDatasetView nativeType
|
||||||
|
* @alias
|
||||||
|
* @type RelationshipType
|
||||||
|
*/
|
||||||
|
type RelationshipType = IDropDownOption<string>;
|
||||||
|
|
||||||
|
export { Relationships, RelationshipType };
|
||||||
|
|||||||
@ -13,6 +13,13 @@ type Iteratee<A, R> = (a: A) => R;
|
|||||||
*/
|
*/
|
||||||
type Many<T> = T | Array<T>;
|
type Many<T> = T | Array<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a number of elements in the list from the start up to the length of the list
|
||||||
|
* @template T type of elements in array
|
||||||
|
* @param {number} [n=0] number of elements to take from the start of the array
|
||||||
|
*/
|
||||||
|
const take = <T>(n: number = 0) => (list: Array<T>): Array<T> => Array.prototype.slice.call(list, 0, n < 0 ? 0 : n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience utility takes a type-safe mapping function, and returns a list mapping function
|
* Convenience utility takes a type-safe mapping function, and returns a list mapping function
|
||||||
* @param {(param: T) => U} mappingFunction maps a single type T to type U
|
* @param {(param: T) => U} mappingFunction maps a single type T to type U
|
||||||
@ -60,17 +67,16 @@ const arrayReduce = <T, U>(
|
|||||||
): ((arr: Array<T>) => U) => (array = []) => array.reduce(iteratee, init);
|
): ((arr: Array<T>) => U) => (array = []) => array.reduce(iteratee, init);
|
||||||
|
|
||||||
// arrayPipe overloads
|
// arrayPipe overloads
|
||||||
function arrayPipe<T>(): (x: T) => T;
|
function arrayPipe<T, R1 = T>(f1: (a1: T) => R1): (x: T) => R1;
|
||||||
function arrayPipe<T, R1>(f1: (a1: T) => R1): (x: T) => R1;
|
function arrayPipe<T, R1 = T, R2 = T>(f1: (a1: T) => R1, f2: (a2: R1) => R2): (x: T) => R2;
|
||||||
function arrayPipe<T, R1, R2>(f1: (a1: T) => R1, f2: (a2: R1) => R2): (x: T) => R2;
|
function arrayPipe<T, R1 = T, R2 = T, R3 = T>(f1: (a1: T) => R1, f2: (a2: R1) => R2, f3: (a3: R2) => R3): (x: T) => R3;
|
||||||
function arrayPipe<T, R1, R2, R3>(f1: (a1: T) => R1, f2: (a2: R1) => R2, f3: (a3: R2) => R3): (x: T) => R3;
|
function arrayPipe<T, R1 = T, R2 = T, R3 = T, R4 = T>(
|
||||||
function arrayPipe<T, R1, R2, R3, R4>(
|
|
||||||
f1: (a1: T) => R1,
|
f1: (a1: T) => R1,
|
||||||
f2: (a2: R1) => R2,
|
f2: (a2: R1) => R2,
|
||||||
f3: (a3: R2) => R3,
|
f3: (a3: R2) => R3,
|
||||||
f4: (a4: R3) => R4
|
f4: (a4: R3) => R4
|
||||||
): (x: T) => R4;
|
): (x: T) => R4;
|
||||||
function arrayPipe<T, R1, R2, R3, R4, R5>(
|
function arrayPipe<T, R1 = T, R2 = T, R3 = T, R4 = T, R5 = T>(
|
||||||
f1: (a1: T) => R1,
|
f1: (a1: T) => R1,
|
||||||
f2: (a2: R1) => R2,
|
f2: (a2: R1) => R2,
|
||||||
f3: (a3: R2) => R3,
|
f3: (a3: R2) => R3,
|
||||||
@ -127,7 +133,7 @@ function arrayPipe<T, R1, R2, R3, R4, R5, R6, R7>(
|
|||||||
*/
|
*/
|
||||||
function arrayPipe<T, R>(...fns: Array<Many<Iteratee<any, any>>>): (x: T) => R {
|
function arrayPipe<T, R>(...fns: Array<Many<Iteratee<any, any>>>): (x: T) => R {
|
||||||
return arrayReduce<(a: T) => any, (x: any) => R>((acc, f) => (x): R => acc(f(x)), identity)(
|
return arrayReduce<(a: T) => any, (x: any) => R>((acc, f) => (x): R => acc(f(x)), identity)(
|
||||||
(<Array<Iteratee<any, any>>>[]).concat(...fns) // flatten if arg is of type Array<>
|
(<Array<Iteratee<any, any>>>[]).concat(...fns.reverse()) // flatten if arg is of type Array<>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +226,7 @@ const reduceArrayAsync = <T, U>(reducer: (arr?: Array<T>) => U) => (list: Array<
|
|||||||
export { Many, Iteratee };
|
export { Many, Iteratee };
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
take,
|
||||||
arrayMap,
|
arrayMap,
|
||||||
arrayFilter,
|
arrayFilter,
|
||||||
arrayReduce,
|
arrayReduce,
|
||||||
|
|||||||
49
wherehows-web/app/utils/datasets/lineage.ts
Normal file
49
wherehows-web/app/utils/datasets/lineage.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Relationships, RelationshipType } from 'wherehows-web/typings/api/datasets/relationships';
|
||||||
|
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||||
|
import { arrayFilter, take } from 'wherehows-web/utils/array';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant for the relationship type i.e. nativeType property with an empty string value, intended
|
||||||
|
* to signify all nativeType
|
||||||
|
* @type {Readonly<{label: string; value: string}>}
|
||||||
|
*/
|
||||||
|
const allRelationshipType: RelationshipType = Object.freeze({ label: 'All Types', value: '' });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a filter function, the will filter an instance of an IDatasetView on it's nativeType
|
||||||
|
* property
|
||||||
|
* @param {IDatasetView.nativeType} [filter='']
|
||||||
|
*/
|
||||||
|
const nativeTypeFilter = (filter: IDatasetView['nativeType'] = '') => ({ nativeType }: IDatasetView): boolean =>
|
||||||
|
filter ? nativeType === filter : true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters a list of Relationships on the nativeType attribute
|
||||||
|
* @param {string} filter
|
||||||
|
* @return {(array: Array<IDatasetView>) => Array<IDatasetView>}
|
||||||
|
*/
|
||||||
|
const filterRelationshipsByType = (filter: string = ''): ((array: Relationships) => Relationships) =>
|
||||||
|
arrayFilter(nativeTypeFilter(filter));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dedupes a list of RelationshipType objects
|
||||||
|
* @param {Array<RelationshipType>} set the deduped list
|
||||||
|
* @param {RelationshipType} relationshipType a RelationshipType element in the list
|
||||||
|
* @returns {Array<RelationshipType>}
|
||||||
|
*/
|
||||||
|
const dedupeType = (set: Array<RelationshipType>, relationshipType: RelationshipType): Array<RelationshipType> => {
|
||||||
|
const isSameType = ({ value }: RelationshipType): boolean => relationshipType.value === value;
|
||||||
|
const hasType = set.find(isSameType);
|
||||||
|
|
||||||
|
return hasType ? set : [...set, relationshipType];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes the first N elements in the list of relationships if the shouldShowAll flag is false
|
||||||
|
* @param {boolean} shouldShowAll flag to determine if all relationships should be shown
|
||||||
|
* @param {number} [n=10]
|
||||||
|
*/
|
||||||
|
const takeNRelationships = (shouldShowAll: boolean, n: number = 10) => (relationships: Relationships): Relationships =>
|
||||||
|
shouldShowAll ? relationships : take<IDatasetView>(n)(relationships);
|
||||||
|
|
||||||
|
export { allRelationshipType, filterRelationshipsByType, dedupeType, takeNRelationships };
|
||||||
Loading…
x
Reference in New Issue
Block a user