UI - Vault API explorer engine (#7044)
* open-api-explorer engine with embedded swagger-ui * move swagger config to a component, rely directly on swagger-ui * filter operations by endpoint, hook up filter to query param, add namespace handling * fix namespace handling * update ember-engines so that we can app.import in a lazy engine * use engine's included hook to move swagger-ui to engine-vendor.* files * show flash message about this being a live vault server * show a namespace reminder and override some styles from swagger-ui * switch filter to use includes instead of startsWith * move flash-message to alert-banner and fix namespace reminder with a block * adds explore web-cli command to navigate to the api-explorer engine * allow passing a preformatted string to flash messages * add multi-line flash-message to api explorer * invert control and trigger events on react app so we can control the layout more and use our components * tweak styling some more and adjust message on the flash * change web cli command from 'explore' to 'api' * shorten namespace warning * fix console * fix comments
This commit is contained in:
parent
9baf59dcdc
commit
311cc49c61
|
@ -14,6 +14,11 @@ App = Application.extend({
|
|||
podModulePrefix: config.podModulePrefix,
|
||||
Resolver,
|
||||
engines: {
|
||||
openApiExplorer: {
|
||||
dependencies: {
|
||||
services: ['auth', 'flash-messages', 'namespace', 'router', 'version'],
|
||||
},
|
||||
},
|
||||
replication: {
|
||||
dependencies: {
|
||||
services: [
|
||||
|
|
|
@ -45,13 +45,13 @@ export default Component.extend({
|
|||
let serviceArgs;
|
||||
|
||||
if (
|
||||
executeUICommand(
|
||||
command,
|
||||
args => this.logAndOutput(args),
|
||||
args => service.clearLog(args),
|
||||
() => this.toggleProperty('isFullscreen'),
|
||||
() => this.get('refreshRoute').perform()
|
||||
)
|
||||
executeUICommand(command, args => this.logAndOutput(args), {
|
||||
api: () => this.routeToExplore.perform(command),
|
||||
clearall: () => service.clearLog(true),
|
||||
clear: () => service.clearLog(),
|
||||
fullscreen: () => this.toggleProperty('isFullscreen'),
|
||||
refresh: () => this.refreshRoute.perform(),
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -104,6 +104,29 @@ export default Component.extend({
|
|||
}
|
||||
}),
|
||||
|
||||
routeToExplore: task(function*(command) {
|
||||
let filter = command.replace('api', '').trim();
|
||||
try {
|
||||
yield this.router.transitionTo('vault.cluster.open-api-explorer.index', {
|
||||
queryParams: { filter },
|
||||
});
|
||||
let content =
|
||||
'Welcome to the Vault API explorer! \nYou can search for endpoints, see what parameters they accept, and even execute requests with your current token.';
|
||||
if (filter) {
|
||||
content = `Welcome to the Vault API explorer! \nWe've filtered the list of endpoints for '${filter}'.`;
|
||||
}
|
||||
this.logAndOutput(null, {
|
||||
type: 'success',
|
||||
content,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logAndOutput(null, {
|
||||
type: 'error',
|
||||
content: 'There was a problem navigating to the api explorer.',
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
shiftCommandIndex(keyCode) {
|
||||
this.get('console').shiftCommandIndex(keyCode, val => {
|
||||
this.set('inputValue', val);
|
||||
|
|
|
@ -2,7 +2,7 @@ import keys from 'vault/lib/keycodes';
|
|||
import argTokenizer from 'yargs-parser/lib/tokenize-arg-string.js';
|
||||
|
||||
const supportedCommands = ['read', 'write', 'list', 'delete'];
|
||||
const uiCommands = ['clearall', 'clear', 'fullscreen', 'refresh'];
|
||||
const uiCommands = ['api', 'clearall', 'clear', 'fullscreen', 'refresh'];
|
||||
|
||||
export function extractDataAndFlags(data, flags) {
|
||||
return data.concat(flags).reduce(
|
||||
|
@ -32,26 +32,15 @@ export function extractDataAndFlags(data, flags) {
|
|||
);
|
||||
}
|
||||
|
||||
export function executeUICommand(command, logAndOutput, clearLog, toggleFullscreen, refreshFn) {
|
||||
const isUICommand = uiCommands.includes(command);
|
||||
export function executeUICommand(command, logAndOutput, commandFns) {
|
||||
let cmd = command.startsWith('api') ? 'api' : command;
|
||||
let isUICommand = uiCommands.includes(cmd);
|
||||
if (isUICommand) {
|
||||
logAndOutput(command);
|
||||
}
|
||||
switch (command) {
|
||||
case 'clearall':
|
||||
clearLog(true);
|
||||
break;
|
||||
case 'clear':
|
||||
clearLog();
|
||||
break;
|
||||
case 'fullscreen':
|
||||
toggleFullscreen();
|
||||
break;
|
||||
case 'refresh':
|
||||
refreshFn();
|
||||
break;
|
||||
if (typeof commandFns[cmd] === 'function') {
|
||||
commandFns[cmd]();
|
||||
}
|
||||
|
||||
return isUICommand;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import DS from 'ember-data';
|
||||
import { computed } from '@ember/object';
|
||||
import parseURL from 'vault/utils/parse-url';
|
||||
import parseURL from 'core/utils/parse-url';
|
||||
const { attr } = DS;
|
||||
|
||||
const DOMAIN_STRINGS = {
|
||||
|
|
|
@ -13,6 +13,7 @@ Router.map(function() {
|
|||
this.route('auth');
|
||||
this.route('init');
|
||||
this.route('logout');
|
||||
this.mount('open-api-explorer', { path: '/api-explorer' });
|
||||
this.route('license');
|
||||
this.route('requests', { path: '/metrics/requests' });
|
||||
this.route('settings', function() {
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
border: 0;
|
||||
margin-top: $spacing-xxs;
|
||||
}
|
||||
.message-body.pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $size-8;
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
{{type.text}}
|
||||
</div>
|
||||
{{#if message}}
|
||||
<p class="message-body" data-test-flash-message-body="true">
|
||||
{{message}}
|
||||
</p>
|
||||
<p class="message-body {{if @isPreformatted 'pre'}}" data-test-flash-message-body="true">{{message}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,9 +9,10 @@ Commands:
|
|||
list List data or secrets
|
||||
|
||||
Web CLI Commands:
|
||||
fullscreen Toggle fullscreen display
|
||||
api Navigate to the Vault API explorer. Use 'api [filter]' to prefilter the list.
|
||||
clear Clear output from the log
|
||||
clearall Clear output and command history
|
||||
fullscreen Toggle fullscreen display
|
||||
refresh Refresh the data on the current screen under the CLI window
|
||||
</pre>
|
||||
</div>
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
{{#if flash.componentName}}
|
||||
{{component flash.componentName content=flash.content}}
|
||||
{{else}}
|
||||
<AlertPopup @type={{message-types flash.type}} @message={{flash.message}} @close={{close}}/>
|
||||
<AlertPopup @type={{message-types flash.type}} @message={{flash.message}} @close={{close}} @isPreformatted={{flash.preformatted}} />
|
||||
{{/if}}
|
||||
{{/flash-message}}
|
||||
{{/each}}
|
||||
|
|
|
@ -23,6 +23,7 @@ module.exports = function(environment) {
|
|||
POLLING_URLS: ['sys/health', 'sys/replication/status', 'sys/seal-status'],
|
||||
// endpoints that UI uses to determine the cluster state
|
||||
// calls to these endpoints will always go to the root namespace
|
||||
// these also need to be updated in the open-api-explorer engine
|
||||
NAMESPACE_ROOT_URLS: ['sys/health', 'sys/seal-status', 'sys/license/features'],
|
||||
// number of records to show on a single page by default - this is used by the client-side pagination
|
||||
DEFAULT_PAGE_SIZE: 100,
|
||||
|
|
|
@ -80,6 +80,7 @@ module.exports = function(defaults) {
|
|||
|
||||
app.import('node_modules/@hashicorp/structure-icons/dist/loading.css');
|
||||
app.import('node_modules/@hashicorp/structure-icons/dist/run.css');
|
||||
|
||||
// Use `app.import` to add additional libraries to the generated
|
||||
// output files.
|
||||
//
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
{{#if showMessage}}
|
||||
<p class="namespace-reminder">
|
||||
This {{noun}} will be {{modeVerb}} in the <span class="tag">{{namespace.path}}/</span>namespace.
|
||||
</p>
|
||||
{{#if (has-block)}}
|
||||
<p class="namespace-reminder">
|
||||
{{yield (hash namespace=namespace)}}
|
||||
</p>
|
||||
{{else}}
|
||||
<p class="namespace-reminder">
|
||||
This {{noun}} will be {{modeVerb}} in the <span class="tag">{{namespace.path}}/</span>namespace.
|
||||
</p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
import Component from '@ember/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import parseURL from 'core/utils/parse-url';
|
||||
import config from 'open-api-explorer/config/environment';
|
||||
import Swag from 'swagger-ui-dist';
|
||||
|
||||
const { SwaggerUIBundle } = Swag;
|
||||
const { APP } = config;
|
||||
|
||||
const SearchFilterPlugin = () => {
|
||||
return {
|
||||
fn: {
|
||||
opsFilter: (taggedOps, phrase) => {
|
||||
// map over the options and filter out operations where the path doesn't match what's typed
|
||||
return (
|
||||
taggedOps
|
||||
.map(tagObj => {
|
||||
let operations = tagObj.get('operations').filter(operationObj => {
|
||||
return operationObj.get('path').includes(phrase);
|
||||
});
|
||||
return tagObj.set('operations', operations);
|
||||
})
|
||||
// then traverse again and remove the top level item if there are no operations left after filtering
|
||||
.filter(tagObj => !!tagObj.get('operations').size)
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const CONFIG = (componentInstance, initialFilter) => {
|
||||
return {
|
||||
dom_id: `#${componentInstance.elementId}-swagger`,
|
||||
url: '/v1/sys/internal/specs/openapi',
|
||||
deepLinking: false,
|
||||
presets: [SwaggerUIBundle.presets.apis],
|
||||
plugins: [SwaggerUIBundle.plugins.DownloadUrl, SearchFilterPlugin],
|
||||
// 'list' expands tags, but not operations
|
||||
docExpansion: 'list',
|
||||
operationsSorter: 'alpha',
|
||||
filter: initialFilter || true,
|
||||
// this makes sure we show the x-vault- options
|
||||
showExtensions: true,
|
||||
// we don't have any models defined currently
|
||||
defaultModelsExpandDepth: -1,
|
||||
defaultModelExpandDepth: 1,
|
||||
requestInterceptor: req => {
|
||||
// we need to add vault authorization header
|
||||
// and namepace headers for things to work properly
|
||||
req.headers['X-Vault-Token'] = componentInstance.auth.currentToken;
|
||||
|
||||
let namespace = componentInstance.namespaceService.path;
|
||||
if (namespace && !APP.NAMESPACE_ROOT_URLS.some(str => req.url.includes(str))) {
|
||||
req.headers['X-Vault-Namespace'] = namespace;
|
||||
}
|
||||
// we want to link to the right JSON in swagger UI so
|
||||
// it's already been pre-pended
|
||||
if (!req.loadSpec) {
|
||||
let { protocol, host, pathname } = parseURL(req.url);
|
||||
//paths in the spec don't have /v1 in them, so we need to add that here
|
||||
// http(s): vlt.io:4200 /sys/mounts
|
||||
req.url = `${protocol}//${host}/v1${pathname}`;
|
||||
}
|
||||
return req;
|
||||
},
|
||||
onComplete: () => {
|
||||
componentInstance.set('swaggerLoading', false);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Component.extend({
|
||||
auth: service(),
|
||||
namespaceService: service('namespace'),
|
||||
initialFilter: null,
|
||||
onFilterChange() {},
|
||||
swaggerLoading: true,
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
// trim any initial slashes
|
||||
let initialFilter = this.initialFilter.replace(/^(\/)+/, '');
|
||||
SwaggerUIBundle(CONFIG(this, initialFilter));
|
||||
},
|
||||
|
||||
actions: {
|
||||
// sets the filter so the query param is updated so we get sharable URLs
|
||||
updateFilter(e) {
|
||||
this.onFilterChange(e.target.value || '');
|
||||
},
|
||||
proxyEvent(e) {
|
||||
let swaggerInput = this.element.querySelector('.operation-filter-input');
|
||||
// if this breaks because of a react upgrade,
|
||||
// change this to
|
||||
//let originalSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
|
||||
//originalSetter.call(swaggerInput, e.target.value);
|
||||
// see post on triggering react events externally for an explanation of
|
||||
// why this works: https://stackoverflow.com/a/46012210
|
||||
let evt = new Event('input', { bubbles: true });
|
||||
evt.simulated = true;
|
||||
swaggerInput.value = e.target.value.replace(/^(\/)+/, '');
|
||||
swaggerInput.dispatchEvent(evt);
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
import Controller from '@ember/controller';
|
||||
|
||||
export default Controller.extend({
|
||||
queryParams: ['filter'],
|
||||
filter: '',
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
import Engine from 'ember-engines/engine';
|
||||
import loadInitializers from 'ember-load-initializers';
|
||||
import Resolver from './resolver';
|
||||
import config from './config/environment';
|
||||
|
||||
const { modulePrefix } = config;
|
||||
/* eslint-disable ember/avoid-leaking-state-in-ember-objects */
|
||||
const Eng = Engine.extend({
|
||||
modulePrefix,
|
||||
Resolver,
|
||||
dependencies: {
|
||||
services: ['auth', 'flash-messages', 'namespace', 'router', 'version'],
|
||||
},
|
||||
});
|
||||
|
||||
loadInitializers(Eng, modulePrefix);
|
||||
|
||||
export default Eng;
|
|
@ -0,0 +1,3 @@
|
|||
import Resolver from 'ember-resolver';
|
||||
|
||||
export default Resolver;
|
|
@ -0,0 +1,5 @@
|
|||
import buildRoutes from 'ember-engines/routes';
|
||||
|
||||
export default buildRoutes(function() {
|
||||
// Define your engine's route map here
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default Route.extend({
|
||||
flashMessages: service(),
|
||||
// without an empty model hook here, ember likes to use the parent model, and then things get weird with
|
||||
// query params, so here we're no-op'ing the model hook
|
||||
model() {},
|
||||
afterModel() {
|
||||
let warning = `The "Try it out" functionality in this API explorer will make requests to this Vault server on your behalf.
|
||||
|
||||
IF YOUR TOKEN HAS THE PROPER CAPABILITIES, THIS WILL CREATE AND DELETE ITEMS ON THE VAULT SERVER.
|
||||
|
||||
Your token will also be shown on the screen in the example curl command output.`;
|
||||
this.flashMessages.warning(warning, {
|
||||
sticky: true,
|
||||
preformatted: true,
|
||||
});
|
||||
},
|
||||
});
|
|
@ -0,0 +1,159 @@
|
|||
/*THIS FILE LOADS AFTER THE SWAGGER-UI CSS, SO WE'LL USE IT TO OVERRIDE STYLES */
|
||||
|
||||
|
||||
|
||||
.swagger-ui .wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.swagger-ui .info {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
/*hide the swagger-ui headers*/
|
||||
.swagger-ui .filter-container,
|
||||
.swagger-ui .information-container.wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*some general de-rounding and removing backgrounds and drop shadows*/
|
||||
.swagger-ui .btn {
|
||||
border-width: 1px;
|
||||
box-shadow: none;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock {
|
||||
background: none;
|
||||
border-width: 1px;
|
||||
border-radius: 2px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
/*START: customize method, path, description so that it's formatted like this:*/
|
||||
/* {method} {path/to/api} */
|
||||
/* {A lengthy description goes here} */
|
||||
.swagger-ui .opblock .opblock-summary,
|
||||
.swagger-ui .opblock .opblock-summary-description {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock .opblock-summary {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock .opblock-summary-description {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock .opblock-summary-method,
|
||||
.swagger-ui .opblock .opblock-summary-path{
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock .opblock-summary-method {
|
||||
border-radius: 1px;
|
||||
min-width: auto;
|
||||
text-align: left;
|
||||
font-size: 10px;
|
||||
box-shadow: 0 0 0 1px currentColor;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
padding: 0 2px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
/*END: customize method, path, description*/
|
||||
|
||||
/*START: make tags look like list items */
|
||||
.swagger-ui .opblock-tag{
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock-tag-section .opblock-tag {
|
||||
color: #0a0a0a;
|
||||
font-weight: 600 !important;
|
||||
font-size: 1rem !important;
|
||||
transition: box-shadow 150ms, margin 150ms, padding 150ms;
|
||||
will-change: box-shadow, margin, padding;
|
||||
background-color: white;
|
||||
border-radius: 0;
|
||||
padding: 1.25rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock-tag:hover,
|
||||
.swagger-ui .opblock-tag:focus,
|
||||
.swagger-ui .opblock-tag:active {
|
||||
margin-left: -0.75rem !important;
|
||||
margin-right: -0.75rem !important;
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 0 -1px #BAC1CC, 0 -2px 0 -1px #BAC1CC, 0 0 0 1px #BAC1CC, 0 8px 4px -4px rgba(10, 10, 10, 0.1), 0 6px 8px -2px rgba(10, 10, 10, 0.05);
|
||||
}
|
||||
|
||||
/*shrink the size of the arrows*/
|
||||
.swagger-ui .expand-methods svg, .swagger-ui .expand-operation svg {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
/*END: make tags look like list items */
|
||||
|
||||
|
||||
/*operation box - GET (blue) */
|
||||
.swagger-ui .opblock.opblock-get {
|
||||
background: #f5f8ff;
|
||||
border: 1px solid #bfd4ff;
|
||||
}
|
||||
|
||||
/*operation label*/
|
||||
.swagger-ui .opblock.opblock-get .opblock-summary-method {
|
||||
color: #1563ff;
|
||||
background: none;
|
||||
}
|
||||
/*and expanded tab highlight */
|
||||
.swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span::after {
|
||||
background: #1563ff;
|
||||
}
|
||||
|
||||
|
||||
/*operation box - POST (green) */
|
||||
.swagger-ui .opblock.opblock-post {
|
||||
background: #fafdfa;
|
||||
border: 1px solid #c6e9c9;
|
||||
}
|
||||
.swagger-ui .opblock.opblock-post .opblock-summary-method {
|
||||
color: #2eb039;
|
||||
background: none;
|
||||
}
|
||||
.swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span::after {
|
||||
background: #2eb039;
|
||||
}
|
||||
|
||||
/*operation box - POST (red) */
|
||||
.swagger-ui .opblock.opblock-delete {
|
||||
background: #fdfafb;
|
||||
border: 1px solid #f9ecee;
|
||||
}
|
||||
.swagger-ui .opblock.opblock-delete .opblock-summary-method {
|
||||
color: #c73445;
|
||||
background: none;
|
||||
}
|
||||
.swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span::after {
|
||||
background: #c73445;
|
||||
}
|
||||
|
||||
/*remove "LOADING" from initial loading spinner*/
|
||||
.swagger-ui .loading-container .loading::after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
/*add text about requests to a live vault server*/
|
||||
.swagger-ui .btn.execute::after {
|
||||
content: " - send a request with your token to Vault."
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{{outlet}}
|
|
@ -0,0 +1,44 @@
|
|||
<PageHeader as |p|>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
<Icon
|
||||
@glyph="code"
|
||||
@size="l"
|
||||
class="has-text-grey-light"
|
||||
/>
|
||||
Vault API explorer
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
</PageHeader>
|
||||
<Toolbar>
|
||||
<ToolbarFilters>
|
||||
<div class="field is-marginless">
|
||||
<p class="control has-icons-left">
|
||||
<input
|
||||
oninput={{queue (action "updateFilter") (action "proxyEvent")}}
|
||||
value={{@initialFilter}}
|
||||
disabled={{this.swaggerLoading}}
|
||||
class="filter input"
|
||||
placeholder="Filter ops by path"
|
||||
/>
|
||||
<Icon
|
||||
@glyph="search"
|
||||
@size="l"
|
||||
class="search-icon has-text-grey-light"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<AlertInline
|
||||
@type="info"
|
||||
@message="All API paths are prefixed with /v1/"
|
||||
class="is-marginless input-hint"
|
||||
/>
|
||||
</ToolbarFilters>
|
||||
</Toolbar>
|
||||
|
||||
<div class="box is-fullwidth is-sideless">
|
||||
<NamespaceReminder as |R|>
|
||||
Requests use the header <code>X-Vault-Namespace: {{R.namespace.path}}</code>. You can also use <code>{{R.namespace.path}}</code> as an API prefix. See <DocLink @path="/api/overview#namespaces">docs</DocLink> for examples.
|
||||
</NamespaceReminder>
|
||||
<div id="{{this.elementId}}-swagger"></div>
|
||||
</div>
|
|
@ -0,0 +1,4 @@
|
|||
<SwaggerUi
|
||||
@onFilterChange={{action (mut this.filter)}}
|
||||
@initialFilter={{this.filter}}
|
||||
/>
|
|
@ -0,0 +1,14 @@
|
|||
/* eslint-env node */
|
||||
'use strict';
|
||||
|
||||
module.exports = function(environment) {
|
||||
let ENV = {
|
||||
modulePrefix: 'open-api-explorer',
|
||||
environment,
|
||||
APP: {
|
||||
NAMESPACE_ROOT_URLS: ['sys/health', 'sys/seal-status', 'sys/license/features'],
|
||||
},
|
||||
};
|
||||
|
||||
return ENV;
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
/* eslint-env node */
|
||||
/* eslint-disable ember/avoid-leaking-state-in-ember-objects */
|
||||
'use strict';
|
||||
|
||||
const EngineAddon = require('ember-engines/lib/engine-addon');
|
||||
|
||||
module.exports = EngineAddon.extend({
|
||||
name: 'open-api-explorer',
|
||||
|
||||
included() {
|
||||
this._super.included && this._super.included.apply(this, arguments);
|
||||
// we want to lazy load these deps, importing them here will result in them being added to the
|
||||
// engine-vendor files that will be lazy loaded with the engine
|
||||
this.import('node_modules/swagger-ui-dist/swagger-ui-bundle.js');
|
||||
this.import('node_modules/swagger-ui-dist/swagger-ui.css');
|
||||
},
|
||||
|
||||
lazyLoading: {
|
||||
enabled: true,
|
||||
},
|
||||
|
||||
isDevelopingAddon() {
|
||||
return true;
|
||||
},
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "open-api-explorer",
|
||||
"keywords": [
|
||||
"ember-addon",
|
||||
"ember-engine"
|
||||
],
|
||||
"dependencies": {
|
||||
"ember-cli-htmlbars": "*",
|
||||
"ember-cli-babel": "*",
|
||||
"ember-auto-import": "*",
|
||||
"swagger-ui-dist": "*"
|
||||
},
|
||||
"ember-addon": {
|
||||
"paths": [
|
||||
"../core"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -93,7 +93,7 @@
|
|||
"ember-copy": "^1.0.0",
|
||||
"ember-data": "~3.4.0",
|
||||
"ember-data-model-fragments": "^3.3.0",
|
||||
"ember-engines": "^0.7.0",
|
||||
"ember-engines": "^0.8.0",
|
||||
"ember-export-application-global": "^2.0.0",
|
||||
"ember-fetch": "^6.5.1",
|
||||
"ember-inflector": "^3.0.0",
|
||||
|
@ -130,6 +130,7 @@
|
|||
"sass-svg-uri": "^1.0.0",
|
||||
"string.prototype.endswith": "^0.2.0",
|
||||
"string.prototype.startswith": "^0.2.0",
|
||||
"swagger-ui-dist": "^3.22.3",
|
||||
"text-encoder-lite": "1.0.0",
|
||||
"walk-sync": "^0.3.3",
|
||||
"xstate": "^3.3.3",
|
||||
|
@ -156,8 +157,9 @@
|
|||
"paths": [
|
||||
"lib/core",
|
||||
"lib/css",
|
||||
"lib/replication",
|
||||
"lib/kmip"
|
||||
"lib/kmip",
|
||||
"lib/open-api-explorer",
|
||||
"lib/replication"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
89
ui/yarn.lock
89
ui/yarn.lock
|
@ -3279,6 +3279,13 @@ babel-plugin-ember-modules-api-polyfill@^2.8.0:
|
|||
dependencies:
|
||||
ember-rfc176-data "^0.3.8"
|
||||
|
||||
babel-plugin-ember-modules-api-polyfill@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.9.0.tgz#8503e7b4192aeb336b00265e6235258ff6b754aa"
|
||||
integrity sha512-c03h50291phJ2gQxo/aIOvFQE2c6glql1A7uagE3XbPXpKVAJOUxtVDjvWG6UAB6BC5ynsJfMWvY0w4TPRKIHQ==
|
||||
dependencies:
|
||||
ember-rfc176-data "^0.3.9"
|
||||
|
||||
babel-plugin-emotion@^10.0.7:
|
||||
version "10.0.7"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.7.tgz#3634ada6dee762140f27db07387feaec8d2cb619"
|
||||
|
@ -4246,7 +4253,7 @@ broccoli-babel-transpiler@^7.0.0:
|
|||
rsvp "^4.8.3"
|
||||
workerpool "^2.3.1"
|
||||
|
||||
broccoli-babel-transpiler@^7.1.2:
|
||||
broccoli-babel-transpiler@^7.1.2, broccoli-babel-transpiler@^7.2.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.2.0.tgz#5c0d694c4055106abb385e2d3d88936d35b7cb18"
|
||||
integrity sha512-lkP9dNFfK810CRHHWsNl9rjyYqcXH3qg0kArnA6tV9Owx3nlZm3Eyr0cGo6sMUQCNLH+2oKrRjOdUGSc6Um6Cw==
|
||||
|
@ -6594,7 +6601,7 @@ debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.2.5:
|
||||
debug@^3.0.1, debug@^3.2.5:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
|
@ -7136,10 +7143,10 @@ ember-api-actions@^0.1.8:
|
|||
"@mike-north/js-lib-semantic-release-config" "^0.0.0-development"
|
||||
semantic-release "^15.9.12"
|
||||
|
||||
ember-asset-loader@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/ember-asset-loader/-/ember-asset-loader-0.5.1.tgz#7a1a1b2a1c6a4185b222a2ead7214b0a6368d619"
|
||||
integrity sha512-+suNUO9Ncxj6S3YSyZpatD46UYKhynVHOv0Y3VpKe2esB/HWDM5LZYHCQAHoM2ea8pIYvMCLqwmCZurYznbqmA==
|
||||
ember-asset-loader@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/ember-asset-loader/-/ember-asset-loader-0.6.1.tgz#2eb81221406164d19127eba5b3d10f908df89a17"
|
||||
integrity sha512-e2zafQJBMLhzl69caTG/+mQMH20uMHYrm7KcmdbmnX0oY2dZ48bhm0Wh1SPLXS/6G2T9NsNMWX6J2pVSnI+xyA==
|
||||
dependencies:
|
||||
broccoli-caching-writer "^3.0.3"
|
||||
broccoli-funnel "^2.0.2"
|
||||
|
@ -7368,6 +7375,33 @@ ember-cli-babel@^7.4.3:
|
|||
ensure-posix-path "^1.0.2"
|
||||
semver "^5.5.0"
|
||||
|
||||
ember-cli-babel@^7.8.0:
|
||||
version "7.8.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.8.0.tgz#e596500eca0f5a7c9aaee755f803d1542f578acf"
|
||||
integrity sha512-xUBgJQ81fqd7k/KIiGU+pjpoXhrmmRf9pUrqLenNSU5N+yeNFT5a1+w0b+p1F7oBphfXVwuxApdZxrmAHOdA3Q==
|
||||
dependencies:
|
||||
"@babel/core" "^7.0.0"
|
||||
"@babel/plugin-proposal-class-properties" "^7.3.4"
|
||||
"@babel/plugin-proposal-decorators" "^7.3.0"
|
||||
"@babel/plugin-transform-modules-amd" "^7.0.0"
|
||||
"@babel/plugin-transform-runtime" "^7.2.0"
|
||||
"@babel/polyfill" "^7.0.0"
|
||||
"@babel/preset-env" "^7.0.0"
|
||||
"@babel/runtime" "^7.2.0"
|
||||
amd-name-resolver "^1.2.1"
|
||||
babel-plugin-debug-macros "^0.3.0"
|
||||
babel-plugin-ember-modules-api-polyfill "^2.9.0"
|
||||
babel-plugin-module-resolver "^3.1.1"
|
||||
broccoli-babel-transpiler "^7.1.2"
|
||||
broccoli-debug "^0.6.4"
|
||||
broccoli-funnel "^2.0.1"
|
||||
broccoli-source "^1.1.0"
|
||||
clone "^2.1.2"
|
||||
ember-cli-babel-plugin-helpers "^1.1.0"
|
||||
ember-cli-version-checker "^2.1.2"
|
||||
ensure-posix-path "^1.0.2"
|
||||
semver "^5.5.0"
|
||||
|
||||
ember-cli-broccoli-sane-watcher@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.1.1.tgz#1687adada9022de26053fba833dc7dd10f03dd08"
|
||||
|
@ -7590,6 +7624,16 @@ ember-cli-preprocess-registry@^3.1.2:
|
|||
process-relative-require "^1.0.0"
|
||||
silent-error "^1.0.0"
|
||||
|
||||
ember-cli-preprocess-registry@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.3.0.tgz#685837a314fbe57224bd54b189f4b9c23907a2de"
|
||||
integrity sha512-60GYpw7VPeB7TvzTLZTuLTlHdOXvayxjAQ+IxM2T04Xkfyu75O2ItbWlftQW7NZVGkaCsXSRAmn22PG03VpLMA==
|
||||
dependencies:
|
||||
broccoli-clean-css "^1.1.0"
|
||||
broccoli-funnel "^2.0.1"
|
||||
debug "^3.0.1"
|
||||
process-relative-require "^1.0.0"
|
||||
|
||||
ember-cli-pretender@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-3.1.1.tgz#289c41683de266fec8bfaf5b7b7f6026aaefc8cf"
|
||||
|
@ -7694,7 +7738,7 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve
|
|||
resolve "^1.3.3"
|
||||
semver "^5.3.0"
|
||||
|
||||
ember-cli-version-checker@^3.0.1, ember-cli-version-checker@^3.1.2:
|
||||
ember-cli-version-checker@^3.1.2, ember-cli-version-checker@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.1.3.tgz#7c9b4f5ff30fdebcd480b1c06c4de43bb51c522c"
|
||||
integrity sha512-PZNSvpzwWgv68hcXxyjREpj3WWb81A7rtYNQq1lLEgrWIchF8ApKJjWP3NBpHjaatwILkZAV8klair5WFlXAKg==
|
||||
|
@ -7904,14 +7948,14 @@ ember-debug-handlers-polyfill@^1.1.1:
|
|||
resolved "https://registry.yarnpkg.com/ember-debug-handlers-polyfill/-/ember-debug-handlers-polyfill-1.1.1.tgz#e9ae0a720271a834221179202367421b580002ef"
|
||||
integrity sha512-lO7FBAqJjzbL+IjnWhVfQITypPOJmXdZngZR/Vdn513W4g/Q6Sjicao/mDzeDCb48Y70C4Facwk0LjdIpSZkRg==
|
||||
|
||||
ember-engines@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-engines/-/ember-engines-0.7.0.tgz#77e2d9c6bcb3878e8e087ea354df4fc8cc187954"
|
||||
integrity sha512-XuKg7J2yl+KJVnYDHxr9RYon5/Dcm6zb1YyWL9GZvSWm+SPwoIPa/5awSOOAT2vH76t7JfYVP6Nz/6zaGgNqtw==
|
||||
ember-engines@^0.8.0:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/ember-engines/-/ember-engines-0.8.2.tgz#d1be1929217c5454b37ec2e6b07a0057075447b8"
|
||||
integrity sha512-Lhwkj02b9/MjOyl3MFToL4Pa1djFtDjQOxI8SY86P81XUBbRDdeZ3pg5tDxU/upEeQ7La7uepoZWTBRj6Lxx0Q==
|
||||
dependencies:
|
||||
amd-name-resolver "1.3.1"
|
||||
babel-plugin-compact-reexports "^1.1.0"
|
||||
broccoli-babel-transpiler "^7.1.2"
|
||||
broccoli-babel-transpiler "^7.2.0"
|
||||
broccoli-concat "^3.7.3"
|
||||
broccoli-debug "^0.6.5"
|
||||
broccoli-dependency-funnel "^2.1.2"
|
||||
|
@ -7919,13 +7963,12 @@ ember-engines@^0.7.0:
|
|||
broccoli-funnel "^2.0.2"
|
||||
broccoli-merge-trees "^3.0.2"
|
||||
broccoli-test-helper "^2.0.0"
|
||||
calculate-cache-key-for-tree "^1.1.0"
|
||||
ember-asset-loader "^0.5.1"
|
||||
ember-cli-babel "^7.4.3"
|
||||
ember-cli-preprocess-registry "^3.1.2"
|
||||
calculate-cache-key-for-tree "^2.0.0"
|
||||
ember-asset-loader "^0.6.1"
|
||||
ember-cli-babel "^7.8.0"
|
||||
ember-cli-preprocess-registry "^3.3.0"
|
||||
ember-cli-string-utils "^1.1.0"
|
||||
ember-cli-version-checker "^3.0.1"
|
||||
ember-maybe-import-regenerator "^0.1.6"
|
||||
ember-cli-version-checker "^3.1.3"
|
||||
lodash "^4.17.11"
|
||||
|
||||
ember-export-application-global@^2.0.0:
|
||||
|
@ -8092,6 +8135,11 @@ ember-rfc176-data@^0.3.8:
|
|||
resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.8.tgz#d46bbef9a0d57c803217b258cfd2e90d8e191848"
|
||||
integrity sha512-SQup3iG7SDLZNuf7nMMx5BC5truO8AYKRi80gApeQ07NsbuXV4LH75i5eOaxF0i8l9+H1tzv34kGe6rEh0C1NQ==
|
||||
|
||||
ember-rfc176-data@^0.3.9:
|
||||
version "0.3.9"
|
||||
resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.9.tgz#44b6e051ead6c044ea87bd551f402e2cf89a7e3d"
|
||||
integrity sha512-EiTo5YQS0Duy0xp9gCP8ekzv9vxirNi7MnIB4zWs+thtWp/mEKgf5mkiiLU2+oo8C5DuavVHhoPQDmyxh8Io1Q==
|
||||
|
||||
ember-router-generator@^1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee"
|
||||
|
@ -17485,6 +17533,11 @@ svgo@0.6.6:
|
|||
sax "~1.2.1"
|
||||
whet.extend "~0.9.9"
|
||||
|
||||
swagger-ui-dist@^3.22.3:
|
||||
version "3.22.3"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.22.3.tgz#f2042966f8e0eef0c5730cf90891a89dab7810e1"
|
||||
integrity sha512-tmjAsqT43pqg5UoiQ2805c+juX0ASSoI/Ash/0c19jjAOFtTfE93ZrzmFd9hjqVgre935CYeXT0uaku42Lu8xg==
|
||||
|
||||
symbol-observable@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
|
||||
|
|
Loading…
Reference in New Issue