Merge pull request #961 from theseyi/tabbed-routes

implements tabbed routes for datasets
This commit is contained in:
Seyi Adebajo 2018-02-09 12:02:04 -08:00 committed by GitHub
commit 068cf873ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 219 additions and 40 deletions

View File

@ -0,0 +1,52 @@
import Route from '@ember/routing/route';
import { assert } from '@ember/debug';
import { set } from '@ember/object';
import DatasetController from 'wherehows-web/controllers/datasets/dataset';
/**
* Defines id strings for page tabs available on the dataset page,
* these also match up with their respective route names
* @type {string}
*/
enum Tabs {
Properties = 'properties',
Access = 'access',
Comments = 'comments',
Schema = 'schema',
Ownership = 'ownership',
Compliance = 'compliance',
SampleData = 'sample',
Relations = 'relations'
}
/**
* Sets the tab selection property on the provided route with the currently selected tab
* @param {Route} route the route instance to update
* @param {Tabs} tabSelected identifier for the selected tab
* @returns {Tabs}
*/
const setTabSelectedOnAncestorController = (route: Route, tabSelected: Tabs): Tabs => {
const { routeName, controllerFor } = route;
assert('route should be a descendant of datasets.dataset', !routeName.indexOf('datasets.dataset.'));
const ancestorController = <DatasetController>controllerFor.call(route, 'datasets.dataset');
return set(ancestorController, 'tabSelected', tabSelected);
};
/**
* Factory creates a dataset Route class that sets the currently selected tab on the parent controller
* @param {{ selectedTab: Tabs }} { selectedTab } options bag contains identifier for the current tab
* @returns {typeof Route} the descendant route class
*/
const descendantDatasetRouteClassFactory = ({ selectedTab }: { selectedTab: Tabs }): typeof Route => {
return class DatasetDescendantRoute extends Route {
actions = {
didTransition(this: DatasetDescendantRoute) {
// on successful route transition
setTabSelectedOnAncestorController(this, selectedTab);
}
};
};
};
export { Tabs, descendantDatasetRouteClassFactory, setTabSelectedOnAncestorController };

View File

@ -14,10 +14,13 @@ import {
import { updateDatasetDeprecation } from 'wherehows-web/utils/api/datasets/properties'; import { updateDatasetDeprecation } from 'wherehows-web/utils/api/datasets/properties';
import { readDatasetView } from 'wherehows-web/utils/api/datasets/dataset'; import { readDatasetView } from 'wherehows-web/utils/api/datasets/dataset';
import { readDatasetOwners, updateDatasetOwners } from 'wherehows-web/utils/api/datasets/owners'; import { readDatasetOwners, updateDatasetOwners } from 'wherehows-web/utils/api/datasets/owners';
import { Tabs } from 'wherehows-web/constants/datasets/shared';
import { action } from 'ember-decorators/object';
const { post, getJSON } = $; const { post, getJSON } = $;
export default Controller.extend({ // gradual refactor into es class, hence extends EmberObject instance
export default class extends Controller.extend({
queryParams: ['urn'], queryParams: ['urn'],
/** /**
* Reference to the application notifications Service * Reference to the application notifications Service
@ -202,20 +205,6 @@ export default Controller.extend({
}, },
actions: { actions: {
/**
* Renders the properties tab elements.
* temporary workaround to query parameters, the file is a holdover from the legacy WH app
*/
showProperties() {
// FIXME: this is a stop gap pending transition to queryParams tabbed nav in datasets.
// :facepalm:
run(() => {
scheduleOnce('afterRender', null, () => {
$('.tabbed-navigation-list li.active:not(#properties)').removeClass('active');
$('.tabbed-navigation-list #properties').addClass('active');
});
});
},
/** /**
* Updates the dataset's deprecation properties * Updates the dataset's deprecation properties
* @param {boolean} isDeprecated * @param {boolean} isDeprecated
@ -334,4 +323,25 @@ export default Controller.extend({
.catch(this.exceptionOnSave); .catch(this.exceptionOnSave);
} }
} }
}); }) {
tabIds = Tabs;
tabSelected;
constructor() {
super();
this.tabSelected || (this.tabSelected = Tabs.Ownership);
}
/**
* Handles user generated tab selection action by transitioning to specified route
* @param {Tabs} tabSelected the currently selected tab
*/
@action
tabSelectionChanged(tabSelected) {
// if the tab selection is same as current, noop
return get(this, 'tabSelected') === tabSelected
? void 0
: this.transitionToRoute(`datasets.dataset.${tabSelected}`, get(this, 'datasetId'));
}
}

View File

@ -57,9 +57,21 @@ AppRouter.map(function() {
path: '/*wildcard' path: '/*wildcard'
}); });
this.route('datasets', function() { this.route('datasets', function() {
this.route('dataset', { this.route(
path: '/:dataset_id' 'dataset',
}); {
path: '/:dataset_id'
},
function() {
this.route('properties');
this.route('comments');
this.route('schema');
this.route('ownership');
this.route('compliance');
this.route('sample');
this.route('relations');
}
);
}); });
this.route('search'); this.route('search');
this.route('metrics', function() { this.route('metrics', function() {

View File

@ -0,0 +1,3 @@
import { descendantDatasetRouteClassFactory, Tabs } from 'wherehows-web/constants/datasets/shared';
export default descendantDatasetRouteClassFactory({ selectedTab: Tabs.Comments });

View File

@ -0,0 +1,3 @@
import { descendantDatasetRouteClassFactory, Tabs } from 'wherehows-web/constants/datasets/shared';
export default descendantDatasetRouteClassFactory({ selectedTab: Tabs.Compliance });

View File

@ -0,0 +1,3 @@
import { descendantDatasetRouteClassFactory, Tabs } from 'wherehows-web/constants/datasets/shared';
export default descendantDatasetRouteClassFactory({ selectedTab: Tabs.Ownership });

View File

@ -0,0 +1,3 @@
import { descendantDatasetRouteClassFactory, Tabs } from 'wherehows-web/constants/datasets/shared';
export default descendantDatasetRouteClassFactory({ selectedTab: Tabs.Properties });

View File

@ -0,0 +1,3 @@
import { descendantDatasetRouteClassFactory, Tabs } from 'wherehows-web/constants/datasets/shared';
export default descendantDatasetRouteClassFactory({ selectedTab: Tabs.Relations });

View File

@ -0,0 +1,3 @@
import { descendantDatasetRouteClassFactory, Tabs } from 'wherehows-web/constants/datasets/shared';
export default descendantDatasetRouteClassFactory({ selectedTab: Tabs.SampleData });

View File

@ -0,0 +1,3 @@
import { descendantDatasetRouteClassFactory, Tabs } from 'wherehows-web/constants/datasets/shared';
export default descendantDatasetRouteClassFactory({ selectedTab: Tabs.Schema });

View File

@ -29,7 +29,8 @@
{{/if}} {{/if}}
{{#if datasetView.deprecated}} {{#if datasetView.deprecated}}
<a data-toggle="tab" href="#propertiestab" {{action "showProperties" preventDefault=false}}> {{#link-to "datasets.dataset.properties" datasetId}}
<span class="deprecated-dataset"> <span class="deprecated-dataset">
DEPRECATED DEPRECATED
</span> </span>
@ -43,7 +44,8 @@
}} }}
</span> </span>
</sup> </sup>
</a>
{{/link-to}}
{{/if}} {{/if}}
<h3>{{ model.name }}</h3> <h3>{{ model.name }}</h3>
@ -152,32 +154,35 @@
{{/if}} {{/if}}
</div> </div>
{{#ivy-tabs selection=selection as |tabs|}} {{#ivy-tabs selection=tabSelected as |tabs|}}
{{#tabs.tablist as |tablist|}} {{#tabs.tablist as |tablist|}}
{{#unless isPinot}} {{#unless isPinot}}
{{#tablist.tab "Properties" on-select=(action (mut selection))}}Properties{{/tablist.tab}} {{#tablist.tab tabIds.Properties on-select=(action "tabSelectionChanged")}}
Properties
{{/tablist.tab}}
{{/unless}} {{/unless}}
{{!--feature not available--}} {{!--feature not available--}}
<span style="display:none"> <span style="display:none">
{{#tablist.tab "Access" on-select=(action (mut selection))}}ACL Access{{/tablist.tab}} {{#tablist.tab tabIds.Access on-select=(action "tabSelectionChanged")}}ACL Access{{/tablist.tab}}
</span> </span>
{{#tablist.tab "Comments" on-select=(action (mut selection))}}Comments{{/tablist.tab}} {{#tablist.tab tabIds.Comments on-select=(action "tabSelectionChanged")}}Comments{{/tablist.tab}}
{{#tablist.tab "Schema" on-select=(action (mut selection))}}Schema{{/tablist.tab}} {{#tablist.tab tabIds.Schema on-select=(action "tabSelectionChanged")}}Schema{{/tablist.tab}}
{{#tablist.tab "Ownership" on-select=(action (mut selection))}} {{#tablist.tab tabIds.Ownership on-select=(action "tabSelectionChanged")}}
Ownership Ownership
{{#if requiredMinNotConfirmed}} {{#if requiredMinNotConfirmed}}
<span class="notification-dot notification-dot--on-tab" aria-hidden="true"></span> <span class="notification-dot notification-dot--on-tab" aria-hidden="true"></span>
{{/if}} {{/if}}
{{/tablist.tab}} {{/tablist.tab}}
{{#if isInternal}} {{#if isInternal}}
{{#tablist.tab "Compliance" on-select=(action (mut selection))}} {{#tablist.tab tabIds.Compliance on-select=(action "tabSelectionChanged")}}
Compliance Compliance
{{#if isNewComplianceInfo}} {{#if isNewComplianceInfo}}
@ -187,14 +192,16 @@
{{/if}} {{/if}}
{{#unless isSFDC}} {{#unless isSFDC}}
{{#tablist.tab "Sample Data" on-select=(action (mut selection))}}Sample Data{{/tablist.tab}} {{#tablist.tab tabIds.SampleData on-select=(action "tabSelectionChanged")}}
Sample Data{{/tablist.tab}}
{{/unless}} {{/unless}}
{{#tablist.tab "Relations" on-select=(action (mut selection))}}Relations{{/tablist.tab}} {{#tablist.tab tabIds.Relations on-select=(action "tabSelectionChanged")}}
Relations{{/tablist.tab}}
{{/tabs.tablist}} {{/tabs.tablist}}
{{#tabs.tabpanel "Properties"}} {{#tabs.tabpanel tabIds.Properties}}
{{#unless isPinot}} {{#unless isPinot}}
{{dataset-deprecation {{dataset-deprecation
deprecated=datasetView.deprecated deprecated=datasetView.deprecated
@ -206,7 +213,7 @@
{{/unless}} {{/unless}}
{{/tabs.tabpanel}} {{/tabs.tabpanel}}
{{#tabs.tabpanel "Comments"}} {{#tabs.tabpanel tabIds.Comments}}
{{dataset-comments {{dataset-comments
comments=datasetComments comments=datasetComments
updateDatasetComment=(action "updateDatasetComment") updateDatasetComment=(action "updateDatasetComment")
@ -215,7 +222,7 @@
}} }}
{{/tabs.tabpanel}} {{/tabs.tabpanel}}
{{#tabs.tabpanel "Schema"}} {{#tabs.tabpanel tabIds.Schema}}
{{dataset-schema {{dataset-schema
isTable=isTable isTable=isTable
json=model.schema json=model.schema
@ -223,7 +230,7 @@
}} }}
{{/tabs.tabpanel}} {{/tabs.tabpanel}}
{{#tabs.tabpanel "Ownership"}} {{#tabs.tabpanel tabIds.Ownership}}
{{dataset-authors {{dataset-authors
owners=owners owners=owners
ownerTypes=ownerTypes ownerTypes=ownerTypes
@ -231,19 +238,19 @@
}} }}
{{/tabs.tabpanel}} {{/tabs.tabpanel}}
{{#tabs.tabpanel "Sample Data"}} {{#tabs.tabpanel tabIds.SampleData}}
{{#unless isSFDC}} {{#unless isSFDC}}
{{dataset-sample hasSamples=hasSamples isPinot=isPinot columns=columns samples=samples}} {{dataset-sample hasSamples=hasSamples isPinot=isPinot columns=columns samples=samples}}
{{/unless}} {{/unless}}
{{/tabs.tabpanel}} {{/tabs.tabpanel}}
{{#tabs.tabpanel "Relations"}} {{#tabs.tabpanel tabIds.Relations}}
{{#unless isSFDC}} {{#unless isSFDC}}
{{dataset-relations hasDepends=hasDepends depends=depends hasReferences=hasReferences references=references}} {{dataset-relations hasDepends=hasDepends depends=depends hasReferences=hasReferences references=references}}
{{/unless}} {{/unless}}
{{/tabs.tabpanel}} {{/tabs.tabpanel}}
{{#tabs.tabpanel "Compliance"}} {{#tabs.tabpanel tabIds.Compliance}}
{{dataset-compliance {{dataset-compliance
datasetName=model.name datasetName=model.name
schemaless=schemaless schemaless=schemaless
@ -258,7 +265,7 @@
}} }}
{{/tabs.tabpanel}} {{/tabs.tabpanel}}
{{#tabs.tabpanel "Access"}} {{#tabs.tabpanel tabIds.Access}}
{{dataset-aclaccess {{dataset-aclaccess
accessInfo=aclAccessResponse accessInfo=aclAccessResponse
currentUser=currentUserInfo currentUser=currentUserInfo

View File

@ -25,6 +25,14 @@ declare module 'ember-simple-auth/services/session' {
} }
declare module 'wherehows-web/utils/datasets/compliance-policy'; declare module 'wherehows-web/utils/datasets/compliance-policy';
declare module 'wherehows-web/controllers/datasets/dataset' {
import Controller from '@ember/controller';
import { Tabs } from 'wherehows-web/constants/datasets/shared';
export default class extends Controller {
tabSelected: Tabs;
}
}
declare module 'ember-cli-mirage'; declare module 'ember-cli-mirage';

View File

@ -1,5 +1,4 @@
import { test } from 'qunit'; import { test } from 'qunit';
import { delay } from 'wherehows-web/utils/promise-delay';
import moduleForAcceptance from 'wherehows-web/tests/helpers/module-for-acceptance'; import moduleForAcceptance from 'wherehows-web/tests/helpers/module-for-acceptance';
import { authenticationUrl, testUser, testPassword } from 'wherehows-web/tests/helpers/login/constants'; import { authenticationUrl, testUser, testPassword } from 'wherehows-web/tests/helpers/login/constants';
import { import {
@ -8,7 +7,7 @@ import {
loginSubmitButton loginSubmitButton
} from 'wherehows-web/tests/helpers/login/page-element-constants'; } from 'wherehows-web/tests/helpers/login/page-element-constants';
moduleForAcceptance('Acceptance | login', { moduleForAcceptance('Acceptance | browse', {
beforeEach() { beforeEach() {
visit(authenticationUrl); visit(authenticationUrl);
fillIn(loginUserInput, testUser); fillIn(loginUserInput, testUser);

View File

@ -0,0 +1,10 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:datasets/dataset/comments', 'Unit | Route | datasets/dataset/comments', {
needs: ['service:metrics']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,10 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:datasets/dataset/compliance', 'Unit | Route | datasets/dataset/compliance', {
needs: ['service:metrics']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,10 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:datasets/dataset/ownership', 'Unit | Route | datasets/dataset/ownership', {
needs: ['service:metrics']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,10 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:datasets/dataset/properties', 'Unit | Route | datasets/dataset/properties', {
needs: ['service:metrics']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,10 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:datasets/dataset/relations', 'Unit | Route | datasets/dataset/relations', {
needs: ['service:metrics']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,10 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:datasets/dataset/sample', 'Unit | Route | datasets/dataset/sample', {
needs: ['service:metrics']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -0,0 +1,10 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:datasets/dataset/schema', 'Unit | Route | datasets/dataset/schema', {
needs: ['service:metrics']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});