diff --git a/wherehows-web/app/components/dataset-compliance-row.ts b/wherehows-web/app/components/dataset-compliance-row.ts index c8732ee96e..8f1abf9467 100644 --- a/wherehows-web/app/components/dataset-compliance-row.ts +++ b/wherehows-web/app/components/dataset-compliance-row.ts @@ -4,7 +4,6 @@ import { computed, get, getProperties, getWithDefault } from '@ember/object'; import { Classification, defaultFieldDataTypeClassification, - fieldIdentifierOptions, fieldIdentifierTypeIds, ComplianceFieldIdValue, hasPredefinedFieldFormat, @@ -30,29 +29,29 @@ export default class DatasetComplianceRow extends DatasetTableRow { field: IComplianceField; /** - * Describes action interface for `onFieldIdentifierTypeChange` + * Describes action interface for `onFieldIdentifierTypeChange` action * @memberof DatasetComplianceRow */ onFieldIdentifierTypeChange: (field: IComplianceField, option: { value: ComplianceFieldIdValue }) => void; /** - * Describes action interface for `onFieldLogicalTypeChange` + * Describes action interface for `onFieldLogicalTypeChange` action * @memberof DatasetComplianceRow */ onFieldLogicalTypeChange: ( field: IComplianceField, - option: { value: void } | Pick + option: { value: void | IFieldFormatDropdownOption['value'] } ) => void; /** - * Describes action interface for `onFieldClassificationChange` + * Describes action interface for `onFieldClassificationChange` action * * @memberof DatasetComplianceRow */ onFieldClassificationChange: (field: IComplianceField, option: { value: '' | Classification }) => void; /** - * Describes action interface for `onSuggestionIntent` + * Describes action interface for `onSuggestionIntent` action * @memberof DatasetComplianceRow */ onSuggestionIntent: (field: IComplianceField, intent?: SuggestionIntent) => void; @@ -71,6 +70,13 @@ export default class DatasetComplianceRow extends DatasetTableRow { */ dataType: ComputedProperty = alias('field.dataType'); + /** + * Dropdown options for each compliance field / record + * @type {Array} + * @memberof DatasetComplianceRow + */ + complianceFieldIdDropdownOptions: Array; + /** * Reference to the current value of the field's SuggestionIntent if present * indicates that the provided suggestion is either accepted or ignored @@ -81,7 +87,7 @@ export default class DatasetComplianceRow extends DatasetTableRow { /** * Maps the suggestion response, if present, to a string resolution - * @type CpmputedProperty + * @type ComputedProperty * @memberof DatasetComplianceRow */ suggestionResolution = computed('suggestionAuthority', function(this: DatasetComplianceRow): string | void { @@ -128,6 +134,10 @@ export default class DatasetComplianceRow extends DatasetTableRow { * @type {string} */ const value = get(get(this, 'field'), fieldProp); + /** + * Field drop down options + */ + const complianceFieldIdDropdownOptions = get(this, 'complianceFieldIdDropdownOptions'); /** * Convenience function to get `label` attribute on the display properties object @@ -137,7 +147,7 @@ export default class DatasetComplianceRow extends DatasetTableRow { ((Array.isArray(dropDownOptions) && dropDownOptions.findBy('value', value)) || { label: void 0 }).label; return { - identifierType: getLabel(fieldIdentifierOptions), + identifierType: getLabel(complianceFieldIdDropdownOptions), logicalType: getLabel(get(this, 'fieldFormats')) }[fieldProp]; } @@ -302,10 +312,10 @@ export default class DatasetComplianceRow extends DatasetTableRow { * Handles the updates when the field logical type changes on this field * @param {IFieldFormatDropdownOption} option contains the selected dropdown value */ - onFieldLogicalTypeChange(this: DatasetComplianceRow, option: IFieldFormatDropdownOption) { - const { value } = option; + onFieldLogicalTypeChange(this: DatasetComplianceRow, option: IFieldFormatDropdownOption | null) { + const { value } = option || { value: void 0 }; const onFieldLogicalTypeChange = get(this, 'onFieldLogicalTypeChange'); - if (typeof onFieldLogicalTypeChange === 'function' && value) { + if (typeof onFieldLogicalTypeChange === 'function') { onFieldLogicalTypeChange(get(this, 'field'), { value }); } }, diff --git a/wherehows-web/app/components/dataset-compliance.js b/wherehows-web/app/components/dataset-compliance.js index 1026e18ad2..69ff1be660 100644 --- a/wherehows-web/app/components/dataset-compliance.js +++ b/wherehows-web/app/components/dataset-compliance.js @@ -4,7 +4,7 @@ import { securityClassificationDropdownOptions, DatasetClassifiers, fieldIdentifierTypes, - fieldIdentifierOptions, + getFieldIdentifierOptions, fieldIdentifierTypeIds, idLogicalTypes, nonIdFieldLogicalTypes, @@ -94,7 +94,6 @@ export default Component.extend({ sortDirection: 'asc', searchTerm: '', helpText, - fieldIdentifierOptions, hiddenTrackingFields, /** @@ -117,6 +116,15 @@ export default Component.extend({ .map(key => steps[key]); }), + /** + * Reads the complianceDataTypes property and transforms into a list of drop down options for the field + * identifier type + * @type {ComputedProperty>} + */ + complianceFieldIdDropdownOptions: computed('complianceDataTypes', function() { + return getFieldIdentifierOptions(get(this, 'complianceDataTypes')); + }), + /** * Handles the transition between steps in the compliance edit wizard * including performing each step's post processing action once a user has diff --git a/wherehows-web/app/constants/dataset-compliance.ts b/wherehows-web/app/constants/dataset-compliance.ts index 0d0347e8c1..2164cd82d8 100644 --- a/wherehows-web/app/constants/dataset-compliance.ts +++ b/wherehows-web/app/constants/dataset-compliance.ts @@ -1,16 +1,29 @@ import Ember from 'ember'; -import { fieldIdentifierTypes } from 'wherehows-web/constants/datasets/compliance'; +import { ComplianceFieldIdValue } from 'wherehows-web/constants/datasets/compliance'; +import { IComplianceDataType } from 'wherehows-web/typings/api/list/compliance-datatypes'; +import { arrayMap } from 'wherehows-web/utils/array'; const { String: { htmlSafe } } = Ember; /** * Defines the interface field identifier drop downs + * @interface IFieldIdentifierOption */ interface IFieldIdentifierOption { value: string; label: string; isDisabled?: boolean; } + +/** + * Defines the interface for compliance data type field options + * @interface IComplianceFieldIdentifierOption + * @extends {IFieldIdentifierOption} + */ +interface IComplianceFieldIdentifierOption extends IFieldIdentifierOption { + value: ComplianceFieldIdValue; +} + /** * Defines a map of values for the compliance policy on a dataset * @type {object} @@ -31,33 +44,20 @@ const compliancePolicyStrings = { }; /** - * List of identifier type keys without the none object value - * @type {Array} + * Takes a compliance data type and transforms it into a compliance field identifier option + * @param {IComplianceDataType} complianceDataType + * @returns {IComplianceFieldIdentifierOption} */ -const fieldIdentifierTypeKeysBarNone: Array = Object.keys(fieldIdentifierTypes).filter(k => k !== 'none'); +const getFieldIdentifierOption = (complianceDataType: IComplianceDataType): IComplianceFieldIdentifierOption => { + const { id, title } = complianceDataType; + return { value: id, label: title }; +}; /** - * Keys for the field display options - * @type {Array} + * Maps over a list of compliance data types objects and transforms to a list of dropdown options + * @type {(array: Array) => Array} */ -const fieldDisplayKeys: Array = ['none', '_', ...fieldIdentifierTypeKeysBarNone]; - -/** - * A list of field identifier types mapped to label, value options for select display - * @type {Array<{value: string, label: string, isDisabled: boolean}>} - */ -const fieldIdentifierOptions: Array = fieldDisplayKeys.map(fieldIdentifierType => { - const divider = '──────────'; - const { value = fieldIdentifierType, displayAs: label = divider } = fieldIdentifierTypes[fieldIdentifierType] || {}; - - // Adds a divider for a value of _ - // Visually this separates ID from none fieldIdentifierTypes - return { - value, - label, - isDisabled: fieldIdentifierType === '_' - }; -}); +const getFieldIdentifierOptions = arrayMap(getFieldIdentifierOption); /** * Defines the html string for informing the user of hidden tracking fields @@ -105,9 +105,11 @@ const getComplianceSteps = ( export { compliancePolicyStrings, - fieldIdentifierOptions, + getFieldIdentifierOption, + getFieldIdentifierOptions, complianceSteps, hiddenTrackingFields, getComplianceSteps, - IFieldIdentifierOption + IFieldIdentifierOption, + IComplianceFieldIdentifierOption }; diff --git a/wherehows-web/app/constants/datasets/compliance.ts b/wherehows-web/app/constants/datasets/compliance.ts index a63578772e..ed464076db 100644 --- a/wherehows-web/app/constants/datasets/compliance.ts +++ b/wherehows-web/app/constants/datasets/compliance.ts @@ -72,7 +72,7 @@ enum ComplianceFieldIdValue { } /** - * Defines the string values for a custom id logical tyoe + * Defines the string values for a custom id logical type * @enum {string} */ enum CustomIdLogicalType { diff --git a/wherehows-web/app/routes/datasets/dataset.js b/wherehows-web/app/routes/datasets/dataset.js index c206884a3e..5f6b598608 100644 --- a/wherehows-web/app/routes/datasets/dataset.js +++ b/wherehows-web/app/routes/datasets/dataset.js @@ -3,6 +3,7 @@ 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, @@ -110,6 +111,7 @@ export default Route.extend({ const [ { schemaless, columns }, compliance, + complianceDataTypes, complianceSuggestion, datasetComments, isInternal, @@ -119,6 +121,7 @@ export default Route.extend({ ] = await Promise.all([ readDatasetColumns(id), readDatasetCompliance(id), + readComplianceDataTypes(), readDatasetComplianceSuggestion(id), readDatasetComments(id), get(this, 'configurator').getConfig('isInternal'), @@ -137,6 +140,7 @@ export default Route.extend({ setProperties(controller, { complianceInfo, + complianceDataTypes, isNewComplianceInfo, complianceSuggestion, datasetComments, diff --git a/wherehows-web/app/templates/datasets/dataset-compliance/-dataset-compliance-entities.hbs b/wherehows-web/app/templates/datasets/dataset-compliance/-dataset-compliance-entities.hbs index 424d2292c6..27782425c9 100644 --- a/wherehows-web/app/templates/datasets/dataset-compliance/-dataset-compliance-entities.hbs +++ b/wherehows-web/app/templates/datasets/dataset-compliance/-dataset-compliance-entities.hbs @@ -111,6 +111,7 @@ {{#body.row field=field isNewComplianceInfo=isNewComplianceInfo + complianceFieldIdDropdownOptions=complianceFieldIdDropdownOptions class=(if field.suggestion "dataset-compliance-fields__has-suggestions") onFieldLogicalTypeChange=(action 'onFieldLogicalTypeChange') onFieldClassificationChange=(action 'onFieldClassificationChange') @@ -161,7 +162,7 @@ {{#row.cell class="dataset-compliance-fields__tall-cell"}} {{ember-selector disabled=(not isEditing) - values=fieldIdentifierOptions + values=complianceFieldIdDropdownOptions selected=(readonly row.identifierType) selectionDidChange=(action row.onFieldIdentifierTypeChange) }} diff --git a/wherehows-web/app/templates/datasets/dataset.hbs b/wherehows-web/app/templates/datasets/dataset.hbs index 36616851b0..24d282d4ba 100644 --- a/wherehows-web/app/templates/datasets/dataset.hbs +++ b/wherehows-web/app/templates/datasets/dataset.hbs @@ -274,6 +274,7 @@ complianceSuggestion=complianceSuggestion isNewComplianceInfo=isNewComplianceInfo schemaFieldNamesMappedToDataTypes=schemaFieldNamesMappedToDataTypes + complianceDataTypes=complianceDataTypes onSave=(action "savePrivacyCompliancePolicy") onReset=(action "resetPrivacyCompliancePolicy") }} diff --git a/wherehows-web/app/typings/api/datasets/compliance.d.ts b/wherehows-web/app/typings/api/datasets/compliance.d.ts index 738425a622..caec1a568e 100644 --- a/wherehows-web/app/typings/api/datasets/compliance.d.ts +++ b/wherehows-web/app/typings/api/datasets/compliance.d.ts @@ -123,29 +123,3 @@ export interface IComplianceSuggestionResponse { status: ApiStatus; complianceSuggestion?: IComplianceSuggestion; } - -/** - * Describes the interface for a complianceDataType - * @export - * @interface IComplianceDataType - */ -export interface IComplianceDataType { - pii: boolean; - idType: boolean; - defaultSecurityClassification: Classification; - title: string; - $URN: string; - supportedFieldFormats: Array; - id: ComplianceFieldIdValue; -} - -/** - * Describes the interface for a request to the complianceDataType endpoint - * @export - * @interface IComplianceDataTypeResponse - */ -export interface IComplianceDataTypeResponse { - status: ApiStatus; - complianceDataTypes?: Array; - msg?: string; -} diff --git a/wherehows-web/app/typings/api/list/compliance-datatypes.d.ts b/wherehows-web/app/typings/api/list/compliance-datatypes.d.ts new file mode 100644 index 0000000000..e3c235ddaf --- /dev/null +++ b/wherehows-web/app/typings/api/list/compliance-datatypes.d.ts @@ -0,0 +1,35 @@ +import { Classification, ComplianceFieldIdValue, IdLogicalType } from 'wherehows-web/constants'; +import { ApiStatus } from 'wherehows-web/utils/api/shared'; + +/** + * Describes the interface for a complianceDataType + * @export + * @interface IComplianceDataType + */ +export interface IComplianceDataType { + // Indicates that id contains pii + pii: boolean; + // Flag indicating if a field with this id is a member identifier + idType: boolean; + // The default security classification for the field with this id + defaultSecurityClassification: Classification; + // User friendly translation for the id string + title: string; + // Urn for the id + $URN: string; + // List of field formats supported for a field with the id, only applicable to fields with idType set to true + supportedFieldFormats: Array; + // The id for the field + id: ComplianceFieldIdValue; +} + +/** + * Describes the interface for a request to the complianceDataType endpoint + * @export + * @interface IComplianceDataTypeResponse + */ +export interface IComplianceDataTypeResponse { + status: ApiStatus; + complianceDataTypes?: Array; + msg?: string; +} diff --git a/wherehows-web/app/utils/api/list/compliance-datatypes.ts b/wherehows-web/app/utils/api/list/compliance-datatypes.ts new file mode 100644 index 0000000000..b709bb2b7a --- /dev/null +++ b/wherehows-web/app/utils/api/list/compliance-datatypes.ts @@ -0,0 +1,28 @@ +import { IComplianceDataType, IComplianceDataTypeResponse } from 'wherehows-web/typings/api/list/compliance-datatypes'; +import { ApiStatus } from 'wherehows-web/utils/api'; +import { getJSON } from 'wherehows-web/utils/api/fetcher'; +import { listUrlRoot } from 'wherehows-web/utils/api/list/shared'; + +/** + * Defines the url endpoint for the list of dataset compliance data types and attributes + * @type {string} + */ +const complianceDataTypesUrl = `${listUrlRoot}/complianceDataTypes`; + +/** + * Requests the list of compliance data types and the related attributes + * @returns {Promise>} + */ +const readComplianceDataTypes = async (): Promise> => { + const { status, complianceDataTypes = [], msg } = await getJSON({ + url: complianceDataTypesUrl + }); + + if (status === ApiStatus.OK && complianceDataTypes.length) { + return complianceDataTypes; + } + + throw new Error(msg); +}; + +export { readComplianceDataTypes }; diff --git a/wherehows-web/mirage/config.ts b/wherehows-web/mirage/config.ts index 06bb17b100..d8ed470383 100644 --- a/wherehows-web/mirage/config.ts +++ b/wherehows-web/mirage/config.ts @@ -13,6 +13,16 @@ export default function(this: IMirageServer) { this.namespace = '/api/v1'; + this.get('/list/complianceDataTypes', function( + this: IFunctionRouteHandler, + { complianceDataTypes }: { complianceDataTypes: any } + ) { + return { + complianceDataTypes: this.serialize(complianceDataTypes.all()), + status: ApiStatus.OK + }; + }); + interface IComplianceSuggestionsObject { complianceSuggestions: any; } @@ -140,6 +150,7 @@ export default function(this: IMirageServer) { status: ApiStatus.OK }; }); + this.passthrough(); } diff --git a/wherehows-web/mirage/fixtures/compliance-data-types.ts b/wherehows-web/mirage/fixtures/compliance-data-types.ts new file mode 100644 index 0000000000..6672e779ff --- /dev/null +++ b/wherehows-web/mirage/fixtures/compliance-data-types.ts @@ -0,0 +1,254 @@ +export default [ + { + pii: true, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Member ID', + $URN: 'urn:li:complianceDataType:MEMBER_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'MEMBER_ID' + }, + { + pii: false, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Organization ID', + $URN: 'urn:li:complianceDataType:COMPANY_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'COMPANY_ID' + }, + { + pii: false, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Group ID', + $URN: 'urn:li:complianceDataType:GROUP_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'GROUP_ID' + }, + { + pii: false, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Mixed ID', + $URN: 'urn:li:complianceDataType:MIXED_ID', + supportedFieldFormats: ['URN'], + id: 'MIXED_ID' + }, + { + pii: true, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Enterprise Profile ID', + $URN: 'urn:li:complianceDataType:ENTERPRISE_PROFILE_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'ENTERPRISE_PROFILE_ID' + }, + { + pii: false, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Enterprise Account ID', + $URN: 'urn:li:complianceDataType:ENTERPRISE_ACCOUNT_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'ENTERPRISE_ACCOUNT_ID' + }, + { + pii: false, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Contract ID', + $URN: 'urn:li:complianceDataType:CONTRACT_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'CONTRACT_ID' + }, + { + pii: true, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Seat ID', + $URN: 'urn:li:complianceDataType:SEAT_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'SEAT_ID' + }, + { + pii: false, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Advertiser ID', + $URN: 'urn:li:complianceDataType:ADVERTISER_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'ADVERTISER_ID' + }, + { + pii: true, + idType: true, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'SlideShare User ID', + $URN: 'urn:li:complianceDataType:SLIDESHARE_USER_ID', + supportedFieldFormats: ['NUMERIC', 'URN', 'REVERSED_URN', 'COMPOSITE_URN'], + id: 'SLIDESHARE_USER_ID' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Name', + $URN: 'urn:li:complianceDataType:NAME', + supportedFieldFormats: [], + id: 'NAME' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Email', + $URN: 'urn:li:complianceDataType:EMAIL', + supportedFieldFormats: [], + id: 'EMAIL' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Phone', + $URN: 'urn:li:complianceDataType:PHONE', + supportedFieldFormats: [], + id: 'PHONE' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Address', + $URN: 'urn:li:complianceDataType:ADDRESS', + supportedFieldFormats: [], + id: 'ADDRESS' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Latitude & Longitude', + $URN: 'urn:li:complianceDataType:LATITUDE_LONGITUDE', + supportedFieldFormats: [], + id: 'LATITUDE_LONGITUDE' + }, + { + pii: false, + idType: false, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'City, State, Region, Country', + $URN: 'urn:li:complianceDataType:CITY_STATE_REGION', + supportedFieldFormats: [], + id: 'CITY_STATE_REGION' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'IP Address', + $URN: 'urn:li:complianceDataType:IP_ADDRESS', + supportedFieldFormats: [], + id: 'IP_ADDRESS' + }, + { + pii: false, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Financial Number', + $URN: 'urn:li:complianceDataType:FINANCIAL_NUMBER', + supportedFieldFormats: [], + id: 'FINANCIAL_NUMBER' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'HIGHLY_CONFIDENTIAL', + title: 'Payment Info', + $URN: 'urn:li:complianceDataType:PAYMENT_INFO', + supportedFieldFormats: [], + id: 'PAYMENT_INFO' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'HIGHLY_CONFIDENTIAL', + title: 'Password & Credentials', + $URN: 'urn:li:complianceDataType:PASSWORD_CREDENTIAL', + supportedFieldFormats: [], + id: 'PASSWORD_CREDENTIAL' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'HIGHLY_CONFIDENTIAL', + title: 'Authentication Token', + $URN: 'urn:li:complianceDataType:AUTHENTICATION_TOKEN', + supportedFieldFormats: [], + id: 'AUTHENTICATION_TOKEN' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'HIGHLY_CONFIDENTIAL', + title: 'Message', + $URN: 'urn:li:complianceDataType:MESSAGE', + supportedFieldFormats: [], + id: 'MESSAGE' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'HIGHLY_CONFIDENTIAL', + title: 'National ID', + $URN: 'urn:li:complianceDataType:NATIONAL_ID', + supportedFieldFormats: [], + id: 'NATIONAL_ID' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Social Network ID', + $URN: 'urn:li:complianceDataType:SOCIAL_NETWORK_ID', + supportedFieldFormats: [], + id: 'SOCIAL_NETWORK_ID' + }, + { + pii: false, + idType: false, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Event Time', + $URN: 'urn:li:complianceDataType:EVENT_TIME', + supportedFieldFormats: [], + id: 'EVENT_TIME' + }, + { + pii: false, + idType: false, + defaultSecurityClassification: 'LIMITED_DISTRIBUTION', + title: 'Transaction Time', + $URN: 'urn:li:complianceDataType:TRANSACTION_TIME', + supportedFieldFormats: [], + id: 'TRANSACTION_TIME' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Cookies, Beacons, Browser ID', + $URN: 'urn:li:complianceDataType:COOKIE_BEACON_BROWSER_ID', + supportedFieldFormats: [], + id: 'COOKIE_BEACON_BROWSER_ID' + }, + { + pii: true, + idType: false, + defaultSecurityClassification: 'CONFIDENTIAL', + title: 'Device ID, Advertising ID', + $URN: 'urn:li:complianceDataType:DEVICE_ID_ADVERTISING_ID', + supportedFieldFormats: [], + id: 'DEVICE_ID_ADVERTISING_ID' + } +]; diff --git a/wherehows-web/mirage/helpers/config.ts b/wherehows-web/mirage/helpers/config.ts index 242132e2a0..f1eee618e0 100644 --- a/wherehows-web/mirage/helpers/config.ts +++ b/wherehows-web/mirage/helpers/config.ts @@ -1,3 +1,4 @@ +import { IFunctionRouteHandler } from 'wherehows-web/typings/ember-cli-mirage'; import { ApiStatus } from 'wherehows-web/utils/api/shared'; /** @@ -5,11 +6,11 @@ import { ApiStatus } from 'wherehows-web/utils/api/shared'; * @param {object} config the config table / factory object * @return {{status: ApiStatus, config: object}} */ -const getConfig = ({ config }: { config: object }) => ({ - status: ApiStatus.OK, - config -}); +const getConfig = function(this: IFunctionRouteHandler, { configs }: { configs: any }) { + return { + status: ApiStatus.OK, + config: this.serialize(configs.first()) + }; +}; -export { - getConfig -} +export { getConfig }; diff --git a/wherehows-web/mirage/models/compliance-data-types.js b/wherehows-web/mirage/models/compliance-data-types.js new file mode 100644 index 0000000000..770b50936d --- /dev/null +++ b/wherehows-web/mirage/models/compliance-data-types.js @@ -0,0 +1,3 @@ +import { Model } from 'ember-cli-mirage'; + +export default Model.extend({}); diff --git a/wherehows-web/mirage/scenarios/default.js b/wherehows-web/mirage/scenarios/default.js index 96f3d93fd7..a0d8dbc115 100644 --- a/wherehows-web/mirage/scenarios/default.js +++ b/wherehows-web/mirage/scenarios/default.js @@ -1,6 +1,7 @@ export default function(server) { - const fixtures = ['dataset-nodes', 'metric-metrics', 'user-entities']; + const fixtures = ['dataset-nodes', 'metric-metrics', 'user-entities', 'compliance-data-types']; server.loadFixtures(...fixtures); + server.create('config'); server.createList('complianceSuggestion', 5); server.createList('owner', 6); server.createList('dataset', 10); diff --git a/wherehows-web/tests/unit/constants/dataset-compliance-test.js b/wherehows-web/tests/unit/constants/dataset-compliance-test.js index 398ac11724..2ef7c78401 100644 --- a/wherehows-web/tests/unit/constants/dataset-compliance-test.js +++ b/wherehows-web/tests/unit/constants/dataset-compliance-test.js @@ -1,5 +1,11 @@ import { module, test } from 'qunit'; -import { getComplianceSteps, complianceSteps } from 'wherehows-web/constants'; +import { + getComplianceSteps, + complianceSteps, + getFieldIdentifierOption, + getFieldIdentifierOptions +} from 'wherehows-web/constants'; +import complianceDataTypes from 'wherehows-web/mirage/fixtures/compliance-data-types'; module('Unit | Constants | dataset compliance'); @@ -20,3 +26,27 @@ test('getComplianceSteps function should behave as expected', function(assert) { 'getComplianceSteps result is expected shape when hasSchema attribute is false' ); }); + +test('getFieldIdentifierOption function should behave as expected', function(assert) { + const [complianceType] = complianceDataTypes; + let result; + + assert.equal(typeof getFieldIdentifierOption, 'function', 'getFieldIdentifierOption is a function'); + result = getFieldIdentifierOption(complianceType); + + assert.ok(result.label === complianceType.title, 'title matches the resulting label'); + assert.ok(result.value === complianceType.id, 'id matches the resulting value'); +}); + +test('getFieldIdentifierOptions function should behave as expected', function(assert) { + let results; + assert.equal(typeof getFieldIdentifierOptions, 'function', 'getFieldIdentifierOptions is a function'); + results = getFieldIdentifierOptions(complianceDataTypes); + + assert.ok(Array.isArray(results), 'getFieldIdentifierOptions returns an array'); + + results.forEach((result, index) => { + assert.ok(result.label === complianceDataTypes[index].title, 'title matches the resulting label'); + assert.ok(result.value === complianceDataTypes[index].id, 'id matches the resulting value'); + }); +}); diff --git a/wherehows-web/tests/unit/utils/api/list/compliance-datatypes-test.js b/wherehows-web/tests/unit/utils/api/list/compliance-datatypes-test.js new file mode 100644 index 0000000000..d6733d6b47 --- /dev/null +++ b/wherehows-web/tests/unit/utils/api/list/compliance-datatypes-test.js @@ -0,0 +1,19 @@ +import * as complianceDataTypesApi from 'wherehows-web/utils/api/list/compliance-datatypes'; +import { module, test } from 'qunit'; +import sinon from 'sinon'; + +const { readComplianceDataTypes } = complianceDataTypesApi; + +module('Unit | Utility | api/list/compliance datatypes', { + beforeEach() { + this.xhr = sinon.useFakeXMLHttpRequest(); + }, + + afterEach() { + this.xhr.restore(); + } +}); + +test('readComplianceDataTypes exhibits expected behaviour', function(assert) { + assert.ok(typeof readComplianceDataTypes({}).then === 'function', 'it returns a Promise object or thennable'); +});