mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-03 12:16:10 +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 { 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;
|
||||
padding: item-spacing(2);
|
||||
color: get-color(black, 0.6);
|
||||
cursor: pointer;
|
||||
|
||||
&--selected {
|
||||
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|}}
|
||||
{{#head.column}}Dataset{{/head.column}}
|
||||
{{#head.column}}
|
||||
@ -37,4 +37,24 @@
|
||||
{{/body.row}}
|
||||
{{/each}}
|
||||
{{/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}}
|
||||
@ -1,4 +1,5 @@
|
||||
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
|
||||
@ -7,4 +8,11 @@ import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||
*/
|
||||
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>;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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);
|
||||
|
||||
// arrayPipe overloads
|
||||
function arrayPipe<T>(): (x: T) => T;
|
||||
function arrayPipe<T, R1>(f1: (a1: T) => R1): (x: T) => R1;
|
||||
function arrayPipe<T, R1, R2>(f1: (a1: T) => R1, f2: (a2: R1) => R2): (x: T) => R2;
|
||||
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, R2, R3, R4>(
|
||||
function arrayPipe<T, R1 = T>(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 = T, R2 = T, R3 = T>(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>(
|
||||
f1: (a1: T) => R1,
|
||||
f2: (a2: R1) => R2,
|
||||
f3: (a3: R2) => R3,
|
||||
f4: (a4: R3) => 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,
|
||||
f2: (a2: R1) => R2,
|
||||
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 {
|
||||
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 {
|
||||
take,
|
||||
arrayMap,
|
||||
arrayFilter,
|
||||
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