mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 09:42:25 +00:00
Add docfy for addon components (#27188)
* move script to scripts folder * add docfy to router and scripts * add docfy to router and scripts * fix jsdoc syntax * add component markdown files to gitignore * improve error handling for scripts * tidy up remaining jsdoc syntax * add sample jsdoc components * add known issue info * make not using multi-line components clearer * make generating docs clearer * update copy * final how to docfy cleanup * fix ts file @module syntax * fix read more syntax * make docfy typescript compatible
This commit is contained in:
1
ui/.gitignore
vendored
1
ui/.gitignore
vendored
@@ -15,6 +15,7 @@
|
||||
/testem.log
|
||||
/yarn-error.log
|
||||
package-lock.json
|
||||
/docs/components/*
|
||||
|
||||
# ember-try
|
||||
/.node_modules.ember-try/
|
||||
|
||||
@@ -28,4 +28,16 @@
|
||||
Documentation
|
||||
</AF.Link>
|
||||
<AF.LegalLinks />
|
||||
<AF.ExtraAfter>
|
||||
{{#if this.isDevelopment}}
|
||||
<Hds::Button
|
||||
target="_blank"
|
||||
@text="Contributing docs"
|
||||
@isIconOnly={{true}}
|
||||
@icon="gift"
|
||||
@color="tertiary"
|
||||
@route="docs"
|
||||
/>
|
||||
{{/if}}
|
||||
</AF.ExtraAfter>
|
||||
</Hds::AppFooter>
|
||||
19
ui/app/components/z-docfy-filter.hbs
Normal file
19
ui/app/components/z-docfy-filter.hbs
Normal file
@@ -0,0 +1,19 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<Hds::Form::TextInput::Field @type="search" placeholder="Filter components" {{on "input" this.filterComponents}} />
|
||||
|
||||
<Hds::Reveal
|
||||
class="docs-collapse-toggle has-top-padding-s"
|
||||
@text="Expand component list"
|
||||
@textWhenOpen="Collapse component list"
|
||||
@isOpen={{true}}
|
||||
>
|
||||
{{#each this.componentList as |component|}}
|
||||
<DocfyLink @to={{component.url}} class="hds-side-nav__list-item-link docs-hover">
|
||||
{{component.title}}
|
||||
</DocfyLink>
|
||||
{{/each}}
|
||||
</Hds::Reveal>
|
||||
24
ui/app/components/z-docfy-filter.js
Normal file
24
ui/app/components/z-docfy-filter.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
// DEVELOPMENT ONLY COMPONENT used for filtering docfy components
|
||||
export default class ZDocfyFilter extends Component {
|
||||
@tracked filterValue;
|
||||
|
||||
@action
|
||||
filterComponents({ target }) {
|
||||
this.filterValue = target.value;
|
||||
}
|
||||
|
||||
get componentList() {
|
||||
return this.filterValue
|
||||
? this.args.components.filter((c) => c.title.toLowerCase().includes(this.filterValue.toLowerCase()))
|
||||
: this.args.components;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import EmberRouter from '@ember/routing/router';
|
||||
import config from 'vault/config/environment';
|
||||
|
||||
import { addDocfyRoutes } from '@docfy/ember';
|
||||
export default class Router extends EmberRouter {
|
||||
location = config.locationType;
|
||||
rootURL = config.rootURL;
|
||||
@@ -217,4 +217,7 @@ Router.map(function () {
|
||||
});
|
||||
this.route('not-found', { path: '/*path' });
|
||||
});
|
||||
if (config.environment !== 'production') {
|
||||
addDocfyRoutes(this);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
@import 'ember-power-select';
|
||||
@import '@hashicorp/design-system-components';
|
||||
@import './core';
|
||||
@import './docs';
|
||||
|
||||
@mixin font-face($name) {
|
||||
@font-face {
|
||||
font-family: $name;
|
||||
src: url('/ui/fonts/#{$name}.woff2') format('woff2'), url('/ui/fonts/#{$name}.woff') format('woff');
|
||||
src:
|
||||
url('/ui/fonts/#{$name}.woff2') format('woff2'),
|
||||
url('/ui/fonts/#{$name}.woff') format('woff');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
121
ui/app/styles/docs.scss
Normal file
121
ui/app/styles/docs.scss
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
.docs-collapse-toggle {
|
||||
.hds-button {
|
||||
color: var(--token-side-nav-color-foreground-primary);
|
||||
background: var(--token-side-nav-color-surface-primary);
|
||||
border-color: transparent;
|
||||
border-radius: var(--token-side-nav-body-list-item-border-radius);
|
||||
&:hover {
|
||||
background: var(--token-side-nav-color-surface-interactive-hover);
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#docfy-content {
|
||||
font-size: 16px;
|
||||
font-family: var(--token-typography-display-300-font-family);
|
||||
margin-left: 1.5rem;
|
||||
margin-right: 2rem;
|
||||
margin-top: 1.5rem;
|
||||
max-width: 90%;
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
border-bottom: 1px solid $grey-light;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 1.15rem;
|
||||
font-size: var(--token-typography-display-500-font-size);
|
||||
line-height: var(--token-typography-display-500-line-height);
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-top: 1rem;
|
||||
font-size: var(--token-typography-display-400-font-size);
|
||||
line-height: var(--token-typography-display-400-line-height);
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc;
|
||||
li {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding-left: $spacing-16;
|
||||
padding-bottom: $spacing-16;
|
||||
}
|
||||
|
||||
pre,
|
||||
code {
|
||||
background-color: $ui-gray-100;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 1rem;
|
||||
padding: 0.5rem;
|
||||
background: $ui-gray-010;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: var(--token-typography-body-300-font-size);
|
||||
font-family: var(--token-typography-font-stack-code);
|
||||
}
|
||||
|
||||
pre code {
|
||||
overflow-x: scroll;
|
||||
max-width: 700px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
pre,
|
||||
table {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
table {
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
td {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
code {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
tr {
|
||||
border-bottom: 1px solid $grey-light;
|
||||
}
|
||||
}
|
||||
|
||||
.docfy-demo {
|
||||
border: 1px solid $grey-lightest;
|
||||
border-radius: 6px;
|
||||
padding: 1rem;
|
||||
overflow: scroll;
|
||||
|
||||
.docfy-demo__example {
|
||||
& pre,
|
||||
code {
|
||||
background: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
79
ui/app/templates/docs.hbs
Normal file
79
ui/app/templates/docs.hbs
Normal file
@@ -0,0 +1,79 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<Hds::AppFrame @hasSidebar={{@showSidebar}} @hasHeader={{false}} @hasFooter={{false}} as |Frame|>
|
||||
<Frame.Sidebar data-test-sidebar-nav>
|
||||
<DocfyOutput @scope="docs" as |docs|>
|
||||
{{#let docs.children as |directories|}}
|
||||
{{#let docs.pages as |pages|}}
|
||||
<Hds::SideNav>
|
||||
<:header>
|
||||
<Hds::SideNav::Header>
|
||||
<:logo>
|
||||
<Hds::SideNav::Header::HomeLink @icon="vault" @route="vault" @ariaLabel="Vault dashboard" />
|
||||
</:logo>
|
||||
<:actions>
|
||||
<Hds::SideNav::Header::IconButton @icon="home" @ariaLabel="Docs index" @route="docs" />
|
||||
</:actions>
|
||||
</Hds::SideNav::Header>
|
||||
</:header>
|
||||
<:body>
|
||||
<Hds::SideNav::List as |Nav|>
|
||||
<Nav.BackLink @text="Back to work (Vault UI)" @route="vault" />
|
||||
<Nav.Link @icon="home" @route="docs.index">
|
||||
Home
|
||||
</Nav.Link>
|
||||
<Nav.Link @icon="edit" @route="docs.how-to-docfy">
|
||||
How to docfy
|
||||
</Nav.Link>
|
||||
|
||||
<Nav.Title>
|
||||
Components
|
||||
</Nav.Title>
|
||||
<Nav.Item>
|
||||
{{! FILTER + COMPONENT LIST }}
|
||||
<ZDocfyFilter @components={{get (find-by "name" "components" directories) "pages"}} />
|
||||
</Nav.Item>
|
||||
|
||||
<Nav.Title>
|
||||
Contributing docs
|
||||
</Nav.Title>
|
||||
{{! Top level files in docs/ directory }}
|
||||
{{#each pages as |page|}}
|
||||
{{#let (concat "docs." (if page.relativeUrl page.relativeUrl "index")) as |url|}}
|
||||
<Nav.Link @route={{url}}>
|
||||
{{page.title}}
|
||||
</Nav.Link>
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
|
||||
{{! Sub directories within docs/ (aside from 'components') }}
|
||||
{{#each directories as |subDirectory|}}
|
||||
{{#if (not-eq subDirectory.name "components")}}
|
||||
<Nav.Title>
|
||||
{{capitalize subDirectory.label}}
|
||||
</Nav.Title>
|
||||
|
||||
{{#each subDirectory.pages as |page|}}
|
||||
{{#let (concat "docs." (if page.relativeUrl page.relativeUrl "index")) as |url|}}
|
||||
<Nav.Link @route={{url}}>
|
||||
{{page.title}}
|
||||
</Nav.Link>
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</Hds::SideNav::List>
|
||||
</:body>
|
||||
</Hds::SideNav>
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
</DocfyOutput>
|
||||
</Frame.Sidebar>
|
||||
|
||||
<Frame.Main id="docfy-content">
|
||||
{{outlet}}
|
||||
</Frame.Main>
|
||||
</Hds::AppFrame>
|
||||
@@ -1,8 +1,12 @@
|
||||
# Writing and consuming components
|
||||
# Building and consuming components
|
||||
|
||||
- [Page components for every route](#page-components-for-every-route)
|
||||
- [Conditional rendering](#conditional-rendering)
|
||||
- [Reusable components](#reusable-components)
|
||||
|
||||
Components can range from small, highly reusable "atoms" to large units with lots of business logic specific to one workflow or action. In any scenario, these are things to keep in mind while developing components for the Vault UI.
|
||||
|
||||
Please note that these guidelines are aspirational and you will see instances of antipatterns in the codebase. Many of these should be updated as we move forward. As with any ruleset, sometimes it is appropriate to break the rule.
|
||||
Please note that these guidelines are aspirational and you will see instances of anti-patterns in the codebase. Many of these should be updated as we move forward. As with any rule set, sometimes it is appropriate to break the rule.
|
||||
|
||||
## Page components for every route
|
||||
|
||||
@@ -24,38 +28,13 @@ Generally, we want the burden of deciding whether a component should render to l
|
||||
|
||||
## Reusable components
|
||||
|
||||
When developing components, make sure to:
|
||||
- Consider yielding something instead of passing a new arg
|
||||
- Less is more! Adding lots of rendering logic means the component is likely doing too much
|
||||
|
||||
- Add splattributes to the top level, eg:
|
||||
|
||||
```hbs
|
||||
<div data-test-stuff ...attributes>Stuff!</div>
|
||||
```
|
||||
|
||||
- Consider passing splattributes or yielding something instead of passing a new arg
|
||||
|
||||
❌ **Instead of:** passing a new arg that controls a style
|
||||
|
||||
```
|
||||
<Block @title="Example" @hasPadding={{false}} />
|
||||
```
|
||||
|
||||
✅ **Prefer:** passing a class or helper that controls a style
|
||||
|
||||
```
|
||||
<Block @title="Example" class="padding-0" />
|
||||
```
|
||||
|
||||
- Minimize the number of args that must be passed
|
||||
|
||||
❌ **Instead of:** Passing in separate args that are both required for icon to render
|
||||
|
||||
```
|
||||
<Block @title="Example" @hasIcon={{true}} @iconName="key" />
|
||||
```
|
||||
|
||||
✅ **Prefer:** One arg that is rendered if present
|
||||
|
||||
```
|
||||
<Block @title="Example" @icon="key" />
|
||||
```
|
||||
| 💡 Tips for reusability | Example |
|
||||
| ----------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| ✅ Add splattributes to the top level | <pre>`<div ...attributes> Something! </div>`</pre> |
|
||||
| ✅ Pass a class or helper that controls a style | <pre>`<Block @title="Example" class="padding-0" />`</pre> |
|
||||
| ❌ Don't pass a new arg that controls a style | <pre>`<Block @title="Example" @hasPadding={{false}} />` </pre> |
|
||||
| ✅ Minimize args passed, pass one arg that is rendered if present | <pre>`<Block @title="Example" @icon="key" />`</pre> |
|
||||
| ❌ Don't pass separate args required for icon to render | <pre>`<Block @title="Example" @hasIcon={{true}} @iconName="key" />` </pre> |
|
||||
99
ui/docs/how-to-docfy.md
Normal file
99
ui/docs/how-to-docfy.md
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: How to docfy
|
||||
order: 1
|
||||
---
|
||||
|
||||
# How to docfy
|
||||
|
||||
http://localhost:4200/ui/docs (navigate to directly or click the present icon in the bottom right of the app footer).
|
||||
|
||||
## `docs/` markdown files
|
||||
|
||||
Side nav links correspond to the file + directory structure within the `docs/` directory. These top-level markdown files **can** be edited directly and any updates should be saved and pushed to main. (Component docs are generated by the `yarn docs` command, see below.)
|
||||
|
||||
## generating component docs
|
||||
|
||||
The `docs/components` directory is where _generated_ markdown files for components live after running `yarn docs`. **Do not edit component markdown files directly**. Instead, update markdown by making changes to the `jsdoc` and then re-running the generate command. The `docs/components/*` files are included in `.gitignore` so they are not pushed to main. `jsdoc-to-markdown` errors log in the console.
|
||||
|
||||
```
|
||||
yarn docfy-md <component name> <addon or engine> <full filepath>
|
||||
```
|
||||
|
||||
> _Note: the above command takes three args, if passing the full filepath for a component then the second arg is unnecessary_
|
||||
|
||||
| Command | Description |
|
||||
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| `yarn docs` | generate markdown file for every\* component in the `addon/core` directory |
|
||||
| `yarn docfy-md some-component-name` | generate markdown file for specific component |
|
||||
| `yarn docfy-md read-more core` | generate markdown for `read-more` component in the `core` addon |
|
||||
| `yarn docfy-md pki-test null ./lib/pki/addon/components/pki-key-usage.ts` | optional third arg is the full component filepath (first arg will become markdown file name) |
|
||||
| `rm -f ./docs/components/*` | cleanup and delete generated component markdown files |
|
||||
|
||||
> _\*replication and `shamir/*` components are skipped as these are not reused and should eventually be moved outside the `addon/core` directory_
|
||||
|
||||
## Writing documentation for a component
|
||||
|
||||
Component docs are generated by the script `yarn docs`. Accurate `jsdoc` syntax is important so `jsdoc-to-markdown` properly generates the markdown file for that component. **Do not edit component markdown files directly**.
|
||||
|
||||
| jsdoc examples | | |
|
||||
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
|
||||
| form-field (`@description` example) | [github ](https://github.com/hashicorp/vault/blob/main/ui/lib/core/addon/components/form-field.js) | [vscode ](../lib/core/addon/components/form-field.js) |
|
||||
| confirmation-modal | [github ](https://github.com/hashicorp/vault/blob/main/ui/lib/core/addon/components/confirmation-modal.js) | [vscode ](../lib/core/addon/components/confirmation-modal.js) |
|
||||
| certificate-card | [github ](https://github.com/hashicorp/vault/blob/main/ui/lib/core/addon/components/certificate-card.js) | [vscode ](../lib/core/addon/components/certificate-card.js) |
|
||||
| alert-inline (`@deprecated` example) | [github](https://github.com/hashicorp/vault/blob/main/ui/lib/core/addon/components/alert-inline.js) | [vscode ](../lib/core/addon/components/alert-inline.js) |
|
||||
| secret-list-header (code snippet only\*) | [github](https://github.com/hashicorp/vault/blob/main/ui/lib/core/addon/components/secret-list-header.js) | [vscode ](../lib/core/addon/components/secret-list-header.js) |
|
||||
|
||||
> _\*renders a template code snippet and not instantiated component because it relies on too many args that cannot be set up for component instance_
|
||||
|
||||
### Syntax tips
|
||||
|
||||
Docfy renders an actual instance of the component beneath `@example` as a sample. Make sure the component uses proper hbs syntax and all args are on a single line.
|
||||
|
||||
> - Check the generated markdown file for syntax errors or typos. To update the markdown, first edit the jsdoc then re-run the generator. _Do not edit component markdown files directly_
|
||||
> - Param types: `object`, `string`, `function`, `array`
|
||||
> - Do not include `null` for empty default values
|
||||
> - Wrap optional params in brackets `[]`
|
||||
> - To include a codeblock in your module's description use `@description`
|
||||
|
||||
```
|
||||
❌ multi-line jsdoc will not render a component example
|
||||
* @example
|
||||
* <Block
|
||||
* @title="Example"
|
||||
* @description="My component"
|
||||
* />
|
||||
```
|
||||
|
||||
```
|
||||
✅ this will render
|
||||
* @example
|
||||
* <Block @title="Example" description="My component" />
|
||||
```
|
||||
|
||||
**Template**
|
||||
|
||||
```
|
||||
/**
|
||||
* @module ComponentName
|
||||
* @description
|
||||
* Description of the component
|
||||
*
|
||||
* @example
|
||||
* <ComponentName @param={{}} optionalParam={{}} />
|
||||
*
|
||||
* @param {object} paramName - description
|
||||
* @param {array} requiredParam=foo - foo is the default value here
|
||||
* @param {function} [optionalParamName] - An optional parameter is wrapped in brackets
|
||||
* @param {string} [param="some default value"] - An optional parameter with a default value
|
||||
*/
|
||||
```
|
||||
|
||||
> ### Config
|
||||
>
|
||||
> - [docfy-md.js](../scripts/docfy-md.js): script that generates component markdown and passes options to `jsdoc2md` command
|
||||
> - [generate-docs.sh](../scripts/docfy-md.js): batch command that iterates over desired javascript and typescript file in the `core` addon engine
|
||||
> - [jsdoc2md.json](../jsdoc2md.json): `jsdoc-to-markdown` config file, necessary so typescript files can be passed to `docfy-md` script
|
||||
|
||||
### More info
|
||||
|
||||
- [Building and consuming components](./building-components.md)
|
||||
21
ui/docs/index.md
Normal file
21
ui/docs/index.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Index
|
||||
---
|
||||
|
||||
# Welcome to our docs!
|
||||
|
||||
These views are generated by files in the `docs/` directory.
|
||||
|
||||
<hr>
|
||||
|
||||
- [How to docfy](./how-to-docfy.md)
|
||||
- [Client pagination](./client-pagination.md)
|
||||
- [Building and consuming components](./building-components.md)
|
||||
- [CSS styling](./css.md)
|
||||
- [Ember Engines](./ember-engines.md)
|
||||
- [Fetch secrets engine config decorator](./fetch-secrets-engine-config.md)
|
||||
- [Forms](./forms.md)
|
||||
- [Model validations](./model-validations.md)
|
||||
- [Models](./models.md)
|
||||
- [Routing](./routing.md)
|
||||
- [Serializers and Adapters](./serializers-adapters.md)
|
||||
18
ui/jsdoc2md.json
Normal file
18
ui/jsdoc2md.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"source": {
|
||||
"includePattern": ".+\\.(js|ts)(doc|x)?$",
|
||||
"excludePattern": ".+\\.(test|spec).(js|ts)"
|
||||
},
|
||||
"plugins": ["plugins/markdown", "node_modules/jsdoc-babel"],
|
||||
"babel": {
|
||||
"extensions": ["ts", "tsx", "js"],
|
||||
"ignore": ["**/*.(test|spec).ts"],
|
||||
"babelrc": false,
|
||||
"presets": [["@babel/preset-env", { "targets": { "node": true } }], "@babel/preset-typescript"],
|
||||
"plugins": [
|
||||
"@babel/proposal-class-properties",
|
||||
"@babel/proposal-object-rest-spread",
|
||||
["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -10,18 +10,22 @@ import { tracked } from '@glimmer/tracking';
|
||||
import { assert } from '@ember/debug';
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @module AlertInline
|
||||
* * Use Hds::Alert @type="compact" for displaying alert messages.
|
||||
* This component renders a compact Hds::Alert that displays a loading icon if the
|
||||
* @message arg changes and then re-renders the updated @message text.
|
||||
* `@message` arg changes and then re-renders the updated `@message` text.
|
||||
* (Example: submitting a form and displaying the number of errors because on re-submit the number may change)
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* <AlertInline @type="danger" @message="There are 2 errors with this form."/>
|
||||
* ```
|
||||
*
|
||||
* @deprecated {string} type - color getter maps type to the Hds::Alert @color
|
||||
* * use Hds::Alert @type="compact" for displaying alert messages instead
|
||||
* <Hds::Alert @type="compact" @color="critical" as |A|>
|
||||
* <A.Title>Error</A.Title>
|
||||
* <A.Description>Something is not right</A.Description>
|
||||
* </Hds::Alert>
|
||||
*
|
||||
* @param {string} type - color getter maps type to the Hds::Alert @color
|
||||
* @param {string} color - Styles alert color and icon, can be one of: critical, warning, success, highlight, neutral
|
||||
* @param {string} message - The message to display within the alert.
|
||||
*/
|
||||
|
||||
@@ -11,20 +11,18 @@ import { action } from '@ember/object';
|
||||
* AutocompleteInput components are used as standard string inputs or optionally select options to append to input value
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <AutocompleteInput @requiredParam={requiredParam} @optionalParam={optionalParam} @param1={{param1}}/>
|
||||
* ```
|
||||
* @callback inputChangeCallback
|
||||
* <AutocompleteInput @label="Label here" @subText="subtext here" @value="foo" @onChange={{log "on change called"}} />
|
||||
*
|
||||
* @param {string} value - input value
|
||||
* @param {inputChangeCallback} onChange - fires when input value changes to mutate value param by caller
|
||||
* @param {function} onChange - fires when input value changes to mutate value param by caller
|
||||
* @param {string} [optionsTrigger] - display options dropdown when trigger character is input
|
||||
* @param {Object[]} [options] - array of { label, value } objects where label is displayed in options dropdown and value is appended to input value
|
||||
* @param {array} [options] - array of `{ label, value }` objects where label is displayed in options dropdown and value is appended to input value
|
||||
* @param {string} [label] - label to display above input
|
||||
* @param {string} [subText] - text to display below label
|
||||
* @param {string} [placeholder] - input placeholder
|
||||
*/
|
||||
|
||||
export default class AutocompleteInput extends Component {
|
||||
export default class AutocompleteInputComponent extends Component {
|
||||
dropdownAPI;
|
||||
inputElement;
|
||||
|
||||
|
||||
@@ -8,14 +8,13 @@ import Component from '@glimmer/component';
|
||||
/**
|
||||
* @module CertificateCard
|
||||
* The CertificateCard component receives data and optionally receives a boolean declaring if that data is meant to be in PEM
|
||||
* Format. It renders using the <HDS::Card::Container>. To the left there is a certificate icon. In the center there is a label
|
||||
* Format. It renders using the Hds::Card::Container. To the left there is a certificate icon. In the center there is a label
|
||||
* which says which format (PEM or DER) the data is in. Below the label is the truncated data. To the right there is a copy
|
||||
* button to copy the data.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <CertificateCard @data={{value}} @isPem={{true}} />
|
||||
* ```
|
||||
* <CertificateCard @isPem={{true}} @data="-----BEGIN CERTIFICATE-----MIIDezCCAmOgAwIBAgIUTBbQcZijQsmd0rjd6COikPsrGyowDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAxMJdGVzdC1yb290MB4XDTIzMDEyMDE3NTcxMloXDTIzMDIy" />
|
||||
*
|
||||
* @param {string} data - the data to be displayed in the component (usually in PEM or DER format)
|
||||
* @param {boolean} [isPem] - optional argument for if the data is required to be in PEM format (and should thus have the PEM Format label)
|
||||
*/
|
||||
|
||||
@@ -22,18 +22,12 @@ interface Field {
|
||||
|
||||
/**
|
||||
* @module CheckboxGrid
|
||||
* CheckboxGrid components are used to allow users to select any
|
||||
* number of predetermined options, aligned in a 3-column grid.
|
||||
* @description
|
||||
* CheckboxGrid components are used to allow users to select any number of predetermined options, aligned in a 3-column grid.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <CheckboxGrid
|
||||
* @name="modelKey"
|
||||
* @label="Model Attribute Label"
|
||||
* @fields={{options}}
|
||||
* @value={{['Hello', 'Yes']}}
|
||||
* />
|
||||
* ```
|
||||
* <CheckboxGrid @name="extKeyUsage" @label="Extended key usage" @fields={{array (hash key="EmailProtection" label="Email Protection") (hash key="TimeStamping" label="Time Stamping") (hash key="ServerAuth" label="Server Auth") }} @value={{array "TimeStamping"}} />
|
||||
*/
|
||||
|
||||
export default class CheckboxGrid extends Component<CheckboxGridArgs> {
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { assert } from '@ember/debug';
|
||||
|
||||
const DIRECTIONS = ['right', 'left', 'up', 'down'];
|
||||
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @module Chevron
|
||||
* `Chevron` components render `Icon` with one of the `chevron-` glyphs.
|
||||
* * Use HDS icons instead
|
||||
* Chevron components render Icon with one of the "chevron-" glyphs.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Chevron @direction="up" />
|
||||
* ```
|
||||
*
|
||||
* @param [direction="right"] {String} - the direction the chevron icon points. Accepted values are
|
||||
* "right", "down", "left", "up".
|
||||
* @param [isButton=false] {String} - if true, adjusts the CSS classes to push the icon closer to the right of a button.
|
||||
* @param {string} [direction="right"] - the direction the chevron icon points. Accepted values are "right", "down", "left", "up".
|
||||
* @param {string} [isButton=false] - if true, adjusts the CSS classes to push the icon closer to the right of a button.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -15,9 +15,8 @@ const pgpKeyFileDefault = () => ({ value: '' });
|
||||
* an interface for the user to upload or paste a PGP key for use
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ChoosePgpKeyForm @onCancel={{this.reset}} @onSubmit={{handleGenerateWithPgpKey}}>
|
||||
* ```
|
||||
* <ChoosePgpKeyForm @onCancel={{log "cancel!"}} @onSubmit={{log "submit!"}} />
|
||||
*
|
||||
* @param {function} onCancel - required - This function will be triggered when the modal intends to be closed
|
||||
* @param {function} onSubmit - required - When the PGP key is confirmed, it will call this method with the pgpKey value as the only param
|
||||
* @param {string} buttonText - Button text for onSubmit. Defaults to "Continue with key"
|
||||
|
||||
@@ -12,39 +12,21 @@ import { tracked } from '@glimmer/tracking';
|
||||
* @module ConfirmAction
|
||||
* ConfirmAction is a button that opens a modal containing a confirmation message with confirm or cancel action.
|
||||
* Splattributes are spread to the button element to apply styling directly without adding extra args.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @example
|
||||
// in dropdown
|
||||
<ConfirmAction
|
||||
@isInDropdown={{true}}
|
||||
@buttonText="Delete"
|
||||
@confirmMessage="This action cannot be undone."
|
||||
@onConfirmAction={{log "my action!"}}
|
||||
/>
|
||||
|
||||
// in toolbar
|
||||
<ConfirmAction
|
||||
class="toolbar-button"
|
||||
@buttonColor="secondary"
|
||||
@buttonText="Delete item"
|
||||
@confirmTitle="Delete item?"
|
||||
@onConfirmAction={{log "my action!"}}
|
||||
@confirmMessage="Are you sure you want to delete this config?"
|
||||
@isRunning={{this.rotateKey.isRunning}}
|
||||
@disabledMessage={{if true "A secondary ID is required perform revocation."}}
|
||||
/>
|
||||
* ```
|
||||
* <ConfirmAction @buttonColor="critical" @buttonText="Delete" @confirmMessage="This action cannot be undone." @onConfirmAction={{fn (mut this.showConfirmModal) false}} />
|
||||
*
|
||||
*
|
||||
* @param {Function} onConfirmAction - The action to take upon confirming.
|
||||
* @param {String} [confirmTitle=Are you sure?] - The title to display in the confirmation modal.
|
||||
* @param {String} [confirmMessage=You will not be able to recover it later.] - The message to display when confirming.
|
||||
* @param {String} [confirmTitle="Are you sure?"] - The title to display in the confirmation modal.
|
||||
* @param {String} [confirmMessage="You will not be able to recover it later."] - The message to display when confirming.
|
||||
* @param {Boolean} isInDropdown - If true styles for dropdowns, button color is 'critical', and renders inside `<li>` elements via `<Hds::Dropdown::ListItem::Interactive`
|
||||
* @param {String} buttonText - Text for the button that toggles modal to open.
|
||||
* @param {String} [buttonColor=primary] - Color of button that toggles modal, only applies when @isInDropdown=false. Options are primary, secondary (use for toolbars), tertiary, or critical
|
||||
* @param {String} [modalColor=critical] - Styles modal color, if 'critical' confirm button is also 'critical'. Possible values: critical, warning or neutral ('neutral' used for @disabledMessage modal)
|
||||
* @param {String} [buttonColor="primary"] - Color of button that toggles modal, only applies when @isInDropdown=false. Options are primary, secondary (use for toolbars), tertiary, or critical
|
||||
* @param {String} [modalColor="critical"] - Styles modal color, if 'critical' confirm button is also 'critical'. Possible values: critical, warning or neutral ('neutral' used for @disabledMessage modal)
|
||||
* @param {Boolean} [isRunning] - Disables the modal confirm button - usually a concurrency task that informs the modal if a process is still running
|
||||
* @param {String} [disabledMessage] - A message explaining why the confirm action is not allowed, usually combined with a conditional that returns a string if true
|
||||
* @param {String} [disabledMessage] - A message explaining why the confirm action is not allowed, usually combined with a conditional that returns a string if true
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -3,29 +3,24 @@
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
import Component from '@glimmer/component';
|
||||
|
||||
/**
|
||||
* @module ConfirmationModal
|
||||
* ConfirmationModal components wrap the <Hds::Modal> component to present a critical (red) type-to-confirm modal
|
||||
* ConfirmationModal components wrap the Hds::Modal component to present a critical (red) type-to-confirm modal
|
||||
* which require the user to type something to confirm the action.
|
||||
* They are used for extremely destructive actions that require extra consideration before confirming.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ConfirmationModal
|
||||
* @onConfirm={action "destructiveAction"}
|
||||
* @title="Do Dangerous Thing?"
|
||||
* @isActive={{isModalActive}}
|
||||
* @onClose={{action (mut isModalActive) false}}
|
||||
* @confirmText="yes"
|
||||
* @onConfirmMsg="deleting this thing to delete."
|
||||
* />
|
||||
* ```
|
||||
* button is not part of component and is just to help demo functionality
|
||||
* <Hds::Button @text="Confirm" @color="secondary" {{on "click" (fn (mut this.isModalOpen) true)}} />
|
||||
* <ConfirmationModal @onConfirm={{fn (mut this.isModalOpen) false}} @title="Do Dangerous Thing?" @isActive={{this.isModalOpen}} @onClose={{fn (mut this.isModalOpen) false}} @confirmText="yes" @onConfirmMsg="deleting this thing to delete." />
|
||||
*
|
||||
* @param {function} onConfirm - onConfirm is the action that happens when user clicks onConfirm after filling in the confirmation block
|
||||
* @param {function} onClose - specify what to do when user attempts to close modal
|
||||
* @param {boolean} isActive - Controls whether the modal is "active" eg. visible or not.
|
||||
* @param {string} title - Title of the modal
|
||||
* @param {string} [confirmText=Yes] - The confirmation text that the user must type before continuing
|
||||
* @param {string} [toConfirmMsg] - Finishes the sentence "Type <confirmText> to confirm <toConfirmMsg>", default is an empty string (ex. 'secret deletion')
|
||||
* @param {string} [toConfirmMsg] - Finishes the sentence "Type `<confirmText>` to confirm `<toConfirmMsg>`", default is an empty string (ex. 'secret deletion')
|
||||
* @param {string} [buttonText=Confirm] - Button text on the confirm button
|
||||
*/
|
||||
|
||||
|
||||
@@ -6,15 +6,17 @@
|
||||
import ExternalLink from './external-link';
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @module DocLink
|
||||
* `DocLink` components are used to render anchor links to relevant Vault documentation at developer.hashicorp.com.
|
||||
* DocLink components are used to render anchor links to relevant Vault documentation at developer.hashicorp.com.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
<DocLink @path="/vault/docs/secrets/kv/kv-v2.html">Learn about KV v2</DocLink>
|
||||
* ```
|
||||
* <DocLink @path="/vault/docs/secrets/kv/kv-v2.html">Learn about KV v2</DocLink>
|
||||
*
|
||||
* @param {string} path="/" - The path to documentation on developer.hashicorp.com that the component should link to.
|
||||
* * Use HDS link components instead with "doc-link" helper for path prefix
|
||||
* <Hds::Link::Standalone @text="Docs" @href={{doc-link "/vault/tutorials"}} @icon="learn-link" @iconPosition="trailing" />
|
||||
*
|
||||
* @param {string} path=/ - The path to documentation on developer.hashicorp.com that the component should link to.
|
||||
*
|
||||
*/
|
||||
export default class DocLinkComponent extends ExternalLink {
|
||||
|
||||
@@ -12,32 +12,23 @@ import { tracked } from '@glimmer/tracking';
|
||||
import { assert } from '@ember/debug';
|
||||
/**
|
||||
* @module DownloadButton
|
||||
* DownloadButton wraps an <Hds::Button> to perform a download action.
|
||||
* * NOTE: when using in an engine, remember to add the 'download' service to its dependencies (in /engine.js) and map to it in /app.js
|
||||
* [ember-docs](https://ember-engines.com/docs/services)
|
||||
* DownloadButton wraps an Hds::Button to perform a download action. [Docs for HDS args](https://helios.hashicorp.design/components/button?tab=code)
|
||||
* * **NOTE**: when using in an engine, remember to add the 'download' service to its dependencies (in /engine.js) and map to it in /app.js
|
||||
* [Ember Engines Services](https://ember-engines.com/docs/services)
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <DownloadButton
|
||||
* @text="Download this stuff"
|
||||
* @color="secondary"
|
||||
* @data={{this.data}}
|
||||
* @filename={{this.filename}}
|
||||
* @mime={{this.mime}}
|
||||
* @extension={{this.extension}}
|
||||
* @stringify={{true}}
|
||||
* />
|
||||
* ```
|
||||
* <DownloadButton @text="Download this stuff" @color="secondary" @data="download data" @filename="my file" />
|
||||
*
|
||||
* @param {string} [filename] - name of file that prefixes the ISO timestamp generated at download
|
||||
* @param {string} [data] - data to download
|
||||
* @param {function} [fetchData] - function that fetches data and returns download content
|
||||
* @param {string} [extension='txt'] - file extension, the download service uses this to determine the mimetype
|
||||
* @param {string} [extension=txt] - file extension, the download service uses this to determine the mimetype
|
||||
* @param {boolean} [stringify=false] - argument to stringify the data before passing to the File constructor
|
||||
* @param {callback} [onSuccess] - callback from parent to invoke if download is successful
|
||||
* @param {boolean} [hideIcon=false] - renders the 'download' icon by default, pass true to hide (ex: when download button appears in a dropdown)
|
||||
* * HDS ARGS https://helios.hashicorp.design/components/button?tab=code
|
||||
* @param {string} [text="Download"] - button text, defaults to 'Download'
|
||||
* @param {string} [text=Download] - button text, defaults to 'Download'
|
||||
* @param {string} [color] - HDS default is primary, but there are four color options: primary, secondary, tertiary, and critical.
|
||||
* @param {string} [iconPosition="leading"] - icon position, 'leading' (HDS default) or 'trailing'
|
||||
* @param {string} [iconPosition=leading] - icon position, 'leading' (HDS default) or 'trailing'
|
||||
* @param {boolean} [isIconOnly] - button only renders an icon, no text
|
||||
*/
|
||||
|
||||
|
||||
@@ -6,16 +6,17 @@
|
||||
import Component from '@glimmer/component';
|
||||
|
||||
/**
|
||||
* @module ExternalLinkComponent
|
||||
* `ExternalLink` components are used to render anchor links to non-cluster links. Automatically opens in a new tab with noopener noreferrer.
|
||||
* To link to developer.hashicorp.com, use DocLink .
|
||||
* @deprecated
|
||||
* @module ExternalLink
|
||||
* ExternalLink components are used to render anchor links to non-cluster links. Automatically opens in a new tab with noopener noreferrer.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
<ExternalLink @href="https://hashicorp.com">Arbitrary Link</ExternalLink>
|
||||
* ```
|
||||
* <ExternalLink @href="https://hashicorp.com">Arbitrary Link</ExternalLink>
|
||||
*
|
||||
* @param {string} href="https://example.com/" - The full href with protocol
|
||||
* * Use HDS links with @isHrefExternal={{true}} instead
|
||||
* <Hds::Link::Inline @icon="external-link" @isHrefExternal={{true}} @href="https://hashicorp.com">My link</Hds::Link::Inline>
|
||||
*
|
||||
* @param {string} href - The full href with protocol
|
||||
* @param {boolean} [sameTab=false] - by default, these links open in new tab. To override, pass @sameTab={{true}}
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -10,16 +10,15 @@ import Component from '@glimmer/component';
|
||||
* FormFieldGroupsLoop components loop through the "groups" set on a model and display them either as default or behind toggle components.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
<FormFieldGroupsLoop @model={{this.model}} @mode={{if @model.isNew "create" "update"}}/>
|
||||
* ```
|
||||
* <FormFieldGroupsLoop @model={{this.model}} @mode={{if @model.isNew "create" "update"}}/>
|
||||
*
|
||||
* @param {class} model - The routes model class.
|
||||
* @param {string} mode - "create" or "update" used to hide the name form field. TODO: not ideal, would prefer to disable it to follow new design patterns.
|
||||
* @param {function} [modelValidations] - Passed through to formField.
|
||||
* @param {boolean} [showHelpText] - Passed through to formField.
|
||||
* @param {string} [groupName="fieldGroups"] - option to override key on the model where groups are located
|
||||
* @param {string} [groupName=fieldGroups] - option to override key on the model where groups are located
|
||||
*/
|
||||
export default class FormFieldGroupsLoop extends Component {
|
||||
export default class FormFieldGroupsLoopComponent extends Component {
|
||||
get fieldGroups() {
|
||||
return this.args.groupName || 'fieldGroups';
|
||||
}
|
||||
|
||||
@@ -9,32 +9,17 @@ import { action } from '@ember/object';
|
||||
|
||||
/**
|
||||
* @module FormFieldGroups
|
||||
* `FormFieldGroups` components are field groups associated with a particular model. They render individual `FormField` components.
|
||||
* FormFieldGroups components are field groups associated with a particular model. They render individual FormField components.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* {{if model.fieldGroups}}
|
||||
* <FormFieldGroups @model={{model}} />
|
||||
* {{/if}}
|
||||
* <FormFieldGroups @model={{mountModel}} @onChange={{action "onTypeChange"}} @renderGroup="Method Options" @onKeyUp={{action "onKeyUp"}} @validationMessages={{validationMessages}} />
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* <FormFieldGroups
|
||||
* @model={{mountModel}}
|
||||
* @onChange={{action "onTypeChange"}}
|
||||
* @renderGroup="Method Options"
|
||||
* @onKeyUp={{action "onKeyUp"}}
|
||||
* @validationMessages={{validationMessages}}
|
||||
* />
|
||||
* ```
|
||||
* @callback onChangeCallback
|
||||
* @callback onKeyUpCallback
|
||||
* @param {Model} model- Model to be passed down to form-field component. If `fieldGroups` is present on the model then it will be iterated over and groups of `FormField` components will be rendered.
|
||||
* @param {string} [renderGroup] - An allow list of groups to include in the render.
|
||||
* @param {onChangeCallback} [onChange] - Handler that will get set on the `FormField` component.
|
||||
* @param {onKeyUpCallback} [onKeyUp] - Handler that will set the value and trigger validation on input changes
|
||||
* @param {ModelValidations} [modelValidations] - Object containing validation message for each property
|
||||
* @param {string} [groupName='fieldGroups'] - attribute name where the field groups are
|
||||
* @param {function} [onChange] - Handler that will get set on the `FormField` component.
|
||||
* @param {function} [onKeyUp] - Handler that will set the value and trigger validation on input changes
|
||||
* @param {object} [modelValidations] - Object containing validation message for each property
|
||||
* @param {string} [groupName=fieldGroups] - attribute name where the field groups are
|
||||
*/
|
||||
|
||||
export default class FormFieldGroupsComponent extends Component {
|
||||
|
||||
@@ -15,38 +15,39 @@ import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||
|
||||
/**
|
||||
* @module FormField
|
||||
* `FormField` components are field elements associated with a particular model.
|
||||
* FormField components are field elements associated with a particular model.
|
||||
* @description
|
||||
* ```
|
||||
* sample attr shape:
|
||||
* attr = {
|
||||
* name: "foo", // name of attribute -- used to populate various fields and pull value from model
|
||||
* type: "boolean" // type of attribute value -- string, boolean, etc.
|
||||
* options: {
|
||||
* label: "To do task", // custom label to be shown, otherwise attr.name will be displayed
|
||||
* defaultValue: "", // default value to display if model value is not present
|
||||
* fieldValue: "toDo", // used for value lookup on model over attr.name
|
||||
* editType: "boolean", type of field to use. List of editTypes:boolean, file, json, kv, optionalText, mountAccessor, password, radio, regex, searchSelect, stringArray, textarea, ttl, yield.
|
||||
* helpText: "This will be in a tooltip",
|
||||
* readOnly: true
|
||||
* },
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* {{#each @model.fields as |attr|}}
|
||||
* <FormField data-test-field @attr={{attr}} @model={{this.model}} />
|
||||
* <FormField data-test-field @attr={{attr}} @model={{@model}} />
|
||||
* {{/each}}
|
||||
* ```
|
||||
* example attr object:
|
||||
* attr = {
|
||||
* name: "foo", // name of attribute -- used to populate various fields and pull value from model
|
||||
* options: {
|
||||
* label: "Foo", // custom label to be shown, otherwise attr.name will be displayed
|
||||
* defaultValue: "", // default value to display if model value is not present
|
||||
* fieldValue: "bar", // used for value lookup on model over attr.name
|
||||
* editType: "ttl", type of field to use. List of editTypes:boolean, file, json, kv, optionalText, mountAccessor, password, radio, regex, searchSelect, stringArray, textarea, ttl, yield.
|
||||
* helpText: "This will be in a tooltip",
|
||||
* readOnly: true
|
||||
* },
|
||||
* type: "boolean" // type of attribute value -- string, boolean, etc.
|
||||
* }
|
||||
* <FormField @attr={{hash name="toDo" options=(hash label="To do task" helpText="helpful text" editType="boolean")}} @model={{hash toDo=true}} />
|
||||
*
|
||||
* @param {Object} attr - usually derived from ember model `attributes` lookup, and all members of `attr.options` are optional
|
||||
* @param {Model} model - Ember Data model that `attr` is defined on
|
||||
* @param {boolean} [disabled=false] - whether the field is disabled
|
||||
* @param {boolean} [showHelpText=true] - whether to show the tooltip with help text from OpenAPI
|
||||
* @param {string} [subText] - text to be displayed below the label
|
||||
* @param {string} [mode] - used when editType is 'kv'
|
||||
* @param {ModelValidations} [modelValidations] - Object of errors. If attr.name is in object and has error message display in AlertInline.
|
||||
* @callback onChangeCallback
|
||||
* @param {onChangeCallback} [onChange] - called whenever a value on the model changes via the component
|
||||
* @callback onKeyUpCallback
|
||||
* @param {onKeyUpCallback} [onKeyUp] - function passed through into MaskedInput to handle validation. It is also handled for certain form-field types here in the action handleKeyUp.
|
||||
* @param {object} [modelValidations] - Object of errors. If attr.name is in object and has error message display in AlertInline.
|
||||
* @param {function} [onChange] - called whenever a value on the model changes via the component
|
||||
* @param {function} [onKeyUp] - function passed through into MaskedInput to handle validation. It is also handled for certain form-field types here in the action handleKeyUp.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -11,19 +11,16 @@ import Component from '@glimmer/component';
|
||||
* To show an overall inline error message, use the :error yielded block like shown below.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <FormSaveButtons @saveButtonText="Save" @isSaving={{isSaving}} @cancelLinkParams={{array
|
||||
* "foo.route"}}>
|
||||
* <FormSaveButtons @saveButtonText="Save" @isSaving={{false}} @cancelLinkParams={{array "vault"}}>
|
||||
* <:error>This is an error</:error>
|
||||
* </FormSaveButtons>
|
||||
* ```
|
||||
*
|
||||
* @param [saveButtonText="Save" {String}] - The text that will be rendered on the Save button.
|
||||
* @param [cancelButtonText="Cancel" {String}] - The text that will be rendered on the Cancel button.
|
||||
* @param [isSaving=false {Boolean}] - If the form is saving, this should be true. This will disable the save button and render a spinner on it;
|
||||
* @param [cancelLinkParams=[] {Array}] - An array of arguments used to construct a link to navigate back to when the Cancel button is clicked.
|
||||
* @param [onCancel=null {Function}] - If the form should call an action on cancel instead of route somewhere, the function can be passed using onCancel instead of passing an array to cancelLinkParams.
|
||||
* @param [includeBox=true {Boolean}] - By default we include padding around the form with underlines. Passing this value as false will remove that padding.
|
||||
* @param {string} [saveButtonText=Save] - The text that will be rendered on the Save button.
|
||||
* @param {string} [cancelButtonText=Cancel] - The text that will be rendered on the Cancel button.
|
||||
* @param {boolean} [isSaving=false] - If the form is saving, this should be true. This will disable the save button and render a spinner on it;
|
||||
* @param {array} [cancelLinkParams] - An array of arguments used to construct a link to navigate back to when the Cancel button is clicked.
|
||||
* @param {function} [onCancel=null] - If the form should call an action on cancel instead of route somewhere, the function can be passed using onCancel instead of passing an array to cancelLinkParams.
|
||||
* @param {boolean} [includeBox=true] - By default we include padding around the form with underlines. Passing this value as false will remove that padding.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -16,15 +16,14 @@ const flightIconNames = flightIconMap.assets.map((asset) => asset.iconName).uniq
|
||||
* Flight icon library at https://helios.hashicorp.design/icons/library
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Icon @name="x-square" @size="24" />
|
||||
* ```
|
||||
* <Icon @name="heart" @size="24" />
|
||||
*
|
||||
* @param {string} name - The name of the SVG to render inline. Required.
|
||||
* @param {string} [size=16] - size for flight icon, can be 16 or 24
|
||||
*
|
||||
*/
|
||||
|
||||
export default class Icon extends Component {
|
||||
export default class IconComponent extends Component {
|
||||
constructor(owner, args) {
|
||||
super(owner, args);
|
||||
assert('Icon component size argument must be either "16" or "24"', ['16', '24'].includes(this.size));
|
||||
|
||||
@@ -17,23 +17,13 @@ import { action } from '@ember/object';
|
||||
* return a wildcard count similar to what is done in the searchSelect component.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <InfoTableItemArray
|
||||
* @label="Roles"
|
||||
* @displayArray={{['test-1','test-2','test-3']}}
|
||||
* @isLink={{true}}
|
||||
* @rootRoute="vault.cluster.secrets.backend.list-root"
|
||||
* @itemRoute="vault.cluster.secrets.backend.show"
|
||||
* @modelType="transform/role"
|
||||
* @queryParam="role"
|
||||
* @backend="transform"
|
||||
* ```
|
||||
* <InfoTableItemArray @label="Roles" @displayArray={{array "test-1" "test-2" "test-3"}} />
|
||||
*
|
||||
* @param {string} label - used to render lowercased display text for "View all <label>."
|
||||
* @param {array} displayArray - The array of data to be displayed. (In InfoTableRow this comes from the @value arg.) If the array length > 10, and @doNotTruncate is false only 5 will show with a count of the number hidden.
|
||||
* @param {string} label - used to render lowercased display text for "View all [label]."
|
||||
* @param {array} displayArray - The array of data to be displayed. (In InfoTableRow this comes from the `@value` arg.) If the array length > 10, and `@doNotTruncate` is false only 5 will show with a count of the number hidden.
|
||||
* @param {boolean} [isLink] - Indicates if the item should contain a link-to component. Only setup for arrays, but this could be changed if needed.
|
||||
* @param {string || array} [rootRoute="vault.cluster.secrets.backend.list-root"] - Tells what route the link should go to when selecting "view all". If the route requires more than one dynamic param, insert an array.
|
||||
* @param {string || array} [itemRoute=vault.cluster.secrets.backend.show] - Tells what route the link should go to when selecting the individual item. If the route requires more than one dynamic param, insert an array.
|
||||
* @param {string | array} [rootRoute=vault.cluster.secrets.backend.list-root] - Tells what route the link should go to when selecting "view all". If the route requires more than one dynamic param, insert an array.
|
||||
* @param {string | array} [itemRoute=vault.cluster.secrets.backend.show] - Tells what route the link should go to when selecting the individual item. If the route requires more than one dynamic param, insert an array.
|
||||
* @param {string} [modelType] - Tells which model you want to query and set allOptions. Used in conjunction with the the isLink.
|
||||
* @param {string} [wildcardLabel] - when you want the component to return a count on the model for options returned when using a wildcard you must provide a label of the count e.g. role. Should be singular.
|
||||
* @param {string} [backend] - To specify which backend to point the link to.
|
||||
|
||||
@@ -14,9 +14,7 @@ import { action } from '@ember/object';
|
||||
* that the value breaks under the label on smaller viewports.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <InfoTableRow @value={{5}} @label="TTL" @helperText="Some description"/>
|
||||
* ```
|
||||
*
|
||||
* @param {string} label=null - The display name for the value.
|
||||
* @param {string} helperText=null - Text to describe the value displayed beneath the label.
|
||||
@@ -29,7 +27,7 @@ import { action } from '@ember/object';
|
||||
* @param {string} [formatDate] - A string of the desired date format that's passed to the date-format helper to render timestamps (ex. "MMM d yyyy, h:mm:ss aaa", see: https://date-fns.org/v2.30.0/docs/format)
|
||||
* @param {boolean} [formatTtl=false] - When true, value is passed to the format-duration helper, useful for TTL values
|
||||
* @param {string} [type=array] - The type of value being passed in. This is used for when you want to trim an array. For example, if you have an array value that can equal length 15+ this will trim to show 5 and count how many more are there
|
||||
* * InfoTableItemArray *
|
||||
*
|
||||
* @param {boolean} [isLink=true] - Passed through to InfoTableItemArray. Indicates if the item should contain a link-to component. Only setup for arrays, but this could be changed if needed.
|
||||
* @param {string} [modelType=null] - Passed through to InfoTableItemArray. Tells what model you want data for the allOptions to be returned from. Used in conjunction with the the isLink.
|
||||
* @param {string} [queryParam] - Passed through to InfoTableItemArray. If you want to specific a tab for the View All XX to display to. Ex= role
|
||||
|
||||
@@ -7,12 +7,10 @@ import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
/**
|
||||
* @module JsonEditor
|
||||
* @module InfoTooltip
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <JsonEditor @title="Policy" @value={{codemirror.string}} @valueUpdated={{ action "codemirrorUpdate"}} />
|
||||
* ```
|
||||
* <InfoTooltip>Important info!</InfoTooltip>
|
||||
*
|
||||
* @param {string} [verticalPosition] - vertical position specification (above, below)
|
||||
* @param {string} [horizontalPosition] - horizontal position specification (center, auto-right)
|
||||
|
||||
@@ -12,11 +12,8 @@ import { tracked } from '@glimmer/tracking';
|
||||
* This component renders an input that fires a callback on "keyup" containing the input's value
|
||||
*
|
||||
* @example
|
||||
* <InputSearch
|
||||
* @initialValue="secret/path/"
|
||||
* @onChange={{this.handleSearch}}
|
||||
* @placeholder="search..."
|
||||
* />
|
||||
* <InputSearch @initialValue="secret/path/" @onChange={{this.handleSearch}} @placeholder="search..." />
|
||||
*
|
||||
* @param {string} [id] - unique id for the input
|
||||
* @param {string} [initialValue] - initial search value, i.e. a secret path prefix, that pre-fills the input field
|
||||
* @param {string} [placeholder] - placeholder text for the input
|
||||
|
||||
@@ -13,9 +13,7 @@ import { obfuscateData } from 'core/utils/advanced-secret';
|
||||
* @module JsonEditor
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <JsonEditor @title="Policy" @value={{codemirror.string}} @valueUpdated={{ action "codemirrorUpdate"}} />
|
||||
* ```
|
||||
* <JsonEditor @title="Policy" @value={{hash foo="bar"}} @viewportMargin={{100}} />
|
||||
*
|
||||
* @param {string} [title] - Name above codemirror view
|
||||
* @param {string} value - a specific string the comes from codemirror. It's the value inside the codemirror display
|
||||
@@ -31,9 +29,7 @@ import { obfuscateData } from 'core/utils/advanced-secret';
|
||||
* @param {String} [viewportMargin] - Size of viewport. Often set to "Infinity" to load/show all text regardless of length.
|
||||
* @param {string} [example] - Example to show when value is null -- when example is provided a restore action will render in the toolbar to clear the current value and show the example after input
|
||||
* @param {string} [screenReaderLabel] - This label is read by the screen readers when CodeMirror text area is focused. This is helpful for accessibility.
|
||||
* * REQUIRED if rendering within a modal *
|
||||
* @container gives context for the <Hd::Copy::Button> and sets autoRefresh=true so JsonEditor renders content (without this property @value only renders if editor is focused)
|
||||
* @param {string} [container] - Selector string or element object of containing element, set the focused element as the container value. This is for the Hds::Copy::Button and to set autoRefresh=true so content renders https://hds-website-hashicorp.vercel.app/components/copy/button?tab=code
|
||||
* @param {string} [container] - **REQUIRED if rendering within a modal** Selector string or element object of containing element, set the focused element as the container value. This is for the Hds::Copy::Button and to set `autoRefresh=true` so content renders https://hds-website-hashicorp.vercel.app/components/copy/button?tab=code
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -12,9 +12,8 @@ import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||
* KeyValueHeader components show breadcrumbs for secret engines.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
<KeyValueHeader @path="vault.cluster.secrets.backend.show" @mode={{this.mode}} @root={{@root}}/>
|
||||
* ```
|
||||
* <KeyValueHeader @path="vault.cluster.secrets.backend.show" @mode={{this.mode}}/>
|
||||
*
|
||||
* @param {string} [mode=null] - Used to set the currentPath.
|
||||
* @param {string} [baseKey=null] - Used to generate the path backward.
|
||||
* @param {string} [path=null] - The fallback path.
|
||||
|
||||
@@ -16,16 +16,11 @@ import KVObject from 'vault/lib/kv-object';
|
||||
* KvObjectEditor components are called in FormFields when the editType on the model is kv. They are used to show a key-value input field.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <KvObjectEditor
|
||||
* @value={{get model valuePath}}
|
||||
* @onChange={{action "setAndBroadcast" valuePath }}
|
||||
* @label="some label"
|
||||
/>
|
||||
* ```
|
||||
* <KvObjectEditor @value={{hash foo="bar"}} @onChange={{log "on change called"}} @label="Label here" />
|
||||
*
|
||||
* @param {string} value - the value is captured from the model.
|
||||
* @param {function} onChange - function that captures the value on change
|
||||
* @param {boolean} [isMasked = false] - when true the <MaskedInput> renders instead of the default <textarea> to input the value portion of the key/value object
|
||||
* @param {boolean} [isMasked = false] - when true the `<MaskedInput>` renders instead of the default `<textarea>` to input the value portion of the key/value object
|
||||
* @param {boolean} [isSingleRow = false] - when true the kv object editor will only show one row and hide the Add button
|
||||
* @param {function} [onKeyUp] - function passed in that handles the dom keyup event. Used for validation on the kv custom metadata.
|
||||
* @param {string} [label] - label displayed over key value inputs
|
||||
|
||||
@@ -16,6 +16,7 @@ import type KvSecretMetadataModel from 'vault/models/kv/metadata';
|
||||
|
||||
/**
|
||||
* @module KvSuggestionInput
|
||||
* @description
|
||||
* Input component that fetches secrets at a provided mount path and displays them as suggestions in a dropdown
|
||||
* As the user types the result set will be filtered providing suggestions for the user to select
|
||||
* After the input debounce wait time (500ms), if the value ends in a slash, secrets will be fetched at that path
|
||||
@@ -24,15 +25,12 @@ import type KvSecretMetadataModel from 'vault/models/kv/metadata';
|
||||
* This allows the user to build a full path to a secret for the provided mount
|
||||
* This is useful for helping the user find deeply nested secrets given the path based policy system
|
||||
* If the user does not have list permission they are still able to enter a path to a secret but will not see suggestions
|
||||
*
|
||||
* Input is disabled when mount path is not provided
|
||||
*
|
||||
* @example
|
||||
* <KvSuggestionInput
|
||||
@label="Select a secret to sync"
|
||||
@subText="Enter the full path to the secret. Suggestions will display below if permitted by policy."
|
||||
@value={{this.secretPath}}
|
||||
@mountPath={{this.mountPath}} // input disabled when mount path is not provided
|
||||
@onChange={{fn (mut this.secretPath)}}
|
||||
/>
|
||||
* <KvSuggestionInput @label="Select a secret to sync" @subText="Enter the full path to the secret. Suggestions will display below if permitted by policy." @value={{this.secretPath}} @mountPath="my-kv/" @onChange={{fn (mut this.secretPath)}} />
|
||||
*
|
||||
* <KvSuggestionInput @label="Select a secret to sync" @subText="Disabled because no mount path provided" @value={{this.secretPath}} @mountPath={{false}} @onChange={{fn (mut this.secretPath)}} />
|
||||
*/
|
||||
|
||||
interface Args {
|
||||
|
||||
@@ -13,16 +13,10 @@ import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||
* LinkedBlock components are linkable divs that yield any content nested within them. They are often used in list views such as when listing the secret engines.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <LinkedBlock
|
||||
* @params={{array 'vault.cluster.secrets.backend.show 'my-secret-path'}}
|
||||
* @queryParams={{hash version=1}}
|
||||
* @class="list-item-row"
|
||||
* data-test-list-item-link
|
||||
* >
|
||||
* // Use any wrapped content here
|
||||
* <LinkedBlock @params={{array "vault.cluster.secrets.backend.show" "my-secret-path"}} class="list-item-row" >
|
||||
* My wrapped content
|
||||
* </LinkedBlock>
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @param {Array} params=null - These are values sent to the router's transitionTo method. First item is route, second is the optional path.
|
||||
* @param {Object} [queryParams=null] - queryParams can be passed via this property. It needs to be an object.
|
||||
|
||||
@@ -11,22 +11,20 @@ import { pluralize } from 'ember-inflector';
|
||||
* `ListView` components are used in conjunction with `ListItem` for rendering a list.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ListView @items={{model}} @itemNoun="role" @paginationRouteName="scope.roles" as |list|>
|
||||
* <ListView @items={{hash meta=(hash currentPage=1 total=1 pageSize=1)}} @itemNoun="role" @paginationRouteName="vault" as |list|>
|
||||
* {{#if list.empty}}
|
||||
* <list.empty @title="No roles here" />
|
||||
* {{else}}
|
||||
* <div>
|
||||
* {{list.item.id}}
|
||||
* my item
|
||||
* </div>
|
||||
* {{/if}}
|
||||
* </ListView>
|
||||
* ```
|
||||
*
|
||||
* @param {array} [items=null] - An Ember array of items (objects) to render as a list. Because it's an Ember array it has properties like length an meta on it.
|
||||
* @param {string} [itemNoun=item] - A noun to use in the empty state of message and title.
|
||||
* @param {string} [message=null] - The message to display within the banner.
|
||||
* @param {string} [paginationRouteName=''] - The link used in the ListPagination component.
|
||||
* @param {string} [paginationRouteName] - The link used in the ListPagination component.
|
||||
* @yields {object} Yields 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.
|
||||
|
||||
@@ -15,20 +15,14 @@ import autosize from 'autosize';
|
||||
* `MaskedInput` components are textarea inputs where the input is hidden. They are used to enter sensitive information like passwords.
|
||||
*
|
||||
* @example
|
||||
* <MaskedInput
|
||||
* @value={{get @model attr.name}}
|
||||
* @allowCopy={{true}}
|
||||
* @allowDownload={{true}}
|
||||
* @onChange={{this.handleChange}}
|
||||
* @onKeyUp={{this.handleKeyUp}}
|
||||
* />
|
||||
* <MaskedInput @value="my secret value" @allowCopy={{true}} @allowDownload={{true}} @onChange={{log "handle change"}} />
|
||||
*
|
||||
* @param value {String} - The value to display in the input.
|
||||
* @param name {String} - The key correlated to the value. Used for the download file name.
|
||||
* @param [onChange=Callback] {Function|action} - Callback triggered on change, sends new value. Must set the value of @value
|
||||
* @param [allowCopy=false] {bool} - Whether or not the input should render with a copy button.
|
||||
* @param [allowDownload=false] {bool} - Renders a download button that prompts a confirmation modal to download the secret value
|
||||
* @param [displayOnly=false] {bool} - Whether or not to display the value as a display only `pre` element or as an input.
|
||||
* @param {string} value - The value to display in the input.
|
||||
* @param {string} name - The key correlated to the value. Used for the download file name.
|
||||
* @param {function} [onChange=Callback] - Callback triggered on change, sends new value. Must set the value of @value
|
||||
* @param {boolean} [allowCopy=false] - Whether or not the input should render with a copy button.
|
||||
* @param {boolean} [allowDownload=false] - Renders a download button that prompts a confirmation modal to download the secret value
|
||||
* @param {boolean} [displayOnly=false] - Whether or not to display the value as a display only `pre` element or as an input.
|
||||
*
|
||||
*/
|
||||
export default class MaskedInputComponent extends Component {
|
||||
|
||||
@@ -9,16 +9,13 @@ import { setComponentTemplate } from '@ember/component';
|
||||
|
||||
/**
|
||||
* @module MessageError
|
||||
* Renders form errors using the <Hds::Alert> component and extracts errors from
|
||||
* Renders form errors using the Hds::Alert component and extracts errors from
|
||||
* a model, passed errorMessage or array of errors and displays each in a separate banner.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <MessageError @model={{model}} />
|
||||
* ```
|
||||
* <MessageError @errorMessage="oh no there is a problem" />
|
||||
*
|
||||
* @param {object} [model=null] - An Ember data model that will be used to bind error states to the internal
|
||||
* `errors` property.
|
||||
* @param {object} [model=null] - An Ember data model that will be used to bind error states to the internal `errors` property.
|
||||
* @param {array} [errors=null] - An array of error strings to show.
|
||||
* @param {string} [errorMessage=null] - An Error string to display.
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,22 @@
|
||||
import Component from '@glimmer/component';
|
||||
import { service } from '@ember/service';
|
||||
|
||||
/**
|
||||
* @module NamespaceReminder
|
||||
* Renders a namespace reminder, typically used when creating a new item.
|
||||
* _The namespace reminder only renders within a namespace, we cannot stub the namespace service here
|
||||
* so manually wrote the component in the **example** below so it renders in docfy_
|
||||
*
|
||||
* @example
|
||||
* <NamespaceReminder @mode="save" @noun="Auth Method" />
|
||||
*
|
||||
* <p class="namespace-reminder" id="namespace-reminder">
|
||||
* This Auth Method will be saved in the <span class="tag">admin/</span>namespace.
|
||||
* </p>
|
||||
*
|
||||
* @param {string} noun - item being created by form
|
||||
* @param {string} [mode=edit] - action happening in form
|
||||
*/
|
||||
export default class NamespaceReminder extends Component {
|
||||
@service namespace;
|
||||
|
||||
|
||||
@@ -19,21 +19,19 @@ import keys from 'core/utils/key-codes';
|
||||
* `NavigateInput` components are used to filter list data.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <NavigateInput @filter={@roleFiltered} @placeholder="placeholder text" urls="{{hash list="vault.cluster.secrets.backend.kubernetes.roles"}}"/>
|
||||
* ```
|
||||
* <NavigateInput @filter={{@roleFiltered}} urls={{hash list="vault.cluster.secrets.backend.kubernetes.roles"}}/>
|
||||
*
|
||||
* @param {String} filter=null - The filtered string.
|
||||
* @param {String} [placeholder="Filter items"] - The message inside the input to indicate what the user should enter into the space.
|
||||
* @param {String} [placeholder=Filter items] - The message inside the input to indicate what the user should enter into the space.
|
||||
* @param {Object} [urls=null] - An object containing list=route url.
|
||||
* @param {Function} [filterFocusDidChange=null] - A function called when the focus changes.
|
||||
* @param {Function} [filterDidChange=null] - A function called when the filter string changes.
|
||||
* @param {Function} [filterMatchesKey=null] - A function used to match to a specific key, such as an Id.
|
||||
* @param {Function} [filterPartialMatch=null] - A function used to filter through a partial match. Such as "oo" of "root".
|
||||
* @param {String} [baseKey=""] - A string to transition by Id.
|
||||
* @param {String} [baseKey] - A string to transition by Id.
|
||||
* @param {Boolean} [shouldNavigateTree=false] - If true, navigate a larger tree, such as when you're navigating leases under access.
|
||||
* @param {String} [mode="secrets"] - Mode which plays into navigation type.
|
||||
* @param {String} [extraNavParams=""] - A string used in route transition when necessary.
|
||||
* @param {String} [mode=secrets] - Mode which plays into navigation type.
|
||||
* @param {String} [extraNavParams] - A string used in route transition when necessary.
|
||||
*/
|
||||
|
||||
const routeFor = function (type, mode, urls) {
|
||||
|
||||
@@ -14,23 +14,25 @@ import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||
* ObjectListInput components are used to render a variable number of text inputs in a single row
|
||||
* with an "Add" button at the end of the row. Clicking 'add' generates a new row of empty inputs.
|
||||
* Each input field is generated by an object in the @objectKeys array. Labels render above each column.
|
||||
* @description
|
||||
* ```
|
||||
* sample object:
|
||||
* {
|
||||
* label: 'Input label', // required key
|
||||
* key: 'attrKey', // required key
|
||||
* placeholder: 'Enter input here'
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ObjectListInput @objectKeys={{this.arrayOfObjects}} @onChange={{this.handleChange}} @inputValue={{this.inputValue}}/>
|
||||
* ```
|
||||
* <ObjectListInput @objectKeys={{hash label="Input label" key="attrKey" placeholder="Enter input here"}} @onChange={{this.handleChange}} @inputValue={{this.inputValue}}/>
|
||||
*
|
||||
* @param {array} objectKeys - an array of objects (sample above), the length determines the number of columns the component renders
|
||||
* @callback onChange - callback triggered when any input changes or when a row is deleted, called with array of objects containing each input's key and value ex: [ { attrKey: 'some input value' } ]
|
||||
* @param {function} onChange - callback triggered when any input changes or when a row is deleted, called with array of objects containing each input's key and value ex: `[ { attrKey: 'some input value' } ]`
|
||||
* @param {string} [inputValue] - an array of objects to pre-fill the component inputs, key name must match objectKey[key]
|
||||
* @param {array} [validationErrors] - an array of validation objects, the index of each object corresponds to the row with an invalid input. each object has a key that matches a key in objectKeys
|
||||
* ex: (the nested object with 'errors' and 'isValid' matches the structure returned by the model validations decorator)
|
||||
* { "attrKey": { "errors": ["Name is required."], "isValid": false } }
|
||||
* `{ "attrKey": { "errors": ["Name is required."], "isValid": false } }`
|
||||
*/
|
||||
|
||||
export default class ObjectListInput extends Component {
|
||||
|
||||
@@ -4,17 +4,13 @@
|
||||
~}}
|
||||
|
||||
<header class="page-header" ...attributes>
|
||||
{{#if this.hasLevel}}
|
||||
{{yield (hash top=(component "page-header-level"))}}
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
{{yield (hash levelLeft=(component "page-header-level"))}}
|
||||
</div>
|
||||
<div class="level-right field is-grouped">
|
||||
{{yield (hash levelRight=(component "page-header-level"))}}
|
||||
</div>
|
||||
{{yield (hash top=(component "page-header-level"))}}
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
{{yield (hash levelLeft=(component "page-header-level"))}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{yield (hash top=(component "page-header-level"))}}
|
||||
{{/if}}
|
||||
<div class="level-right field is-grouped">
|
||||
{{yield (hash levelRight=(component "page-header-level"))}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
|
||||
export default class PageHeader extends Component {
|
||||
get hasLevel() {
|
||||
return this.args.hasLevel === undefined ? true : this.args.hasLevel;
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,8 @@ interface Breadcrumb {
|
||||
* Page::Breadcrumbs components are used to display an array of breadcrumbs at the top of the page.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
|
||||
* ```
|
||||
* <Page::Breadcrumbs @breadcrumbs={{array (hash label="Home" route="vault") (hash label="my-secret")}} />
|
||||
*
|
||||
* @param {array} breadcrumbs - array of Breadcrumb objects, must contain a label key. If no route is provided, crumb is assumed to be the current page
|
||||
*/
|
||||
|
||||
|
||||
@@ -8,15 +8,16 @@ import Component from '@glimmer/component';
|
||||
/**
|
||||
* @module PolicyExample
|
||||
* The PolicyExample component receives a policy type ('acl', 'rgp', or 'egp') and renders a copyable policy example of
|
||||
* that type using the <JsonEditor> component. Inside a modal, the PolicyExample component must be wrapped in a conditional
|
||||
* (example below), otherwise the <JsonEditor> value won't render until it's focused.
|
||||
* that type using the JsonEditor component. Inside a modal, the PolicyExample component must be wrapped in a conditional
|
||||
* (example below), otherwise the JsonEditor value won't render until it's focused.
|
||||
*
|
||||
* @example
|
||||
* <PolicyExample
|
||||
* @policyType={{@model.policyType}}
|
||||
* @container="#search-select-modal"
|
||||
* />
|
||||
* ```
|
||||
* <PolicyExample @policyType="acl" @container="#search-select-modal" />
|
||||
* @example
|
||||
* <PolicyExample @policyType="rgp" />
|
||||
* @example
|
||||
* <PolicyExample @policyType="egp" />
|
||||
*
|
||||
* @param {string} policyType - policy type to decide which template to render; can either be "acl" or "rgp"
|
||||
* @param {string} container - selector for the container the example renders inside, passed to the copy button in JsonEditor
|
||||
*/
|
||||
|
||||
@@ -11,13 +11,18 @@ import { tracked } from '@glimmer/tracking';
|
||||
|
||||
/**
|
||||
* @module ReadMore
|
||||
* @description
|
||||
* ReadMore components are used to wrap long text that we'd like to show as one line initially with the option to expand and read.
|
||||
* Text which is shorter than the surrounding div will not truncate or show the See More button.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ReadMore>My <em>super</em> long text goes in here</ReadMore>
|
||||
* ```
|
||||
* <div style="width:100px;border: solid purple 2px; margin:20px">
|
||||
* <ReadMore>My <em>super</em> long text goes in here.</ReadMore>
|
||||
* </div>
|
||||
*
|
||||
* <div style="width:100px;border: solid purple 2px; margin:20px">
|
||||
* <ReadMore>This text fits!</ReadMore>
|
||||
* </div>
|
||||
*/
|
||||
|
||||
class ReadMoreComponent extends Component {
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
|
||||
/**
|
||||
* @module ReadonlyFormField
|
||||
* ReadonlyFormField components are used to...
|
||||
* ReadonlyFormField components are used to render an attribute that is read only
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ReadonlyFormField @attr={attr} />
|
||||
* ```
|
||||
* <ReadonlyFormField @attr={{hash name="toDo" options=(hash label="To do task" helpText="helpful text")}} @value="Complete!"/>
|
||||
*
|
||||
* @param {object} attr - Should be an attribute from a model exported with expandAttributeMeta
|
||||
* @param {any} value - The value that should be displayed on the input
|
||||
*/
|
||||
|
||||
@@ -16,11 +16,8 @@ import { waitFor } from '@ember/test-waiters';
|
||||
* It is the top level component on routes displaying replication dashboards.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ReplicationPage
|
||||
@model={{cluster}}
|
||||
/>
|
||||
* ```
|
||||
* <ReplicationPage @model={{cluster}}/>
|
||||
*
|
||||
* @param {Object} model=null - An Ember data object that is pulled from the Ember Cluster Model.
|
||||
*/
|
||||
|
||||
|
||||
@@ -14,34 +14,23 @@ import { addToArray } from 'vault/helpers/add-to-array';
|
||||
|
||||
/**
|
||||
* @module SearchSelectWithModal
|
||||
* The `SearchSelectWithModal` is an implementation of the [ember-power-select](https://github.com/cibernox/ember-power-select) used for form elements where options come dynamically from the API.
|
||||
* The SearchSelectWithModal is an implementation of the [ember-power-select](https://github.com/cibernox/ember-power-select) used for form elements where options come dynamically from the API.
|
||||
* It renders a passed template component that parents a form so records can be created inline, via a modal that pops up after clicking 'No results found for "${term}". Click here to create it.' from the dropdown menu.
|
||||
* **!! NOTE: any form passed must be able to receive an @onSave and @onCancel arg so that the modal will close properly. See `oidc/client-form.hbs` that renders a modal for the `oidc-assignment-template.hbs` as an example.
|
||||
* **!! NOTE: any form passed must be able to receive an `@onSave` and `@onCancel` arg so that the modal will close properly. See `oidc/client-form.hbs` that renders a modal for the `oidc-assignment-template.hbs` as an example.
|
||||
* @example
|
||||
* <SearchSelectWithModal
|
||||
* @id="assignments"
|
||||
* @models={{array "oidc/assignment"}}
|
||||
* @label="assignment name"
|
||||
* @subText="Search for an existing assignment, or type a new name to create it."
|
||||
* @inputValue={{map-by "id" @model.assignments}}
|
||||
* @onChange={{this.handleSearchSelect}}
|
||||
* {{! since this is the "limited" radio select option we do not want to include 'allow_all' }}
|
||||
* @excludeOptions={{array "allow_all"}}
|
||||
* @fallbackComponent="string-list"
|
||||
* @modalFormTemplate="modal-form/some-template"
|
||||
* @modalSubtext="Use assignment to specify which Vault entities and groups are allowed to authenticate."
|
||||
* <SearchSelectWithModal @id="assignments" @models={{array "oidc/assignment"}} @label="assignment name" @subText="Search for an existing assignment, or type a new name to create it." @inputValue={{map-by "id" @model.assignments}} @onChange={{this.handleSearchSelect}} @excludeOptions={{array "allow_all"}} @fallbackComponent="string-list" @modalFormTemplate="modal-form/some-template" @modalSubtext="Use assignment to specify which Vault entities and groups are allowed to authenticate."
|
||||
* />
|
||||
*
|
||||
// * component functionality
|
||||
* component functionality
|
||||
* @param {function} onChange - The onchange action for this form field. ** SEE EXAMPLE ** mfa-login-enforcement-form.js (onMethodChange) for example when selecting models from a hasMany relationship
|
||||
* @param {array} [inputValue] - Array of strings corresponding to the input's initial value, e.g. an array of model ids that on edit will appear as selected items below the input
|
||||
* @param {boolean} [shouldRenderName=false] - By default an item's id renders in the dropdown, `true` displays the name with its id in smaller text beside it *NOTE: the boolean flips automatically with 'identity' models
|
||||
* @param {array} [excludeOptions] - array of strings containing model ids to filter from the dropdown (ex: ['allow_all'])
|
||||
|
||||
// * query params for dropdown items
|
||||
* query params for dropdown items
|
||||
* @param {array} models - models to fetch from API. models with varying permissions should be ordered from least restricted to anticipated most restricted (ex. if one model is an enterprise only feature, pass it in last)
|
||||
|
||||
// * template only/display args
|
||||
* template only/display args
|
||||
* @param {string} id - The name of the form field
|
||||
* @param {string} [label] - Label appears above the form field
|
||||
* @param {string} [labelClass] - overwrite default label size (14px) from class="is-label"
|
||||
|
||||
@@ -16,19 +16,9 @@ import { assert } from '@ember/debug';
|
||||
/**
|
||||
* @module SearchSelect
|
||||
* The `SearchSelect` is an implementation of the [ember-power-select](https://github.com/cibernox/ember-power-select) used for form elements where options come dynamically from the API.
|
||||
*
|
||||
* @example
|
||||
* <SearchSelect
|
||||
* @id="policy"
|
||||
* @models={{array "policies/acl"}}
|
||||
* @onChange={{this.onChange}}
|
||||
* @inputValue={{get @model this.valuePath}}
|
||||
* @wildcardLabel="role"
|
||||
* @fallbackComponent="string-list"
|
||||
* @selectLimit={{1}}
|
||||
* @backend={{@model.backend}}
|
||||
* @disallowNewItems={{true}}
|
||||
* class={{if this.validationError "dropdown-has-error-border"}}
|
||||
* />
|
||||
* <SearchSelect @id="policy" @models={{array "policies/acl"}} @onChange={{this.onChange}} @inputValue={{get @model this.valuePath}} @wildcardLabel="role" @fallbackComponent="string-list" @selectLimit={{1}} @backend={{@model.backend}} @disallowNewItems={{true}} class={{if this.validationError "dropdown-has-error-border"}} />
|
||||
*
|
||||
// * component functionality
|
||||
* @param {function} onChange - The onchange action for this form field. ** SEE EXAMPLE ** mfa-login-enforcement-form.js (onMethodChange) for example when selecting models from a hasMany relationship
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <SecretListHeaderTab @displayName='Database' @id='database-2' @path='roles' @label='Roles' @tab='roles'/>
|
||||
* ```
|
||||
*
|
||||
* @param {string} [displayName] - set on options-for-backend this sets a conditional to see if capabilities are being checked
|
||||
* @param {string} [id] - if fetching capabilities used for making the query url. It is the name the user has assigned to the instance of the engine.
|
||||
* @param {string} [path] - set on options-for-backend this tells us the specifics of the URL the query should hit.
|
||||
|
||||
@@ -7,23 +7,15 @@ import Component from '@glimmer/component';
|
||||
|
||||
/**
|
||||
* @module SecretListHeader
|
||||
* SecretListHeader component is breadcrumb, title with icon and menu with tabs component.
|
||||
* SecretListHeader component is breadcrumb, title with icon and menu with tabs component. Hello
|
||||
*
|
||||
* Example is wrapped in back ticks because this component relies on routing and cannot render an isolated sample, so just rendering template sample
|
||||
* @example
|
||||
* ```js
|
||||
* <SecretListHeader
|
||||
@model={{this.model}}
|
||||
@backendCrumb={{hash
|
||||
label=this.model.id
|
||||
text=this.model.id
|
||||
path="vault.cluster.secrets.backend.list-root"
|
||||
model=this.model.id
|
||||
}}
|
||||
/>
|
||||
* ```
|
||||
* <SecretListHeader @isCertTab={{eq this.tab "cert"}} @model={{this.model}} @baseKey={{this.baseKey}} @backendCrumb={{this.backendCrumb}} @filter={{this.filter}} />
|
||||
* ```
|
||||
*
|
||||
* @param {object} model - Model used to pull information about icon and title and backend type for navigation.
|
||||
* @param {string} [baseKey] - Provided for navigation on the breadcrumbs.
|
||||
* @param {object} [backendCrumb] - Includes label, text, path and model ID.
|
||||
*/
|
||||
|
||||
export default class SecretListHeader extends Component {
|
||||
|
||||
@@ -11,19 +11,17 @@ import layout from '../templates/components/select';
|
||||
* Select components are used to render a dropdown.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Select @label='Date Range' @options={{[{ value: 'berry', label: 'Berry' }]}} @onChange={{onChange}}/>
|
||||
* ```
|
||||
* <Select @label='Date Range' @options={{[{ value: 'berry', label: 'Berry' }]}} @onChange={{log "on change"}}/>
|
||||
*
|
||||
* @param {string} [label=null] - The label for the select element.
|
||||
* @param {Array} [options=null] - A list of items that the user will select from. This can be an array of strings or objects.
|
||||
* @param {string} [selectedValue=null] - The currently selected item. Can also be used to set the default selected item. This should correspond to the `value` of one of the `<option>`s.
|
||||
* @param {string} [name = null] - The name of the select, used for the test selector.
|
||||
* @param {string} [valueAttribute = value]- When `options` is an array objects, the key to check for when assigning the option elements value.
|
||||
* @param {string} [labelAttribute = label] - When `options` is an array objects, the key to check for when assigning the option elements' inner text.
|
||||
* @param {boolean} [isInline = false] - Whether or not the select should be displayed as inline-block or block.
|
||||
* @param {boolean} [isFullwidth = false] - Whether or not the select should take up the full width of the parent element.
|
||||
* @param {boolean} [noDefault = false] - shows Select One with empty value as first option
|
||||
* @param {string} [valueAttribute=value]- When `options` is an array objects, the key to check for when assigning the option elements value.
|
||||
* @param {string} [labelAttribute=label] - When `options` is an array objects, the key to check for when assigning the option elements' inner text.
|
||||
* @param {boolean} [isInline=false] - Whether or not the select should be displayed as inline-block or block.
|
||||
* @param {boolean} [isFullwidth=false] - Whether or not the select should take up the full width of the parent element.
|
||||
* @param {boolean} [noDefault=false] - shows Select One with empty value as first option
|
||||
* @param {Func} [onChange] - The action to take once the user has selected an item. This method will be passed the `value` of the select.
|
||||
* @param {string} [ariaLabel] - pass when label is defined elsewhere to ensure the select input has a valid label
|
||||
*/
|
||||
|
||||
@@ -17,9 +17,8 @@ import { removeFromArray } from 'vault/helpers/remove-from-array';
|
||||
* @module StringList
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <StringList @label={label} @onChange={{this.setAndBroadcast}} @inputValue={{this.valuePath}}/>
|
||||
* ```
|
||||
* <StringList @label="My label" @inputValue={{array "one" "two"}} />
|
||||
*
|
||||
* @param {string} label - Text displayed in the header above all the inputs.
|
||||
* @param {function} onChange - Function called when any of the inputs change.
|
||||
* @param {string} inputValue - A string or an array of strings.
|
||||
|
||||
@@ -14,17 +14,12 @@ import { buildWaiter } from '@ember/test-waiters';
|
||||
* that changes the input into a textarea
|
||||
*
|
||||
* @example
|
||||
* <TextFile
|
||||
* @uploadOnly={{true}}
|
||||
* @helpText="help text"
|
||||
* @onChange={{this.handleChange}}
|
||||
* @label="PEM Bundle"
|
||||
* />
|
||||
* <TextFile @uploadOnly={{true}} @helpText="help text" @onChange={{this.handleChange}} @label="PEM Bundle" />
|
||||
*
|
||||
* @param {function} onChange - Callback function to call when the value of the input changes, returns an object in the shape of { value: fileContents, filename: 'some-file.txt' }
|
||||
* @param {bool} [uploadOnly=false] - When true, renders a static file upload input and removes the option to toggle and input plain text
|
||||
* @param {string} [helpText] - Text underneath label.
|
||||
* @param {string} [label='File'] - Text to use as the label for the file input. If none, default of 'File' is rendered
|
||||
* @param {string} [label=File] - Text to use as the label for the file input. If none, default of 'File' is rendered
|
||||
*/
|
||||
|
||||
const waiter = buildWaiter('text-file');
|
||||
|
||||
@@ -10,21 +10,19 @@ import Component from '@glimmer/component';
|
||||
* `ToggleButton` components are used to expand and collapse content with a toggle.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ToggleButton @isOpen={{this.showOptions}} @openLabel="Encrypt Output with PGP" @closedLabel="Encrypt Output with PGP" @onClick={{fn (mut this.showOptions}} />
|
||||
* {{#if showOptions}}
|
||||
* <ToggleButton @isOpen={{this.showOptions}} @openLabel="Show stuff" @closedLabel="Hide the stuff" @onClick={{fn (mut this.showOptions) (not this.showOptions)}} />
|
||||
* {{#if this.showOptions}}
|
||||
* <div>
|
||||
* <p>
|
||||
* I will be toggled!
|
||||
* </p>
|
||||
* </div>
|
||||
* {{/if}}
|
||||
* ```
|
||||
* @callback onClickCallback
|
||||
*
|
||||
* @param {boolean} isOpen - determines whether to show open or closed label
|
||||
* @param {onClickCallback} onClick - fired when button is clicked
|
||||
* @param {string} [openLabel="Hide options"] - The message to display when the toggle is open.
|
||||
* @param {string} [closedLabel="More options"] - The message to display when the toggle is closed.
|
||||
* @param {function} onClick - fired when button is clicked
|
||||
* @param {string} [openLabel=Hide options] - The message to display when the toggle is open.
|
||||
* @param {string} [closedLabel=More options] - The message to display when the toggle is closed.
|
||||
*/
|
||||
export default class ToggleButtonComponent extends Component {
|
||||
get openLabel() {
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
* They are a stylistic alternative to checkboxes, but still use the input[type="checkbox"] under the hood.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Toggle @requiredParam={requiredParam} @optionalParam={optionalParam} @param1={{param1}}/>
|
||||
* ```
|
||||
* <Toggle/>
|
||||
*
|
||||
* @param {function} onChange - onChange is triggered on checkbox change (select, deselect). Must manually mutate checked value
|
||||
* @param {string} name - name is passed along to the form field, as well as to generate the ID of the input & "for" value of the label
|
||||
* @param {boolean} [checked=false] - checked status of the input, and must be passed in and mutated from the parent
|
||||
|
||||
@@ -7,6 +7,28 @@ import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { debounce } from '@ember/runloop';
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @module ToolTip
|
||||
*
|
||||
* @example
|
||||
* <ToolTip @verticalPosition="above" as |T|>
|
||||
* <T.Trigger>
|
||||
* <Icon @name="check-circle" class="has-text-success" />
|
||||
* </T.Trigger>
|
||||
* <T.Content @defaultClass="tool-tip">
|
||||
* <div class="box">
|
||||
* My tooltip text
|
||||
* </div>
|
||||
* </T.Content>
|
||||
* </ToolTip>
|
||||
*
|
||||
* * Use HDS tooltip instead
|
||||
|
||||
* @param {string} [verticalPosition] - vertical position specification (above, below)
|
||||
* @param {string} [horizontalPosition] - horizontal position specification (center, auto-right)
|
||||
*
|
||||
*/
|
||||
export default class ToolTipComponent extends Component {
|
||||
get delay() {
|
||||
return this.args.delay || 200;
|
||||
|
||||
@@ -10,15 +10,13 @@ import Component from '@glimmer/component';
|
||||
* It should only be used inside of `Toolbar`.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Toolbar>
|
||||
* <ToolbarActions>
|
||||
* <ToolbarLink @route="vault.cluster.policies.create" @type="add" @disabled={{true}} @disabledTooltip="This link is disabled">
|
||||
* <ToolbarLink @route="vault" @type="add" @disabled={{true}} @disabledTooltip="This link is disabled">
|
||||
* Create policy
|
||||
* </ToolbarLink>
|
||||
* </ToolbarActions>
|
||||
* </Toolbar>
|
||||
* ```
|
||||
*
|
||||
* @param {string} route - route to pass to LinkTo
|
||||
* @param {Model} model - model to pass to LinkTo
|
||||
|
||||
@@ -12,18 +12,17 @@
|
||||
* - recalculates the time when the unit is changed by the user (eg 60s -> 1m)
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <TtlPicker @onChange={{this.handleChange}} @initialEnabled={{@model.myAttribute}} @initialValue={{@model.myAttribute}}/>
|
||||
* ```
|
||||
* @param onChange {Function} - This function will be passed a TTL object, which includes enabled{bool}, seconds{number}, timeString{string}, goSafeTimeString{string}.
|
||||
* @param initialEnabled=false {Boolean} - Set this value if you want the toggle on when component is mounted
|
||||
* @param label="Time to live (TTL)" {String} - Label is the main label that lives next to the toggle. Yielded values will replace the label
|
||||
* @param labelDisabled=Label to display when TTL is toggled off
|
||||
* @param helperTextEnabled="" {String} - This helper text is shown under the label when the toggle is switched on
|
||||
* @param helperTextDisabled="" {String} - This helper text is shown under the label when the toggle is switched off
|
||||
* @param initialValue=null {string} - InitialValue is the duration value which will be shown when the component is loaded. If it can't be parsed, will default to 0.
|
||||
* @param changeOnInit=false {boolean} - if true, calls the onChange hook when component is initialized
|
||||
* @param hideToggle=false {Boolean} - set this value if you'd like to hide the toggle and just leverage the input field
|
||||
*
|
||||
* @param {function} onChange - This function will be passed a TTL object, which includes enabled{bool}, seconds{number}, timeString{string}, goSafeTimeString{string}.
|
||||
* @param {boolean} initialEnabled=false - Set this value if you want the toggle on when component is mounted
|
||||
* @param {string} label=Time to live (TTL) - Label is the main label that lives next to the toggle. Yielded values will replace the label
|
||||
* @param {string} labelDisabled=Label to display when TTL is toggled off
|
||||
* @param {string} helperTextEnabled - This helper text is shown under the label when the toggle is switched on
|
||||
* @param {string} helperTextDisabled - This helper text is shown under the label when the toggle is switched off
|
||||
* @param {string} initialValue=null - InitialValue is the duration value which will be shown when the component is loaded. If it can't be parsed, will default to 0.
|
||||
* @param {boolean} changeOnInit=false - if true, calls the onChange hook when component is initialized
|
||||
* @param {boolean} hideToggle=false - set this value if you'd like to hide the toggle and just leverage the input field
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
/**
|
||||
* @module UpgradePage
|
||||
*
|
||||
* @example
|
||||
* <UpgradePage @title="Namespaces" @minimumEdition="Vault Enterprise Pro" />
|
||||
*
|
||||
*/
|
||||
|
||||
export default class UpgradePage extends Component {
|
||||
get minimumEdition() {
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
"scripts": {
|
||||
"build": "ember build --environment=production && cp metadata.json ../http/web_ui/metadata.json",
|
||||
"build:dev": "ember build",
|
||||
"docs": "sh scripts/generate-docs.sh",
|
||||
"docfy-md": "node scripts/docfy-md.js",
|
||||
"lint:css": "stylelint \"**/*.css\"",
|
||||
"lint:css:fix": "yarn lint:css --fix",
|
||||
"lint:fix": "concurrently -c \"auto\" -n lint: \"yarn:lint:*:fix\"",
|
||||
@@ -53,11 +55,16 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.24.6",
|
||||
"@babel/core": "^7.23.2",
|
||||
"@babel/eslint-parser": "^7.22.15",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.23.2",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
|
||||
"@babel/plugin-transform-block-scoping": "^7.12.1",
|
||||
"@babel/preset-env": "^7.24.6",
|
||||
"@babel/preset-typescript": "^7.24.6",
|
||||
"@docfy/ember": "^0.8.5",
|
||||
"@ember-data/legacy-compat": "~4.12.4",
|
||||
"@ember/legacy-built-in-components": "^0.4.1",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
@@ -150,6 +157,8 @@
|
||||
"eslint-plugin-qunit": "^8.0.1",
|
||||
"filesize": "^4.2.1",
|
||||
"flat": "^6.0.1",
|
||||
"jsdoc-babel": "^0.5.0",
|
||||
"jsdoc-to-markdown": "^8.0.1",
|
||||
"jsondiffpatch": "^0.4.1",
|
||||
"jsonlint": "^1.6.3",
|
||||
"lint-staged": "^10.5.1",
|
||||
@@ -173,7 +182,7 @@
|
||||
"swagger-ui-dist": "^5.9.0",
|
||||
"text-encoder-lite": "2.0.0",
|
||||
"tracked-built-ins": "^3.3.0",
|
||||
"typescript": "^4.9.5",
|
||||
"typescript": "^5.4.5",
|
||||
"walk-sync": "^2.0.2",
|
||||
"webpack": "5.89.0"
|
||||
},
|
||||
|
||||
54
ui/scripts/docfy-md.js
Normal file
54
ui/scripts/docfy-md.js
Normal file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
/*
|
||||
run from the ui directory:
|
||||
yarn docfy-md some-component
|
||||
|
||||
or if the docs are for a component in an in-repo-addon or an engine:
|
||||
yarn docfy-md some-component name-of-engine
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const jsdoc2md = require('jsdoc-to-markdown');
|
||||
|
||||
// the fullFilepath arg will override the assumed inputFile which is built using the addonOrEngine arg
|
||||
const [nameOrFile, addonOrEngine, fullFilepath] = process.argv.slice(2);
|
||||
|
||||
const isFile = nameOrFile.includes('.');
|
||||
const name = isFile ? nameOrFile?.split('.')[0] : nameOrFile; // can pass component-name or component-name.js
|
||||
const path = isFile ? nameOrFile : `${nameOrFile}.js`; // default to js
|
||||
|
||||
const inputFile = addonOrEngine ? `lib/${addonOrEngine}/addon/components/${path}` : `app/components/${path}`;
|
||||
const outputFile = `docs/components/${name}.md`;
|
||||
|
||||
const outputFormat = `
|
||||
{{#module}}
|
||||
# {{name}}
|
||||
{{>body}}
|
||||
{{/module}}
|
||||
`;
|
||||
|
||||
const options = {
|
||||
files: fullFilepath || inputFile,
|
||||
'example-lang': 'hbs preview-template',
|
||||
configure: './jsdoc2md.json',
|
||||
template: outputFormat,
|
||||
};
|
||||
|
||||
try {
|
||||
const md = jsdoc2md.renderSync(options);
|
||||
// for some reason components without a jsdoc @module doesn't throw, so throw manually
|
||||
if (md.includes('ERROR')) throw `${md} (there is probably no jsdoc for this component)`;
|
||||
fs.writeFileSync(outputFile, md);
|
||||
console.log(`✅ ${name}`);
|
||||
} catch (error) {
|
||||
console.log(`❌ ${name}`);
|
||||
console.log(error);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ const testHelper = require('./test-helper');
|
||||
console.log('VAULT_ADDR=' + vaultAddr);
|
||||
|
||||
try {
|
||||
const testArgs = ['test', '-c', 'testem.enos.js'];
|
||||
const testArgs = ['test', '-c', 'scripts/testem.enos.js'];
|
||||
|
||||
if (process.env.TEST_FILTER && process.env.TEST_FILTER.length > 0) {
|
||||
testArgs.push('-f=' + process.env.TEST_FILTER);
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// run this script via yarn in the ui directory:
|
||||
// yarn gen-story-md some-component
|
||||
//
|
||||
// or if the story is for a component in an in-repo-addon or an engine:
|
||||
// yarn gen-story-md some-component name-of-engine
|
||||
|
||||
const fs = require('fs');
|
||||
const jsdoc2md = require('jsdoc-to-markdown');
|
||||
var args = process.argv.slice(2);
|
||||
const name = args[0];
|
||||
const addonOrEngine = args[1];
|
||||
const inputFile = addonOrEngine
|
||||
? `lib/${addonOrEngine}/addon/components/${name}.js`
|
||||
: `app/components/${name}.js`;
|
||||
const outputFile = addonOrEngine ? `lib/${addonOrEngine}/stories/${name}.md` : `stories/${name}.md`;
|
||||
|
||||
const component = name
|
||||
.split('-')
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join('');
|
||||
const options = {
|
||||
files: inputFile,
|
||||
template: fs.readFileSync('./lib/story-md.hbs', 'utf8'),
|
||||
'example-lang': 'js',
|
||||
};
|
||||
let md = jsdoc2md.renderSync(options);
|
||||
|
||||
const pageBreakIndex = md.lastIndexOf('---'); //this is our last page break
|
||||
|
||||
const seeLinks = `**See**
|
||||
- [Uses of ${component}](https://github.com/hashicorp/vault/search?l=Handlebars&q=${component}+OR+${name})
|
||||
- [${component} Source Code](https://github.com/hashicorp/vault/blob/main/ui/${inputFile})
|
||||
`;
|
||||
const generatedWarning = `<!--THIS FILE IS AUTO GENERATED. This file is generated from JSDoc comments in ${inputFile}. To make changes, first edit that file and run "yarn gen-story-md ${name}" to re-generate the content.-->
|
||||
`;
|
||||
md = generatedWarning + md.slice(0, pageBreakIndex) + seeLinks + md.slice(pageBreakIndex);
|
||||
|
||||
fs.writeFileSync(outputFile, md);
|
||||
19
ui/scripts/generate-docs.sh
Normal file
19
ui/scripts/generate-docs.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
echo "Generating markdown files for components in core addon..."
|
||||
|
||||
# iterate over every .ts and .js file in core/addon/components (including nested files)
|
||||
# skip .hbs files and shamir/ directory
|
||||
find "./lib/core/addon/components" -type f ! -name "*.hbs" -not -path "*/shamir*" -print0 | while IFS= read -r -d '' file; do
|
||||
component=`eval "echo $file | cut -d/ -f6"`;
|
||||
|
||||
# skip replication components
|
||||
if [[ "$component" == replication* ]]; then
|
||||
echo "🔃 skipping $component"
|
||||
continue
|
||||
fi
|
||||
|
||||
yarn docfy-md $component core $file
|
||||
done
|
||||
2171
ui/yarn.lock
2171
ui/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user