diff --git a/wherehows-web/app/components/dataset-confidential.js b/wherehows-web/app/components/dataset-confidential.js index 0ac95e13cf..e5379da208 100644 --- a/wherehows-web/app/components/dataset-confidential.js +++ b/wherehows-web/app/components/dataset-confidential.js @@ -1,6 +1,6 @@ import Ember from 'ember'; import isTrackingHeaderField from 'wherehows-web/utils/validators/tracking-headers'; -import { defaultFieldDataTypeClassification, classifiers } from 'wherehows-web/constants'; +import { defaultFieldDataTypeClassification, classifiers, datasetClassifiers } from 'wherehows-web/constants'; const { get, @@ -14,15 +14,29 @@ const { String: { htmlSafe } } = Ember; -// String constant identifying the classified fields on the security spec +/** + * String constant identifying the classified fields on the security spec + * @type {String} + */ const sourceClassificationKey = 'securitySpecification.classification'; +/** + * String constant identifying the datasetClassification on the security spec + * @type {String} + */ +const datasetClassificationKey = 'securitySpecification.datasetClassification'; + /** * List of logical types / field level data types * https://iwww.corp.linkedin.com/wiki/cf/display/DWH/List+of+Metadata+for+Data+Sets * @type {Array} */ const logicalTypes = Object.keys(defaultFieldDataTypeClassification); +/** + * A list of available keys for the datasetClassification map on the security specification + * @type {Array} + */ +const datasetClassifiersKeys = Object.keys(datasetClassifiers); // TODO: DSS-6671 Extract to constants module const successUpdating = 'Your changes have been successfully saved!'; @@ -69,6 +83,24 @@ export default Component.extend({ }; }), + /** + * Computed property that is dependent on all the keys in the datasetClassification map + * Returns a new map of datasetClassificationKey: String-> Object. + * @type {Ember.computed} + */ + datasetClassification: computed(`${datasetClassificationKey}.{${datasetClassifiersKeys.join(',')}}`, function() { + const sourceDatasetClassification = getWithDefault(this, datasetClassificationKey, {}); + + return Object.keys(datasetClassifiers).reduce((datasetClassification, classifier) => { + datasetClassification[classifier] = { + value: sourceDatasetClassification[classifier], + label: datasetClassifiers[classifier] + }; + + return datasetClassification; + }, {}); + }), + /** * Creates a lookup table of fieldNames to classification * Also, the expectation is that the association from fieldName -> classification @@ -76,9 +108,7 @@ export default Component.extend({ * in the lookup assignment */ fieldNameToClass: computed( - `${sourceClassificationKey}.confidential.[]`, - `${sourceClassificationKey}.limitedDistribution.[]`, - `${sourceClassificationKey}.highlyConfidential.[]`, + `${sourceClassificationKey}.{confidential,limitedDistribution,highlyConfidential}.[]`, function () { const sourceClasses = getWithDefault(this, sourceClassificationKey, []); // Creates a lookup table of fieldNames to classification @@ -105,9 +135,7 @@ export default Component.extend({ * securitySpecification.classification or null if not found */ classificationDataFields: computed( - `${sourceClassificationKey}.confidential.[]`, - `${sourceClassificationKey}.limitedDistribution.[]`, - `${sourceClassificationKey}.highlyConfidential.[]`, + `${sourceClassificationKey}.{confidential,limitedDistribution,highlyConfidential}.[]`, 'schemaFieldNamesMappedToDataTypes', function () { // Set default or if already in policy, retrieve current values from @@ -330,6 +358,16 @@ export default Component.extend({ } }, + /** + * Updates the source object representing the current datasetClassification map + * @param {String} classifier the property on the datasetClassification to update + * @param {Boolean} value flag indicating if this dataset contains member data for the specified classifier + */ + didChangeDatasetClassification(classifier, value) { + const sourceDatasetClassification = getWithDefault(this, datasetClassificationKey, {}); + return set(sourceDatasetClassification, classifier, value); + }, + /** * Notify controller to propagate changes * @return {Boolean} diff --git a/wherehows-web/app/constants/dataset-classification.js b/wherehows-web/app/constants/dataset-classification.js new file mode 100644 index 0000000000..0176fcd973 --- /dev/null +++ b/wherehows-web/app/constants/dataset-classification.js @@ -0,0 +1,24 @@ +const datasetClassifiers = { + CONNECTIONS_FOLLOWERS_FOLLOWING: 'Connections + Followers + Following', + PROFILE_DATA: 'Profile Data', + MESSAGING_DATA: 'Messaging Data (Metadata + Content)', + THIRD_PARTY_INTEGRATIONS: 'Third Party Integrations In Use', + ACTIVITY: 'Activity (Newsfeed Posts + Shares + Likes)', + JOB_APPLICATION_FLOW_DATA: 'Job Application Flow Data (Job Application + AWLI + Resumes + Application Answers)', + ENTERPRISE_PRODUCT_DATA: 'Enterprise Product Data', + ACCOUNT_STATUS: 'Account Status', + ADDRESS_BOOK_IMPORT_DATA: 'Address Book Import Data', + MICROSOFT_DATA: 'Data from Microsoft', + SUBSIDIARY_DATA: 'Data from companies LinkedIn acquired (Lynda, Slideshare, Connectifier, Bizo, etcetera)', + THIRD_PARTY_DATA: 'Data from Third-party Integrations', + DEVICE_DATA: 'Device Data', + SEARCH_HISTORY: 'Search History', + COURSE_VIEWING_HISTORY: 'Course Viewing History', + WVMP: "Who's Viewed My Profile", + PROFILE_VIEWS_BY_ME: 'Profile Views (by me)', + ADVERTISING_DATA: 'Advertising related (LMS) Data', + USAGE_ERROR_CONNECTIVITY_DATA: 'Usage, Error Reporting, Connectivity Data', + OTHER_CLICKSTREAM_BROWSING_DATA: 'Other Clickstream Data + Browsing history' +}; + +export { datasetClassifiers }; diff --git a/wherehows-web/app/constants/index.js b/wherehows-web/app/constants/index.js index 69cc91a0a4..f115174e3d 100644 --- a/wherehows-web/app/constants/index.js +++ b/wherehows-web/app/constants/index.js @@ -1 +1,2 @@ export * from 'wherehows-web/constants/metadata-acquisition'; +export * from 'wherehows-web/constants/dataset-classification'; diff --git a/wherehows-web/app/styles/components/dataset-author/_owner-table.scss b/wherehows-web/app/styles/components/dataset-author/_owner-table.scss index 90e55085c9..a44da6b6c1 100644 --- a/wherehows-web/app/styles/components/dataset-author/_owner-table.scss +++ b/wherehows-web/app/styles/components/dataset-author/_owner-table.scss @@ -1,14 +1,9 @@ $user-name-width: 170px; -$zebra: set-color(grey, light); .ownership-actions { margin-bottom: 10px; } -.dataset-author-row:nth-child(odd) { - background-color: tint($zebra, 80%); -} - .dataset-author-cell { max-width: $user-name-width; width: $user-name-width; diff --git a/wherehows-web/app/styles/components/dataset-compliance/_compliance-prompts.scss b/wherehows-web/app/styles/components/dataset-compliance/_compliance-prompts.scss index c91eead6bb..3438d21d4c 100644 --- a/wherehows-web/app/styles/components/dataset-compliance/_compliance-prompts.scss +++ b/wherehows-web/app/styles/components/dataset-compliance/_compliance-prompts.scss @@ -27,3 +27,25 @@ background-color: tint(set-color(green, green5), 65%); } } + +/// Wraps a status notification icon for a given dataset +.dataset-tag-container { + width: 20px; + display: inline-block; +} + +/// A notification that a dataset contains a tag +.dataset-tagged { + + &::before { + color: set-color(green, green5); + } +} + +/// A notification that a dataset does not contains a tag +.dataset-not-tagged { + + &::before { + color: set-color(red, red5); + } +} diff --git a/wherehows-web/app/styles/components/nacho/_nacho-table.scss b/wherehows-web/app/styles/components/nacho/_nacho-table.scss index a3cc44d1b0..0c8c7df49b 100644 --- a/wherehows-web/app/styles/components/nacho/_nacho-table.scss +++ b/wherehows-web/app/styles/components/nacho/_nacho-table.scss @@ -5,6 +5,7 @@ restyle-var(header-color): set-color(grey, light), restyle-var(horizontal-padding): 10px, restyle-var(font-size): 16px, + restyle-var(zebra): tint(set-color(grey, light), 80%), border-collapse: collapse, border-spacing: 0, text-align: left, @@ -30,6 +31,11 @@ restyle-modifiers: ( 'with a border': ( border: 1px solid restyle-var(border-color) + ), + 'with stripped rows': ( + '& tr:nth-child(odd)': ( + background-color: restyle-var(zebra) + ) ) ) )); @@ -40,4 +46,8 @@ &--bordered { @include restyle(table with a border); } + + &--stripped { + @include restyle(table with stripped rows); + } } diff --git a/wherehows-web/app/templates/components/dataset-author.hbs b/wherehows-web/app/templates/components/dataset-author.hbs index 852ae472e0..5ae40a5863 100644 --- a/wherehows-web/app/templates/components/dataset-author.hbs +++ b/wherehows-web/app/templates/components/dataset-author.hbs @@ -60,7 +60,7 @@ {{/if}} - +
@@ -111,8 +111,8 @@
User Name{{owner.idType}} {{owner.source}} - {{!-- e.g Jul 18th '16, 11:11 am --}} - {{moment-calendar owner.modifiedTime sameElse="MMM Do 'YY, h:m a"}} + {{!-- e.g Jul 18th 2016, 11:11 am --}} + {{moment-calendar owner.modifiedTime sameElse="MMM Do YYYY, h:mm a"}} {{ember-selector diff --git a/wherehows-web/app/templates/components/dataset-confidential.hbs b/wherehows-web/app/templates/components/dataset-confidential.hbs index dde0d3df6f..1ed0b80f08 100644 --- a/wherehows-web/app/templates/components/dataset-confidential.hbs +++ b/wherehows-web/app/templates/components/dataset-confidential.hbs @@ -26,6 +26,73 @@ {{/if}} + + + + + + + + + + + {{#each-in datasetClassification as |classification props|}} + + + + + {{/each-in}} + +
Dataset Content TypeIs this type of member data contained in this dataset?
+ {{props.label}} + + + {{#if (eq props.value true)}} + + {{/if}} + + {{#if (eq props.value false)}} + + {{/if}} + + + {{#radio-button-composer + value=true + name=classification + groupValue=(readonly props.value) + changed=(action "didChangeDatasetClassification")}} + Yes + {{/radio-button-composer}} + {{#radio-button-composer + value=false + name=classification + groupValue=(readonly props.value) + changed=(action "didChangeDatasetClassification")}} + No + {{/radio-button-composer}} +
+ +
+ {{!--Renders content of `hiddenTrackingFields` to the viewer if the dataset contains hidden tracking fields--}} {{#if containsHiddenTrackingFields}}