mirror of
https://github.com/datahub-project/datahub.git
synced 2025-07-15 05:04:45 +00:00
v2: add intergration tests for container components. temporarily skips acceptance tests for datasets. further i implementation for v2 api integration and urn handling
This commit is contained in:
parent
1dbcaf1476
commit
0eb87ec99b
@ -71,10 +71,10 @@ export default class DatasetAuthors extends Component {
|
||||
|
||||
/**
|
||||
* A list of valid owner type strings returned from the remote api endpoint
|
||||
* @type {Array<string>}
|
||||
* @type {Array<OwnerType>}
|
||||
* @memberof DatasetAuthors
|
||||
*/
|
||||
ownerTypes: Array<string>;
|
||||
ownerTypes: Array<OwnerType>;
|
||||
|
||||
/**
|
||||
* Flag that resolves in the affirmative if the number of confirmed owner is less the minimum required
|
||||
|
@ -204,7 +204,13 @@ export default class DatasetCompliance extends ObservableDecorator {
|
||||
isCompliancePolicyAvailable: boolean = false;
|
||||
showAllDatasetMemberData: boolean;
|
||||
complianceInfo: void | IComplianceInfo;
|
||||
complianceSuggestion: IComplianceSuggestion;
|
||||
|
||||
/**
|
||||
* Suggested values for compliance types e.g. identifier type and/or logical type
|
||||
* @type {IComplianceSuggestion | void}
|
||||
*/
|
||||
complianceSuggestion: IComplianceSuggestion | void;
|
||||
|
||||
schemaFieldNamesMappedToDataTypes: Array<Pick<IDatasetColumn, 'dataType' | 'fieldName'>>;
|
||||
onReset: <T extends { status: ApiStatus }>() => Promise<T>;
|
||||
onSave: <T extends { status: ApiStatus }>() => Promise<T>;
|
||||
@ -676,10 +682,12 @@ export default class DatasetCompliance extends ObservableDecorator {
|
||||
function(this: DatasetCompliance): ISchemaFieldsToPolicy {
|
||||
const { complianceEntities = [], modifiedTime = '0' } = get(this, 'complianceInfo') || {};
|
||||
// Truncated list of Dataset field names and data types currently returned from the column endpoint
|
||||
const columnFieldProps = get(this, 'schemaFieldNamesMappedToDataTypes').map(({ fieldName, dataType }) => ({
|
||||
identifierField: fieldName,
|
||||
dataType
|
||||
}));
|
||||
const columnFieldProps = getWithDefault(this, 'schemaFieldNamesMappedToDataTypes', []).map(
|
||||
({ fieldName, dataType }) => ({
|
||||
identifierField: fieldName,
|
||||
dataType
|
||||
})
|
||||
);
|
||||
|
||||
return this.mapColumnIdFieldsToCurrentPrivacyPolicy(columnFieldProps, complianceEntities, {
|
||||
policyModificationTime: modifiedTime
|
||||
|
@ -1,6 +1,8 @@
|
||||
import Component from '@ember/component';
|
||||
import { set, get, setProperties, getProperties } from '@ember/object';
|
||||
import { warn } from '@ember/debug';
|
||||
import { action } from 'ember-decorators/object';
|
||||
import { IDatasetColumn, IDatasetColumnWithHtmlComments } from 'wherehows-web/typings/api/datasets/columns';
|
||||
|
||||
/**
|
||||
* Cached module reference to the class name for visually hiding toggled off schema view
|
||||
@ -23,16 +25,22 @@ export default class DatasetSchema extends Component {
|
||||
json = '{}';
|
||||
|
||||
/**
|
||||
* Reference to the jsonViewer dom element
|
||||
* @type {Element}
|
||||
* List of schema properties for the dataset
|
||||
* @type {IDatasetColumnWithHtmlComments | IDatasetColumn}
|
||||
*/
|
||||
jsonViewer = <Element | null>null;
|
||||
schemas: Array<IDatasetColumnWithHtmlComments | IDatasetColumn>;
|
||||
|
||||
/**
|
||||
* Reference to the jsonViewer dom element
|
||||
* @type {Element | null}
|
||||
*/
|
||||
jsonViewer: Element | null = null;
|
||||
|
||||
/**
|
||||
* Reference to the jsonTable dom element
|
||||
* @type {Element}
|
||||
* @type {Element | null}
|
||||
*/
|
||||
jsonTable = <Element | null>null;
|
||||
jsonTable: Element | null = null;
|
||||
|
||||
/**
|
||||
* Constructs a readable JSON structure of the dataset schema
|
||||
@ -54,6 +62,19 @@ export default class DatasetSchema extends Component {
|
||||
*/
|
||||
buildTableView = (jsonTable: Element) => $(jsonTable).treegrid();
|
||||
|
||||
/**
|
||||
* Builds or rebuild the dataset schema / json view based on a flag to toggle this behaviour
|
||||
*/
|
||||
buildView() {
|
||||
if (get(this, 'isTable')) {
|
||||
const jsonTable = get(this, 'jsonTable');
|
||||
jsonTable && this.buildTableView(jsonTable);
|
||||
} else {
|
||||
const jsonViewer = get(this, 'jsonViewer');
|
||||
jsonViewer && this.buildJsonView(jsonViewer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains references to the DOM elements for showing the schema
|
||||
*/
|
||||
@ -71,13 +92,7 @@ export default class DatasetSchema extends Component {
|
||||
}
|
||||
|
||||
didReceiveAttrs(this: DatasetSchema) {
|
||||
if (get(this, 'isTable')) {
|
||||
const jsonTable = get(this, 'jsonTable');
|
||||
jsonTable && this.buildTableView(jsonTable);
|
||||
} else {
|
||||
const jsonViewer = get(this, 'jsonViewer');
|
||||
jsonViewer && this.buildJsonView(jsonViewer);
|
||||
}
|
||||
this.buildView();
|
||||
}
|
||||
|
||||
didRender() {
|
||||
@ -91,21 +106,21 @@ export default class DatasetSchema extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
actions = {
|
||||
/**
|
||||
* Handles the toggle for which schema view to be rendered.
|
||||
* Currently toggled between a table render and a JSON view
|
||||
* @param {"table" | "json"} [view = table]
|
||||
*/
|
||||
showView(this: DatasetSchema, view: 'table' | 'json' = 'table') {
|
||||
const isTable = set(this, 'isTable', view === 'table');
|
||||
const { jsonViewer, jsonTable } = getProperties(this, ['jsonTable', 'jsonViewer']);
|
||||
@action
|
||||
/**
|
||||
* Handles the toggling of table vs. json view of dataset schema information
|
||||
* @param {"table" | "json"} view
|
||||
*/
|
||||
showView(this: DatasetSchema, view: 'table' | 'json' = 'table') {
|
||||
const isTable = set(this, 'isTable', view === 'table');
|
||||
const { jsonViewer, jsonTable } = getProperties(this, ['jsonTable', 'jsonViewer']);
|
||||
|
||||
if (jsonTable && jsonViewer) {
|
||||
isTable
|
||||
? (jsonViewer.classList.add(hiddenClassName), jsonTable.classList.remove(hiddenClassName))
|
||||
: (jsonViewer.classList.remove(hiddenClassName), jsonTable.classList.add(hiddenClassName));
|
||||
}
|
||||
if (jsonTable && jsonViewer) {
|
||||
this.buildView();
|
||||
|
||||
isTable
|
||||
? (jsonViewer.classList.add(hiddenClassName), jsonTable.classList.remove(hiddenClassName))
|
||||
: (jsonViewer.classList.remove(hiddenClassName), jsonTable.classList.add(hiddenClassName));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,166 @@
|
||||
import Component from '@ember/component';
|
||||
import { get, set, setProperties, getProperties } from '@ember/object';
|
||||
import { task, TaskInstance } from 'ember-concurrency';
|
||||
import { action } from 'ember-decorators/object';
|
||||
import { IDatasetColumn } from 'wherehows-web/typings/api/datasets/columns';
|
||||
import { IComplianceInfo, IComplianceSuggestion } from 'wherehows-web/typings/api/datasets/compliance';
|
||||
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||
import { IDatasetSchema } from 'wherehows-web/typings/api/datasets/schema';
|
||||
import { IComplianceDataType } from 'wherehows-web/typings/api/list/compliance-datatypes';
|
||||
import {
|
||||
IReadComplianceResult,
|
||||
readDatasetComplianceByUrn,
|
||||
readDatasetComplianceSuggestionByUrn,
|
||||
saveDatasetComplianceByUrn
|
||||
} from 'wherehows-web/utils/api';
|
||||
import { columnDataTypesAndFieldNames } from 'wherehows-web/utils/api/datasets/columns';
|
||||
import { readDatasetSchemaByUrn } from 'wherehows-web/utils/api/datasets/schema';
|
||||
import { readComplianceDataTypes } from 'wherehows-web/utils/api/list/compliance-datatypes';
|
||||
|
||||
export default class DatasetComplianceContainer extends Component {
|
||||
/**
|
||||
* Mapping of field names on the dataset schema to the respective dataType
|
||||
* @type {Array<Pick<IDatasetColumn, 'dataType' | 'fieldName'>>}
|
||||
*/
|
||||
schemaFieldNamesMappedToDataTypes: Array<Pick<IDatasetColumn, 'dataType' | 'fieldName'>> = [];
|
||||
|
||||
/**
|
||||
* List of compliance data-type objects
|
||||
* @type {Array<IComplianceDataType>}
|
||||
*/
|
||||
complianceDataTypes: Array<IComplianceDataType> = [];
|
||||
|
||||
/**
|
||||
* Flag indicating that the compliance information for this dataset is new
|
||||
* @type {boolean}
|
||||
*/
|
||||
isNewComplianceInfo: boolean = false;
|
||||
|
||||
/**
|
||||
* Object containing the suggested values for the compliance form
|
||||
* @type {IComplianceSuggestion | void}
|
||||
*/
|
||||
complianceSuggestion: IComplianceSuggestion | void;
|
||||
|
||||
/**
|
||||
* Object containing the compliance information for the dataset
|
||||
* @type {IComplianceInfo | void}
|
||||
*/
|
||||
complianceInfo: IComplianceInfo | void;
|
||||
|
||||
/**
|
||||
* The platform / db that the dataset is persisted
|
||||
* @type {IDatasetView.platform}
|
||||
*/
|
||||
platform: IDatasetView['platform'];
|
||||
|
||||
/**
|
||||
* Flag indicating if the dataset has a schema representation
|
||||
* @type {boolean}
|
||||
*/
|
||||
schemaless: boolean = false;
|
||||
|
||||
/**
|
||||
* The nativeName of the dataset
|
||||
* @type {string}
|
||||
*/
|
||||
datasetName: string = '';
|
||||
|
||||
/**
|
||||
* The urn identifier for the dataset
|
||||
* @type {string}
|
||||
*/
|
||||
urn: string;
|
||||
|
||||
didInsertElement() {
|
||||
get(this, 'getContainerDataTask').perform();
|
||||
}
|
||||
|
||||
didUpdateAttrs() {
|
||||
get(this, 'getContainerDataTask').perform();
|
||||
}
|
||||
|
||||
/**
|
||||
* An async parent task to group all data tasks for this container component
|
||||
* @type {Task<TaskInstance<Promise<any>>, (a?: any) => TaskInstance<TaskInstance<Promise<any>>>>}
|
||||
*/
|
||||
getContainerDataTask = task(function*(
|
||||
this: DatasetComplianceContainer
|
||||
): IterableIterator<TaskInstance<Promise<any>>> {
|
||||
const tasks = Object.values(
|
||||
getProperties(this, [
|
||||
'getComplianceTask',
|
||||
'getComplianceDataTypesTask',
|
||||
'getComplianceSuggestionsTask',
|
||||
'getDatasetSchemaTask'
|
||||
])
|
||||
);
|
||||
|
||||
yield* tasks.map(task => task.perform());
|
||||
});
|
||||
|
||||
/**
|
||||
* Reads the compliance properties for the dataset
|
||||
* @type {Task<Promise<IReadComplianceResult>, (a?: any) => TaskInstance<Promise<IReadComplianceResult>>>}
|
||||
*/
|
||||
getComplianceTask = task(function*(
|
||||
this: DatasetComplianceContainer
|
||||
): IterableIterator<Promise<IReadComplianceResult>> {
|
||||
const { isNewComplianceInfo, complianceInfo } = yield readDatasetComplianceByUrn(get(this, 'urn'));
|
||||
|
||||
setProperties(this, { isNewComplianceInfo, complianceInfo });
|
||||
});
|
||||
|
||||
/**
|
||||
* Reads the compliance data types
|
||||
* @type {Task<Promise<Array<IComplianceDataType>>, (a?: any) => TaskInstance<Promise<Array<IComplianceDataType>>>>}
|
||||
*/
|
||||
getComplianceDataTypesTask = task(function*(
|
||||
this: DatasetComplianceContainer
|
||||
): IterableIterator<Promise<Array<IComplianceDataType>>> {
|
||||
const complianceDataTypes = yield readComplianceDataTypes();
|
||||
|
||||
set(this, 'complianceDataTypes', complianceDataTypes);
|
||||
});
|
||||
|
||||
/**
|
||||
* Reads the suggestions for the compliance properties on the dataset
|
||||
* @type {Task<Promise<IComplianceSuggestion>, (a?: any) => TaskInstance<Promise<IComplianceSuggestion>>>}
|
||||
*/
|
||||
getComplianceSuggestionsTask = task(function*(
|
||||
this: DatasetComplianceContainer
|
||||
): IterableIterator<Promise<IComplianceSuggestion>> {
|
||||
const complianceSuggestion = yield readDatasetComplianceSuggestionByUrn(get(this, 'urn'));
|
||||
|
||||
set(this, 'complianceSuggestion', complianceSuggestion);
|
||||
});
|
||||
|
||||
/**
|
||||
* Reads the schema properties for the dataset
|
||||
* @type {Task<Promise<IDatasetSchema>, (a?: any) => TaskInstance<Promise<IDatasetSchema>>>}
|
||||
*/
|
||||
getDatasetSchemaTask = task(function*(this: DatasetComplianceContainer): IterableIterator<Promise<IDatasetSchema>> {
|
||||
const { columns, schemaless } = yield readDatasetSchemaByUrn(get(this, 'urn'));
|
||||
const schemaFieldNamesMappedToDataTypes = columnDataTypesAndFieldNames(columns);
|
||||
|
||||
setProperties(this, { schemaFieldNamesMappedToDataTypes, schemaless });
|
||||
});
|
||||
|
||||
@action
|
||||
/**
|
||||
* Persists the updates to the compliance policy on the remote host
|
||||
* @param {IComplianceInfo} complianceInfo
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
savePrivacyCompliancePolicy(complianceInfo: IComplianceInfo): Promise<void> {
|
||||
return saveDatasetComplianceByUrn(get(this, 'urn'), complianceInfo);
|
||||
}
|
||||
|
||||
@action
|
||||
/**
|
||||
* Resets the compliance information for the dataset with the previously persisted properties
|
||||
*/
|
||||
resetPrivacyCompliancePolicy() {
|
||||
get(this, 'getComplianceTask').perform();
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
import Component from '@ember/component';
|
||||
import { get, set, getProperties } from '@ember/object';
|
||||
import { task, TaskInstance } from 'ember-concurrency';
|
||||
import { action } from 'ember-decorators/object';
|
||||
import { IOwner } from 'wherehows-web/typings/api/datasets/owners';
|
||||
import {
|
||||
OwnerType,
|
||||
readDatasetOwnersByUrn,
|
||||
readDatasetOwnerTypesWithoutConsumer,
|
||||
updateDatasetOwnersByUrn
|
||||
} from 'wherehows-web/utils/api/datasets/owners';
|
||||
|
||||
export default class DatasetOwnershipContainer extends Component {
|
||||
/**
|
||||
* The urn identifier for the dataset
|
||||
* @type {string}
|
||||
*/
|
||||
urn: string;
|
||||
|
||||
/**
|
||||
* List of owners for the dataset
|
||||
* @type {Array<IOwner>}
|
||||
*/
|
||||
owners: Array<IOwner>;
|
||||
|
||||
/**
|
||||
* List of types available for a dataset owner
|
||||
* @type {Array<OwnerType>}
|
||||
*/
|
||||
ownerTypes: Array<OwnerType>;
|
||||
|
||||
didInsertElement() {
|
||||
get(this, 'getContainerDataTask').perform();
|
||||
}
|
||||
|
||||
didUpdateAttrs() {
|
||||
get(this, 'getContainerDataTask').perform();
|
||||
}
|
||||
|
||||
/**
|
||||
* An async parent task to group all data tasks for this container component
|
||||
* @type {Task<TaskInstance<Promise<any>>, (a?: any) => TaskInstance<TaskInstance<Promise<any>>>>}
|
||||
*/
|
||||
getContainerDataTask = task(function*(this: DatasetOwnershipContainer): IterableIterator<TaskInstance<Promise<any>>> {
|
||||
const tasks = Object.values(getProperties(this, ['getDatasetOwnersTask', 'getDatasetOwnerTypesTask']));
|
||||
|
||||
yield* tasks.map(task => task.perform());
|
||||
});
|
||||
|
||||
/**
|
||||
* Reads the owners for this dataset
|
||||
* @type {Task<Promise<Array<IOwner>>, (a?: any) => TaskInstance<Promise<Array<IOwner>>>>}
|
||||
*/
|
||||
getDatasetOwnersTask = task(function*(this: DatasetOwnershipContainer): IterableIterator<Promise<Array<IOwner>>> {
|
||||
const owners = yield readDatasetOwnersByUrn(get(this, 'urn'));
|
||||
|
||||
set(this, 'owners', owners);
|
||||
});
|
||||
|
||||
/**
|
||||
* Reads the owner types available
|
||||
* @type {Task<Promise<Array<OwnerType>>, (a?: any) => TaskInstance<Promise<Array<OwnerType>>>>}
|
||||
*/
|
||||
getDatasetOwnerTypesTask = task(function*(
|
||||
this: DatasetOwnershipContainer
|
||||
): IterableIterator<Promise<Array<OwnerType>>> {
|
||||
const ownerTypes = yield readDatasetOwnerTypesWithoutConsumer();
|
||||
set(this, 'ownerTypes', ownerTypes);
|
||||
});
|
||||
|
||||
@action
|
||||
/**
|
||||
* Persists the changes to the owners list
|
||||
* @param {Array<IOwner>} updatedOwners
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
saveOwnerChanges(updatedOwners: Array<IOwner>): Promise<void> {
|
||||
return updateDatasetOwnersByUrn(get(this, 'urn'), '', updatedOwners);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
import Component from '@ember/component';
|
||||
import { get, setProperties } from '@ember/object';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { action } from 'ember-decorators/object';
|
||||
import { IDatasetView } from 'wherehows-web/typings/api/datasets/dataset';
|
||||
import { readDatasetByUrn } from 'wherehows-web/utils/api/datasets/dataset';
|
||||
import { updateDatasetDeprecationByUrn } from 'wherehows-web/utils/api/datasets/properties';
|
||||
|
||||
export default class DatasetPropertiesContainer extends Component {
|
||||
/**
|
||||
* The urn identifier for the dataset
|
||||
* @type {string}
|
||||
*/
|
||||
urn: string;
|
||||
|
||||
/**
|
||||
* Flag indicating that the dataset is deprecated
|
||||
* @type {boolean | null}
|
||||
*/
|
||||
deprecated: boolean | null;
|
||||
|
||||
/**
|
||||
* Text string, intended to indicate the reason for deprecation
|
||||
* @type {string | null}
|
||||
*/
|
||||
deprecationNote: string | null;
|
||||
|
||||
/**
|
||||
* THe list of properties for the dataset, currently unavailable for v2
|
||||
* @type {any[]}
|
||||
*/
|
||||
properties: Array<never> = [];
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.deprecationNote || (this.deprecationNote = '');
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
get(this, 'getDeprecationPropertiesTask').perform();
|
||||
}
|
||||
|
||||
didUpdateAttrs() {
|
||||
get(this, 'getDeprecationPropertiesTask').perform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the persisted deprecation properties for the dataset
|
||||
* @type {Task<Promise<IDatasetView>, (a?: any) => TaskInstance<Promise<IDatasetView>>>}
|
||||
*/
|
||||
getDeprecationPropertiesTask = task(function*(
|
||||
this: DatasetPropertiesContainer
|
||||
): IterableIterator<Promise<IDatasetView>> {
|
||||
const { deprecated, deprecationNote } = yield readDatasetByUrn(get(this, 'urn'));
|
||||
setProperties(this, { deprecated, deprecationNote });
|
||||
});
|
||||
|
||||
@action
|
||||
/**
|
||||
* Persists the changes to the dataset deprecation properties upstream
|
||||
* @param {boolean} isDeprecated
|
||||
* @param {string} updatedDeprecationNote
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async updateDeprecation(isDeprecated: boolean, updatedDeprecationNote: string): Promise<void> {
|
||||
await updateDatasetDeprecationByUrn(get(this, 'urn'), isDeprecated, updatedDeprecationNote);
|
||||
get(this, 'getDeprecationPropertiesTask').perform();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
import Component from '@ember/component';
|
||||
import { get, setProperties } from '@ember/object';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { IDatasetColumn, IDatasetColumnWithHtmlComments } from 'wherehows-web/typings/api/datasets/columns';
|
||||
import { IDatasetSchema } from 'wherehows-web/typings/api/datasets/schema';
|
||||
import { augmentObjectsWithHtmlComments } from 'wherehows-web/utils/api/datasets/columns';
|
||||
import { readDatasetSchemaByUrn } from 'wherehows-web/utils/api/datasets/schema';
|
||||
|
||||
export default class DatasetSchemaContainer extends Component {
|
||||
/**
|
||||
* The urn identifier for the dataset
|
||||
* @type {string}
|
||||
*/
|
||||
urn: string;
|
||||
|
||||
/**
|
||||
* json string for the dataset schema properties
|
||||
* @type {string}
|
||||
*/
|
||||
json: string;
|
||||
|
||||
/**
|
||||
* List of schema properties for the dataset
|
||||
* @type {IDatasetColumnWithHtmlComments | IDatasetColumn}
|
||||
*/
|
||||
schemas: Array<IDatasetColumnWithHtmlComments | IDatasetColumn>;
|
||||
|
||||
didInsertElement() {
|
||||
get(this, 'getDatasetSchemaTask').perform();
|
||||
}
|
||||
|
||||
didUpdateAttrs() {
|
||||
get(this, 'getDatasetSchemaTask').perform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the schema for the dataset
|
||||
* @type {Task<Promise<IDatasetSchema>, (a?: any) => TaskInstance<Promise<IDatasetSchema>>>}
|
||||
*/
|
||||
getDatasetSchemaTask = task(function*(this: DatasetSchemaContainer): IterableIterator<Promise<IDatasetSchema>> {
|
||||
let schemas,
|
||||
{ columns, rawSchema: json } = yield readDatasetSchemaByUrn(get(this, 'urn'));
|
||||
schemas = augmentObjectsWithHtmlComments(columns);
|
||||
json || (json = '{}');
|
||||
|
||||
setProperties(this, { schemas, json });
|
||||
});
|
||||
}
|
@ -4,9 +4,6 @@ import $ from 'jquery';
|
||||
|
||||
export default Controller.extend({
|
||||
urn: null,
|
||||
currentName: null,
|
||||
urnWatched: false,
|
||||
detailview: true,
|
||||
previousPage: computed('model.data.page', function() {
|
||||
var model = this.get('model');
|
||||
if (model && model.data && model.data.page) {
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
deleteDatasetComment,
|
||||
updateDatasetComment
|
||||
} from 'wherehows-web/utils/api';
|
||||
import { encodeUrn } from 'wherehows-web/utils/validators/urn';
|
||||
import { updateDatasetDeprecation } from 'wherehows-web/utils/api/datasets/properties';
|
||||
import { readDatasetView } from 'wherehows-web/utils/api/datasets/dataset';
|
||||
import { readDatasetOwners, updateDatasetOwners } from 'wherehows-web/utils/api/datasets/owners';
|
||||
@ -28,14 +29,8 @@ export default class extends Controller.extend({
|
||||
*/
|
||||
notifications: service(),
|
||||
|
||||
isTable: true,
|
||||
hasImpacts: false,
|
||||
hasSamples: false,
|
||||
currentVersion: '0',
|
||||
latestVersion: '0',
|
||||
init() {
|
||||
setProperties(this, {
|
||||
ownerTypes: [],
|
||||
userTypes: [
|
||||
{ name: 'Corporate User', value: 'urn:li:corpuser' },
|
||||
{ name: 'Group User', value: 'urn:li:corpGroup' }
|
||||
@ -205,19 +200,6 @@ export default class extends Controller.extend({
|
||||
},
|
||||
|
||||
actions: {
|
||||
/**
|
||||
* Updates the dataset's deprecation properties
|
||||
* @param {boolean} isDeprecated
|
||||
* @param {string} deprecationNote
|
||||
* @return {IDatasetView}
|
||||
*/
|
||||
async updateDeprecation(isDeprecated, deprecationNote) {
|
||||
const datasetId = get(this, 'datasetId');
|
||||
|
||||
await updateDatasetDeprecation(datasetId, isDeprecated, deprecationNote);
|
||||
return set(this, 'datasetView', await readDatasetView(datasetId));
|
||||
},
|
||||
|
||||
/**
|
||||
* Action handler creates a dataset comment with the type and text pas
|
||||
* @param {CommentTypeUnion} type the comment type
|
||||
@ -324,12 +306,29 @@ export default class extends Controller.extend({
|
||||
}
|
||||
}
|
||||
}) {
|
||||
/**
|
||||
* Enum of tab properties
|
||||
* @type {Tabs}
|
||||
*/
|
||||
tabIds = Tabs;
|
||||
|
||||
/**
|
||||
* The currently selected tab in view
|
||||
* @type {Tabs}
|
||||
*/
|
||||
tabSelected;
|
||||
|
||||
/**
|
||||
* Converts the uri on a model to a usable URN format
|
||||
* @type {ComputedProperty<string>}
|
||||
*/
|
||||
encodedUrn = computed('model', function() {
|
||||
const { uri = '' } = get(this, 'model');
|
||||
return encodeUrn(uri);
|
||||
});
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
super(...arguments);
|
||||
this.tabSelected || (this.tabSelected = Tabs.Ownership);
|
||||
}
|
||||
|
||||
@ -342,6 +341,6 @@ export default class extends Controller.extend({
|
||||
// if the tab selection is same as current, noop
|
||||
return get(this, 'tabSelected') === tabSelected
|
||||
? void 0
|
||||
: this.transitionToRoute(`datasets.dataset.${tabSelected}`, get(this, 'datasetId'));
|
||||
: this.transitionToRoute(`datasets.dataset.${tabSelected}`, get(this, 'encodedUrn'));
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { set, get, setProperties } from '@ember/object';
|
||||
import { inject } from '@ember/service';
|
||||
import $ from 'jquery';
|
||||
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';
|
||||
@ -15,29 +14,12 @@ import {
|
||||
|
||||
import { readDatasetOwners, getUserEntities } from 'wherehows-web/utils/api/datasets/owners';
|
||||
import { isRequiredMinOwnersNotConfirmed } from 'wherehows-web/constants/datasets/owner';
|
||||
import {
|
||||
readDatasetById,
|
||||
datasetUrnToId,
|
||||
readDatasetView,
|
||||
readDatasetByUrn
|
||||
} from 'wherehows-web/utils/api/datasets/dataset';
|
||||
import { isWhUrn, isLiUrn } from 'wherehows-web/utils/validators/urn';
|
||||
import { readDatasetById, readDatasetByUrn } from 'wherehows-web/utils/api/datasets/dataset';
|
||||
import isUrn, { isWhUrn, isLiUrn, convertWhUrnToLiUrn, encodeUrn, decodeUrn } from 'wherehows-web/utils/validators/urn';
|
||||
|
||||
import { checkAclAccess } from 'wherehows-web/utils/api/datasets/acl-access';
|
||||
import { currentUser } from 'wherehows-web/utils/api/authentication';
|
||||
|
||||
const { getJSON } = $;
|
||||
// TODO: DSS-6581 Move to URL retrieval module
|
||||
const datasetsUrlRoot = '/api/v1/datasets';
|
||||
const datasetUrl = id => `${datasetsUrlRoot}/${id}`;
|
||||
const ownerTypeUrlRoot = '/api/v1/owner/types';
|
||||
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 getDatasetInstanceUrl = id => `${datasetUrl(id)}/instances`;
|
||||
const getDatasetVersionUrl = (id, dbId) => `${datasetUrl(id)}/versions/db/${dbId}`;
|
||||
import { refreshModelQueryParams } from 'wherehows-web/utils/helpers/routes';
|
||||
|
||||
export default Route.extend({
|
||||
/**
|
||||
@ -45,31 +27,39 @@ export default Route.extend({
|
||||
* @type {Ember.Service}
|
||||
*/
|
||||
configurator: inject(),
|
||||
/**
|
||||
* Reference to the application notifications Service
|
||||
* @type {ComputedProperty<Notifications>}
|
||||
*/
|
||||
notifications: inject(),
|
||||
|
||||
queryParams: {
|
||||
urn: {
|
||||
refreshModel: true
|
||||
}
|
||||
},
|
||||
queryParams: refreshModelQueryParams(['urn']),
|
||||
|
||||
/**
|
||||
* Reads the dataset given a identifier from the dataset endpoint
|
||||
* @param {string} dataset_id a identifier / id for the dataset to be fetched
|
||||
* @param {string} [urn] optional urn identifier for dataset
|
||||
* @return {Promise<IDataset>}
|
||||
* @return {Promise<IDataset|IDatasetView>}
|
||||
*/
|
||||
async model({ dataset_id: datasetId, urn }) {
|
||||
if (datasetId === 'urn') {
|
||||
if (isWhUrn(urn)) {
|
||||
return readDatasetById(await datasetUrnToId(urn));
|
||||
async model({ dataset_id: identifier, urn }) {
|
||||
const isIdentifierUrn = isUrn(decodeUrn(String(identifier)));
|
||||
|
||||
if (identifier === 'urn' || isIdentifierUrn) {
|
||||
isIdentifierUrn && (urn = identifier);
|
||||
const decodedUrn = decodeUrn(urn);
|
||||
|
||||
isWhUrn(decodedUrn) && (urn = convertWhUrnToLiUrn(decodedUrn));
|
||||
|
||||
if (isLiUrn(decodeUrn(urn))) {
|
||||
return await readDatasetByUrn(encodeUrn(urn));
|
||||
}
|
||||
|
||||
if (isLiUrn(urn)) {
|
||||
return await readDatasetByUrn(urn);
|
||||
}
|
||||
get(this, 'notifications.notify')('error', {
|
||||
content: 'Could not adequately determine the URN for the requested dataset.'
|
||||
});
|
||||
}
|
||||
|
||||
return await readDatasetById(datasetId);
|
||||
return await readDatasetById(identifier);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -80,259 +70,22 @@ export default Route.extend({
|
||||
set(controller, 'urn', void 0);
|
||||
},
|
||||
|
||||
//TODO: DSS-6632 Correct server-side if status:error and record not found but response is 200OK
|
||||
setupController(controller, model) {
|
||||
let source = '';
|
||||
let id = 0;
|
||||
let urn = '';
|
||||
|
||||
if (model && model.id) {
|
||||
({ id, source, urn } = model);
|
||||
let { originalSchema = null } = model;
|
||||
|
||||
this.controllerFor('datasets').set('detailview', true);
|
||||
if (originalSchema) {
|
||||
set(model, 'schema', originalSchema);
|
||||
}
|
||||
|
||||
controller.set('model', model);
|
||||
} else if (model.dataset) {
|
||||
({ id, source, urn } = model.dataset);
|
||||
|
||||
controller.set('model', model.dataset);
|
||||
this.controllerFor('datasets').set('detailview', true);
|
||||
}
|
||||
|
||||
// Don't set default zero Ids on controller
|
||||
if (id) {
|
||||
id = +id;
|
||||
controller.set('datasetId', id);
|
||||
|
||||
/**
|
||||
* ****************************
|
||||
* Note: Refactor in progress *
|
||||
* ****************************
|
||||
* async IIFE sets the the complianceInfo and schemaFieldNamesMappedToDataTypes
|
||||
* at once so observers will be buffered
|
||||
* @param {number} id the dataset id
|
||||
* @return {Promise.<void>}
|
||||
*/
|
||||
(async id => {
|
||||
try {
|
||||
let properties;
|
||||
|
||||
const [
|
||||
{ schemaless, columns },
|
||||
compliance,
|
||||
complianceDataTypes,
|
||||
complianceSuggestion,
|
||||
datasetComments,
|
||||
isInternal,
|
||||
datasetView,
|
||||
owners,
|
||||
{ userEntitiesSource, userEntitiesMaps }
|
||||
] = await Promise.all([
|
||||
readDatasetColumns(id),
|
||||
readDatasetCompliance(id),
|
||||
readComplianceDataTypes(),
|
||||
readDatasetComplianceSuggestion(id),
|
||||
readDatasetComments(id),
|
||||
get(this, 'configurator').getConfig('isInternal'),
|
||||
readDatasetView(id),
|
||||
readDatasetOwners(id),
|
||||
getUserEntities()
|
||||
]);
|
||||
const { complianceInfo, isNewComplianceInfo } = compliance;
|
||||
const schemas = augmentObjectsWithHtmlComments(columns);
|
||||
|
||||
if (String(source).toLowerCase() === 'pinot') {
|
||||
properties = await readPinotProperties(id);
|
||||
} else {
|
||||
properties = { properties: await readNonPinotProperties(id) };
|
||||
}
|
||||
|
||||
setProperties(controller, {
|
||||
complianceInfo,
|
||||
complianceDataTypes,
|
||||
isNewComplianceInfo,
|
||||
complianceSuggestion,
|
||||
datasetComments,
|
||||
schemaless,
|
||||
schemas,
|
||||
isInternal,
|
||||
datasetView,
|
||||
schemaFieldNamesMappedToDataTypes: columnDataTypesAndFieldNames(columns),
|
||||
...properties,
|
||||
owners,
|
||||
userEntitiesMaps,
|
||||
userEntitiesSource,
|
||||
requiredMinNotConfirmed: isRequiredMinOwnersNotConfirmed(owners)
|
||||
});
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
})(id);
|
||||
}
|
||||
|
||||
Promise.resolve(getJSON(getDatasetInstanceUrl(id)))
|
||||
.then(({ status, instances = [] }) => {
|
||||
if (status === 'ok' && instances.length) {
|
||||
const [firstInstance = {}] = instances;
|
||||
const { dbId } = firstInstance;
|
||||
|
||||
setProperties(controller, {
|
||||
instances,
|
||||
hasinstances: true,
|
||||
currentInstance: firstInstance,
|
||||
latestInstance: firstInstance
|
||||
});
|
||||
|
||||
return Promise.resolve(getJSON(getDatasetVersionUrl(id, dbId))).then(({ status, versions = [] }) => {
|
||||
if (status === 'ok' && versions.length) {
|
||||
const [firstVersion] = versions;
|
||||
|
||||
setProperties(controller, {
|
||||
versions,
|
||||
hasversions: true,
|
||||
currentVersion: firstVersion,
|
||||
latestVersion: firstVersion
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(new Error('Dataset versions request failed.'));
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(new Error('Dataset instances request failed.'));
|
||||
})
|
||||
.catch(() => {
|
||||
setProperties(controller, {
|
||||
hasinstances: false,
|
||||
hasversions: false,
|
||||
currentInstance: '0',
|
||||
latestInstance: '0',
|
||||
currentVersion: '0',
|
||||
latestVersion: '0'
|
||||
});
|
||||
});
|
||||
async setupController(controller, model) {
|
||||
set(controller, 'model', model);
|
||||
setProperties(controller, {
|
||||
isInternal: await get(this, 'configurator').getConfig('isInternal')
|
||||
// ...properties,
|
||||
// requiredMinNotConfirmed: isRequiredMinOwnersNotConfirmed(owners)
|
||||
});
|
||||
|
||||
// If urn exists, create a breadcrumb list
|
||||
// TODO: DSS-7068 Refactoring in progress , move this to a computed prop on a container component
|
||||
// FIXME: DSS-7068 browse.entity?urn route does not exist for last item in breadcrumb i.e. the dataset
|
||||
// currently being viewed. Should this even be a link in the first place?
|
||||
if (urn) {
|
||||
set(controller, 'breadcrumbs', makeUrnBreadcrumbs(urn));
|
||||
if (model.uri) {
|
||||
set(controller, 'breadcrumbs', makeUrnBreadcrumbs(model.uri));
|
||||
}
|
||||
|
||||
// Get the list of ownerTypes from endpoint,
|
||||
// then prevent display of the `consumer`
|
||||
// insert on controller
|
||||
Promise.resolve(getJSON(ownerTypeUrlRoot)).then(({ status, ownerTypes = [] }) => {
|
||||
ownerTypes = ownerTypes
|
||||
.filter(ownerType => String(ownerType).toLowerCase() !== 'consumer')
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
status === 'ok' && set(controller, 'ownerTypes', ownerTypes);
|
||||
});
|
||||
|
||||
if (source.toLowerCase() !== 'pinot') {
|
||||
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));
|
||||
}
|
||||
|
||||
Promise.resolve(getJSON(getDatasetImpactAnalysisUrl(id)))
|
||||
.then(({ status, impacts = [] }) => {
|
||||
if (status === 'ok') {
|
||||
if (impacts.length) {
|
||||
return setProperties(controller, {
|
||||
hasImpacts: true,
|
||||
impacts: impacts
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(new Error('Dataset partitions request failed.'));
|
||||
})
|
||||
.catch(() => set(controller, 'hasAccess', false));
|
||||
|
||||
Promise.resolve(getJSON(getDatasetReferencesUrl(id)))
|
||||
.then(({ status, references = [] }) => {
|
||||
if (status === 'ok' && references.length) {
|
||||
setTimeout(window.initializeReferencesTreeGrid, 500);
|
||||
|
||||
return setProperties(controller, {
|
||||
references,
|
||||
hasReferences: true
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(new Error('Dataset references request failed.'));
|
||||
})
|
||||
.catch(() => set(controller, 'hasReferences', false));
|
||||
|
||||
// TODO: Get current user ACL permission info for ACL access tab
|
||||
Promise.resolve(currentUser())
|
||||
.then(userInfo => {
|
||||
@ -353,13 +106,5 @@ export default Route.extend({
|
||||
currentUserInfo: ''
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
getDataset() {
|
||||
Promise.resolve(getJSON(datasetUrl(this.get('controller.model.id')))).then(
|
||||
({ status, dataset }) => status === 'ok' && set(this, 'controller.model', dataset)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -11,4 +11,15 @@
|
||||
&__actions {
|
||||
margin-top: item-spacing(2);
|
||||
}
|
||||
|
||||
&__toggle-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
margin-bottom: item-spacing(3);
|
||||
|
||||
&__label {
|
||||
margin: item-spacing(0 2 0 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
{{#if isOwnerInActive}}
|
||||
|
||||
<br>
|
||||
<span class="nacho-button nacho-button--small dataset-author-record__indicator--inactive">
|
||||
Inactive
|
||||
</span>
|
||||
|
@ -1,15 +1,23 @@
|
||||
<form {{action "onSave" on="submit"}}>
|
||||
<label for="dataset-is-deprecated">
|
||||
Dataset is deprecated?
|
||||
</label>
|
||||
|
||||
{{input
|
||||
id="dataset-is-deprecated"
|
||||
type="checkbox"
|
||||
title="Is this dataset deprecated?"
|
||||
checked=(readonly deprecatedAlias)
|
||||
change=(action "toggleDeprecatedStatus")
|
||||
}}
|
||||
<div class="dataset-deprecation-toggle__toggle-header">
|
||||
|
||||
<p class="dataset-deprecation-toggle__toggle-header__label">
|
||||
Is this dataset deprecated?
|
||||
</p>
|
||||
|
||||
{{input
|
||||
id="dataset-is-deprecated"
|
||||
type="checkbox"
|
||||
title="Is this dataset deprecated?"
|
||||
class="toggle-switch toggle-switch--light"
|
||||
checked=(readonly deprecatedAlias)
|
||||
change=(action "toggleDeprecatedStatus")
|
||||
}}
|
||||
<label for="dataset-is-deprecated" class="toggle-button">
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
{{#if deprecatedAlias}}
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
{{dataset-compliance
|
||||
datasetName=datasetName
|
||||
schemaless=schemaless
|
||||
platform=platform
|
||||
complianceInfo=complianceInfo
|
||||
complianceSuggestion=complianceSuggestion
|
||||
isNewComplianceInfo=isNewComplianceInfo
|
||||
schemaFieldNamesMappedToDataTypes=schemaFieldNamesMappedToDataTypes
|
||||
complianceDataTypes=complianceDataTypes
|
||||
onSave=(action "savePrivacyCompliancePolicy")
|
||||
onReset=(action "resetPrivacyCompliancePolicy")
|
||||
}}
|
@ -0,0 +1,5 @@
|
||||
{{dataset-authors
|
||||
owners=owners
|
||||
ownerTypes=ownerTypes
|
||||
save=(action "saveOwnerChanges")
|
||||
}}
|
@ -0,0 +1,7 @@
|
||||
{{dataset-deprecation
|
||||
deprecated=deprecated
|
||||
deprecationNote=deprecationNote
|
||||
onUpdateDeprecation=(action "updateDeprecation")
|
||||
}}
|
||||
|
||||
{{dataset-property properties=properties}}
|
@ -0,0 +1,4 @@
|
||||
{{dataset-schema
|
||||
json=json
|
||||
schemas=schemas
|
||||
}}
|
@ -11,7 +11,7 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
{{#if datasetView.removed}}
|
||||
{{#if model.removed}}
|
||||
<span class="removed-dataset">
|
||||
REMOVED
|
||||
</span>
|
||||
@ -28,8 +28,8 @@
|
||||
</sup>
|
||||
{{/if}}
|
||||
|
||||
{{#if datasetView.deprecated}}
|
||||
{{#link-to "datasets.dataset.properties" datasetId}}
|
||||
{{#if model.deprecated}}
|
||||
{{#link-to "datasets.dataset.properties" encodedUrn}}
|
||||
|
||||
<span class="deprecated-dataset">
|
||||
DEPRECATED
|
||||
@ -48,110 +48,10 @@
|
||||
{{/link-to}}
|
||||
{{/if}}
|
||||
|
||||
<h3>{{ model.name }}</h3>
|
||||
</div>
|
||||
<div class="col-xs-7 text-right">
|
||||
<ul class="datasetDetailsLinks">
|
||||
<li>
|
||||
{{#dataset-favorite dataset=model action="didFavorite"}}
|
||||
{{/dataset-favorite}}
|
||||
<span class="hidden-sm hidden-xs">
|
||||
{{#if model.isFavorite}}
|
||||
Unfavorite
|
||||
{{else}}
|
||||
Favorite
|
||||
{{/if}}
|
||||
</span>
|
||||
</li>
|
||||
{{#if model.hdfsBrowserLink}}
|
||||
<li>
|
||||
<a target="_blank" href={{model.hdfsBrowserLink}}
|
||||
title="View on HDFS">
|
||||
<i class="fa fa-database"></i>
|
||||
<span class="hidden-sm hidden-xs">
|
||||
HDFS
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li>
|
||||
{{#link-to 'lineage.dataset' model.id title='View Lineage'}}
|
||||
<i class="fa fa-sitemap"></i>
|
||||
<span class="hidden-sm hidden-xs">Lineage</span>
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{#if model.hasSchemaHistory}}
|
||||
<li>
|
||||
<a target="_blank" href={{schemaHistoryUrl}}
|
||||
title="View Schema History">
|
||||
<i class="fa fa-history"></i>
|
||||
<span class="hidden-sm hidden-xs">
|
||||
Schema History
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li>
|
||||
{{#dataset-watch dataset=model getDatasets="getDataset"}}
|
||||
{{/dataset-watch}}
|
||||
<span class="hidden-xs hidden-sm">
|
||||
{{#if model.isWatched}}
|
||||
Unwatch
|
||||
{{else}}
|
||||
Watch
|
||||
{{/if}}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>{{ model.nativeName }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
{{dataset-owner-list owners=owners datasetName=model.name}}
|
||||
|
||||
{{#if hasinstances}}
|
||||
<div class="row">
|
||||
<span class="col-xs-1">Instances:</span>
|
||||
<div class="btn-toolbar col-xs-11" role="toolbar">
|
||||
{{#each instances as |instance index|}}
|
||||
<div class="btn-group" role="group">
|
||||
{{#if index}}
|
||||
<button type="button" data-value="{{ instance.dbCode }}" class="btn btn-default instance-btn" {{action
|
||||
"updateInstance" instance}}>
|
||||
{{ instance.dbCode }}
|
||||
</button>
|
||||
{{else}}
|
||||
<button type="button" data-value="{{ instance.dbCode }}" class="btn btn-primary instance-btn" {{action
|
||||
"updateInstance" instance}}>
|
||||
{{ instance.dbCode }}
|
||||
</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if hasversions}}
|
||||
<div class="row">
|
||||
<span class="col-xs-1">Versions:</span>
|
||||
<div class="btn-toolbar col-xs-11" role="toolbar">
|
||||
{{#each versions as |version index|}}
|
||||
<div class="btn-group" role="group">
|
||||
{{#if index}}
|
||||
<button type="button" data-value="{{ version }}" class="btn btn-default version-btn" {{action
|
||||
"updateVersion" version}}>
|
||||
{{ version }}
|
||||
</button>
|
||||
{{else}}
|
||||
<button type="button" data-value="{{ version }}" class="btn btn-primary version-btn" {{action
|
||||
"updateVersion" version}}>
|
||||
{{ version }}
|
||||
</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{dataset-owner-list owners=owners datasetName=model.nativeName}}
|
||||
</div>
|
||||
|
||||
{{#ivy-tabs selection=tabSelected as |tabs|}}
|
||||
@ -169,8 +69,6 @@
|
||||
{{#tablist.tab tabIds.Access on-select=(action "tabSelectionChanged")}}ACL Access{{/tablist.tab}}
|
||||
</span>
|
||||
|
||||
{{#tablist.tab tabIds.Comments on-select=(action "tabSelectionChanged")}}Comments{{/tablist.tab}}
|
||||
|
||||
{{#tablist.tab tabIds.Schema on-select=(action "tabSelectionChanged")}}Schema{{/tablist.tab}}
|
||||
|
||||
{{#tablist.tab tabIds.Ownership on-select=(action "tabSelectionChanged")}}
|
||||
@ -191,26 +89,14 @@
|
||||
{{/tablist.tab}}
|
||||
{{/if}}
|
||||
|
||||
{{#unless isSFDC}}
|
||||
{{#tablist.tab tabIds.SampleData on-select=(action "tabSelectionChanged")}}
|
||||
Sample Data{{/tablist.tab}}
|
||||
{{/unless}}
|
||||
|
||||
{{#tablist.tab tabIds.Relations on-select=(action "tabSelectionChanged")}}
|
||||
Relations{{/tablist.tab}}
|
||||
|
||||
{{/tabs.tablist}}
|
||||
|
||||
{{#tabs.tabpanel tabIds.Properties}}
|
||||
{{#unless isPinot}}
|
||||
{{dataset-deprecation
|
||||
deprecated=datasetView.deprecated
|
||||
deprecationNote=datasetView.deprecationNote
|
||||
onUpdateDeprecation=(action "updateDeprecation")
|
||||
}}
|
||||
|
||||
{{dataset-property properties=properties}}
|
||||
{{/unless}}
|
||||
{{datasets/containers/dataset-properties
|
||||
urn=encodedUrn
|
||||
deprecated=model.deprecated
|
||||
deprecationNote=model.deprecationNote
|
||||
}}
|
||||
{{/tabs.tabpanel}}
|
||||
|
||||
{{#tabs.tabpanel tabIds.Comments}}
|
||||
@ -223,45 +109,18 @@
|
||||
{{/tabs.tabpanel}}
|
||||
|
||||
{{#tabs.tabpanel tabIds.Schema}}
|
||||
{{dataset-schema
|
||||
isTable=isTable
|
||||
json=model.schema
|
||||
schemas=schemas
|
||||
}}
|
||||
{{datasets/containers/dataset-schema urn=encodedUrn}}
|
||||
{{/tabs.tabpanel}}
|
||||
|
||||
{{#tabs.tabpanel tabIds.Ownership}}
|
||||
{{dataset-authors
|
||||
owners=owners
|
||||
ownerTypes=ownerTypes
|
||||
save=(action "saveOwnerChanges")
|
||||
}}
|
||||
{{/tabs.tabpanel}}
|
||||
|
||||
{{#tabs.tabpanel tabIds.SampleData}}
|
||||
{{#unless isSFDC}}
|
||||
{{dataset-sample hasSamples=hasSamples isPinot=isPinot columns=columns samples=samples}}
|
||||
{{/unless}}
|
||||
{{/tabs.tabpanel}}
|
||||
|
||||
{{#tabs.tabpanel tabIds.Relations}}
|
||||
{{#unless isSFDC}}
|
||||
{{dataset-relations hasDepends=hasDepends depends=depends hasReferences=hasReferences references=references}}
|
||||
{{/unless}}
|
||||
{{datasets/containers/dataset-ownership urn=encodedUrn}}
|
||||
{{/tabs.tabpanel}}
|
||||
|
||||
{{#tabs.tabpanel tabIds.Compliance}}
|
||||
{{dataset-compliance
|
||||
datasetName=model.name
|
||||
schemaless=schemaless
|
||||
platform=datasetView.platform
|
||||
complianceInfo=complianceInfo
|
||||
complianceSuggestion=complianceSuggestion
|
||||
isNewComplianceInfo=isNewComplianceInfo
|
||||
schemaFieldNamesMappedToDataTypes=schemaFieldNamesMappedToDataTypes
|
||||
complianceDataTypes=complianceDataTypes
|
||||
onSave=(action "savePrivacyCompliancePolicy")
|
||||
onReset=(action "resetPrivacyCompliancePolicy")
|
||||
{{datasets/containers/dataset-compliance
|
||||
urn=encodedUrn
|
||||
platform=model.platform
|
||||
datasetName=model.nativeName
|
||||
}}
|
||||
{{/tabs.tabpanel}}
|
||||
|
||||
|
@ -37,4 +37,14 @@ interface IOwnerPostResponse {
|
||||
msg?: string;
|
||||
}
|
||||
|
||||
export { IOwnerPostResponse, IOwnerResponse, IOwner };
|
||||
/**
|
||||
* Describes the properties on a response to a request for owner types
|
||||
* @interface
|
||||
*/
|
||||
interface IOwnerTypeResponse {
|
||||
status: ApiStatus;
|
||||
ownerTypes?: Array<OwnerType>;
|
||||
msg?: string;
|
||||
}
|
||||
|
||||
export { IOwnerPostResponse, IOwnerResponse, IOwner, IOwnerTypeResponse };
|
||||
|
22
wherehows-web/app/typings/api/datasets/schema.d.ts
vendored
Normal file
22
wherehows-web/app/typings/api/datasets/schema.d.ts
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
import { IDatasetColumn } from 'wherehows-web/typings/api/datasets/columns';
|
||||
|
||||
/**
|
||||
* Describes the properties on a dataset schema object
|
||||
* @interface
|
||||
*/
|
||||
interface IDatasetSchema {
|
||||
schemaless: boolean;
|
||||
rawSchema: null | string;
|
||||
keySchema: null | string;
|
||||
columns: Array<IDatasetColumn>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the properties on a response to a request for dataset schema
|
||||
* @interface
|
||||
*/
|
||||
interface IDatasetSchemaGetResponse {
|
||||
schema: IDatasetSchema;
|
||||
}
|
||||
|
||||
export { IDatasetSchema, IDatasetSchemaGetResponse };
|
@ -25,16 +25,20 @@ const datasetColumnUrlById = (id: number): string => `${datasetUrlById(id)}/colu
|
||||
|
||||
/**
|
||||
* Maps an object with a column prop to an object containing markdown comments, if the dataset has a comment attribute
|
||||
* @template T
|
||||
* @template T
|
||||
* @param {T} objectWithComment
|
||||
* @return {T & {commentHtml: string} | {} & T}
|
||||
* @returns {(T | T & {commentHtml: string})}
|
||||
*/
|
||||
const augmentWithHtmlComment = <T extends { comment: string }>(objectWithComment: T) => {
|
||||
const augmentWithHtmlComment = <T extends { comment: string }>(
|
||||
objectWithComment: T
|
||||
): T | T & { commentHtml: string } => {
|
||||
const { comment } = objectWithComment;
|
||||
// TODO: DSS-6122 Refactor global function reference to marked
|
||||
// not using spread operator here: https://github.com/Microsoft/TypeScript/issues/10727
|
||||
// current ts version: 2.5.3
|
||||
return Object.assign({}, objectWithComment, comment && { commentHtml: window.marked(comment).htmlSafe() });
|
||||
return comment
|
||||
? Object.assign({}, objectWithComment, { commentHtml: window.marked(comment).htmlSafe() })
|
||||
: objectWithComment;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -55,7 +59,9 @@ const columnDataTypeAndFieldName = ({
|
||||
* Takes a list of objects with comments and returns an array of objects with comments or html comments
|
||||
* @type {(array: Array<T extends { comment: string } & Object>) => Array<T | T extends { commentHtml: string }>}
|
||||
*/
|
||||
const augmentObjectsWithHtmlComments = arrayMap(augmentWithHtmlComment);
|
||||
const augmentObjectsWithHtmlComments = arrayMap<IDatasetColumn, IDatasetColumnWithHtmlComments | IDatasetColumn>(
|
||||
augmentWithHtmlComment
|
||||
);
|
||||
|
||||
/**
|
||||
* Takes a list of IDatasetColumn / IDatasetColumn with html comments and pulls the dataType and and fullFieldPath (as fieldName) attributes
|
||||
|
@ -1,9 +1,10 @@
|
||||
import Ember from 'ember';
|
||||
import { IDatasetComment, IDatasetCommentsGetResponse } from 'wherehows-web/typings/api/datasets/comments';
|
||||
import { datasetUrlById } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import { datasetUrlById, datasetUrlByUrn } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import { ApiStatus } from 'wherehows-web/utils/api/shared';
|
||||
import { getJSON } from 'wherehows-web/utils/api/fetcher';
|
||||
|
||||
const { $: { getJSON, post, ajax } } = Ember;
|
||||
const { $: { getJSON: $getJSON, post, ajax } } = Ember;
|
||||
|
||||
// TODO: DSS-6122 Create and move to Error module
|
||||
/**
|
||||
@ -25,6 +26,13 @@ const csrfToken = '_UNUSED_';
|
||||
*/
|
||||
const datasetCommentsUrlById = (id: number): string => `${datasetUrlById(id)}/comments`;
|
||||
|
||||
/**
|
||||
* Returns the url for a dataset comment by urn
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const datasetCommentsUrnByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/comments`;
|
||||
|
||||
/**
|
||||
* Gets a specific comment on a dataset
|
||||
* @param {number} datasetId the id of the dataset
|
||||
@ -40,7 +48,7 @@ const datasetCommentUrlById = (datasetId: number, commentId: number): string =>
|
||||
* @return {Promise<Array<IDatasetComment>>}
|
||||
*/
|
||||
const readDatasetComments = async (id: number): Promise<Array<IDatasetComment>> => {
|
||||
const response: IDatasetCommentsGetResponse = await Promise.resolve(getJSON(datasetCommentsUrlById(id)));
|
||||
const response: IDatasetCommentsGetResponse = await Promise.resolve($getJSON(datasetCommentsUrlById(id)));
|
||||
const { status, data: { comments } } = response;
|
||||
|
||||
if (status === ApiStatus.OK) {
|
||||
@ -50,6 +58,18 @@ const readDatasetComments = async (id: number): Promise<Array<IDatasetComment>>
|
||||
throw new Error(datasetCommentsApiException);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads the dataset comments related to the urn
|
||||
* @param {string} urn
|
||||
* @return {Promise<Array<IDatasetComment>>}
|
||||
*/
|
||||
const readDatasetCommentsByUrn = async (urn: string): Promise<Array<IDatasetComment>> => {
|
||||
const { data: { comments } } = await getJSON<Pick<IDatasetCommentsGetResponse, 'data'>>({
|
||||
url: datasetCommentsUrnByUrn(urn)
|
||||
});
|
||||
return comments;
|
||||
};
|
||||
|
||||
/**
|
||||
* Posts a new comment on a dataset
|
||||
* @param {number} id the id of the dataset
|
||||
@ -138,4 +158,10 @@ const updateDatasetComment = async (
|
||||
}
|
||||
};
|
||||
|
||||
export { readDatasetComments, createDatasetComment, deleteDatasetComment, updateDatasetComment };
|
||||
export {
|
||||
readDatasetComments,
|
||||
createDatasetComment,
|
||||
deleteDatasetComment,
|
||||
updateDatasetComment,
|
||||
readDatasetCommentsByUrn
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { assert } from '@ember/debug';
|
||||
import { createInitialComplianceInfo } from 'wherehows-web/utils/datasets/compliance-policy';
|
||||
import { datasetUrlById } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import { datasetUrlById, datasetUrlByUrn } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import { ApiStatus } from 'wherehows-web/utils/api/shared';
|
||||
import {
|
||||
IComplianceGetResponse,
|
||||
@ -8,7 +8,7 @@ import {
|
||||
IComplianceSuggestion,
|
||||
IComplianceSuggestionResponse
|
||||
} from 'wherehows-web/typings/api/datasets/compliance';
|
||||
import { getJSON } from 'wherehows-web/utils/api/fetcher';
|
||||
import { getJSON, postJSON } from 'wherehows-web/utils/api/fetcher';
|
||||
|
||||
/**
|
||||
* Constructs the dataset compliance url
|
||||
@ -17,6 +17,13 @@ import { getJSON } from 'wherehows-web/utils/api/fetcher';
|
||||
*/
|
||||
const datasetComplianceUrlById = (id: number): string => `${datasetUrlById(id)}/compliance`;
|
||||
|
||||
/**
|
||||
* Returns the url for a datasets compliance policy by urn
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const datasetComplianceUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/compliance`;
|
||||
|
||||
/**
|
||||
* Constructs the compliance suggestions url based of the compliance id
|
||||
* @param {number} id the id of the dataset
|
||||
@ -24,6 +31,13 @@ const datasetComplianceUrlById = (id: number): string => `${datasetUrlById(id)}/
|
||||
*/
|
||||
const datasetComplianceSuggestionsUrlById = (id: number): string => `${datasetComplianceUrlById(id)}/suggestions`;
|
||||
|
||||
/**
|
||||
* Returns the url for a dataset compliance suggestion by urn
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const datasetComplianceSuggestionUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/complianceSuggestion`;
|
||||
|
||||
/**
|
||||
* Determines if the client app should 'new' a compliance policy
|
||||
* If the endpoint responds with a failed status, and the msg contains the indicator that a compliance does not exist
|
||||
@ -35,14 +49,21 @@ const requiresCompliancePolicyCreation = ({ status, msg }: IComplianceGetRespons
|
||||
return status === ApiStatus.FAILED && String(msg).includes(notFound);
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the properties on a map generated by reading the compliance policy for a dataset
|
||||
* @interface
|
||||
*/
|
||||
export interface IReadComplianceResult {
|
||||
isNewComplianceInfo: boolean;
|
||||
complianceInfo: IComplianceInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the current compliance policy for a dataset with thi given id
|
||||
* @param {number} id the id of the dataset
|
||||
* @returns {(Promise<{ isNewComplianceInfo: boolean; complianceInfo: IComplianceInfo }>)}
|
||||
* @returns {(Promise<IReadComplianceResult>)}
|
||||
*/
|
||||
const readDatasetCompliance = async (
|
||||
id: number
|
||||
): Promise<{ isNewComplianceInfo: boolean; complianceInfo: IComplianceInfo }> => {
|
||||
const readDatasetCompliance = async (id: number): Promise<IReadComplianceResult> => {
|
||||
assert(`Expected id to be a number but received ${typeof id}`, typeof id === 'number');
|
||||
|
||||
const response = await getJSON<IComplianceGetResponse>({ url: datasetComplianceUrlById(id) });
|
||||
@ -60,6 +81,35 @@ const readDatasetCompliance = async (
|
||||
throw new Error(msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads the dataset compliance policy by urn
|
||||
* @param {string} urn
|
||||
* @return {Promise<IReadComplianceResult>}
|
||||
*/
|
||||
const readDatasetComplianceByUrn = async (urn: string): Promise<IReadComplianceResult> => {
|
||||
let { complianceInfo } = await getJSON<Pick<IComplianceGetResponse, 'complianceInfo'>>({
|
||||
url: datasetComplianceUrlByUrn(urn)
|
||||
});
|
||||
const isNewComplianceInfo = !complianceInfo;
|
||||
|
||||
if (isNewComplianceInfo) {
|
||||
complianceInfo = createInitialComplianceInfo(urn);
|
||||
}
|
||||
|
||||
return { isNewComplianceInfo, complianceInfo: complianceInfo! };
|
||||
};
|
||||
|
||||
/**
|
||||
* Persists the dataset compliance policy
|
||||
* @param {string} urn
|
||||
* @param {IComplianceInfo} complianceInfo
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
const saveDatasetComplianceByUrn = (urn: string, complianceInfo: IComplianceInfo): Promise<void> => {
|
||||
const url = datasetUrlByUrn(urn);
|
||||
return postJSON<void>({ url, data: complianceInfo });
|
||||
};
|
||||
|
||||
/**
|
||||
* Requests the compliance suggestions for a given dataset Id and returns the suggestion list
|
||||
* @param {number} id the id of the dataset
|
||||
@ -73,4 +123,29 @@ const readDatasetComplianceSuggestion = async (id: number): Promise<IComplianceS
|
||||
return complianceSuggestion;
|
||||
};
|
||||
|
||||
export { readDatasetCompliance, readDatasetComplianceSuggestion, datasetComplianceUrlById };
|
||||
/**
|
||||
* Reads the suggestions for a dataset compliance policy by urn
|
||||
* @param {string} urn
|
||||
* @return {Promise<IComplianceSuggestion>}
|
||||
*/
|
||||
const readDatasetComplianceSuggestionByUrn = async (urn: string): Promise<IComplianceSuggestion> => {
|
||||
let complianceSuggestion: IComplianceSuggestion = <IComplianceSuggestion>{};
|
||||
try {
|
||||
({ complianceSuggestion = <IComplianceSuggestion>{} } = await getJSON<
|
||||
Pick<IComplianceSuggestionResponse, 'complianceSuggestion'>
|
||||
>({ url: datasetComplianceSuggestionUrlByUrn(urn) }));
|
||||
} catch {
|
||||
return complianceSuggestion;
|
||||
}
|
||||
|
||||
return complianceSuggestion;
|
||||
};
|
||||
|
||||
export {
|
||||
readDatasetCompliance,
|
||||
readDatasetComplianceSuggestion,
|
||||
datasetComplianceUrlById,
|
||||
readDatasetComplianceByUrn,
|
||||
saveDatasetComplianceByUrn,
|
||||
readDatasetComplianceSuggestionByUrn
|
||||
};
|
||||
|
@ -1,13 +1,19 @@
|
||||
import { IOwner, IOwnerPostResponse, IOwnerResponse } from 'wherehows-web/typings/api/datasets/owners';
|
||||
import {
|
||||
IOwner,
|
||||
IOwnerPostResponse,
|
||||
IOwnerResponse,
|
||||
IOwnerTypeResponse
|
||||
} from 'wherehows-web/typings/api/datasets/owners';
|
||||
import {
|
||||
IPartyEntity,
|
||||
IPartyEntityResponse,
|
||||
IPartyProps,
|
||||
IUserEntityMap
|
||||
} from 'wherehows-web/typings/api/datasets/party-entities';
|
||||
import { datasetUrlById } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import { datasetUrlById, datasetUrlByUrn } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import { getJSON, postJSON } from 'wherehows-web/utils/api/fetcher';
|
||||
import { getApiRoot, ApiStatus } from 'wherehows-web/utils/api/shared';
|
||||
import { arrayFilter, arrayMap } from 'wherehows-web/utils/array';
|
||||
|
||||
/**
|
||||
* Defines a string enum for valid owner types
|
||||
@ -57,8 +63,25 @@ enum OwnerSource {
|
||||
*/
|
||||
const datasetOwnersUrlById = (id: number): string => `${datasetUrlById(id)}/owners`;
|
||||
|
||||
/**
|
||||
* Returns the dataset owners url by urn
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const datasetOwnersUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/owners`;
|
||||
|
||||
/**
|
||||
* Returns the party entities url
|
||||
* @type {string}
|
||||
*/
|
||||
const partyEntitiesUrl = `${getApiRoot()}/party/entities`;
|
||||
|
||||
/**
|
||||
* Returns the owner types url
|
||||
* @return {string}
|
||||
*/
|
||||
const datasetOwnerTypesUrl = () => `${getApiRoot()}/owner/types`;
|
||||
|
||||
/**
|
||||
* Requests the list of dataset owners from the GET endpoint, converts the modifiedTime property
|
||||
* to a date object
|
||||
@ -68,15 +91,38 @@ const partyEntitiesUrl = `${getApiRoot()}/party/entities`;
|
||||
const readDatasetOwners = async (id: number): Promise<Array<IOwner>> => {
|
||||
const { owners = [], status, msg } = await getJSON<IOwnerResponse>({ url: datasetOwnersUrlById(id) });
|
||||
if (status === ApiStatus.OK) {
|
||||
return owners.map(owner => ({
|
||||
...owner,
|
||||
modifiedTime: new Date(<number>owner.modifiedTime!) // Api response is always in number format
|
||||
}));
|
||||
return ownersWithModifiedTimeAsDate(owners);
|
||||
}
|
||||
|
||||
throw new Error(msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Modifies an owner object by applying the modified date property as a Date object
|
||||
* @param {IOwner} owner
|
||||
* @return {IOwner}
|
||||
*/
|
||||
const ownerWithModifiedTimeAsDate = (owner: IOwner): IOwner => ({
|
||||
...owner,
|
||||
modifiedTime: new Date(<number>owner.modifiedTime)
|
||||
}); // Api response is always in number format
|
||||
|
||||
/**
|
||||
* Modifies a list of owners with a modified date property as a Date object
|
||||
* @type {(array: Array<IOwner>) => Array<IOwner>}
|
||||
*/
|
||||
const ownersWithModifiedTimeAsDate = arrayMap(ownerWithModifiedTimeAsDate);
|
||||
|
||||
/**
|
||||
* Reads the owners for dataset by urn
|
||||
* @param {string} urn
|
||||
* @return {Promise<Array<IOwner>>}
|
||||
*/
|
||||
const readDatasetOwnersByUrn = async (urn: string): Promise<Array<IOwner>> => {
|
||||
const { owners = [] } = await getJSON<Pick<IOwnerResponse, 'owners'>>({ url: datasetOwnersUrlByUrn(urn) });
|
||||
return ownersWithModifiedTimeAsDate(owners);
|
||||
};
|
||||
|
||||
/**
|
||||
* Persists the updated list of dataset owners
|
||||
* @param {number} id the id of the dataset
|
||||
@ -105,6 +151,47 @@ const updateDatasetOwners = async (
|
||||
throw new Error(msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the owners on a dataset by urn
|
||||
* @param {string} urn
|
||||
* @param {string} csrfToken
|
||||
* @param {Array<IOwner>} updatedOwners
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
const updateDatasetOwnersByUrn = (urn: string, csrfToken: string = '', updatedOwners: Array<IOwner>): Promise<void> => {
|
||||
return postJSON<void>({
|
||||
url: datasetOwnersUrlByUrn(urn),
|
||||
headers: { 'csrf-token': csrfToken },
|
||||
data: {
|
||||
csrfToken,
|
||||
owners: updatedOwners
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads the owner types list on a dataset
|
||||
* @return {Promise<Array<OwnerType>>}
|
||||
*/
|
||||
const readDatasetOwnerTypes = async (): Promise<Array<OwnerType>> => {
|
||||
const url = datasetOwnerTypesUrl();
|
||||
const { ownerTypes = [] } = await getJSON<IOwnerTypeResponse>({ url });
|
||||
return ownerTypes.sort((a: string, b: string) => a.localeCompare(b));
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if an owner type supplied is not of type consumer
|
||||
* @param {OwnerType} ownerType
|
||||
* @return {boolean}
|
||||
*/
|
||||
const isNotAConsumer = (ownerType: OwnerType): boolean => ownerType !== OwnerType.Consumer;
|
||||
|
||||
/**
|
||||
* Reads the dataset owner types and filters out the OwnerType.Consumer type from the list
|
||||
* @return {Promise<Array<OwnerType>>}
|
||||
*/
|
||||
const readDatasetOwnerTypesWithoutConsumer = async () => arrayFilter(isNotAConsumer)(await readDatasetOwnerTypes());
|
||||
|
||||
/**
|
||||
* Requests party entities and if the response status is OK, resolves with an array of entities
|
||||
* @return {Promise<Array<IPartyEntity>>}
|
||||
@ -179,6 +266,9 @@ const readPartyEntitiesMap = (partyEntities: Array<IPartyEntity>): IUserEntityMa
|
||||
|
||||
export {
|
||||
readDatasetOwners,
|
||||
readDatasetOwnersByUrn,
|
||||
updateDatasetOwnersByUrn,
|
||||
readDatasetOwnerTypesWithoutConsumer,
|
||||
readPartyEntities,
|
||||
readPartyEntitiesMap,
|
||||
getUserEntities,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { warn } from '@ember/debug';
|
||||
import { ApiStatus } from 'wherehows-web/utils/api';
|
||||
import { getJSON, putJSON } from 'wherehows-web/utils/api/fetcher';
|
||||
import { datasetUrlById } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import { datasetUrlById, datasetUrlByUrn } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import {
|
||||
IDatasetProperties,
|
||||
IDatasetPropertiesGetResponse,
|
||||
@ -27,6 +27,13 @@ const datasetPropertiesUrlById = (id: number) => `${datasetUrlById(id)}/properti
|
||||
|
||||
const datasetDeprecationUrlById = (id: number) => `${datasetUrlById(id)}/deprecate`;
|
||||
|
||||
/**
|
||||
* Returns the url for a dataset deprecation endpoint by urn
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const datasetDeprecationUrlByUrn = (urn: string) => `${datasetUrlByUrn(urn)}/deprecate`;
|
||||
|
||||
/**
|
||||
* Reads the response from the dataset properties endpoint and returns properties if found
|
||||
* @param {number} id the dataset id to get properties for
|
||||
@ -197,4 +204,31 @@ const updateDatasetDeprecation = async (id: number, deprecated: boolean, depreca
|
||||
}
|
||||
};
|
||||
|
||||
export { readDatasetProperties, readNonPinotProperties, readPinotProperties, updateDatasetDeprecation };
|
||||
/**
|
||||
* Persists the changes to a datasets deprecation properties by urn
|
||||
* @param {string} urn
|
||||
* @param {boolean} deprecated
|
||||
* @param {string} deprecationNote
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
const updateDatasetDeprecationByUrn = (
|
||||
urn: string,
|
||||
deprecated: boolean,
|
||||
deprecationNote: string = ''
|
||||
): Promise<void> => {
|
||||
return putJSON<void>({
|
||||
url: datasetDeprecationUrlByUrn(urn),
|
||||
data: {
|
||||
deprecated,
|
||||
deprecationNote
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
readDatasetProperties,
|
||||
readNonPinotProperties,
|
||||
readPinotProperties,
|
||||
updateDatasetDeprecation,
|
||||
updateDatasetDeprecationByUrn
|
||||
};
|
||||
|
22
wherehows-web/app/utils/api/datasets/schema.ts
Normal file
22
wherehows-web/app/utils/api/datasets/schema.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { IDatasetSchema, IDatasetSchemaGetResponse } from 'wherehows-web/typings/api/datasets/schema';
|
||||
import { datasetUrlByUrn } from 'wherehows-web/utils/api/datasets/shared';
|
||||
import { getJSON } from 'wherehows-web/utils/api/fetcher';
|
||||
|
||||
/**
|
||||
* Returns the url for a dataset schema by urn
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const datasetSchemaUrlByUrn = (urn: string): string => `${datasetUrlByUrn(urn)}/schema`;
|
||||
|
||||
/**
|
||||
* Reads the schema for a dataset with the related urn
|
||||
* @param {string} urn
|
||||
* @return {Promise<IDatasetSchema>}
|
||||
*/
|
||||
const readDatasetSchemaByUrn = async (urn: string): Promise<IDatasetSchema> => {
|
||||
const { schema } = await getJSON<IDatasetSchemaGetResponse>({ url: datasetSchemaUrlByUrn(urn) });
|
||||
return schema;
|
||||
};
|
||||
|
||||
export { readDatasetSchemaByUrn };
|
@ -19,9 +19,8 @@ export const datasetUrlById = (id: number): string => `${datasetsUrlRoot('v1')}/
|
||||
* @param {string} urn
|
||||
* @returns {string}
|
||||
*/
|
||||
export const datasetUrlByUrn = (urn: string): string => `${getApiRoot('v2')}/dataset/${urn}`;
|
||||
//FIXME api plurality ^^^^^^^^^^
|
||||
// export const datasetUrlByUrn = (urn: string): string => `${datasetsUrlRoot('v2')}/${urn}`;
|
||||
export const datasetUrlByUrn = (urn: string): string => `${datasetsUrlRoot('v2')}/${urn}`;
|
||||
|
||||
/**
|
||||
* Composes the datasets count url from a given platform and or prefix if provided
|
||||
* @param {Partial<IReadDatasetsOptionBag>} [{ platform, prefix }={}]
|
||||
|
@ -1,19 +1,24 @@
|
||||
import { DatasetClassifiers } from 'wherehows-web/constants/dataset-classification';
|
||||
import { lastSeenSuggestionInterval } from 'wherehows-web/constants/metadata-acquisition';
|
||||
import { assert, warn } from '@ember/debug';
|
||||
import { decodeUrn } from 'wherehows-web/utils/validators/urn';
|
||||
|
||||
/**
|
||||
* Builds a default shape for securitySpecification & privacyCompliancePolicy with default / unset values
|
||||
* for non null properties as per Avro schema
|
||||
* @param {number} datasetId id for the dataset that this privacy object applies to
|
||||
* @param {number} datasetId identifier for the dataset that this privacy object applies to
|
||||
*/
|
||||
const createInitialComplianceInfo = datasetId => ({
|
||||
datasetId,
|
||||
complianceType: '',
|
||||
compliancePurgeNote: '',
|
||||
complianceEntities: [],
|
||||
datasetClassification: {}
|
||||
});
|
||||
const createInitialComplianceInfo = datasetId => {
|
||||
const identifier = typeof datasetId === 'string' ? { urn: decodeUrn(datasetId) } : { datasetId };
|
||||
|
||||
return {
|
||||
...identifier,
|
||||
complianceType: '',
|
||||
compliancePurgeNote: '',
|
||||
complianceEntities: [],
|
||||
datasetClassification: {}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -1,33 +0,0 @@
|
||||
import { urnRegex } from 'wherehows-web/utils/validators/urn';
|
||||
|
||||
/**
|
||||
* Takes a urn string and parse it into an array of breadcrumb objects with crumb, and urn as
|
||||
* properties.
|
||||
* Hierarchy is implied in element ordering
|
||||
* @param {String} urn
|
||||
* @return {Array.<{crumb, urn}>|null}
|
||||
*/
|
||||
export default urn => {
|
||||
const urnMatch = urnRegex.exec(urn);
|
||||
|
||||
if (urnMatch) {
|
||||
// Initial element in a match array from RegExp#exec is the full match, not needed here
|
||||
const urnParts = urnMatch.filter((match, index) => index);
|
||||
// Splits the 2nd captured group into an array of urn names and spreads into a new list
|
||||
const crumbs = [urnParts[0], ...urnParts[1].split('/')];
|
||||
|
||||
// Reduces the crumbs into a list of crumb names and urn paths
|
||||
return crumbs.reduce((breadcrumbs, crumb, index) => {
|
||||
const previousCrumb = breadcrumbs[index - 1];
|
||||
const breadcrumb = {
|
||||
crumb,
|
||||
// First item is root
|
||||
urn: !index ? `${crumb}:///` : `${previousCrumb.urn}${crumb}/`
|
||||
};
|
||||
|
||||
return [...breadcrumbs, breadcrumb];
|
||||
}, []);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
41
wherehows-web/app/utils/entities/make-urn-breadcrumbs.ts
Normal file
41
wherehows-web/app/utils/entities/make-urn-breadcrumbs.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { datasetUrnRegexWH } from 'wherehows-web/utils/validators/urn';
|
||||
|
||||
interface IBreadCrumb {
|
||||
crumb: string;
|
||||
urn: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a urn string and parse it into an array of breadcrumb objects with crumb, and urn as
|
||||
* properties.
|
||||
* Hierarchy is implied in element ordering
|
||||
* @param {String} urn
|
||||
* @return {Array.<{crumb, urn}>|null}
|
||||
*/
|
||||
export default (urn: string): Array<{ crumb: string; urn: string }> | null => {
|
||||
const urnMatch = datasetUrnRegexWH.exec(urn);
|
||||
|
||||
if (urnMatch) {
|
||||
// Initial element in a match array from RegExp#exec is the full match, not needed here
|
||||
const urnParts = urnMatch.filter((_match, index) => index);
|
||||
// Splits the 2nd captured group into an array of urn names and spreads into a new list
|
||||
const crumbs = [urnParts[0], ...urnParts[1].split('/')];
|
||||
|
||||
// Reduces the crumbs into a list of crumb names and urn paths
|
||||
return crumbs.reduce(
|
||||
(breadcrumbs, crumb, index) => {
|
||||
const previousCrumb = breadcrumbs[index - 1];
|
||||
const breadcrumb: IBreadCrumb = {
|
||||
crumb,
|
||||
// First item is root
|
||||
urn: !index ? `${crumb}:///` : `${previousCrumb.urn}${crumb}/`
|
||||
};
|
||||
|
||||
return [...breadcrumbs, breadcrumb];
|
||||
},
|
||||
<Array<IBreadCrumb>>[]
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
@ -1,17 +1,19 @@
|
||||
import { assert } from '@ember/debug';
|
||||
|
||||
/**
|
||||
* Matches a url string with a `urn` query. urn query with letters or underscore segment of any length greater
|
||||
* than 1 followed by colon and 3 forward slashes and a segment containing letters, {, }, _ or /, or none
|
||||
* The value following the urn key is retained
|
||||
* @type {RegExp}
|
||||
*/
|
||||
const datasetUrnRegexWH = /([a-z_]+):\/{3}([a-z0-9_\-/{}]*)/i;
|
||||
const datasetUrnRegexWH = /([a-z_]+):\/{3}([a-z0-9_\-/{}.]*)/i;
|
||||
|
||||
/**
|
||||
* Matches a urn string that follows the pattern captures, the comma delimited platform, segment and fabric
|
||||
* e.g urn:li:dataset:(urn:li:dataPlatform:PLATFORM,SEGMENT,FABRIC)
|
||||
* @type {RegExp}
|
||||
*/
|
||||
const datasetUrnRegexLI = /urn:li:dataset:\(urn:li:dataPlatform:(\w+),([\w.\-]+),(\w+)\)/;
|
||||
const datasetUrnRegexLI = /urn:li:dataset:\(urn:li:dataPlatform:(\w+),([\w.\-\/]+),(\w+)\)/;
|
||||
|
||||
/**
|
||||
* Matches urn's that occur in flow urls
|
||||
@ -53,6 +55,61 @@ const getPlatformFromUrn = (candidateUrn: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a WH URN format to a LI URN format
|
||||
* @param {string} whUrn
|
||||
* @return {string}
|
||||
*/
|
||||
const convertWhUrnToLiUrn = (whUrn: string): string => {
|
||||
assert(`Expected ${whUrn} to be in the WH urn format`, isWhUrn(whUrn));
|
||||
const [, platform, path] = datasetUrnRegexWH.exec(whUrn)!;
|
||||
|
||||
return `urn:li:dataset:(urn:li:dataPlatform:${platform},${path},PROD)`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cached RegExp object for a global search of /
|
||||
* @type {RegExp}
|
||||
*/
|
||||
const encodedSlashRegExp = new RegExp(encodeURIComponent('/'), 'g');
|
||||
/**
|
||||
* Replaces any occurrence of / with the encoded equivalent
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const encodeForwardSlash = (urn: string): string => urn.replace(/\//g, encodeURIComponent('/'));
|
||||
|
||||
/**
|
||||
* Replaces encoded slashes with /
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const decodeForwardSlash = (urn: string): string => urn.replace(encodedSlashRegExp, decodeURIComponent('/'));
|
||||
|
||||
/**
|
||||
* Replaces occurrences of / with the encoded counterpart in a urn string
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const encodeUrn = (urn: string): string => encodeForwardSlash(urn);
|
||||
|
||||
/**
|
||||
* Replaces encoded occurrences of / with the string /
|
||||
* @param {string} urn
|
||||
* @return {string}
|
||||
*/
|
||||
const decodeUrn = (urn: string): string => decodeForwardSlash(urn);
|
||||
|
||||
export default isUrn;
|
||||
|
||||
export { datasetUrnRegexWH, datasetUrnRegexLI, isWhUrn, isLiUrn, specialFlowUrnRegex, getPlatformFromUrn };
|
||||
export {
|
||||
datasetUrnRegexWH,
|
||||
datasetUrnRegexLI,
|
||||
isWhUrn,
|
||||
isLiUrn,
|
||||
specialFlowUrnRegex,
|
||||
getPlatformFromUrn,
|
||||
convertWhUrnToLiUrn,
|
||||
encodeUrn,
|
||||
decodeUrn
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { faker } from 'ember-cli-mirage';
|
||||
import { IFunctionRouteHandler, IMirageServer } from 'wherehows-web/typings/ember-cli-mirage';
|
||||
import { ApiStatus } from 'wherehows-web/utils/api/shared';
|
||||
import { getDatasetColumns } from 'wherehows-web/mirage/helpers/columns';
|
||||
import { getDatasetColumns, getDatasetSchema } from 'wherehows-web/mirage/helpers/columns';
|
||||
import { getDatasetCompliance } from 'wherehows-web/mirage/helpers/compliance';
|
||||
import { getComplianceDataTypes } from 'wherehows-web/mirage/helpers/compliance-data-types';
|
||||
import { getDatasetComplianceSuggestion } from 'wherehows-web/mirage/helpers/compliance-suggestions';
|
||||
@ -32,6 +32,16 @@ export default function(this: IMirageServer) {
|
||||
|
||||
this.namespace = '/api/v2';
|
||||
|
||||
this.get('/datasets/:identifier/', getDatasetView);
|
||||
|
||||
this.get('/datasets/:identifier/owners', getDatasetOwners);
|
||||
|
||||
this.get('/datasets/:dataset_id/schema', getDatasetSchema);
|
||||
|
||||
this.get('/datasets/:dataset_id/compliance/suggestions', getDatasetComplianceSuggestion);
|
||||
|
||||
this.get('/datasets/:dataset_id/owners', getDatasetOwners);
|
||||
|
||||
this.get('/list/complianceDataTypes', getComplianceDataTypes);
|
||||
|
||||
this.get('/list/platforms', getDatasetPlatforms);
|
||||
|
3
wherehows-web/mirage/fixtures/urn.ts
Normal file
3
wherehows-web/mirage/fixtures/urn.ts
Normal file
@ -0,0 +1,3 @@
|
||||
const urn = 'urn:li:dataset:(urn:li:dataPlatform:hdfs,%2Fjobs%2Faffinity%2FeAffinity%2Fmaster%2Fold-job-seeker,PROD)';
|
||||
|
||||
export { urn };
|
@ -9,4 +9,15 @@ const getDatasetColumns = function(this: IFunctionRouteHandler, { columns }: { c
|
||||
};
|
||||
};
|
||||
|
||||
export { getDatasetColumns };
|
||||
const getDatasetSchema = function(this: IFunctionRouteHandler, { columns }: { columns: any }) {
|
||||
return {
|
||||
schema: {
|
||||
columns: this.serialize(columns.all()),
|
||||
schemaless: false,
|
||||
keySchema: null,
|
||||
rawSchema: '{}'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { getDatasetColumns, getDatasetSchema };
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { IFunctionRouteHandler } from 'wherehows-web/typings/ember-cli-mirage';
|
||||
import { ApiStatus } from 'wherehows-web/utils/api/shared';
|
||||
|
||||
const getDatasetOwners = function(this: IFunctionRouteHandler, { owners }: { owners: any }) {
|
||||
return {
|
||||
owners: this.serialize(owners.all()),
|
||||
status: ApiStatus.OK
|
||||
owners: this.serialize(owners.all())
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { IFunctionRouteHandler } from 'wherehows-web/typings/ember-cli-mirage';
|
||||
import { ApiStatus } from 'wherehows-web/utils/api/shared';
|
||||
|
||||
const getDatasetView = function(this: IFunctionRouteHandler, { datasetViews }: { datasetViews: any }) {
|
||||
return {
|
||||
dataset: this.serialize(datasetViews.first()),
|
||||
status: ApiStatus.OK
|
||||
dataset: this.serialize(datasetViews.first())
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { test } from 'qunit';
|
||||
import { skip } from 'qunit';
|
||||
import moduleForAcceptance from 'wherehows-web/tests/helpers/module-for-acceptance';
|
||||
import { visit, find, currentURL, waitUntil } from 'ember-native-dom-helpers';
|
||||
import defaultScenario from 'wherehows-web/mirage/scenarios/default';
|
||||
@ -10,7 +10,8 @@ moduleForAcceptance('Acceptance | datasets/dataset/comments', {
|
||||
}
|
||||
});
|
||||
|
||||
test('visiting /datasets/dataset/comments', async function(assert) {
|
||||
// feature not yet supported in v2
|
||||
skip('visiting /datasets/dataset/comments', async function(assert) {
|
||||
assert.expect(2);
|
||||
defaultScenario(server);
|
||||
const url = '/datasets/12345/comments';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { test } from 'qunit';
|
||||
import { skip } from 'qunit';
|
||||
import moduleForAcceptance from 'wherehows-web/tests/helpers/module-for-acceptance';
|
||||
import defaultScenario from 'wherehows-web/mirage/scenarios/default';
|
||||
import { visit, find, currentURL, waitUntil } from 'ember-native-dom-helpers';
|
||||
@ -10,7 +10,7 @@ moduleForAcceptance('Acceptance | datasets/dataset/ownership', {
|
||||
}
|
||||
});
|
||||
|
||||
test('visiting /datasets/dataset/ownership', async function(assert) {
|
||||
skip('visiting /datasets/dataset/ownership', async function(assert) {
|
||||
assert.expect(2);
|
||||
defaultScenario(server);
|
||||
const url = '/datasets/12345/ownership';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { test } from 'qunit';
|
||||
import { skip } from 'qunit';
|
||||
import moduleForAcceptance from 'wherehows-web/tests/helpers/module-for-acceptance';
|
||||
import defaultScenario from 'wherehows-web/mirage/scenarios/default';
|
||||
import { visit, find, currentURL, waitUntil } from 'ember-native-dom-helpers';
|
||||
@ -10,7 +10,7 @@ moduleForAcceptance('Acceptance | datasets/dataset/properties', {
|
||||
}
|
||||
});
|
||||
|
||||
test('visiting /datasets/dataset/properties', async function(assert) {
|
||||
skip('visiting /datasets/dataset/properties', async function(assert) {
|
||||
assert.expect(2);
|
||||
defaultScenario(server);
|
||||
const url = '/datasets/12345/properties';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { test } from 'qunit';
|
||||
import { skip } from 'qunit';
|
||||
import moduleForAcceptance from 'wherehows-web/tests/helpers/module-for-acceptance';
|
||||
import { visit, find, currentURL, waitUntil } from 'ember-native-dom-helpers';
|
||||
import defaultScenario from 'wherehows-web/mirage/scenarios/default';
|
||||
@ -10,7 +10,7 @@ moduleForAcceptance('Acceptance | datasets/dataset/relations', {
|
||||
}
|
||||
});
|
||||
|
||||
test('visiting /datasets/dataset/relations', async function(assert) {
|
||||
skip('visiting /datasets/dataset/relations', async function(assert) {
|
||||
assert.expect(2);
|
||||
defaultScenario(server);
|
||||
const url = '/datasets/12345/relations';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { test } from 'qunit';
|
||||
import { skip } from 'qunit';
|
||||
import moduleForAcceptance from 'wherehows-web/tests/helpers/module-for-acceptance';
|
||||
import { visit, find, currentURL, waitUntil } from 'ember-native-dom-helpers';
|
||||
import defaultScenario from 'wherehows-web/mirage/scenarios/default';
|
||||
@ -10,7 +10,7 @@ moduleForAcceptance('Acceptance | datasets/dataset/sample', {
|
||||
}
|
||||
});
|
||||
|
||||
test('visiting /datasets/dataset/sample', async function(assert) {
|
||||
skip('visiting /datasets/dataset/sample', async function(assert) {
|
||||
assert.expect(2);
|
||||
defaultScenario(server);
|
||||
const url = '/datasets/12345/sample';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { test } from 'qunit';
|
||||
import { skip } from 'qunit';
|
||||
import moduleForAcceptance from 'wherehows-web/tests/helpers/module-for-acceptance';
|
||||
import { visit, find, currentURL, waitUntil } from 'ember-native-dom-helpers';
|
||||
import defaultScenario from 'wherehows-web/mirage/scenarios/default';
|
||||
@ -10,7 +10,7 @@ moduleForAcceptance('Acceptance | datasets/dataset/schema', {
|
||||
}
|
||||
});
|
||||
|
||||
test('visiting /datasets/dataset/schema', async function(assert) {
|
||||
skip('visiting /datasets/dataset/schema', async function(assert) {
|
||||
assert.expect(2);
|
||||
defaultScenario(server);
|
||||
const url = '/datasets/12345/schema';
|
||||
|
@ -23,7 +23,7 @@ test('it renders', function(assert) {
|
||||
this.$()
|
||||
.text()
|
||||
.trim(),
|
||||
'Dataset is deprecated?',
|
||||
'Is this dataset deprecated?',
|
||||
'shows the question asking if the dataset is deprecated'
|
||||
);
|
||||
assert.equal(this.$('#dataset-is-deprecated').length, 1, 'has one input checkbox with known selector');
|
||||
|
@ -0,0 +1,54 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { waitUntil, find } from 'ember-native-dom-helpers';
|
||||
import { urn } from 'wherehows-web/mirage/fixtures/urn';
|
||||
import sinon from 'sinon';
|
||||
|
||||
moduleForComponent(
|
||||
'datasets/containers/dataset-compliance',
|
||||
'Integration | Component | datasets/containers/dataset compliance',
|
||||
{
|
||||
integration: true,
|
||||
|
||||
beforeEach() {
|
||||
this.server = sinon.createFakeServer();
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
this.server.restore();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
this.set('urn', urn);
|
||||
this.server.respondWith('GET', /\/api\/v2\/datasets\/.*/, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({})
|
||||
]);
|
||||
this.server.respondWith(/.*\/complianceDataTypes/, [200, { 'Content-Type': 'application/json' }, JSON.stringify([])]);
|
||||
this.server.respondWith(/.*\/complianceSuggestion/, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({})
|
||||
]);
|
||||
this.server.respondWith(/.*\/schema/, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({
|
||||
schema: {
|
||||
schemaless: false,
|
||||
columns: [],
|
||||
rawSchema: null,
|
||||
keySchema: null
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
this.render(hbs`{{datasets/containers/dataset-compliance urn=urn}}`);
|
||||
this.server.respond();
|
||||
|
||||
await waitUntil(() => find('.compliance-container'));
|
||||
assert.ok(document.querySelector('empty-state'), 'renders the empty state component');
|
||||
});
|
@ -0,0 +1,46 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { waitUntil, find } from 'ember-native-dom-helpers';
|
||||
import { urn } from 'wherehows-web/mirage/fixtures/urn';
|
||||
import sinon from 'sinon';
|
||||
|
||||
moduleForComponent(
|
||||
'datasets/containers/dataset-ownership',
|
||||
'Integration | Component | datasets/containers/dataset ownership',
|
||||
{
|
||||
integration: true,
|
||||
|
||||
beforeEach() {
|
||||
this.server = sinon.createFakeServer();
|
||||
this.server.respondImmediately = true;
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
this.server.restore();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
const lookupClass = '.dataset-author-user-lookup';
|
||||
this.set('urn', urn);
|
||||
this.server.respondWith('GET', /\/api\/v2\/datasets.*/, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({})
|
||||
]);
|
||||
this.server.respondWith('GET', '/api/v1/owner/types', [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify([])
|
||||
]);
|
||||
|
||||
this.render(hbs`{{datasets/containers/dataset-ownership urn=urn}}`);
|
||||
|
||||
await waitUntil(() => find(lookupClass));
|
||||
assert.equal(
|
||||
document.querySelector(lookupClass).textContent.trim(),
|
||||
'Add an Owner',
|
||||
'shows dataset authors component'
|
||||
);
|
||||
});
|
@ -0,0 +1,35 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { waitUntil, find } from 'ember-native-dom-helpers';
|
||||
import { urn } from 'wherehows-web/mirage/fixtures/urn';
|
||||
|
||||
moduleForComponent(
|
||||
'datasets/containers/dataset-properties',
|
||||
'Integration | Component | datasets/containers/dataset properties',
|
||||
{
|
||||
integration: true,
|
||||
|
||||
beforeEach() {
|
||||
this.server = sinon.createFakeServer();
|
||||
this.server.respondImmediately = true;
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
this.server.restore();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
test('it renders', function(assert) {
|
||||
const labelClass = '.dataset-deprecation-toggle__toggle-header__label';
|
||||
this.set('urn', urn);
|
||||
this.server.respondWith('GET', /\/api\/v2\/datasets.*/, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({})
|
||||
]);
|
||||
|
||||
this.render(hbs`{{datasets/containers/dataset-properties urn=urn}}`);
|
||||
|
||||
assert.equal(find(labelClass).textContent.trim(), 'Is this dataset deprecated?', 'renders presentation component');
|
||||
});
|
@ -0,0 +1,28 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { find } from 'ember-native-dom-helpers';
|
||||
import { urn } from 'wherehows-web/mirage/fixtures/urn';
|
||||
import sinon from 'sinon';
|
||||
|
||||
moduleForComponent(
|
||||
'datasets/containers/dataset-schema',
|
||||
'Integration | Component | datasets/containers/dataset schema',
|
||||
{
|
||||
integration: true,
|
||||
|
||||
beforeEach() {
|
||||
this.server = sinon.createFakeServer();
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
this.server.restore();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
test('it renders', function(assert) {
|
||||
this.set('urn', urn);
|
||||
this.render(hbs`{{datasets/containers/dataset-schema urn=urn}}`);
|
||||
|
||||
assert.ok(find('#json-viewer'), 'renders the dataset schema component');
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user