From 1ececa7c1b8090d02b1ab8faa7362ddbecd5c3af Mon Sep 17 00:00:00 2001 From: cptran777 Date: Thu, 16 Aug 2018 15:01:30 -0700 Subject: [PATCH 1/7] Finalize handling for api for metadata health endpoint and showing results --- .../datasets/containers/dataset-health.ts | 52 ++++++++++++++----- .../app/controllers/datasets/dataset.ts | 24 +++++++++ wherehows-web/app/services/dataset-meta.ts | 15 ++++++ .../app/templates/datasets/dataset.hbs | 10 ++-- .../app/utils/api/datasets/health.ts | 20 +++++++ .../tests/unit/services/dataset-meta-test.ts | 14 +++++ .../unit/utils/api/datasets/validator-test.js | 10 ++++ 7 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 wherehows-web/app/services/dataset-meta.ts create mode 100644 wherehows-web/tests/unit/services/dataset-meta-test.ts create mode 100644 wherehows-web/tests/unit/utils/api/datasets/validator-test.js diff --git a/wherehows-web/app/components/datasets/containers/dataset-health.ts b/wherehows-web/app/components/datasets/containers/dataset-health.ts index fdcad18c6c..e3e00663fd 100644 --- a/wherehows-web/app/components/datasets/containers/dataset-health.ts +++ b/wherehows-web/app/components/datasets/containers/dataset-health.ts @@ -4,10 +4,12 @@ import { task } from 'ember-concurrency'; import ComputedProperty from '@ember/object/computed'; import { IChartDatum } from 'wherehows-web/typings/app/visualization/charts'; import { IHealthScore, IDatasetHealth } from 'wherehows-web/typings/api/datasets/health'; -import { healthCategories, healthSeverity, healthDetail } from 'wherehows-web/constants/data/temp-mock/health'; -import { readDatasetHealthByUrn } from 'wherehows-web/utils/api/datasets/health'; +import { readDatasetHealthByUrn, getCategory } from 'wherehows-web/utils/api/datasets/health'; import { Tabs } from 'wherehows-web/constants/datasets/shared'; import { equal } from '@ember-decorators/object/computed'; +import { IObject } from 'wherehows-web/typings/generic'; +import { service } from '@ember-decorators/service'; +import DatasetMeta from 'wherehows-web/services/dataset-meta'; /** * Used for the dataset health tab, represents the fieldnames for the health score table @@ -88,6 +90,9 @@ export default class DatasetHealthContainer extends Component { @equal('tabSelected', Tabs.Health) isActiveTab: boolean; + @service + datasetMeta: ComputedProperty; + /** * Modified categoryMetrics to add properties that will help us render our actual charts without modifying the original * data @@ -145,21 +150,40 @@ export default class DatasetHealthContainer extends Component { * @type {Task>, (a?: any) => TaskInstance>>>} */ getContainerDataTask = task(function*(this: DatasetHealthContainer): IterableIterator> { - const { health } = yield readDatasetHealthByUrn(get(this, 'urn')); - // Pretend like we're getting data from somehwere - const healthData = { - categories: healthCategories, - severity: healthSeverity, - detail: healthDetail - }; + const health = yield readDatasetHealthByUrn(get(this, 'urn')); - setProperties(this, { - categoryMetrics: healthData.categories, - severityMetrics: healthData.severity, - tableData: healthData.detail + const details = health.validations || []; + const total = details.length; + const categories: IObject = {}; + const severities: IObject = {}; + + // Go through the details and find the COUNT of severity and category groupings + const tableData: Array = details.map(detail => { + const category = getCategory(detail.validator); + const severity = detail.tier || 'none'; + categories[category] = (categories[category] || 0) + 1; + severities[severity] = (severities[severity] || 0) + 1; + + return { category, severity, description: detail.description, score: detail.score * 100 }; }); - return health; // Do something with health information + const categoryMetrics: Array = Object.keys(categories).map(category => ({ + name: category, + value: Math.round((categories[category] / total) * 100) + })); + + const severityMetrics: Array = Object.keys(severities).map(severity => ({ + name: severity, + value: Math.round((severities[severity] / total) * 100) + })); + + get(this, 'datasetMeta').set('healthScore', health.score * 100 || 0); + + setProperties(this, { + categoryMetrics, + severityMetrics, + tableData + }); }); /** diff --git a/wherehows-web/app/controllers/datasets/dataset.ts b/wherehows-web/app/controllers/datasets/dataset.ts index c5473b29a2..1532e033b2 100644 --- a/wherehows-web/app/controllers/datasets/dataset.ts +++ b/wherehows-web/app/controllers/datasets/dataset.ts @@ -7,6 +7,9 @@ import { Tabs } from 'wherehows-web/constants/datasets/shared'; import { action } from '@ember-decorators/object'; import { DatasetPlatform } from 'wherehows-web/constants'; import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset'; +import { alias } from '@ember-decorators/object/computed'; +import DatasetMeta from 'wherehows-web/services/dataset-meta'; +import { service } from '@ember-decorators/service'; export default class DatasetController extends Controller { queryParams = ['urn']; @@ -102,6 +105,21 @@ export default class DatasetController extends Controller { */ datasetContainsPersonalData: boolean; + /** + * Including the datasetmeta property that is connected to each child container for the routable + * tabs. Can be used to share information between these tabs from a higher level + * @type {Ember.Service} + */ + @service + datasetMeta: ComputedProperty; + + /** + * Easy access in the template to the datasetMeta health score provided by the /health endpoint + * called in the dataset-health container + */ + @alias('datasetMeta.healthScore') + datasetHealthScore: ComputedProperty; + /** * Flag indicating that the compliance policy needs user attention * @type {ComputedProperty} @@ -121,6 +139,12 @@ export default class DatasetController extends Controller { return encodeUrn(uri); }); + shouldShowHealthGauge: ComputedProperty = computed('datasetHealthScore', function( + this: DatasetController + ): boolean { + return typeof get(this, 'datasetHealthScore') === 'number'; + }); + /** * Checks if the current platform exists in the supported list of JIT ACL whitelisted platforms * @type {ComputedProperty} diff --git a/wherehows-web/app/services/dataset-meta.ts b/wherehows-web/app/services/dataset-meta.ts new file mode 100644 index 0000000000..58cdc9bab6 --- /dev/null +++ b/wherehows-web/app/services/dataset-meta.ts @@ -0,0 +1,15 @@ +import Service from '@ember/service'; + +/** + * The dataset meta service can be used to share information between dataset route containers. + * Used to share health score but can be expanded to other meta informations + */ +export default class DatasetMeta extends Service { + healthScore: number; +} + +declare module '@ember/service' { + interface Registry { + 'dataset-meta': DatasetMeta; + } +} diff --git a/wherehows-web/app/templates/datasets/dataset.hbs b/wherehows-web/app/templates/datasets/dataset.hbs index 44c2cf9ebe..813dd3411c 100644 --- a/wherehows-web/app/templates/datasets/dataset.hbs +++ b/wherehows-web/app/templates/datasets/dataset.hbs @@ -62,10 +62,12 @@ class="dataset-owner-list" shouldShowDatasetHealth=shouldShowDatasetHealth}} - {{visualization/charts/score-gauge - class="dataset-health-score" - score=83 - title="Health Score:"}} + {{#if shouldShowHealthGauge}} + {{visualization/charts/score-gauge + class="dataset-health-score" + score=datasetHealthScore + title="Health Score:"}} + {{/if}} {{/if}} diff --git a/wherehows-web/app/utils/api/datasets/health.ts b/wherehows-web/app/utils/api/datasets/health.ts index ffc16788dd..0ed272832e 100644 --- a/wherehows-web/app/utils/api/datasets/health.ts +++ b/wherehows-web/app/utils/api/datasets/health.ts @@ -9,6 +9,26 @@ import { IHealthScoreResponse, IDatasetHealth } from 'wherehows-web/typings/api/ */ const datasetHealthUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/health`; +/** + * Constant for formatting of the validator string + * @type {string} + */ +const validatorFormat = 'com.linkedin.metadata.validators'; + +/** + * Useful for removing extraneous information outside of category + * @type {RegExp} + */ +const validationRegex = new RegExp(`${validatorFormat}.|Validator`, 'gi'); + +/** + * Given a string in the format 'com.linkedin.metadata.validators.[Category]Validator', extract + * Category and return it. + * @param validator - Given validator string + * @returns {string} + */ +export const getCategory = (validator: string) => validator.replace(validationRegex, ''); + export const readDatasetHealthByUrn = async (urn: string): Promise => { const defaultResponse = { score: 0, validations: [] }; diff --git a/wherehows-web/tests/unit/services/dataset-meta-test.ts b/wherehows-web/tests/unit/services/dataset-meta-test.ts new file mode 100644 index 0000000000..e83e8183d4 --- /dev/null +++ b/wherehows-web/tests/unit/services/dataset-meta-test.ts @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Service | dataset-meta', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let service = this.owner.lookup('service:dataset-meta'); + assert.ok(service); + + service.set('healthScore', 50); + assert.equal(service.get('healthScore'), 50); + }); +}); diff --git a/wherehows-web/tests/unit/utils/api/datasets/validator-test.js b/wherehows-web/tests/unit/utils/api/datasets/validator-test.js new file mode 100644 index 0000000000..aa0f58e362 --- /dev/null +++ b/wherehows-web/tests/unit/utils/api/datasets/validator-test.js @@ -0,0 +1,10 @@ +import { module, test } from 'qunit'; +import { getCategory } from 'wherehows-web/utils/api/datasets/health'; + +module('Unit | Utility | api/datasets/health', function() { + test('extracting category from validator string works', function(assert) { + const testSTtring = 'com.linkedin.metadata.validators.OwnershipValidator'; + + assert.equal(getCategory(testSTtring), 'Ownership'); + }); +}); From 1592bd55f89110111a8ace9684a2caee9c5ab3cd Mon Sep 17 00:00:00 2001 From: cptran777 Date: Thu, 16 Aug 2018 15:01:30 -0700 Subject: [PATCH 2/7] Finalize handling for api for metadata health endpoint and showing results --- .../datasets/containers/dataset-health.ts | 52 ++++++++++++++----- .../app/controllers/datasets/dataset.ts | 24 +++++++++ wherehows-web/app/services/dataset-meta.ts | 15 ++++++ .../app/templates/datasets/dataset.hbs | 10 ++-- .../app/utils/api/datasets/health.ts | 20 +++++++ .../tests/unit/services/dataset-meta-test.ts | 14 +++++ .../unit/utils/api/datasets/validator-test.js | 10 ++++ 7 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 wherehows-web/app/services/dataset-meta.ts create mode 100644 wherehows-web/tests/unit/services/dataset-meta-test.ts create mode 100644 wherehows-web/tests/unit/utils/api/datasets/validator-test.js diff --git a/wherehows-web/app/components/datasets/containers/dataset-health.ts b/wherehows-web/app/components/datasets/containers/dataset-health.ts index fdcad18c6c..e3e00663fd 100644 --- a/wherehows-web/app/components/datasets/containers/dataset-health.ts +++ b/wherehows-web/app/components/datasets/containers/dataset-health.ts @@ -4,10 +4,12 @@ import { task } from 'ember-concurrency'; import ComputedProperty from '@ember/object/computed'; import { IChartDatum } from 'wherehows-web/typings/app/visualization/charts'; import { IHealthScore, IDatasetHealth } from 'wherehows-web/typings/api/datasets/health'; -import { healthCategories, healthSeverity, healthDetail } from 'wherehows-web/constants/data/temp-mock/health'; -import { readDatasetHealthByUrn } from 'wherehows-web/utils/api/datasets/health'; +import { readDatasetHealthByUrn, getCategory } from 'wherehows-web/utils/api/datasets/health'; import { Tabs } from 'wherehows-web/constants/datasets/shared'; import { equal } from '@ember-decorators/object/computed'; +import { IObject } from 'wherehows-web/typings/generic'; +import { service } from '@ember-decorators/service'; +import DatasetMeta from 'wherehows-web/services/dataset-meta'; /** * Used for the dataset health tab, represents the fieldnames for the health score table @@ -88,6 +90,9 @@ export default class DatasetHealthContainer extends Component { @equal('tabSelected', Tabs.Health) isActiveTab: boolean; + @service + datasetMeta: ComputedProperty; + /** * Modified categoryMetrics to add properties that will help us render our actual charts without modifying the original * data @@ -145,21 +150,40 @@ export default class DatasetHealthContainer extends Component { * @type {Task>, (a?: any) => TaskInstance>>>} */ getContainerDataTask = task(function*(this: DatasetHealthContainer): IterableIterator> { - const { health } = yield readDatasetHealthByUrn(get(this, 'urn')); - // Pretend like we're getting data from somehwere - const healthData = { - categories: healthCategories, - severity: healthSeverity, - detail: healthDetail - }; + const health = yield readDatasetHealthByUrn(get(this, 'urn')); - setProperties(this, { - categoryMetrics: healthData.categories, - severityMetrics: healthData.severity, - tableData: healthData.detail + const details = health.validations || []; + const total = details.length; + const categories: IObject = {}; + const severities: IObject = {}; + + // Go through the details and find the COUNT of severity and category groupings + const tableData: Array = details.map(detail => { + const category = getCategory(detail.validator); + const severity = detail.tier || 'none'; + categories[category] = (categories[category] || 0) + 1; + severities[severity] = (severities[severity] || 0) + 1; + + return { category, severity, description: detail.description, score: detail.score * 100 }; }); - return health; // Do something with health information + const categoryMetrics: Array = Object.keys(categories).map(category => ({ + name: category, + value: Math.round((categories[category] / total) * 100) + })); + + const severityMetrics: Array = Object.keys(severities).map(severity => ({ + name: severity, + value: Math.round((severities[severity] / total) * 100) + })); + + get(this, 'datasetMeta').set('healthScore', health.score * 100 || 0); + + setProperties(this, { + categoryMetrics, + severityMetrics, + tableData + }); }); /** diff --git a/wherehows-web/app/controllers/datasets/dataset.ts b/wherehows-web/app/controllers/datasets/dataset.ts index c5473b29a2..1532e033b2 100644 --- a/wherehows-web/app/controllers/datasets/dataset.ts +++ b/wherehows-web/app/controllers/datasets/dataset.ts @@ -7,6 +7,9 @@ import { Tabs } from 'wherehows-web/constants/datasets/shared'; import { action } from '@ember-decorators/object'; import { DatasetPlatform } from 'wherehows-web/constants'; import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset'; +import { alias } from '@ember-decorators/object/computed'; +import DatasetMeta from 'wherehows-web/services/dataset-meta'; +import { service } from '@ember-decorators/service'; export default class DatasetController extends Controller { queryParams = ['urn']; @@ -102,6 +105,21 @@ export default class DatasetController extends Controller { */ datasetContainsPersonalData: boolean; + /** + * Including the datasetmeta property that is connected to each child container for the routable + * tabs. Can be used to share information between these tabs from a higher level + * @type {Ember.Service} + */ + @service + datasetMeta: ComputedProperty; + + /** + * Easy access in the template to the datasetMeta health score provided by the /health endpoint + * called in the dataset-health container + */ + @alias('datasetMeta.healthScore') + datasetHealthScore: ComputedProperty; + /** * Flag indicating that the compliance policy needs user attention * @type {ComputedProperty} @@ -121,6 +139,12 @@ export default class DatasetController extends Controller { return encodeUrn(uri); }); + shouldShowHealthGauge: ComputedProperty = computed('datasetHealthScore', function( + this: DatasetController + ): boolean { + return typeof get(this, 'datasetHealthScore') === 'number'; + }); + /** * Checks if the current platform exists in the supported list of JIT ACL whitelisted platforms * @type {ComputedProperty} diff --git a/wherehows-web/app/services/dataset-meta.ts b/wherehows-web/app/services/dataset-meta.ts new file mode 100644 index 0000000000..58cdc9bab6 --- /dev/null +++ b/wherehows-web/app/services/dataset-meta.ts @@ -0,0 +1,15 @@ +import Service from '@ember/service'; + +/** + * The dataset meta service can be used to share information between dataset route containers. + * Used to share health score but can be expanded to other meta informations + */ +export default class DatasetMeta extends Service { + healthScore: number; +} + +declare module '@ember/service' { + interface Registry { + 'dataset-meta': DatasetMeta; + } +} diff --git a/wherehows-web/app/templates/datasets/dataset.hbs b/wherehows-web/app/templates/datasets/dataset.hbs index 44c2cf9ebe..813dd3411c 100644 --- a/wherehows-web/app/templates/datasets/dataset.hbs +++ b/wherehows-web/app/templates/datasets/dataset.hbs @@ -62,10 +62,12 @@ class="dataset-owner-list" shouldShowDatasetHealth=shouldShowDatasetHealth}} - {{visualization/charts/score-gauge - class="dataset-health-score" - score=83 - title="Health Score:"}} + {{#if shouldShowHealthGauge}} + {{visualization/charts/score-gauge + class="dataset-health-score" + score=datasetHealthScore + title="Health Score:"}} + {{/if}} {{/if}} diff --git a/wherehows-web/app/utils/api/datasets/health.ts b/wherehows-web/app/utils/api/datasets/health.ts index ffc16788dd..0ed272832e 100644 --- a/wherehows-web/app/utils/api/datasets/health.ts +++ b/wherehows-web/app/utils/api/datasets/health.ts @@ -9,6 +9,26 @@ import { IHealthScoreResponse, IDatasetHealth } from 'wherehows-web/typings/api/ */ const datasetHealthUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/health`; +/** + * Constant for formatting of the validator string + * @type {string} + */ +const validatorFormat = 'com.linkedin.metadata.validators'; + +/** + * Useful for removing extraneous information outside of category + * @type {RegExp} + */ +const validationRegex = new RegExp(`${validatorFormat}.|Validator`, 'gi'); + +/** + * Given a string in the format 'com.linkedin.metadata.validators.[Category]Validator', extract + * Category and return it. + * @param validator - Given validator string + * @returns {string} + */ +export const getCategory = (validator: string) => validator.replace(validationRegex, ''); + export const readDatasetHealthByUrn = async (urn: string): Promise => { const defaultResponse = { score: 0, validations: [] }; diff --git a/wherehows-web/tests/unit/services/dataset-meta-test.ts b/wherehows-web/tests/unit/services/dataset-meta-test.ts new file mode 100644 index 0000000000..e83e8183d4 --- /dev/null +++ b/wherehows-web/tests/unit/services/dataset-meta-test.ts @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Service | dataset-meta', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let service = this.owner.lookup('service:dataset-meta'); + assert.ok(service); + + service.set('healthScore', 50); + assert.equal(service.get('healthScore'), 50); + }); +}); diff --git a/wherehows-web/tests/unit/utils/api/datasets/validator-test.js b/wherehows-web/tests/unit/utils/api/datasets/validator-test.js new file mode 100644 index 0000000000..aa0f58e362 --- /dev/null +++ b/wherehows-web/tests/unit/utils/api/datasets/validator-test.js @@ -0,0 +1,10 @@ +import { module, test } from 'qunit'; +import { getCategory } from 'wherehows-web/utils/api/datasets/health'; + +module('Unit | Utility | api/datasets/health', function() { + test('extracting category from validator string works', function(assert) { + const testSTtring = 'com.linkedin.metadata.validators.OwnershipValidator'; + + assert.equal(getCategory(testSTtring), 'Ownership'); + }); +}); From c913900f765ff8b160298b896a7360db1e9d8081 Mon Sep 17 00:00:00 2001 From: cptran777 Date: Thu, 16 Aug 2018 15:04:20 -0700 Subject: [PATCH 3/7] Fix issue with post commit prettier removing vital symbol From 724171185325d87aef20ae0049ea214a95f81ea0 Mon Sep 17 00:00:00 2001 From: cptran777 Date: Thu, 16 Aug 2018 15:06:25 -0700 Subject: [PATCH 4/7] Refix issue with prettier --- .../app/components/datasets/containers/dataset-health.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wherehows-web/app/components/datasets/containers/dataset-health.ts b/wherehows-web/app/components/datasets/containers/dataset-health.ts index e3e00663fd..338292077f 100644 --- a/wherehows-web/app/components/datasets/containers/dataset-health.ts +++ b/wherehows-web/app/components/datasets/containers/dataset-health.ts @@ -150,7 +150,7 @@ export default class DatasetHealthContainer extends Component { * @type {Task>, (a?: any) => TaskInstance>>>} */ getContainerDataTask = task(function*(this: DatasetHealthContainer): IterableIterator> { - const health = yield readDatasetHealthByUrn(get(this, 'urn')); + const health: IDatasetHealth = yield readDatasetHealthByUrn(get(this, 'urn')); const details = health.validations || []; const total = details.length; From c1925e38046d70bb56b1e78f0bc18aa84ef7bdb3 Mon Sep 17 00:00:00 2001 From: cptran777 Date: Thu, 16 Aug 2018 19:10:10 -0700 Subject: [PATCH 5/7] Fix modify twice on same render error and create new container to handle health gauge data task --- .../datasets/containers/dataset-health.ts | 7 ---- .../datasets/containers/health-score-gauge.ts | 39 ++++++++++++++++++ .../visualization/charts/score-gauge.ts | 40 ++++++++++++++----- .../app/controllers/datasets/dataset.ts | 24 ----------- wherehows-web/app/services/dataset-meta.ts | 13 ++++-- .../containers/health-score-gauge.hbs | 4 ++ .../visualization/charts/score-gauge.hbs | 2 +- .../app/templates/datasets/dataset.hbs | 7 +--- .../containers/health-score-gauge-test.js | 14 +++++++ .../tests/unit/services/dataset-meta-test.ts | 14 ------- 10 files changed, 98 insertions(+), 66 deletions(-) create mode 100644 wherehows-web/app/components/datasets/containers/health-score-gauge.ts create mode 100644 wherehows-web/app/templates/components/datasets/containers/health-score-gauge.hbs create mode 100644 wherehows-web/tests/integration/components/datasets/containers/health-score-gauge-test.js delete mode 100644 wherehows-web/tests/unit/services/dataset-meta-test.ts diff --git a/wherehows-web/app/components/datasets/containers/dataset-health.ts b/wherehows-web/app/components/datasets/containers/dataset-health.ts index 338292077f..2f96c93fee 100644 --- a/wherehows-web/app/components/datasets/containers/dataset-health.ts +++ b/wherehows-web/app/components/datasets/containers/dataset-health.ts @@ -8,8 +8,6 @@ import { readDatasetHealthByUrn, getCategory } from 'wherehows-web/utils/api/dat import { Tabs } from 'wherehows-web/constants/datasets/shared'; import { equal } from '@ember-decorators/object/computed'; import { IObject } from 'wherehows-web/typings/generic'; -import { service } from '@ember-decorators/service'; -import DatasetMeta from 'wherehows-web/services/dataset-meta'; /** * Used for the dataset health tab, represents the fieldnames for the health score table @@ -90,9 +88,6 @@ export default class DatasetHealthContainer extends Component { @equal('tabSelected', Tabs.Health) isActiveTab: boolean; - @service - datasetMeta: ComputedProperty; - /** * Modified categoryMetrics to add properties that will help us render our actual charts without modifying the original * data @@ -177,8 +172,6 @@ export default class DatasetHealthContainer extends Component { value: Math.round((severities[severity] / total) * 100) })); - get(this, 'datasetMeta').set('healthScore', health.score * 100 || 0); - setProperties(this, { categoryMetrics, severityMetrics, diff --git a/wherehows-web/app/components/datasets/containers/health-score-gauge.ts b/wherehows-web/app/components/datasets/containers/health-score-gauge.ts new file mode 100644 index 0000000000..8e8cfafa51 --- /dev/null +++ b/wherehows-web/app/components/datasets/containers/health-score-gauge.ts @@ -0,0 +1,39 @@ +import Component from '@ember/component'; +import { task } from 'ember-concurrency'; +import { IDatasetHealth } from 'wherehows-web/typings/api/datasets/health'; +import { readDatasetHealthByUrn } from 'wherehows-web/utils/api/datasets/health'; +import { get, set } from '@ember/object'; + +// import { once } from '@ember/runloop'; + +export default class HealthScoreGauge extends Component { + /** + * The urn identifier for the dataset + * @type {string} + */ + urn: string; + + /** + * Defines the tag to be used in the rendered html element for this component + * @type {string} + */ + tagName: ''; + + /** + * The health score to be passed to the container + */ + healthScore: number; + + didInsertElement() { + get(this, 'getHealthScoreTask').perform(); + } + + /** + * An async parent task to group all data tasks for this container component + * @type {Task>, (a?: any) => TaskInstance>>>} + */ + getHealthScoreTask = task(function*(this: HealthScoreGauge): IterableIterator> { + const health: IDatasetHealth = yield readDatasetHealthByUrn(get(this, 'urn')); + set(this, 'healthScore', health.score * 100 || 0); + }).restartable(); +} diff --git a/wherehows-web/app/components/visualization/charts/score-gauge.ts b/wherehows-web/app/components/visualization/charts/score-gauge.ts index 7be5c597ee..e49cfdea00 100644 --- a/wherehows-web/app/components/visualization/charts/score-gauge.ts +++ b/wherehows-web/app/components/visualization/charts/score-gauge.ts @@ -56,7 +56,7 @@ export default class VisualizationChartsScoreGauge extends Component { * @type {number} * @default 0 */ - score: number; + score: number = this.score || 0; /** * Represents the maximum value a score can be. Helps us to calculate a percentage score @@ -119,24 +119,44 @@ export default class VisualizationChartsScoreGauge extends Component { */ chartData: Array; - constructor() { - super(...arguments); - + /** + * Performs update functions for the charts upon initial and subsequent renders + */ + updateChart(): void { const chartOptions = getBaseGaugeConfig(); const chartData = getBaseChartDataConfig('score'); - const maxScore = typeof this.maxScore === 'number' ? this.maxScore : 100; - const score = this.score || NaN; + const score = this.score || 0; + // Adds our information to the highcharts formatted configurations so that they can be read in the chart - chartOptions.yAxis.max = maxScore; + chartOptions.yAxis.max = get(this, 'maxScore'); chartData[0].data = [score]; setProperties(this, { - score, - maxScore, chartOptions, - chartData, + chartData + }); + } + + /** + * Allows us to rerender the graph when the score gets updated. Useful for when API calls haven't been + * resolved yet at initial render + */ + didUpdateAttrs() { + this._super(...arguments); + this.updateChart(); + } + + constructor() { + super(...arguments); + // Prevents "modify twice in single render" issue + this.score = this.score || 0; + + setProperties(this, { + maxScore: typeof this.maxScore === 'number' ? this.maxScore : 100, title: this.title || '', scoreDisplay: this.scoreDisplay || ScoreDisplay.percentage }); + + this.updateChart(); } } diff --git a/wherehows-web/app/controllers/datasets/dataset.ts b/wherehows-web/app/controllers/datasets/dataset.ts index 1532e033b2..c5473b29a2 100644 --- a/wherehows-web/app/controllers/datasets/dataset.ts +++ b/wherehows-web/app/controllers/datasets/dataset.ts @@ -7,9 +7,6 @@ import { Tabs } from 'wherehows-web/constants/datasets/shared'; import { action } from '@ember-decorators/object'; import { DatasetPlatform } from 'wherehows-web/constants'; import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset'; -import { alias } from '@ember-decorators/object/computed'; -import DatasetMeta from 'wherehows-web/services/dataset-meta'; -import { service } from '@ember-decorators/service'; export default class DatasetController extends Controller { queryParams = ['urn']; @@ -105,21 +102,6 @@ export default class DatasetController extends Controller { */ datasetContainsPersonalData: boolean; - /** - * Including the datasetmeta property that is connected to each child container for the routable - * tabs. Can be used to share information between these tabs from a higher level - * @type {Ember.Service} - */ - @service - datasetMeta: ComputedProperty; - - /** - * Easy access in the template to the datasetMeta health score provided by the /health endpoint - * called in the dataset-health container - */ - @alias('datasetMeta.healthScore') - datasetHealthScore: ComputedProperty; - /** * Flag indicating that the compliance policy needs user attention * @type {ComputedProperty} @@ -139,12 +121,6 @@ export default class DatasetController extends Controller { return encodeUrn(uri); }); - shouldShowHealthGauge: ComputedProperty = computed('datasetHealthScore', function( - this: DatasetController - ): boolean { - return typeof get(this, 'datasetHealthScore') === 'number'; - }); - /** * Checks if the current platform exists in the supported list of JIT ACL whitelisted platforms * @type {ComputedProperty} diff --git a/wherehows-web/app/services/dataset-meta.ts b/wherehows-web/app/services/dataset-meta.ts index 58cdc9bab6..6c79b5a315 100644 --- a/wherehows-web/app/services/dataset-meta.ts +++ b/wherehows-web/app/services/dataset-meta.ts @@ -1,13 +1,18 @@ import Service from '@ember/service'; +import { IObject } from 'wherehows-web/typings/generic'; +import { get } from '@ember/object'; -/** - * The dataset meta service can be used to share information between dataset route containers. - * Used to share health score but can be expanded to other meta informations - */ export default class DatasetMeta extends Service { healthScore: number; + + healthScores: IObject = {}; + + setHealthScoreForUrn(urn: string, score: number) { + get(this, 'healthScores')[urn] = score; + } } +// DO NOT DELETE: this is how TypeScript knows how to look up your services. declare module '@ember/service' { interface Registry { 'dataset-meta': DatasetMeta; diff --git a/wherehows-web/app/templates/components/datasets/containers/health-score-gauge.hbs b/wherehows-web/app/templates/components/datasets/containers/health-score-gauge.hbs new file mode 100644 index 0000000000..c10b475ba0 --- /dev/null +++ b/wherehows-web/app/templates/components/datasets/containers/health-score-gauge.hbs @@ -0,0 +1,4 @@ +{{visualization/charts/score-gauge + class="dataset-health-score" + score=healthScore + title="Health Score:"}} \ No newline at end of file diff --git a/wherehows-web/app/templates/components/visualization/charts/score-gauge.hbs b/wherehows-web/app/templates/components/visualization/charts/score-gauge.hbs index 8ad1b508c0..91fc410dcd 100644 --- a/wherehows-web/app/templates/components/visualization/charts/score-gauge.hbs +++ b/wherehows-web/app/templates/components/visualization/charts/score-gauge.hbs @@ -1,4 +1,4 @@ -{{high-charts chartOptions=chartOptions content=chartData}} +{{high-charts chartOptions=(readonly chartOptions) content=(readonly chartData)}}
{{title}} diff --git a/wherehows-web/app/templates/datasets/dataset.hbs b/wherehows-web/app/templates/datasets/dataset.hbs index 813dd3411c..49b6f24a3e 100644 --- a/wherehows-web/app/templates/datasets/dataset.hbs +++ b/wherehows-web/app/templates/datasets/dataset.hbs @@ -62,12 +62,7 @@ class="dataset-owner-list" shouldShowDatasetHealth=shouldShowDatasetHealth}} - {{#if shouldShowHealthGauge}} - {{visualization/charts/score-gauge - class="dataset-health-score" - score=datasetHealthScore - title="Health Score:"}} - {{/if}} + {{datasets/containers/health-score-gauge urn=encodedUrn}} {{/if}}
diff --git a/wherehows-web/tests/integration/components/datasets/containers/health-score-gauge-test.js b/wherehows-web/tests/integration/components/datasets/containers/health-score-gauge-test.js new file mode 100644 index 0000000000..5e973a4c6b --- /dev/null +++ b/wherehows-web/tests/integration/components/datasets/containers/health-score-gauge-test.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | datasets/containers/health-score-gauge', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + await render(hbs`{{datasets/containers/health-score-gauge}}`); + + assert.ok(this.element, 'Renders without errors'); + }); +}); diff --git a/wherehows-web/tests/unit/services/dataset-meta-test.ts b/wherehows-web/tests/unit/services/dataset-meta-test.ts deleted file mode 100644 index e83e8183d4..0000000000 --- a/wherehows-web/tests/unit/services/dataset-meta-test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; - -module('Unit | Service | dataset-meta', function(hooks) { - setupTest(hooks); - - test('it exists', function(assert) { - let service = this.owner.lookup('service:dataset-meta'); - assert.ok(service); - - service.set('healthScore', 50); - assert.equal(service.get('healthScore'), 50); - }); -}); From 7192f9b6ffbaa1c4939b82841210c8fa42356b4f Mon Sep 17 00:00:00 2001 From: cptran777 Date: Fri, 17 Aug 2018 09:01:49 -0700 Subject: [PATCH 6/7] Minor modification --- .../app/components/visualization/charts/score-gauge.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wherehows-web/app/components/visualization/charts/score-gauge.ts b/wherehows-web/app/components/visualization/charts/score-gauge.ts index e49cfdea00..f7ccf4744d 100644 --- a/wherehows-web/app/components/visualization/charts/score-gauge.ts +++ b/wherehows-web/app/components/visualization/charts/score-gauge.ts @@ -149,7 +149,7 @@ export default class VisualizationChartsScoreGauge extends Component { constructor() { super(...arguments); // Prevents "modify twice in single render" issue - this.score = this.score || 0; + this.score = typeof this.score === 'number' ? this.score : 0; setProperties(this, { maxScore: typeof this.maxScore === 'number' ? this.maxScore : 100, From 6ec7b2151eb69ee7aa998128c8a9480f13c2e61c Mon Sep 17 00:00:00 2001 From: cptran777 Date: Fri, 17 Aug 2018 14:14:16 -0700 Subject: [PATCH 7/7] Code cleanup for health score gauge handler --- .../datasets/containers/health-score-gauge.ts | 8 ++++---- .../visualization/charts/score-gauge.ts | 2 +- wherehows-web/app/services/dataset-meta.ts | 20 ------------------- .../containers/health-score-gauge.hbs | 12 +++++++---- 4 files changed, 13 insertions(+), 29 deletions(-) delete mode 100644 wherehows-web/app/services/dataset-meta.ts diff --git a/wherehows-web/app/components/datasets/containers/health-score-gauge.ts b/wherehows-web/app/components/datasets/containers/health-score-gauge.ts index 8e8cfafa51..08d7e5feb2 100644 --- a/wherehows-web/app/components/datasets/containers/health-score-gauge.ts +++ b/wherehows-web/app/components/datasets/containers/health-score-gauge.ts @@ -4,8 +4,6 @@ import { IDatasetHealth } from 'wherehows-web/typings/api/datasets/health'; import { readDatasetHealthByUrn } from 'wherehows-web/utils/api/datasets/health'; import { get, set } from '@ember/object'; -// import { once } from '@ember/runloop'; - export default class HealthScoreGauge extends Component { /** * The urn identifier for the dataset @@ -17,12 +15,14 @@ export default class HealthScoreGauge extends Component { * Defines the tag to be used in the rendered html element for this component * @type {string} */ - tagName: ''; + tagName = ''; + + elementId = undefined; /** * The health score to be passed to the container */ - healthScore: number; + healthScore: number = 0; didInsertElement() { get(this, 'getHealthScoreTask').perform(); diff --git a/wherehows-web/app/components/visualization/charts/score-gauge.ts b/wherehows-web/app/components/visualization/charts/score-gauge.ts index f7ccf4744d..bacce33c38 100644 --- a/wherehows-web/app/components/visualization/charts/score-gauge.ts +++ b/wherehows-web/app/components/visualization/charts/score-gauge.ts @@ -56,7 +56,7 @@ export default class VisualizationChartsScoreGauge extends Component { * @type {number} * @default 0 */ - score: number = this.score || 0; + score: number; /** * Represents the maximum value a score can be. Helps us to calculate a percentage score diff --git a/wherehows-web/app/services/dataset-meta.ts b/wherehows-web/app/services/dataset-meta.ts deleted file mode 100644 index 6c79b5a315..0000000000 --- a/wherehows-web/app/services/dataset-meta.ts +++ /dev/null @@ -1,20 +0,0 @@ -import Service from '@ember/service'; -import { IObject } from 'wherehows-web/typings/generic'; -import { get } from '@ember/object'; - -export default class DatasetMeta extends Service { - healthScore: number; - - healthScores: IObject = {}; - - setHealthScoreForUrn(urn: string, score: number) { - get(this, 'healthScores')[urn] = score; - } -} - -// DO NOT DELETE: this is how TypeScript knows how to look up your services. -declare module '@ember/service' { - interface Registry { - 'dataset-meta': DatasetMeta; - } -} diff --git a/wherehows-web/app/templates/components/datasets/containers/health-score-gauge.hbs b/wherehows-web/app/templates/components/datasets/containers/health-score-gauge.hbs index c10b475ba0..4833ba635d 100644 --- a/wherehows-web/app/templates/components/datasets/containers/health-score-gauge.hbs +++ b/wherehows-web/app/templates/components/datasets/containers/health-score-gauge.hbs @@ -1,4 +1,8 @@ -{{visualization/charts/score-gauge - class="dataset-health-score" - score=healthScore - title="Health Score:"}} \ No newline at end of file +{{#if getHealthScoreTask.isIdle}} + {{visualization/charts/score-gauge + class="dataset-health-score" + score=healthScore + title="Health Score:"}} +{{else}} + {{pendulum-ellipsis-animation}} +{{/if}}