mirror of
				https://github.com/datahub-project/datahub.git
				synced 2025-11-04 04:39:10 +00:00 
			
		
		
		
	Finalize handling for api for metadata health endpoint and showing results
This commit is contained in:
		
							parent
							
								
									7cc30b7e8b
								
							
						
					
					
						commit
						1ececa7c1b
					
				@ -4,10 +4,12 @@ import { task } from 'ember-concurrency';
 | 
				
			|||||||
import ComputedProperty from '@ember/object/computed';
 | 
					import ComputedProperty from '@ember/object/computed';
 | 
				
			||||||
import { IChartDatum } from 'wherehows-web/typings/app/visualization/charts';
 | 
					import { IChartDatum } from 'wherehows-web/typings/app/visualization/charts';
 | 
				
			||||||
import { IHealthScore, IDatasetHealth } from 'wherehows-web/typings/api/datasets/health';
 | 
					import { IHealthScore, IDatasetHealth } from 'wherehows-web/typings/api/datasets/health';
 | 
				
			||||||
import { healthCategories, healthSeverity, healthDetail } from 'wherehows-web/constants/data/temp-mock/health';
 | 
					import { readDatasetHealthByUrn, getCategory } from 'wherehows-web/utils/api/datasets/health';
 | 
				
			||||||
import { readDatasetHealthByUrn } from 'wherehows-web/utils/api/datasets/health';
 | 
					 | 
				
			||||||
import { Tabs } from 'wherehows-web/constants/datasets/shared';
 | 
					import { Tabs } from 'wherehows-web/constants/datasets/shared';
 | 
				
			||||||
import { equal } from '@ember-decorators/object/computed';
 | 
					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
 | 
					 * 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)
 | 
					  @equal('tabSelected', Tabs.Health)
 | 
				
			||||||
  isActiveTab: boolean;
 | 
					  isActiveTab: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @service
 | 
				
			||||||
 | 
					  datasetMeta: ComputedProperty<DatasetMeta>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Modified categoryMetrics to add properties that will help us render our actual charts without modifying the original
 | 
					   * Modified categoryMetrics to add properties that will help us render our actual charts without modifying the original
 | 
				
			||||||
   * data
 | 
					   * data
 | 
				
			||||||
@ -145,21 +150,40 @@ export default class DatasetHealthContainer extends Component {
 | 
				
			|||||||
   * @type {Task<TaskInstance<Promise<any>>, (a?: any) => TaskInstance<TaskInstance<Promise<any>>>>}
 | 
					   * @type {Task<TaskInstance<Promise<any>>, (a?: any) => TaskInstance<TaskInstance<Promise<any>>>>}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  getContainerDataTask = task(function*(this: DatasetHealthContainer): IterableIterator<Promise<IDatasetHealth>> {
 | 
					  getContainerDataTask = task(function*(this: DatasetHealthContainer): IterableIterator<Promise<IDatasetHealth>> {
 | 
				
			||||||
    const { health } = yield readDatasetHealthByUrn(get(this, 'urn'));
 | 
					    const health = <IDatasetHealth>yield readDatasetHealthByUrn(get(this, 'urn'));
 | 
				
			||||||
    // Pretend like we're getting data from somehwere
 | 
					 | 
				
			||||||
    const healthData = {
 | 
					 | 
				
			||||||
      categories: healthCategories,
 | 
					 | 
				
			||||||
      severity: healthSeverity,
 | 
					 | 
				
			||||||
      detail: healthDetail
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setProperties(this, {
 | 
					    const details = health.validations || [];
 | 
				
			||||||
      categoryMetrics: healthData.categories,
 | 
					    const total = details.length;
 | 
				
			||||||
      severityMetrics: healthData.severity,
 | 
					    const categories: IObject<number> = {};
 | 
				
			||||||
      tableData: healthData.detail
 | 
					    const severities: IObject<number> = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Go through the details and find the COUNT of severity and category groupings
 | 
				
			||||||
 | 
					    const tableData: Array<IHealthScore> = 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<IChartDatum> = Object.keys(categories).map(category => ({
 | 
				
			||||||
 | 
					      name: category,
 | 
				
			||||||
 | 
					      value: Math.round((categories[category] / total) * 100)
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const severityMetrics: Array<IChartDatum> = 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
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,9 @@ import { Tabs } from 'wherehows-web/constants/datasets/shared';
 | 
				
			|||||||
import { action } from '@ember-decorators/object';
 | 
					import { action } from '@ember-decorators/object';
 | 
				
			||||||
import { DatasetPlatform } from 'wherehows-web/constants';
 | 
					import { DatasetPlatform } from 'wherehows-web/constants';
 | 
				
			||||||
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
 | 
					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 {
 | 
					export default class DatasetController extends Controller {
 | 
				
			||||||
  queryParams = ['urn'];
 | 
					  queryParams = ['urn'];
 | 
				
			||||||
@ -102,6 +105,21 @@ export default class DatasetController extends Controller {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  datasetContainsPersonalData: boolean;
 | 
					  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<DatasetMeta>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 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<number>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Flag indicating that the compliance policy needs user attention
 | 
					   * Flag indicating that the compliance policy needs user attention
 | 
				
			||||||
   * @type {ComputedProperty<boolean>}
 | 
					   * @type {ComputedProperty<boolean>}
 | 
				
			||||||
@ -121,6 +139,12 @@ export default class DatasetController extends Controller {
 | 
				
			|||||||
    return encodeUrn(uri);
 | 
					    return encodeUrn(uri);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  shouldShowHealthGauge: ComputedProperty<boolean> = 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
 | 
					   * Checks if the current platform exists in the supported list of JIT ACL whitelisted platforms
 | 
				
			||||||
   * @type {ComputedProperty<boolean>}
 | 
					   * @type {ComputedProperty<boolean>}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										15
									
								
								wherehows-web/app/services/dataset-meta.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								wherehows-web/app/services/dataset-meta.ts
									
									
									
									
									
										Normal file
									
								
							@ -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;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -62,10 +62,12 @@
 | 
				
			|||||||
              class="dataset-owner-list"
 | 
					              class="dataset-owner-list"
 | 
				
			||||||
              shouldShowDatasetHealth=shouldShowDatasetHealth}}
 | 
					              shouldShowDatasetHealth=shouldShowDatasetHealth}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {{visualization/charts/score-gauge
 | 
					            {{#if shouldShowHealthGauge}}
 | 
				
			||||||
              class="dataset-health-score"
 | 
					              {{visualization/charts/score-gauge
 | 
				
			||||||
              score=83
 | 
					                class="dataset-health-score"
 | 
				
			||||||
              title="Health Score:"}}
 | 
					                score=datasetHealthScore
 | 
				
			||||||
 | 
					                title="Health Score:"}}
 | 
				
			||||||
 | 
					            {{/if}}
 | 
				
			||||||
          {{/if}}
 | 
					          {{/if}}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,26 @@ import { IHealthScoreResponse, IDatasetHealth } from 'wherehows-web/typings/api/
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
const datasetHealthUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/health`;
 | 
					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<IDatasetHealth> => {
 | 
					export const readDatasetHealthByUrn = async (urn: string): Promise<IDatasetHealth> => {
 | 
				
			||||||
  const defaultResponse = { score: 0, validations: [] };
 | 
					  const defaultResponse = { score: 0, validations: [] };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								wherehows-web/tests/unit/services/dataset-meta-test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								wherehows-web/tests/unit/services/dataset-meta-test.ts
									
									
									
									
									
										Normal file
									
								
							@ -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);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -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');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user