Merge pull request #47 from hashicorp/chore-breadcrumbs

Integrate breadcrumbs with core UI
This commit is contained in:
Susmitha Girumala authored and GitHub committed 2020-06-16 10:59:19 -04:00
commit e092ac54f6
28 files changed
+402 -81

No files matched your search

@@ -13,7 +13,7 @@
.rose-layout-global-body {
grid-area: body;
margin: 0 sizing.rems(m);
padding: sizing.rems(l);
}
.rose-layout-global-header {
@@ -11,6 +11,7 @@
color: var(--color);
text-decoration: none;
cursor: pointer;
display: inline-flex;
&:hover {
--color: var(--action);
View File
Whitespace-only changes.
+15
View File
@@ -0,0 +1,15 @@
{{#if this.breadCrumbs}}
<Rose::Nav::Breadcrumbs as |crumbs|>
{{#each this.breadCrumbs as |crumb|}}
{{#if crumb.model}}
<crumbs.link @route={{crumb.path}} @model={{crumb.model}}>
{{crumb.label}}
</crumbs.link>
{{else}}
<crumbs.link @route={{crumb.path}}>
{{crumb.label}}
</crumbs.link>
{{/if}}
{{/each}}
</Rose::Nav::Breadcrumbs>
{{/if}}
View File
Whitespace-only changes.
@@ -0,0 +1,19 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default class OrgsOrgProjectsController extends Controller {
// =services
@service intl;
// =attributes
/**
* @type {string}
*/
get breadCrumb() {
return this.intl.t('resources.projects');
}
}
@@ -0,0 +1,19 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default class OrgsOrgProjectsNewController extends Controller {
// =services
@service intl;
// =attributes
/**
* @type {string}
*/
get breadCrumb() {
return this.intl.t('titles.new');
}
}
@@ -0,0 +1,13 @@
import Controller from '@ember/controller';
import { alias } from '@ember/object/computed';
export default class OrgsOrgProjectsProjectController extends Controller {
// =attributes
/**
* @type {string}
*/
@alias('model.name') breadCrumb;
}
@@ -0,0 +1,19 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default class OrgsOrgProjectsProjectHostCatalogsController extends Controller {
// =services
@service intl;
// =attributes
/**
* @type {string}
*/
get breadCrumb() {
return this.intl.t('resources.host-catalogs');
}
}
@@ -0,0 +1,13 @@
import Controller from '@ember/controller';
import { alias } from '@ember/object/computed';
export default class OrgsOrgProjectsProjectHostCatalogsHostCatalogController extends Controller {
// =attributes
/**
* @type {string}
*/
@alias('model.name') breadCrumb;
}
@@ -0,0 +1,19 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default class OrgsOrgProjectsProjectHostCatalogsNewController extends Controller {
// =services
@service intl;
// =attributes
/**
* @type {string}
*/
get breadCrumb() {
return this.intl.t('titles.new');
}
}
-28
View File
@@ -18,31 +18,3 @@
}
}
}
.project-overview,
.project-new {
.breadcrumbs,
.breadcrumbs a {
color: #6f7682;
text-decoration: none;
}
.project-new-form {
.form-actions {
display: flex;
flex-direction: row;
position: relative;
float: right;
button {
margin-right: 10px;
}
}
input,
textarea {
box-sizing: border-box;
width: 100%;
}
}
}
@@ -1,4 +1,8 @@
<Rose::Layout::Page class="projects-overview" as |page|>
<Rose::Layout::Page as |page|>
<page.breadcrumbs>
<BreadCrumbs />
</page.breadcrumbs>
<page.header>
<h2>{{t "resources.projects"}}</h2>
@@ -1,10 +1,6 @@
<Rose::Layout::Page class="project-new" as |page|>
<Rose::Layout::Page as |page|>
<page.breadcrumbs>
<div class="breadcrumbs">
<LinkTo @route='orgs.org.projects'>{{t "resources.projects"}}</LinkTo>
>
<LinkTo @route='orgs.org.projects.new'>{{t "titles.new"}}</LinkTo>
</div>
<BreadCrumbs />
</page.breadcrumbs>
<page.header>
@@ -16,7 +12,6 @@
@model={{@model}}
@submit={{route-action "save" @model}}
@cancel={{route-action "cancel" @model}}
class="project-new-form"
/>
</page.body>
</Rose::Layout::Page>
@@ -1,18 +1,27 @@
<div class="project-overview">
<Rose::Layout::Page as |page|>
<h2>{{t "resources.host-catalog"}}</h2>
<page.breadcrumbs>
<BreadCrumbs />
</page.breadcrumbs>
<Form::HostCatalog
@model={{@model}}
@submit={{route-action "save" @model}}
@cancel={{route-action "cancel" @model}}
/>
<page.header>
<h2>{{t "resources.host-catalog"}}</h2>
</page.header>
<Rose::Button
@style="warning"
@disabled={{@model.canSave}}
{{on "click" (route-action "delete" @model)}}
>
{{t 'actions.delete'}}
</Rose::Button>
</div>
<page.body>
<Form::HostCatalog
@model={{@model}}
@submit={{route-action "save" @model}}
@cancel={{route-action "cancel" @model}}
/>
<Rose::Button
@style="warning"
@disabled={{@model.canSave}}
{{on "click" (route-action "delete" @model)}}
>
{{t 'actions.delete'}}
</Rose::Button>
</page.body>
</Rose::Layout::Page>
@@ -1,4 +1,9 @@
<Rose::Layout::Page class="host-catalogs" as |page|>
<Rose::Layout::Page as |page|>
<page.breadcrumbs>
<BreadCrumbs />
</page.breadcrumbs>
<page.header>
<h2>{{t 'resources.host-catalogs'}}</h2>
</page.header>
@@ -1,5 +1,9 @@
<Rose::Layout::Page as |page|>
<page.breadcrumbs>
<BreadCrumbs />
</page.breadcrumbs>
<page.header>
<h2>{{t "titles.new"}}</h2>
</page.header>
@@ -1,30 +1,35 @@
<div class="project-overview">
<div class="breadcrumbs">
<LinkTo @route='orgs.org.projects'>{{t "resources.projects"}}</LinkTo>
<Rose::Layout::Page as |page|>
<page.breadcrumbs>
<BreadCrumbs />
</page.breadcrumbs>
<page.header>
<h2>{{t "resources.project"}}</h2>
</page.header>
<page.navigation>
<Rose::Nav::Tabs as |nav|>
<nav.link @route='orgs.org.projects.project'>
{{t 'titles.settings'}}
</nav.link>
</Rose::Nav::Tabs>
</page.navigation>
<page.body>
<Form::Project
@model={{@model}}
@submit={{route-action "save" @model}}
@cancel={{route-action "cancel" @model}}
/>
<Rose::Button
@style="warning"
@disabled={{@model.canSave}}
{{on "click" (route-action "delete" @model)}}
>
<LinkTo @route='orgs.org.projects.project'>{{@model.name}}</LinkTo>
</div>
{{t 'actions.delete'}}
</Rose::Button>
</page.body>
<h2>{{t "resources.project"}}</h2>
<Rose::Nav::Tabs as |nav|>
<nav.link @route='orgs.org.projects.project'>
{{t 'titles.settings'}}
</nav.link>
</Rose::Nav::Tabs>
<Form::Project
@model={{@model}}
@submit={{route-action "save" @model}}
@cancel={{route-action "cancel" @model}}
class="project-new-form"
/>
<Rose::Button
@style="warning"
@disabled={{@model.canSave}}
{{on "click" (route-action "delete" @model)}}
>
{{t 'actions.delete'}}
</Rose::Button>
</div>
</Rose::Layout::Page>
+1
View File
@@ -38,6 +38,7 @@
"doctoc": "^1.4.0",
"ember-a11y-testing": "^3.0.0",
"ember-auto-import": "^1.5.3",
"ember-breadcrumbs": "^0.2.3",
"ember-cli": "~3.16.1",
"ember-cli-app-version": "^3.2.0",
"ember-cli-babel": "^7.17.2",
@@ -0,0 +1,82 @@
import { module, test } from 'qunit';
import { visit, currentURL, click, find, findAll } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
module('Acceptance | breadcrumbs', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
let project;
let hostCatalog;
let projectsURL;
let newProjectURL;
let projectURL;
let hostCatalogsURL;
let newHostCatalogURL;
let hostCatalogURL;
let crumbPath;
hooks.beforeEach(function () {
project = this.server.create('project');
hostCatalog = this.server.create('host-catalog');
projectsURL = `/orgs/1/projects`;
newProjectURL = `${projectsURL}/new`;
projectURL = `${projectsURL}/${project.id}`;
hostCatalogsURL = `${projectURL}/host-catalogs`;
newHostCatalogURL = `${hostCatalogsURL}/new`;
hostCatalogURL = `${hostCatalogsURL}/${hostCatalog.id}`;
});
test('can navigate via breadcrumbs to projects from project', async function (assert) {
assert.expect(3);
await visit(projectURL);
assert.equal(currentURL(), projectURL, 'We begin on th expected page.');
crumbPath = new URL(find('.rose-nav-breadcrumbs-link:last-child').href).pathname;
assert.equal(crumbPath, projectURL, 'Last crumb has expected URL.');
await click(find('.rose-nav-breadcrumbs-link:first-child'));
assert.equal(currentURL(), '/orgs/1/projects', 'After navigating via breadcrumbs, we are one level up.');
});
test('can navigate via breadcrumbs to projects from new project', async function (assert) {
assert.expect(3);
await visit(newProjectURL);
assert.equal(currentURL(), newProjectURL, 'We begin on th expected page.');
crumbPath = new URL(find('.rose-nav-breadcrumbs-link:last-child').href).pathname;
assert.equal(crumbPath, newProjectURL, 'Last crumb has expected URL.');
await click(find('.rose-nav-breadcrumbs-link:first-child'));
assert.equal(currentURL(), '/orgs/1/projects', 'After navigating via breadcrumbs, we are one level up.');
});
test('can navigate via breadcrumbs to project from host catalogs', async function (assert) {
assert.expect(3);
await visit(hostCatalogsURL);
assert.equal(currentURL(), hostCatalogsURL, 'We begin on th expected page.');
crumbPath = new URL(find('.rose-nav-breadcrumbs-link:last-child').href).pathname;
assert.equal(crumbPath, hostCatalogsURL, 'Last crumb has expected URL.');
await click(findAll('.rose-nav-breadcrumbs-link')[1]);
assert.equal(currentURL(), projectURL, 'After navigating via breadcrumbs, we are one level up.');
});
test('can navigate via breadcrumbs to host catalogs from host catalog', async function (assert) {
assert.expect(3);
await visit(hostCatalogURL);
assert.equal(currentURL(), hostCatalogURL, 'We begin on th expected page.');
crumbPath = new URL(find('.rose-nav-breadcrumbs-link:last-child').href).pathname;
assert.equal(crumbPath, hostCatalogURL, 'Last crumb has expected URL.');
await click(findAll('.rose-nav-breadcrumbs-link')[2]);
assert.equal(currentURL(), hostCatalogsURL, 'After navigating via breadcrumbs, we are one level up.');
});
test('can navigate via breadcrumbs to host catalogs from new host catalog', async function (assert) {
assert.expect(3);
await visit(newHostCatalogURL);
assert.equal(currentURL(), newHostCatalogURL, 'We begin on th expected page.');
crumbPath = new URL(find('.rose-nav-breadcrumbs-link:last-child').href).pathname;
assert.equal(crumbPath, newHostCatalogURL, 'Last crumb has expected URL.');
await click(findAll('.rose-nav-breadcrumbs-link')[2]);
assert.equal(currentURL(), hostCatalogsURL, 'After navigating via breadcrumbs, we are one level up.');
});
});
@@ -0,0 +1,47 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find, findAll } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | bread-crumbs', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
this.set('breadCrumbs', [{label: 'Level 1'}]);
await render(hbs`<BreadCrumbs @breadCrumbs={{this.breadCrumbs}} />`);
// Default index route
assert.ok(find('.rose-nav-breadcrumbs a').href.match(/#$/));
assert.equal(find('.rose-nav-breadcrumbs').textContent.trim(), 'Level 1');
});
test('it renders with model', async function(assert) {
let store = this.owner.lookup('service:store');
let project = store.createRecord('project', {id: '1234'});
this.set('breadCrumbs', [{
label: 'Level 2',
path: 'orgs.org.projects.project',
model: project
}]);
await render(hbs`<BreadCrumbs @breadCrumbs={{this.breadCrumbs}} />`);
assert.equal(find('.rose-nav-breadcrumbs').textContent.trim(), 'Level 2');
});
test('it renders multiple breadCrumbs', async function(assert) {
this.set('breadCrumbs', [{
label: 'Level 1'
},{
label: 'Level 2'
}, {
label: 'Level 3'
}]);
await render(hbs`<BreadCrumbs @breadCrumbs={{this.breadCrumbs}} />`);
assert.equal(findAll('a').length, 3);
assert.equal(findAll('a')[0].textContent.trim(), 'Level 1');
assert.equal(findAll('a')[1].textContent.trim(), 'Level 2');
assert.equal(findAll('a')[2].textContent.trim(), 'Level 3');
});
});
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | orgs/org/projects', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:orgs/org/projects');
assert.ok(controller);
});
});
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | orgs/org/projects/new', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:orgs/org/projects/new');
assert.ok(controller);
});
});
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | orgs/org/projects/project', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:orgs/org/projects/project');
assert.ok(controller);
});
});
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | orgs/org/projects/project/host-catalogs', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:orgs/org/projects/project/host-catalogs');
assert.ok(controller);
});
});
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | orgs/org/projects/project/host-catalogs/host-catalog', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:orgs/org/projects/project/host-catalogs/host-catalog');
assert.ok(controller);
});
});
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | orgs/org/projects/project/host-catalogs/new', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:orgs/org/projects/project/host-catalogs/new');
assert.ok(controller);
});
});
+7
View File
@@ -7058,6 +7058,13 @@ ember-auto-import@^1.2.15, ember-auto-import@^1.2.19, ember-auto-import@^1.5.3:
walk-sync "^0.3.3"
webpack "~4.28"
ember-breadcrumbs@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/ember-breadcrumbs/-/ember-breadcrumbs-0.2.3.tgz#a95e02b73fdc2150f3d552e84a479d6dc96a8b31"
integrity sha512-QUiPXwAlTeiXykF5RnyilEgcj9NSFGciAawktImv6V6Lq9sNfmJHZAYZXAg8U/wA1tw7CG0fQl991K+jtuBTKQ==
dependencies:
ember-cli-babel "^7.10.0"
ember-cli-addon-docs-yuidoc@^0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/ember-cli-addon-docs-yuidoc/-/ember-cli-addon-docs-yuidoc-0.2.4.tgz#dd8f5cf4982e8492b255fb677e9d771925e27dce"