Sets initial refactor dataset.dataset route and template

This commit is contained in:
Seyi Adebajo 2017-03-24 22:15:48 -07:00 committed by Mars Lan
parent c558934fd0
commit b83ceb99f7
2 changed files with 374 additions and 335 deletions

View File

@ -1,87 +1,83 @@
import Ember from 'ember'; import Ember from 'ember';
import {
createPrivacyCompliancePolicy,
createSecuritySpecification
} from 'wherehows-web/utils/datasets/functions';
export default Ember.Route.extend({ const {
Route,
get,
set,
setProperties,
isPresent,
$: { getJSON }
} = Ember;
// TODO: DSS-6581 Create URL retrieval module
const datasetsUrlRoot = '/api/v1/datasets';
const datasetUrl = id => `${datasetsUrlRoot}/${id}`;
const ownerTypeUrlRoot = '/api/v1/owner/types';
const userSettingsUrlRoot = '/api/v1/user/me';
const partyEntitiesUrl = '/api/v1/party/entities';
const getDatasetColumnUrl = id => `${datasetUrl(id)}/columns`;
const getDatasetPropertiesUrl = id => `${datasetUrl(id)}/properties`;
const getDatasetSampleUrl = id => `${datasetUrl(id)}/sample`;
const getDatasetImpactAnalysisUrl = id => `${datasetUrl(id)}/impacts`;
const getDatasetDependsUrl = id => `${datasetUrl(id)}/depends`;
const getDatasetPartitionsUrl = id => `${datasetUrl(id)}/access`;
const getDatasetReferencesUrl = id => `${datasetUrl(id)}/references`;
const getDatasetOwnersUrl = id => `${datasetUrl(id)}/owners`;
const getDatasetInstanceUrl = id => `${datasetUrl(id)}/instances`;
const getDatasetVersionUrl = (id, dbId) =>
`${datasetUrl(id)}/versions/db/${dbId}`;
const getDatasetSecurityUrl = id => `${datasetUrl(id)}/security`;
const getDatasetComplianceUrl = id => `${datasetUrl(id)}/compliance`;
let getDatasetColumn;
export default Route.extend({
//TODO: DSS-6632 Correct server-side if status:error and record not found but response is 200OK
setupController(controller, model) { setupController(controller, model) {
currentTab = 'Datasets'; currentTab = 'Datasets';
updateActiveTab(); window.updateActiveTab();
let source = '';
var id = 0; var id = 0;
var source = '';
var urn = ''; var urn = '';
var name = '';
let instanceUrl;
let propertiesUrl;
const ownerTypeUrl = '/api/v1/owner/types';
/**
* Builds a privacyCompliancePolicy map with default / unset values for non null properties
*/
const createPrivacyCompliancePolicy = () => {
// TODO: Move to a more accessible location, this app does not use modules at the moment, so potentially
// ->TODO: registering it as factory
const complianceTypes = ['AUTO_PURGE', 'CUSTOM_PURGE', 'LIMITED_RETENTION', 'PURGE_NOT_APPLICABLE'];
const policy = {
//default to first item in compliance types list
complianceType: complianceTypes.get('firstObject'),
compliancePurgeEntities: []
};
// Ensure we deep clone map to prevent mutation from consumers
return JSON.parse(JSON.stringify(policy));
};
/**
* Builds a securitySpecification map with default / unset values for non null properties as per avro schema
* @param {number} id
*/
const createSecuritySpecification = id => {
const classification = [
'highlyConfidential', 'confidential', 'limitedDistribution', 'mustBeEncrypted', 'mustBeMasked'
].reduce((classification, classifier) => {
classification[classifier] = [];
return classification;
}, {});
const securitySpecification = {
classification,
datasetId: id,
geographicAffinity: {affinity: ''},
recordOwnerType: '',
retentionPolicy: {retentionType: ''}
};
return JSON.parse(JSON.stringify(securitySpecification));
};
/** /**
* Series of chain-able functions invoked to set set properties on the controller required for dataset tab sections * Series of chain-able functions invoked to set set properties on the controller required for dataset tab sections
* @type {{privacyCompliancePolicy: ((id)), securitySpecification: ((id)), datasetSchemaFieldNamesAndTypes: ((id))}} * @type {{privacyCompliancePolicy: ((id)), securitySpecification: ((id)), datasetSchemaFieldNamesAndTypes: ((id))}}
*/ */
const fetchThenSetOnController = { const fetchThenSetOnController = {
privacyCompliancePolicy(id) { privacyCompliancePolicy(id, controller) {
Ember.$.getJSON(`/api/v1/datasets/${id}/compliance`) Promise.resolve(getJSON(getDatasetComplianceUrl(id))).then(({
.then(({privacyCompliancePolicy = createPrivacyCompliancePolicy(), return_code}) => privacyCompliancePolicy = createPrivacyCompliancePolicy(),
controller.setProperties({ return_code
}) =>
setProperties(controller, {
privacyCompliancePolicy, privacyCompliancePolicy,
'isNewPrivacyCompliancePolicy': return_code === 404 isNewPrivacyCompliancePolicy: return_code === 404
})); }));
return this; return this;
}, },
securitySpecification(id) { securitySpecification(id, controller) {
Ember.$.getJSON(`/api/v1/datasets/${id}/security`) Promise.resolve(getJSON(getDatasetSecurityUrl(id))).then(({
.then(({securitySpecification = createSecuritySpecification(id), return_code}) => securitySpecification = createSecuritySpecification(id),
controller.setProperties({ return_code
}) =>
setProperties(controller, {
securitySpecification, securitySpecification,
'isNewSecuritySpecification': return_code === 404 isNewSecuritySpecification: return_code === 404
})); }));
return this; return this;
}, },
datasetSchemaFieldNamesAndTypes(id) { datasetSchemaFieldNamesAndTypes(id, controller) {
Ember.$.getJSON(`/api/v1/datasets/${id}`) Promise.resolve(getJSON(datasetUrl(id))).then(({
.then(({dataset: {schema} = {schema: undefined}} = {}) => { dataset: { schema } = { schema: undefined }
} = {}) => {
/** /**
* Parses a JSON dataset schema representation and extracts the field names and types into a list of maps * Parses a JSON dataset schema representation and extracts the field names and types into a list of maps
* @param {JSON} schema * @param {JSON} schema
@ -98,41 +94,49 @@ export default Ember.Route.extend({
* @param {Array} [fields] * @param {Array} [fields]
* @returns {Array.<*>} * @returns {Array.<*>}
*/ */
function getFieldTypeMappingArray({schema: {fields: nestedFields = []} = {schema: {}}, fields}) { function getFieldTypeMappingArray(
{ schema: { fields: nestedFields = [] } = { schema: {} }, fields }
) {
fields = Array.isArray(fields) ? fields : nestedFields; fields = Array.isArray(fields) ? fields : nestedFields;
// As above, field may contain a label with string property or a name property // As above, field may contain a label with string property or a name property
return fields.map(({ label: { string } = {}, name, type }) => ({ return fields.map(({ label: { string } = {}, name, type }) => ({
name: string || name, name: string || name,
type: Array.isArray(type) ? (type[0] === 'null' ? type.slice(1) : type) : [type] type: Array.isArray(type)
? type[0] === 'null' ? type.slice(1) : type
: [type]
})); }));
} }
schema = JSON.parse(schema); schema = JSON.parse(schema);
return [].concat(...getFieldTypeMappingArray(schema)); return [...getFieldTypeMappingArray(schema)];
} }
controller.set('datasetSchemaFieldsAndTypes', getFieldNamesAndTypesFrom(schema)); set(
controller,
'datasetSchemaFieldsAndTypes',
getFieldNamesAndTypesFrom(schema)
);
}); });
return this; return this;
} }
}; };
controller.set("hasProperty", false); set(controller, 'hasProperty', false);
if (model && model.id) { if (model && model.id) {
({id, source, urn, name} = model); ({ id, source, urn } = model);
let { originalSchema = null } = model; let { originalSchema = null } = model;
this.controllerFor('datasets').set('detailview', true); this.controllerFor('datasets').set('detailview', true);
if (originalSchema) { if (originalSchema) {
Ember.set(model, 'schema', originalSchema); set(model, 'schema', originalSchema);
} }
controller.set('model', model); controller.set('model', model);
} else if (model.dataset) { } else if (model.dataset) {
({id, source, urn, name} = model.dataset); ({ id, source, urn } = model.dataset);
controller.set('model', model.dataset); controller.set('model', model.dataset);
this.controllerFor('datasets').set('detailview', true); this.controllerFor('datasets').set('detailview', true);
@ -143,40 +147,59 @@ export default Ember.Route.extend({
controller.set('datasetId', id); controller.set('datasetId', id);
// Creates list of partially applied functions from `fetchThenSetController` and invokes each in turn // Creates list of partially applied functions from `fetchThenSetController` and invokes each in turn
Object.keys(fetchThenSetOnController) Object.keys(fetchThenSetOnController)
.map(funcRef => fetchThenSetOnController[funcRef]['bind'](fetchThenSetOnController, id)) .map(funcRef =>
fetchThenSetOnController[funcRef]['bind'](
fetchThenSetOnController,
id,
controller
))
.forEach(func => func()); .forEach(func => func());
} }
instanceUrl = '/api/v1/datasets/' + id + '/instances'; Promise.resolve(getJSON(getDatasetInstanceUrl(id)))
$.get(instanceUrl, function (data) { .then(({ status, instances = [] }) => {
if (data && data.status == "ok" && data.instances && data.instances.length > 0) { if (status === 'ok' && instances.length) {
controller.set("hasinstances", true); const [firstInstance = {}] = instances;
controller.set("instances", data.instances); const { dbId } = firstInstance;
controller.set("currentInstance", data.instances[0]);
controller.set("latestInstance", data.instances[0]); setProperties(controller, {
var versionUrl = '/api/v1/datasets/' + id + "/versions/db/" + data.instances[0].dbId; instances,
$.get(versionUrl, function (data) { hasinstances: true,
if (data && data.status == "ok" && data.versions && data.versions.length > 0) { currentInstance: firstInstance,
controller.set("hasversions", true); latestInstance: firstInstance
controller.set("versions", data.versions); });
controller.set("currentVersion", data.versions[0]);
controller.set("latestVersion", data.versions[0]); return Promise.resolve(
} getJSON(getDatasetVersionUrl(id, dbId))
else { ).then(({ status, versions = [] }) => {
controller.set("hasversions", false); if (status === 'ok' && versions.length) {
controller.set("currentVersion", '0'); const [firstVersion] = versions;
controller.set("latestVersion", '0');
} setProperties(controller, {
versions,
hasversions: true,
currentVersion: firstVersion,
latestVersion: firstVersion
}); });
} }
else {
controller.set("hasinstances", false); return Promise.reject(
controller.set("currentInstance", '0'); new Error('Dataset versions request failed.')
controller.set("latestInstance", '0'); );
controller.set("hasversions", false); });
controller.set("currentVersion", '0');
controller.set("latestVersion", '0');
} }
return Promise.reject(new Error('Dataset instances request failed.'));
})
.catch(() => {
setProperties(controller, {
hasinstances: false,
hasversions: false,
currentInstance: '0',
latestInstance: '0',
currentVersion: '0',
latestVersion: '0'
});
}); });
if (urn) { if (urn) {
@ -240,229 +263,260 @@ export default Ember.Route.extend({
controller.set("breadcrumbs", breadcrumbs); controller.set("breadcrumbs", breadcrumbs);
} }
$.get(ownerTypeUrl, function (data) { Promise.resolve(getJSON(ownerTypeUrlRoot)).then(
if (data && data.status == "ok") { ({ status, ownerTypes }) =>
controller.set("ownerTypes", data.ownerTypes); status === 'ok' && set(controller, 'ownerTypes', ownerTypes)
);
Promise.resolve(getJSON(userSettingsUrlRoot)).then(({ status, user }) => {
if (status === 'ok') {
// TODO: DSS-6633 Remove `data.user.userSetting.detailDefaultView` from
// '/api/v1/user/me' endpoint
controller.set('currentUser', user);
} }
}); });
var userSettingsUrl = '/api/v1/user/me'; getDatasetColumn = id =>
$.get(userSettingsUrl, function (data) { Promise.resolve(getJSON(getDatasetColumnUrl(id)))
var tabview; .then(({ status, columns }) => {
if (data && data.status == "ok") { if (status === 'ok') {
controller.set("currentUser", data.user); if (columns && columns.length) {
if (data.user && data.user.userSetting && data.user.userSetting.detailDefaultView) { const columnsWithHTMLComments = columns.map(column => {
if (data.user.userSetting.detailDefaultView == 'tab') { const { comment } = column;
tabview = true;
if (comment) {
// TODO: DSS-6122 Refactor global function reference
column.commentHtml = window.marked(comment).htmlSafe();
} }
}
} return column;
controller.set("tabview", true);
}); });
var columnUrl = '/api/v1/datasets/' + id + "/columns"; controller.set('hasSchemas', true);
$.get(columnUrl, function (data) { controller.set('schemas', columnsWithHTMLComments);
if (data && data.status == "ok") {
if (data.columns && (data.columns.length > 0)) {
controller.set("hasSchemas", true);
data.columns = data.columns.map(function (item, idx) { // TODO: DSS-6122 Refactor direct method invocation on controller
if (item.comment) { controller.buildJsonView();
item.commentHtml = marked(item.comment).htmlSafe() // TODO: DSS-6122 Refactor setTimeout,
// global function reference
setTimeout(window.initializeColumnTreeGrid, 500);
} }
return item
return;
}
return Promise.reject(new Error('Dataset columns request failed.'));
}) })
controller.set("schemas", data.columns); .catch(() =>
controller.buildJsonView(); setProperties(controller, {
setTimeout(initializeColumnTreeGrid, 500); hasSchemas: false,
} else { schemas: null
controller.set("hasSchemas", false); }));
controller.set("schemas", null);
controller.buildJsonView();
}
} else {
controller.set("hasSchemas", false);
controller.set("schemas", null);
controller.buildJsonView();
}
});
if (source.toLowerCase() != 'pinot') { getDatasetColumn(id);
propertiesUrl = '/api/v1/datasets/' + id + "/properties";
$.get(propertiesUrl, function (data) { if (source.toLowerCase() !== 'pinot') {
if (data && data.status == "ok") { Promise.resolve(getJSON(getDatasetPropertiesUrl(id)))
if (data.properties) { .then(({ status, properties }) => {
var propertyArray = convertPropertiesToArray(data.properties); if (status === 'ok' && properties) {
if (propertyArray && propertyArray.length > 0) { const propertyArray = window.convertPropertiesToArray(
controller.set("hasProperty", true); properties
controller.set("properties", propertyArray); ) || [];
} else { if (propertyArray.length) {
controller.set("hasProperty", false); controller.set('hasProperty', true);
return controller.set('properties', propertyArray);
} }
} }
} else {
controller.set("hasProperty", false); return Promise.reject(
new Error('Dataset properties request failed.')
);
})
.catch(() => controller.set('hasProperty', false));
Promise.resolve(getJSON(getDatasetSampleUrl(id)))
.then(({ status, sampleData = {} }) => {
if (status === 'ok') {
const { sample = [] } = sampleData;
const { length } = sample;
if (length) {
const samplesObject = sample.reduce(
(sampleObject, record, index) =>
((sampleObject[`record${index}`] = record), sampleObject),
{}
);
// TODO: DSS-6122 Refactor global function reference
const node = window.JsonHuman.format(samplesObject);
controller.set('hasSamples', true);
// TODO: DSS-6122 Refactor setTimeout
setTimeout(
function() {
const jsonHuman = document.getElementById(
'datasetSampleData-json-human'
);
if (jsonHuman) {
if (jsonHuman.children && jsonHuman.children.length) {
jsonHuman.removeChild(
jsonHuman.childNodes[jsonHuman.children.length - 1]
);
} }
jsonHuman.appendChild(node);
}
},
500
);
}
return;
}
return Promise.reject(new Error('Dataset sample request failed.'));
})
.catch(() => set(controller, 'hasSamples', false));
}
if (source.toLowerCase() === 'pinot') {
Promise.resolve(getJSON(getDatasetPropertiesUrl(id))).then(({
status,
properties = {}
}) => {
if (status === 'ok') {
const { elements = [] } = properties;
const [{ columnNames = [], results } = {}] = elements;
if (columnNames.length) {
return setProperties(controller, {
hasSamples: true,
samples: results,
columns: columnNames
});
}
}
return Promise.reject(new Error('Dataset properties request failed.'));
}); });
} }
var sampleUrl; Promise.resolve(getJSON(getDatasetImpactAnalysisUrl(id)))
if (source.toLowerCase() == 'pinot') { .then(({ status, impacts = [] }) => {
sampleUrl = '/api/v1/datasets/' + id + "/properties"; if (status === 'ok') {
$.get(sampleUrl, function (data) { if (impacts.length) {
if (data && data.status == "ok") { return setProperties(controller, {
if (data.properties && data.properties.elements && (data.properties.elements.length > 0) hasImpacts: true,
&& data.properties.elements[0] && data.properties.elements[0].columnNames impacts: impacts
&& (data.properties.elements[0].columnNames.length > 0)) {
controller.set("hasSamples", true);
controller.set("samples", data.properties.elements[0].results);
controller.set("columns", data.properties.elements[0].columnNames);
} else {
controller.set("hasSamples", false);
}
} else {
controller.set("hasSamples", false);
}
}); });
} }
else {
sampleUrl = '/api/v1/datasets/' + id + "/sample";
$.get(sampleUrl, function (data) {
if (data && data.status == "ok") {
if (data.sampleData && data.sampleData.sample && (data.sampleData.sample.length > 0)) {
controller.set("hasSamples", true);
var tmp = {};
var count = data.sampleData.sample.length
var d = data.sampleData.sample
for (var i = 0; i < count; i++) {
tmp['record ' + i] = d[i]
}
var node = JsonHuman.format(tmp)
setTimeout(function () {
var json_human = document.getElementById('datasetSampleData-json-human');
if (json_human) {
if (json_human.children && json_human.children.length > 0) {
json_human.removeChild(json_human.childNodes[json_human.children.length - 1]);
} }
json_human.appendChild(node) return Promise.reject(
new Error('Dataset impact analysis request failed.')
);
})
.catch(() => set(controller, 'hasImpacts', false));
Promise.resolve(getJSON(getDatasetDependsUrl(id)))
.then(({ status, depends = [] }) => {
if (status === 'ok') {
if (depends.length) {
// TODO: DSS-6122 Refactor setTimeout,
// global function reference
setTimeout(window.initializeDependsTreeGrid, 500);
return setProperties(controller, {
depends,
hasDepends: true
});
} }
}, 500);
} else {
controller.set("hasSamples", false);
}
} else {
controller.set("hasSamples", false);
} }
return Promise.reject(new Error('Dataset depends request failed.'));
})
.catch(() => set(controller, 'hasDepends', false));
Promise.resolve(getJSON(getDatasetPartitionsUrl(id)))
.then(({ status, access = [] }) => {
if (status === 'ok' && access.length) {
return setProperties(controller, {
hasAccess: true,
accessibilities: access
}); });
} }
var impactAnalysisUrl = '/api/v1/datasets/' + id + "/impacts"; return Promise.reject(new Error('Dataset partitions request failed.'));
$.get(impactAnalysisUrl, function (data) { })
if (data && data.status == "ok") { .catch(() => set(controller, 'hasAccess', false));
if (data.impacts && (data.impacts.length > 0)) {
controller.set("hasImpacts", true);
controller.set("impacts", data.impacts);
} else {
controller.set("hasImpacts", false);
}
}
});
var datasetDependsUrl = '/api/v1/datasets/' + id + "/depends"; Promise.resolve(getJSON(getDatasetReferencesUrl(id)))
$.get(datasetDependsUrl, function (data) { .then(({ status, references = [] }) => {
if (data && data.status == "ok") { if (status === 'ok' && references.length) {
if (data.depends && (data.depends.length > 0)) { setTimeout(window.initializeReferencesTreeGrid, 500);
controller.set("hasDepends", true);
controller.set("depends", data.depends);
setTimeout(initializeDependsTreeGrid, 500);
} else {
controller.set("hasDepends", false);
}
}
});
var datasetPartitionsUrl = '/api/v1/datasets/' + id + "/access"; return setProperties(controller, {
$.get(datasetPartitionsUrl, function (data) { references,
if (data && data.status == "ok") { hasReferences: true
if (data.access && (data.access.length > 0)) {
controller.set("hasAccess", true);
controller.set("accessibilities", data.access);
} else {
controller.set("hasAccess", false);
}
}
}); });
var datasetReferencesUrl = '/api/v1/datasets/' + id + "/references";
$.get(datasetReferencesUrl, function (data) {
if (data && data.status == "ok") {
if (data.references && (data.references.length > 0)) {
controller.set("hasReferences", true);
controller.set("references", data.references);
setTimeout(initializeReferencesTreeGrid, 500);
} else {
controller.set("hasReferences", false);
} }
}
});
Promise.resolve($.get(`/api/v1/datasets/${id}/owners`)) return Promise.reject(new Error('Dataset references request failed.'));
})
.catch(() => set(controller, 'hasReferences', false));
Promise.resolve(getJSON(getDatasetOwnersUrl(id)))
.then(({ status, owners = [] }) => { .then(({ status, owners = [] }) => {
status === 'ok' && controller.set('owners', owners); status === 'ok' && set(controller, 'owners', owners);
}) })
.then($.get.bind($, '/api/v1/party/entities')) .then(() => getJSON(partyEntitiesUrl))
.then(({ status, userEntities = [] }) => { .then(({ status, userEntities = [] }) => {
if (status === 'ok' && userEntities.length) { if (status === 'ok' && userEntities.length) {
/** /**
* @type {Object} userEntitiesMaps hash of userEntities: label -> displayName * @type {Object} userEntitiesMaps hash of userEntities: label -> displayName
*/ */
const userEntitiesMaps = userEntities.reduce((map, {label, displayName}) => const userEntitiesMaps = userEntities.reduce(
(map[label] = displayName, map), {}); (map, { label, displayName }) => ((map[label] = displayName), map),
{}
);
controller.setProperties({ setProperties(controller, {
userEntitiesSource: Object.keys(userEntitiesMaps), userEntitiesMaps,
userEntitiesMaps userEntitiesSource: Object.keys(userEntitiesMaps)
}); });
} }
}); });
}, },
model: ({dataset_id}) => Ember.$.getJSON(`/api/v1/datasets/${dataset_id}`), model: ({ dataset_id }) => {
const datasetUrl = `${datasetsUrlRoot}/${dataset_id}`;
return Promise.resolve(getJSON(datasetUrl))
.then(({ status, dataset }) => {
return status === 'ok' && isPresent(dataset)
? dataset
: Promise.reject(
new Error(`Request for ${datasetUrl} failed with: ${status}`)
);
})
.catch(() => ({}));
},
actions: { actions: {
getSchema: function() { getSchema: function() {
var controller = this.get('controller') const controller = get(this, 'controller');
var id = this.get('controller.model.id') const id = get(controller, 'model.id');
var columnUrl = '/api/v1/datasets/' + id + "/columns";
controller.set("isTable", true); set(controller, 'isTable', true);
controller.set("isJSON", false); set(controller, 'isJSON', false);
$.get(columnUrl, function (data) { typeof getDatasetColumn === 'function' && getDatasetColumn(id);
if (data && data.status == "ok") {
if (data.columns && (data.columns.length > 0)) {
controller.set("hasSchemas", true);
data.columns = data.columns.map(function (item, idx) {
item.commentHtml = marked(item.comment).htmlSafe()
return item
})
controller.set("schemas", data.columns);
setTimeout(initializeColumnTreeGrid, 500);
}
else {
controller.set("hasSchemas", false);
}
}
else {
controller.set("hasSchemas", false);
}
});
}, },
getDataset: function () {
$.get('/api/v1/datasets/' + this.get('controller.model.id'), data => { getDataset() {
if (data.status == "ok") { Promise.resolve(
this.set('controller.model', data.dataset) getJSON(datasetUrl(this.get('controller.model.id')))
} ).then(
}) ({ status, dataset }) =>
status === 'ok' && set(this, 'controller.model', dataset)
);
} }
} }
}); });

View File

@ -1,19 +1,4 @@
<div id="dataset"> <div id="dataset">
<div class="well well-sm">
<div class="row">
<div class="col-xs-11">
<ul class="breadcrumbs">
{{#each breadcrumbs as |crumb|}}
<li>
{{#dynamic-link params=crumb title=crumb.text}}
{{crumb.text}}
{{/dynamic-link}}
</li>
{{/each}}
</ul>
</div>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-xs-5"> <div class="col-xs-5">
<h3>{{ model.name }}</h3> <h3>{{ model.name }}</h3>