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:
Seyi Adebajo 2018-07-23 10:51:27 -07:00
parent ca5d969dbe
commit 386b065ca6
6 changed files with 233 additions and 10 deletions

View File

@ -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');
}
}

View File

@ -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);

View File

@ -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}}

View File

@ -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 };

View File

@ -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,

View 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 };