From 86804ac2c97fcbe3c63636f949b369b6d22a514d Mon Sep 17 00:00:00 2001 From: Seyi Adebajo Date: Thu, 22 Feb 2018 11:16:50 -0800 Subject: [PATCH] reenable breadcumb navigation based on li urn format. support either hdfs / non-hdfs. add home --- .../components/datasets/urn-breadcrumbs.ts | 29 ++++++++++ wherehows-web/app/routes/datasets/dataset.js | 21 ------- .../components/datasets/urn-breadcrumbs.hbs | 25 +++++++++ .../app/templates/datasets/dataset.hbs | 10 +--- .../utils/entities/bake-urn-breadcrumbs.ts | 48 ++++++++++++++++ wherehows-web/app/utils/entities/index.ts | 4 +- .../utils/entities/make-urn-breadcrumbs.ts | 41 -------------- wherehows-web/mirage/fixtures/urn.ts | 6 +- .../datasets/urn-breadcrumbs-test.js | 56 +++++++++++++++++++ 9 files changed, 167 insertions(+), 73 deletions(-) create mode 100644 wherehows-web/app/components/datasets/urn-breadcrumbs.ts create mode 100644 wherehows-web/app/templates/components/datasets/urn-breadcrumbs.hbs create mode 100644 wherehows-web/app/utils/entities/bake-urn-breadcrumbs.ts delete mode 100644 wherehows-web/app/utils/entities/make-urn-breadcrumbs.ts create mode 100644 wherehows-web/tests/integration/components/datasets/urn-breadcrumbs-test.js diff --git a/wherehows-web/app/components/datasets/urn-breadcrumbs.ts b/wherehows-web/app/components/datasets/urn-breadcrumbs.ts new file mode 100644 index 0000000000..5dea6e0a7c --- /dev/null +++ b/wherehows-web/app/components/datasets/urn-breadcrumbs.ts @@ -0,0 +1,29 @@ +import Component from '@ember/component'; +import { computed, get } from '@ember/object'; +import ComputedProperty from '@ember/object/computed'; +import { bakeUrnBreadcrumbs } from 'wherehows-web/utils/entities'; +import { IDatasetBreadcrumb } from 'wherehows-web/utils/entities/bake-urn-breadcrumbs'; + +export default class UrnBreadcrumbs extends Component { + tagName = 'ul'; + + classNames = ['nacho-breadcrumbs']; + + /** + * Urn for the dataset to be represented in the breadcrumbs + * @type {string} + * @memberof UrnBreadcrumbs + */ + urn: string; + + /** + * Builds the breadcrumbs for the dataset with the related urn + * @type {ComputedProperty>} + * @memberof UrnBreadcrumbs + */ + breadcrumbs: ComputedProperty> = computed('urn', function( + this: UrnBreadcrumbs + ): Array { + return bakeUrnBreadcrumbs(get(this, 'urn')); + }); +} diff --git a/wherehows-web/app/routes/datasets/dataset.js b/wherehows-web/app/routes/datasets/dataset.js index b5d116287a..3dd8397676 100644 --- a/wherehows-web/app/routes/datasets/dataset.js +++ b/wherehows-web/app/routes/datasets/dataset.js @@ -2,17 +2,6 @@ import Route from '@ember/routing/route'; import { set, get, setProperties } from '@ember/object'; import { inject } from '@ember/service'; import { makeUrnBreadcrumbs } from 'wherehows-web/utils/entities'; -import { readDatasetCompliance, readDatasetComplianceSuggestion } from 'wherehows-web/utils/api/datasets/compliance'; -import { readNonPinotProperties, readPinotProperties } from 'wherehows-web/utils/api/datasets/properties'; -import { readDatasetComments } from 'wherehows-web/utils/api/datasets/comments'; -import { readComplianceDataTypes } from 'wherehows-web/utils/api/list/compliance-datatypes'; -import { - readDatasetColumns, - columnDataTypesAndFieldNames, - augmentObjectsWithHtmlComments -} from 'wherehows-web/utils/api/datasets/columns'; - -import { readDatasetOwners, getUserEntities } from 'wherehows-web/utils/api/datasets/owners'; import { isRequiredMinOwnersNotConfirmed } from 'wherehows-web/constants/datasets/owner'; import { readDatasetById, readDatasetByUrn } from 'wherehows-web/utils/api/datasets/dataset'; import isUrn, { isWhUrn, isLiUrn, convertWhUrnToLiUrn, encodeUrn, decodeUrn } from 'wherehows-web/utils/validators/urn'; @@ -74,18 +63,8 @@ export default Route.extend({ set(controller, 'model', model); setProperties(controller, { isInternal: await get(this, 'configurator').getConfig('isInternal') - // ...properties, - // requiredMinNotConfirmed: isRequiredMinOwnersNotConfirmed(owners) }); - // If urn exists, create a breadcrumb list - // TODO: DSS-7068 Refactoring in progress , move this to a computed prop on a container component - // FIXME: DSS-7068 browse.entity?urn route does not exist for last item in breadcrumb i.e. the dataset - // currently being viewed. Should this even be a link in the first place? - if (model.uri) { - set(controller, 'breadcrumbs', makeUrnBreadcrumbs(model.uri)); - } - // TODO: Get current user ACL permission info for ACL access tab Promise.resolve(currentUser()) .then(userInfo => { diff --git a/wherehows-web/app/templates/components/datasets/urn-breadcrumbs.hbs b/wherehows-web/app/templates/components/datasets/urn-breadcrumbs.hbs new file mode 100644 index 0000000000..7a0dbb3065 --- /dev/null +++ b/wherehows-web/app/templates/components/datasets/urn-breadcrumbs.hbs @@ -0,0 +1,25 @@ +
  • + + {{link-to + "datasets" + "browse.entity" + "datasets" + (query-params page=1 prefix="" platform="") + class="nacho-breadcrumbs__crumb__grain" + }} + +
  • + +{{#each breadcrumbs as |crumb|}} +
  • + + {{link-to + crumb.crumb + "browse.entity" + "datasets" + (query-params page=1 prefix=crumb.prefix platform=crumb.platform) + class="nacho-breadcrumbs__crumb__grain" + }} + +
  • +{{/each}} diff --git a/wherehows-web/app/templates/datasets/dataset.hbs b/wherehows-web/app/templates/datasets/dataset.hbs index 5765c94c29..0359ad25eb 100644 --- a/wherehows-web/app/templates/datasets/dataset.hbs +++ b/wherehows-web/app/templates/datasets/dataset.hbs @@ -1,13 +1,6 @@
    -
      - {{#each breadcrumbs as |crumb|}} -
    • - {{link-to crumb.crumb "browse.entity" "datasets" (query-params page=1 urn=crumb.urn) - class="nacho-breadcrumbs__crumb__grain"}} -
    • - {{/each}} -
    + {{datasets/urn-breadcrumbs urn=model.uri}}
    @@ -51,6 +44,7 @@

    {{ model.nativeName }}

    + {{dataset-owner-list owners=owners datasetName=model.nativeName}}
    diff --git a/wherehows-web/app/utils/entities/bake-urn-breadcrumbs.ts b/wherehows-web/app/utils/entities/bake-urn-breadcrumbs.ts new file mode 100644 index 0000000000..fa63284639 --- /dev/null +++ b/wherehows-web/app/utils/entities/bake-urn-breadcrumbs.ts @@ -0,0 +1,48 @@ +import { DatasetPlatform } from 'wherehows-web/constants'; +import { datasetUrnRegexLI } from 'wherehows-web/utils/validators/urn'; + +/** + * Describes the interface for a breadcrumb object + * @interface IDatasetBreadcrumb + */ +export interface IDatasetBreadcrumb { + crumb: string; + platform: DatasetPlatform; + prefix: string; +} + +/** + * Takes a urn string and parses it into an array of breadcrumb objects with crumb, and query params, prefix and/or platform as + * properties. + * Hierarchy is implied in element ordering + * @param {string} urn the dataset urn in li format + * @returns {Array} + */ +export default (urn: string): Array => { + const liDatasetUrn = datasetUrnRegexLI.exec(urn); + const breadcrumbs: Array = []; + + if (liDatasetUrn) { + const [, platform, segments] = liDatasetUrn; + const isHdfs = String(platform).toLowerCase() === DatasetPlatform.HDFS; + // For HDFS drop leading slash + const hierarchy = isHdfs ? segments.split('/').slice(1) : segments.split('.'); + + return [platform, ...hierarchy].reduce((breadcrumbs, crumb, index) => { + const previousCrumb = breadcrumbs[index - 1]; + // if hdfs, precede with slash, otherwise trailing period + const prefix = !index ? '' : isHdfs ? `${previousCrumb.prefix}/${crumb}` : `${previousCrumb.prefix}${crumb}.`; + + return [ + ...breadcrumbs, + { + crumb, + prefix, + platform: platform + } + ]; + }, breadcrumbs); + } + + return breadcrumbs; +}; diff --git a/wherehows-web/app/utils/entities/index.ts b/wherehows-web/app/utils/entities/index.ts index 4c9c894f72..2803371da6 100644 --- a/wherehows-web/app/utils/entities/index.ts +++ b/wherehows-web/app/utils/entities/index.ts @@ -1,3 +1,3 @@ -import makeUrnBreadcrumbs from 'wherehows-web/utils/entities/make-urn-breadcrumbs'; +import bakeUrnBreadcrumbs from 'wherehows-web/utils/entities/bake-urn-breadcrumbs'; -export { makeUrnBreadcrumbs }; +export { bakeUrnBreadcrumbs }; diff --git a/wherehows-web/app/utils/entities/make-urn-breadcrumbs.ts b/wherehows-web/app/utils/entities/make-urn-breadcrumbs.ts deleted file mode 100644 index d206d96b03..0000000000 --- a/wherehows-web/app/utils/entities/make-urn-breadcrumbs.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { datasetUrnRegexWH } from 'wherehows-web/utils/validators/urn'; - -interface IBreadCrumb { - crumb: string; - urn: string; -} - -/** - * Takes a urn string and parse it into an array of breadcrumb objects with crumb, and urn as - * properties. - * Hierarchy is implied in element ordering - * @param {String} urn - * @return {Array.<{crumb, urn}>|null} - */ -export default (urn: string): Array<{ crumb: string; urn: string }> | null => { - const urnMatch = datasetUrnRegexWH.exec(urn); - - if (urnMatch) { - // Initial element in a match array from RegExp#exec is the full match, not needed here - const urnParts = urnMatch.filter((_match, index) => index); - // Splits the 2nd captured group into an array of urn names and spreads into a new list - const crumbs = [urnParts[0], ...urnParts[1].split('/')]; - - // Reduces the crumbs into a list of crumb names and urn paths - return crumbs.reduce( - (breadcrumbs, crumb, index) => { - const previousCrumb = breadcrumbs[index - 1]; - const breadcrumb: IBreadCrumb = { - crumb, - // First item is root - urn: !index ? `${crumb}:///` : `${previousCrumb.urn}${crumb}/` - }; - - return [...breadcrumbs, breadcrumb]; - }, - >[] - ); - } - - return null; -}; diff --git a/wherehows-web/mirage/fixtures/urn.ts b/wherehows-web/mirage/fixtures/urn.ts index 1cac579a72..a88691c5b0 100644 --- a/wherehows-web/mirage/fixtures/urn.ts +++ b/wherehows-web/mirage/fixtures/urn.ts @@ -1,4 +1,8 @@ +import { decodeUrn } from 'wherehows-web/utils/validators/urn'; + const urn = 'urn:li:dataset:(urn:li:dataPlatform:hdfs,%2Fseg1s%2Fseg2%2Fseg3%2Fseg4%2Fdataset-node,PROD)'; +const nonHdfsUrn = 'urn:li:dataset:(urn:li:dataPlatform:db,ABOOK.ABOOK_DATA,PROD)'; +const hdfsUrn = decodeUrn(urn); const whUrnToLiUrnMap = [ ['espresso:///ETLInfra/AllTables', 'urn:li:dataset:(urn:li:dataPlatform:espresso,ETLInfra.AllTables,PROD)'], @@ -13,4 +17,4 @@ const whUrnToLiUrnMap = [ ['oracle:///ABOOK/ABOOK_DATA', 'urn:li:dataset:(urn:li:dataPlatform:oracle,ABOOK.ABOOK_DATA,PROD)'] ]; -export { urn, whUrnToLiUrnMap }; +export { urn, whUrnToLiUrnMap, hdfsUrn, nonHdfsUrn }; diff --git a/wherehows-web/tests/integration/components/datasets/urn-breadcrumbs-test.js b/wherehows-web/tests/integration/components/datasets/urn-breadcrumbs-test.js new file mode 100644 index 0000000000..bd192f6214 --- /dev/null +++ b/wherehows-web/tests/integration/components/datasets/urn-breadcrumbs-test.js @@ -0,0 +1,56 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; +import { hdfsUrn, nonHdfsUrn } from 'wherehows-web/mirage/fixtures/urn'; +import { datasetUrnRegexLI } from 'wherehows-web/utils/validators/urn'; + +moduleForComponent('datasets/urn-breadcrumbs', 'Integration | Component | datasets/urn breadcrumbs', { + integration: true +}); + +const home = ['datasets']; + +test('it renders only the home breadcrumb without a valid urn', function(assert) { + this.render(hbs`{{datasets/urn-breadcrumbs}}`); + const homeCrumb = document.querySelector('.nacho-breadcrumbs__crumb'); + + assert.equal(homeCrumb.textContent.trim(), 'datasets', 'shows the home breadcrumb'); + assert.equal( + document.querySelectorAll('.nacho-breadcrumbs__crumb').length, + 1, + 'only one breadcrumb is rendered when a urn is not provided' + ); +}); + +test('it renders breadcrumbs with a valid hdfs urn', function(assert) { + const [, platform, segments] = datasetUrnRegexLI.exec(hdfsUrn); + const segmentParts = segments.split('/').slice(1); + let crumbs; + + this.set('urn', hdfsUrn); + this.render(hbs`{{datasets/urn-breadcrumbs urn=urn}}`); + + crumbs = document.querySelectorAll('.nacho-breadcrumbs__crumb'); + + assert.equal(crumbs.length, home.length + [platform].length + segmentParts.length, ''); + + [...home, platform, ...segmentParts].forEach((node, index) => + assert.equal(node, crumbs[index].textContent.trim(), `breadcrumb ${index} has expected text ${node}`) + ); +}); + +test('it renders breadcrumbs with a valid non hdfs urn', function(assert) { + const [, platform, segments] = datasetUrnRegexLI.exec(nonHdfsUrn); + const segmentParts = segments.split('.'); + let crumbs; + + this.set('urn', nonHdfsUrn); + this.render(hbs`{{datasets/urn-breadcrumbs urn=urn}}`); + + crumbs = document.querySelectorAll('.nacho-breadcrumbs__crumb'); + + assert.equal(crumbs.length, home.length + [platform].length + segmentParts.length, ''); + + [...home, platform, ...segmentParts].forEach((node, index) => + assert.equal(node, crumbs[index].textContent.trim(), `breadcrumb ${index} has expected text ${node}`) + ); +});