diff --git a/changelog/23700.txt b/changelog/23700.txt
new file mode 100644
index 000000000..59a69fbcf
--- /dev/null
+++ b/changelog/23700.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: Update flat, shell-quote and swagger-ui-dist packages. Remove swagger-ui styling overrides.
+```
\ No newline at end of file
diff --git a/ui/app/styles/core.scss b/ui/app/styles/core.scss
index d3c970716..3951d8781 100644
--- a/ui/app/styles/core.scss
+++ b/ui/app/styles/core.scss
@@ -16,6 +16,9 @@
@import './utils/mixins';
@import './utils/animations';
+// Open-api styling
+@import './utils/swagger';
+
// Core Styles: each file styles a class that is not associated with a component. Ex: box and not box-label.
@import './core/alert-banner';
@import './core/box';
diff --git a/ui/app/styles/utils/swagger.scss b/ui/app/styles/utils/swagger.scss
new file mode 100644
index 000000000..e1ab09542
--- /dev/null
+++ b/ui/app/styles/utils/swagger.scss
@@ -0,0 +1,11 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+// This file defines the scss for open-api-explorer.
+
+/* align list items with container */
+.swagger-ember .swagger-ui .wrapper {
+ padding: 0;
+}
diff --git a/ui/lib/open-api-explorer/addon/components/swagger-ui.js b/ui/lib/open-api-explorer/addon/components/swagger-ui.js
index 9ecc938cc..a80d89acb 100644
--- a/ui/lib/open-api-explorer/addon/components/swagger-ui.js
+++ b/ui/lib/open-api-explorer/addon/components/swagger-ui.js
@@ -1,109 +1,92 @@
/**
* Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: MPL-2.0
+ * SPDX-License-Identifier: BUSL-1.1
*/
-import Component from '@ember/component';
+import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { tracked } from '@glimmer/tracking';
import parseURL from 'core/utils/parse-url';
import config from 'open-api-explorer/config/environment';
+import { guidFor } from '@ember/object/internals';
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) => {
- const 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)
- );
+export default class SwaggerUiComponent extends Component {
+ @service auth;
+ @service namespace;
+
+ @tracked swaggerLoading = true;
+
+ inputId = `${guidFor(this)}-swagger`;
+
+ 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) => {
+ const 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)
+ );
+ },
},
- },
+ };
+ }
+
+ CONFIG = (SwaggerUIBundle, componentInstance) => {
+ return {
+ dom_id: `#${componentInstance.inputId}`,
+ url: '/v1/sys/internal/specs/openapi',
+ deepLinking: false,
+ presets: [SwaggerUIBundle.presets.apis],
+ plugins: [SwaggerUIBundle.plugins.DownloadUrl, this.SearchFilterPlugin],
+ // 'list' expands tags, but not operations
+ docExpansion: 'list',
+ operationsSorter: 'alpha',
+ filter: 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 namespace headers for things to work properly
+ req.headers['X-Vault-Token'] = componentInstance.auth.currentToken;
+ const namespace = componentInstance.namespace.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) {
+ const { protocol, host, pathname, search } = 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}${search}`;
+ }
+ return req;
+ },
+ onComplete: () => {
+ componentInstance.swaggerLoading = false;
+ },
+ };
};
-};
-const CONFIG = (SwaggerUIBundle, 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;
-
- const 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) {
- const { protocol, host, pathname, search } = 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}${search}`;
- }
- return req;
- },
- onComplete: () => {
- componentInstance.set('swaggerLoading', false);
- },
- };
-};
-
-export default Component.extend({
- auth: service(),
- namespaceService: service('namespace'),
- initialFilter: null,
- onFilterChange() {},
- swaggerLoading: true,
-
- async didInsertElement() {
+ // using an action to bind the correct "this" context
+ @action async swaggerInit() {
const { default: SwaggerUIBundle } = await import('swagger-ui-dist/swagger-ui-bundle.js');
- this._super(...arguments);
- // trim any initial slashes
- const initialFilter = this.initialFilter.replace(/^(\/)+/, '');
- SwaggerUIBundle(CONFIG(SwaggerUIBundle, 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) {
- const 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
- const evt = new Event('input', { bubbles: true });
- evt.simulated = true;
- swaggerInput.value = e.target.value.replace(/^(\/)+/, '');
- swaggerInput.dispatchEvent(evt);
- },
- },
-});
+ // trim any slashes on the filter value
+ const configSettings = this.CONFIG(SwaggerUIBundle, this);
+ SwaggerUIBundle(configSettings);
+ }
+}
diff --git a/ui/lib/open-api-explorer/addon/controllers/index.js b/ui/lib/open-api-explorer/addon/controllers/index.js
deleted file mode 100644
index 413c837f7..000000000
--- a/ui/lib/open-api-explorer/addon/controllers/index.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: MPL-2.0
- */
-
-import Controller from '@ember/controller';
-
-export default Controller.extend({
- queryParams: ['filter'],
- filter: '',
-});
diff --git a/ui/lib/open-api-explorer/addon/routes/index.js b/ui/lib/open-api-explorer/addon/routes/index.js
index 9b8ec81e6..721308a57 100644
--- a/ui/lib/open-api-explorer/addon/routes/index.js
+++ b/ui/lib/open-api-explorer/addon/routes/index.js
@@ -1,16 +1,14 @@
/**
* Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: MPL-2.0
+ * SPDX-License-Identifier: BUSL-1.1
*/
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() {},
+export default class OpenApiExplorerIndex extends Route {
+ @service flashMessages;
+
afterModel() {
const warning = `The "Try it out" functionality in this API explorer will make requests to this Vault server on your behalf.
@@ -21,5 +19,5 @@ Your token will also be shown on the screen in the example curl command output.`
sticky: true,
preformatted: true,
});
- },
-});
+ }
+}
diff --git a/ui/lib/open-api-explorer/addon/styles/addon.css b/ui/lib/open-api-explorer/addon/styles/addon.css
deleted file mode 100644
index 1dfe71809..000000000
--- a/ui/lib/open-api-explorer/addon/styles/addon.css
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: MPL-2.0
- */
-
-.swagger-ember .swagger-ui .wrapper {
- padding: 0;
-}
-
-.swagger-ember .swagger-ui .info {
- margin: 25px 0;
-}
-
-/*hide the swagger-ui headers*/
-.swagger-ember .swagger-ui .filter-container,
-.swagger-ember .swagger-ui .information-container.wrapper {
- display: none;
-}
-
-/*some general de-rounding and removing backgrounds and drop shadows*/
-.swagger-ember .swagger-ui .btn {
- border-width: 1px;
- box-shadow: none;
- border-radius: 0px;
-}
-
-.swagger-ember .swagger-ui .opblock {
- background: none;
- border-width: 1px;
- border-radius: 2px;
- box-shadow: none;
-}
-
-
-/*customize method, path, description*/
-.swagger-ember .swagger-ui .opblock .opblock-summary,
-.swagger-ember .swagger-ui .opblock .opblock-summary-description {
- display: block;
- margin: 0;
- padding: 0;
-}
-
-.swagger-ember .swagger-ui .opblock .opblock-summary {
- padding: 1rem;
-}
-
-.swagger-ember .swagger-ui .opblock .opblock-summary-description {
- font-size: 14px;
-}
-
-.swagger-ember .swagger-ui .opblock .opblock-summary-method,
-.swagger-ember .swagger-ui .opblock .opblock-summary-path{
- display: inline-block;
- margin: 0;
- padding: 0;
-}
-
-.swagger-ember .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;
-}
-
-/*make tags look like list items */
-.swagger-ember .swagger-ui .opblock-tag{
- font-size: 16px;
-}
-
-.swagger-ember .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-ember .swagger-ui .opblock-tag:hover,
-.swagger-ember .swagger-ui .opblock-tag:focus,
-.swagger-ember .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-ember .swagger-ui .expand-methods svg,
-.swagger-ember .swagger-ui .expand-operation svg {
- height: 12px;
- width: 12px;
-}
-
-
-/*operation box - GET (blue) */
-.swagger-ember .swagger-ui .opblock.opblock-get {
- background: #f5f8ff;
- border: 1px solid #bfd4ff;
-}
-
-/*operation label*/
-.swagger-ember .swagger-ui .opblock.opblock-get .opblock-summary-method {
- color: #1563ff;
- background: none;
-}
- /*and expanded tab highlight */
-.swagger-ember .swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span::after {
- background: #1563ff;
-}
-
-
-/*operation box - POST (green) */
-.swagger-ember .swagger-ui .opblock.opblock-post {
- background: #fafdfa;
- border: 1px solid #c6e9c9;
-}
-.swagger-ember .swagger-ui .opblock.opblock-post .opblock-summary-method {
- color: #2eb039;
- background: none;
-}
-.swagger-ember .swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span::after {
- background: #2eb039;
-}
-
-/*operation box - POST (red) */
-.swagger-ember .swagger-ui .opblock.opblock-delete {
- background: #fdfafb;
- border: 1px solid #f9ecee;
-}
-.swagger-ember .swagger-ui .opblock.opblock-delete .opblock-summary-method {
- color: #c73445;
- background: none;
-}
-.swagger-ember .swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span::after {
- background: #c73445;
-}
-
-/*remove "LOADING" from initial loading spinner*/
-.swagger-ember .swagger-ui .loading-container .loading::after {
- content: "";
-}
-
-/*add text about requests to a live vault server*/
-.swagger-ember .swagger-ui .btn.execute::after {
- content: " - send a request with your token to Vault."
-}
diff --git a/ui/lib/open-api-explorer/addon/templates/components/swagger-ui.hbs b/ui/lib/open-api-explorer/addon/templates/components/swagger-ui.hbs
index 2219b9460..230fe6aec 100644
--- a/ui/lib/open-api-explorer/addon/templates/components/swagger-ui.hbs
+++ b/ui/lib/open-api-explorer/addon/templates/components/swagger-ui.hbs
@@ -1,32 +1,7 @@
-
-
-