Skip to content

Commit

Permalink
UI kmip acceptance (#7129)
Browse files Browse the repository at this point in the history
* change the story blueprint so that using -ir will generate a story in the expected place for in-repo addons and engines

* update gen-story-md script to do output md to stories folder inside of in-repo addons and engines

* update storybook config to look for story files in /lib

* add story for list-view component

* add list view page object

* add kmip page objects and tests

* update storybook commands in the README

* split tests up more

* update var name in storybook
  • Loading branch information
meirish authored Aug 1, 2019
1 parent 0271486 commit 783bb2b
Show file tree
Hide file tree
Showing 27 changed files with 495 additions and 42 deletions.
6 changes: 4 additions & 2 deletions ui/.storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { assign } from '@ember/polyfills';

function loadStories() {
// automatically import all files ending in *.stories.js
const req = require.context('../stories/', true, /.stories.js$/);
req.keys().forEach(filename => req(filename));
const appStories = require.context('../stories', true, /.stories.js$/);
const addonAndRepoStories = require.context('../lib', true, /.stories.js$/);
appStories.keys().forEach(filename => appStories(filename));
addonAndRepoStories.keys().forEach(filename => addonAndRepoStories(filename));
}

addParameters({
Expand Down
12 changes: 7 additions & 5 deletions ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,16 @@ The Vault UI uses Storybook to catalog all of its components. Below are details
### Storybook Commands at a Glance

| Command | Description |
| ------------------------------------------ | ------------------------- |
| `yarn storybook` | run storybook |
| `ember generate story [name-of-component]` | generate a new story |
| `yarn gen-story-md [name-of-component]` | update a story notes file |
| ------------------------------------------------------------------------ | ---------------------------------------------------------- |
| `yarn storybook` | run storybook |
| `ember generate story [name-of-component]` | generate a new story |
| `ember generate story [name-of-component] -ir [name-of-engine-or-addon]` | generate a new story in the specified engine or addon |
| `yarn gen-story-md [name-of-component]` | update a story notes file |
| `yarn gen-story-md [name-of-component] [name-of-engine-or-addon]` | update a story notes file in the specified engine or addon |

### Writing Stories

Each component in `vault/ui/app/components` should have a corresponding `[component-name].stories.js` and `[component-name].md` files within `vault/ui/stories`.
Each component in `vault/ui/app/components` should have a corresponding `[component-name].stories.js` and `[component-name].md` files within `vault/ui/stories`. Components in the `core` addon located at `vault/ui/lib/core/addon/components` have corresponding stories and markdown files in `vault/ui/lib/core/stories`.

#### Adding a new story

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ storiesOf('<%= classifiedModuleName %>/', module)
.addParameters({ options: { showPanel: true } })
.add(`<%= classifiedModuleName %>`, () => ({
template: hbs`
<h5 class="title is-5"><%= header %></h5>
<<%= classifiedModuleName %>/>
<h5 class="title is-5"><%= header %></h5>
<<%= classifiedModuleName %>/>
`,
context: {},
}),
Expand Down
19 changes: 19 additions & 0 deletions ui/blueprints/story/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
'use strict';
const getPathOption = require('ember-cli-get-component-path-option');
const stringUtil = require('ember-cli-string-utils');
const path = require('path');

function findAddonByName(addonOrProject, name) {
let addon = addonOrProject.addons.find(addon => addon.name === name);

if (addon) {
return addon;
}

return addonOrProject.addons.find(addon => findAddonByName(addon, name));
}

module.exports = {
description: 'generates a story for storybook',

fileMapTokens: function() {
let { project } = this;
return {
__path__: function(options) {
if (options.inRepoAddon) {
let addon = findAddonByName(project, options.inRepoAddon);
return path.relative(project.root, addon.root);
}
return path.relative(project.root, project.root);
},
__markdownname__: function(options) {
return options.dasherizedModuleName;
},
Expand Down
37 changes: 31 additions & 6 deletions ui/lib/core/addon/components/list-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,45 @@ import { computed } from '@ember/object';
import { pluralize } from 'ember-inflector';
import layout from '../templates/components/list-view';

/**
* @module ListView
* `ListView` components are used in conjuction with `ListItem` for rendering a list.
*
* @example
* ```js
* <ListView @items={{model}} @itemNoun="role" @paginationRouteName="scope.roles" as |list|>
* {{#if list.empty}}
* <list.empty @title="No roles here" />
* {{else}}
* <div>
* {{list.item.id}}
* </div>
* {{/if}}
* </ListView>
* ```
*
* @param items=null {Array} - An array of items to render as a list
* @param [itemNoun=null {String}] - A noun to use in the empty state of message and title.
* @param [message=null {String}] - The message to display within the banner.
* @yields Object with `item` that is the current item in the loop.
* @yields If there are no objects in items, then `empty` will be yielded - this is an instance of
* the EmptyState component.
* @yields If `item` or `empty` isn't present on the object, the component can still yield a block - this is
* useful for showing states where there are items but there may be a filter applied that returns an
* empty set.
*
*/
export default Component.extend({
layout,
tagName: '',
items: null,
itemNoun: 'item',
// the dasherized name of a component to render
// in the EmptyState component if there are no items in items.length
emptyActions: '',
paginationRouteName: '',
showPagination: computed('paginationRouteName', 'items.meta{lastPage,total}', function() {
return this.paginationRouteName && this.items.meta.lastPage > 1 && this.items.meta.total > 0;
let meta = this.items.meta;
return this.paginationRouteName && meta && meta.lastPage > 1 && meta.total > 0;
}),

paginationRouteName: '',

emptyTitle: computed('itemNoun', function() {
let items = pluralize(this.get('itemNoun'));
return `No ${items} yet`;
Expand Down
2 changes: 1 addition & 1 deletion ui/lib/core/addon/templates/components/empty-state.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="empty-state" ...attributes>
<div data-test-component="empty-state" class="empty-state" ...attributes>
<div class="empty-state-content">
<h3 class="empty-state-title" data-test-empty-state-title>
{{title}}
Expand Down
10 changes: 5 additions & 5 deletions ui/lib/core/addon/templates/components/list-item.hbs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{{#if componentName}}
{{component componentName item=item}}
{{else if linkParams}}
<LinkedBlock @params={{linkParams}} @linkPrefix={{@linkPrefix}} @class="list-item-row">
<LinkedBlock @params={{linkParams}} @linkPrefix={{@linkPrefix}} @class="list-item-row" data-test-list-item-link>
<div class="level is-mobile">
<div class="level-left is-flex-1">
<div class="level-left is-flex-1" data-test-list-item-content>
{{#link-to params=linkParams class="has-text-weight-semibold has-text-black is-display-flex is-flex-1 is-no-underline"}}
{{yield (hash content=(component "list-item/content"))}}
{{/link-to}}
</div>
<div class="level-right">
<div class="level-item">
<div class="level-item" data-test-list-item-popup>
{{yield (hash callMethod=callMethod menu=(component "list-item/popup-menu" item=item hasMenu=hasMenu))}}
</div>
</div>
Expand All @@ -18,11 +18,11 @@
{{else}}
<div class="list-item-row">
<div class="level is-mobile">
<div class="level-left is-flex-1 has-text-weight-semibold">
<div class="level-left is-flex-1 has-text-weight-semibold" data-test-list-item>
{{yield (hash content=(component "list-item/content"))}}
</div>
<div class="level-right">
<div class="level-item">
<div class="level-item" data-test-list-item-popup>
{{yield (hash callMethod=callMethod menu=(component "list-item/popup-menu" item=item hasMenu=hasMenu))}}
</div>
</div>
Expand Down
5 changes: 3 additions & 2 deletions ui/lib/core/addon/templates/components/list-view.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
items.length
)
}}
<div class="box is-fullwidth is-bottomless is-sideless is-paddingless">
{{#each items as |item|}}
<div class="box is-fullwidth is-bottomless is-sideless is-paddingless" data-test-list-view-list>
{{#each (or items.content items) as |item|}}
{{yield (hash item=item)}}
{{else}}
{{yield}}
Expand All @@ -15,6 +15,7 @@
@page={{items.meta.currentPage}}
@lastPage={{items.meta.lastPage}}
@link={{@paginationRouteName}}
data-test-list-view-pagination
/>
{{/if}}
</div>
Expand Down
1 change: 1 addition & 0 deletions ui/lib/core/addon/templates/components/navigate-input.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
value={{@filter}}
placeholder={{ or @placeholder "Filter keys" }}
type="text"
data-test-comoponent="navigate-input"

oninput={{action "handleInput" value="target.value"}}
onkeyup={{action "handleKeyUp" }}
Expand Down
1 change: 1 addition & 0 deletions ui/lib/core/addon/templates/components/toolbar-link.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
data-test-policy-create-link={{data-test-policy-create-link}}
data-test-policy-edit-toggle={{data-test-policy-edit-toggle}}
data-test-secret-backend-configure={{data-test-secret-backend-configure}}
...attributes
>
{{yield}}
<Icon @glyph={{glyph}} />
Expand Down
32 changes: 32 additions & 0 deletions ui/lib/core/stories/list-view.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!--THIS FILE IS AUTO GENERATED. This file is generated from JSDoc comments in lib/core/addon/components/list-view.js. To make changes, first edit that file and run "yarn gen-story-md list-view" to re-generate the content.-->

## ListView
`ListView` components are used in conjuction with `ListItem` for rendering a list.


| Param | Type | Default | Description |
| --- | --- | --- | --- |
| items | <code>Array</code> | <code></code> | An array of items to render as a list |
| [itemNoun] | <code>String</code> | <code></code> | A noun to use in the empty state of message and title. |
| [message] | <code>String</code> | <code></code> | The message to display within the banner. |

**Example**

```js
<ListView @items={{model}} @itemNoun="role" @paginationRouteName="scope.roles" as |list|>
{{#if list.empty}}
<list.empty @title="No roles here" />
{{else}}
<div>
{{list.item.id}}
</div>
{{/if}}
</ListView>
```

**See**

- [Uses of ListView](https://github.com/hashicorp/vault/search?l=Handlebars&q=ListView+OR+list-view)
- [ListView Source Code](https://github.com/hashicorp/vault/blob/master/ui/lib/core/addon/components/list-view.js)

---
58 changes: 58 additions & 0 deletions ui/lib/core/stories/list-view.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* eslint-disable import/extensions */
import hbs from 'htmlbars-inline-precompile';
import { storiesOf } from '@storybook/ember';
import { withKnobs, select } from '@storybook/addon-knobs';
import notes from './list-view.md';

import ArrayProxy from '@ember/array/proxy';

let filtered = ArrayProxy.create({ content: [] });
filtered.set('meta', {
lastPage: 1,
currentPage: 1,
total: 100,
});

let paginated = ArrayProxy.create({
content: [{ id: 'middle' }, { id: 'of' }, { id: 'the' }, { id: 'list' }],
});
paginated.set('meta', {
lastPage: 10,
currentPage: 4,
total: 100,
});

let options = {
list: [{ id: 'one' }, { id: 'two' }],
empty: [],
filtered,
paginated,
};

storiesOf('ListView/', module)
.addParameters({ options: { showPanel: true } })
.addDecorator(withKnobs())
.add(
`ListView`,
() => ({
template: hbs`
<h5 class="title is-5">{{title}}</h5>
<ListView @items={{items}} @itemNoun={{or noun "role"}} @paginationRouteName="vault" as |list|>
{{#if list.empty}}
<list.empty @title="No roles here" />
{{else if list.item}}
<div class="box is-marginless">
{{list.item.id}}
</div>
{{else}}
<div class="box">There aren't any items in this filter</div>
{{/if}}
</ListView>
`,
context: {
title: 'ListView',
items: select('items', options, options['list']),
},
}),
{ notes }
);
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
</div>
{{#if cancelLinkParams}}
<div class="control">
{{#link-to params=cancelLinkParams class="button"}}
{{#link-to params=cancelLinkParams class="button" data-test-edit-form-cancel="true"}}
Cancel
{{/link-to}}
</div>
Expand Down
4 changes: 2 additions & 2 deletions ui/lib/kmip/addon/templates/components/header-credentials.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
<nav class="tabs">
<ul>
{{#link-to "credentials.index" @scope @role tagName="li"}}
{{#link-to "credentials.index" @scope @role}}
{{#link-to "credentials.index" @scope @role data-test-kmip-link-credentials="true"}}
Credentials
{{/link-to}}
{{/link-to}}
{{#link-to "role" @scope @role tagName="li"}}
{{#link-to "role" @scope @role}}
{{#link-to "role" @scope @role data-test-kmip-link-role-details="true"}}
Details
{{/link-to}}
{{/link-to}}
Expand Down
4 changes: 2 additions & 2 deletions ui/lib/kmip/addon/templates/components/header-scope.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
<nav class="tabs">
<ul>
{{#link-to "scopes.index" tagName="li"}}
{{#link-to "scopes.index"}}
{{#link-to "scopes.index" data-test-kmip-link-scopes="true"}}
Scopes
{{/link-to}}
{{/link-to}}
{{#link-to "configuration" tagName="li"}}
{{#link-to "configuration"}}
{{#link-to "configuration" data-test-kmip-link-config="true"}}
Configuration
{{/link-to}}
{{/link-to}}
Expand Down
1 change: 1 addition & 0 deletions ui/lib/kmip/addon/templates/configuration.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
{{/if}}
<ToolbarLink
@params={{array "configure"}}
data-test-kmip-link-configure
>
Configure
</ToolbarLink>
Expand Down
1 change: 1 addition & 0 deletions ui/lib/kmip/addon/templates/credentials/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<ToolbarLink
@type="add"
@params={{array "credentials.generate"}}
data-test-kmip-link-generate-credentials
>
Generate credentials
</ToolbarLink>
Expand Down
1 change: 1 addition & 0 deletions ui/lib/kmip/addon/templates/credentials/show.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<ToolbarActions>
<ToolbarLink
@params={{array "credentials.index" this.scope this.role}}
data-test-kmip-link-back-to-role
>
Back to role
</ToolbarLink>
Expand Down
1 change: 1 addition & 0 deletions ui/lib/kmip/addon/templates/role.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
{{#if model.updatePath.canUpdate}}
<ToolbarLink
@params={{array "role.edit" this.scope this.role}}
data-test-kmip-link-edit-role
>
Edit role
</ToolbarLink>
Expand Down
1 change: 1 addition & 0 deletions ui/lib/kmip/addon/templates/scope/roles.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<ToolbarLink
@type="add"
@params={{array "scope.roles.create"}}
data-test-role-create
>
Create role
</ToolbarLink>
Expand Down
Loading

0 comments on commit 783bb2b

Please sign in to comment.