grape-swagger-rails 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61a592b658be0f0b08a98137d907c771b4444627d3da072b40b73cfe4ea40773
4
- data.tar.gz: c44bec534d280e3d579ecb71f4f0f63b722f672538b5b45495c6c5ca107da168
3
+ metadata.gz: 5bd45e9462ec3fceba7a6b3b75fc6fee6ad6ce11349b52378ee7aaad8fc429f3
4
+ data.tar.gz: 7d531ce1a74556e0ef0ff17c14bf5515ed255916ccd27f63a1a1ec9ec6d0cadb
5
5
  SHA512:
6
- metadata.gz: 1fd25759115054c6885fdb7c31a8dd9be252c0b82f6935d50c639d37e349d1149773302db8265f2569799ba99e87f74f63827d41a25af9b6b14b4ecee7c804e1
7
- data.tar.gz: cfedf854908cda46fd6ba7d55bb35fc02d5e65c35034251e12e90abaafe8889f137703564aec572acd470fe3e4d1574aa1d7185ad098fcc58dc9ca4c7b11421d
6
+ metadata.gz: fe07aff0e76be3d93a2e4cd62b1effb5517a17f1d79452ba764166a03d1afa5010de6e04d6789dec767536f5cef004c2c6e431bf3ebe5b166fbb784e56ad133e
7
+ data.tar.gz: 04defb6acca696ffc3c24e3f577091afe5f0829ebf8a0c2c7aea11689b256125a9307483ec3582442210d93adf116893b8cb9871892712a6a3ffdc2cc9fe5e17
@@ -8,7 +8,7 @@ jobs:
8
8
  frontend:
9
9
  runs-on: ubuntu-latest
10
10
  steps:
11
- - uses: actions/checkout@v5
11
+ - uses: actions/checkout@v6
12
12
  - name: Set up Node
13
13
  uses: actions/setup-node@v4
14
14
  with:
@@ -4,7 +4,7 @@ jobs:
4
4
  rubocop:
5
5
  runs-on: ubuntu-latest
6
6
  steps:
7
- - uses: actions/checkout@v5
7
+ - uses: actions/checkout@v6
8
8
  - name: Set up Ruby
9
9
  uses: ruby/setup-ruby@v1
10
10
  with:
@@ -0,0 +1,61 @@
1
+ name: Swagger UI Update
2
+
3
+ "on":
4
+ schedule:
5
+ - cron: "0 8 * * 1"
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ update:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v6
17
+
18
+ - name: Set up Ruby
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: "3.4"
22
+ bundler-cache: true
23
+
24
+ - name: Check latest Swagger UI release
25
+ id: swagger-ui
26
+ env:
27
+ GH_TOKEN: ${{ github.token }}
28
+ run: |
29
+ current_version="$(ruby -r ./lib/grape-swagger-rails/version -e 'print GrapeSwaggerRails::SWAGGER_UI_VERSION')"
30
+ latest_tag="$(gh api repos/swagger-api/swagger-ui/releases/latest --jq .tag_name)"
31
+ latest_version="${latest_tag#v}"
32
+
33
+ echo "current-version=${current_version}" >> "$GITHUB_OUTPUT"
34
+ echo "latest-tag=${latest_tag}" >> "$GITHUB_OUTPUT"
35
+ echo "latest-version=${latest_version}" >> "$GITHUB_OUTPUT"
36
+
37
+ if [ "$current_version" != "$latest_version" ]; then
38
+ echo "update-needed=true" >> "$GITHUB_OUTPUT"
39
+ else
40
+ echo "update-needed=false" >> "$GITHUB_OUTPUT"
41
+ fi
42
+
43
+ - name: Update Swagger UI assets
44
+ if: steps.swagger-ui.outputs.update-needed == 'true'
45
+ env:
46
+ SWAGGER_UI_VERSION: ${{ steps.swagger-ui.outputs.latest-tag }}
47
+ run: bundle exec rake swagger_ui:dist:update
48
+
49
+ - name: Create pull request
50
+ if: steps.swagger-ui.outputs.update-needed == 'true'
51
+ uses: peter-evans/create-pull-request@v7
52
+ with:
53
+ token: ${{ github.token }}
54
+ branch: update-swagger-ui-${{ steps.swagger-ui.outputs.latest-version }}
55
+ delete-branch: true
56
+ commit-message: Bump Swagger UI to ${{ steps.swagger-ui.outputs.latest-version }}
57
+ title: Bump Swagger UI to ${{ steps.swagger-ui.outputs.latest-version }}
58
+ body: |
59
+ Updates bundled Swagger UI assets from swagger-api/swagger-ui `${{ steps.swagger-ui.outputs.latest-tag }}`.
60
+
61
+ Generated by the scheduled Swagger UI update workflow.
@@ -44,7 +44,7 @@ jobs:
44
44
  GRAPE_SWAGGER_VERSION: ${{ matrix.grape-swagger }}
45
45
  RAILS_VERSION: ${{ matrix.rails }}
46
46
  steps:
47
- - uses: actions/checkout@v5
47
+ - uses: actions/checkout@v6
48
48
  - name: Set up Ruby
49
49
  uses: ruby/setup-ruby@v1
50
50
  with:
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  * Your contribution here.
4
4
 
5
+ ### 1.0.2 (2026/05/26)
6
+
7
+ * [#162](https://github.com/ruby-grape/grape-swagger-rails/pull/162): Fix vertical alignment for property rows in swagger ui model box - [@moskvin](https://github.com/moskvin).
8
+ * [#160](https://github.com/ruby-grape/grape-swagger-rails/pull/160): Hide Swagger UI's confusing "Clear" button by default; expose `display[:clear_button]` to opt back in - [@moskvin](https://github.com/moskvin).
9
+ * [#159](https://github.com/ruby-grape/grape-swagger-rails/pull/159): Added github action update swagger ui version - [@moskvin](https://github.com/moskvin).
10
+
5
11
  ### 1.0.1 (2026/05/17)
6
12
 
7
13
  * [#155](https://github.com/ruby-grape/grape-swagger-rails/pull/155): Fix: autoload default spec and restyle version dropdown - [@moskvin](https://github.com/moskvin).
data/README.md CHANGED
@@ -46,9 +46,9 @@ This gem is continuously tested against the following stack:
46
46
 
47
47
  | Ruby | Rails | Grape | grape-swagger | Swagger UI |
48
48
  |-----:|--------:|--------:|--------------:|-----------:|
49
- | 3.4 | 7.2.2.2 | 1.8.x | 1.6.1 | 5.32.5 |
50
- | 3.2+ | 7.2.2.2 | 3.1.x | 2.1.4 | 5.32.5 |
51
- | 3.2+ | 8.1.x | 3.1.x | 2.1.4 | 5.32.5 |
49
+ | 3.4 | 7.2.2.2 | 1.8.x | 1.6.1 | 5.32.6 |
50
+ | 3.2+ | 7.2.2.2 | 3.1.x | 2.1.4 | 5.32.6 |
51
+ | 3.2+ | 8.1.x | 3.1.x | 2.1.4 | 5.32.6 |
52
52
 
53
53
  The dummy app and CI also exercise both supported Rails asset pipelines: Sprockets and Propshaft.
54
54
 
@@ -267,7 +267,8 @@ GrapeSwaggerRails.options.display = {
267
267
  api_key_input: false,
268
268
  info_url: false,
269
269
  doc_version: false,
270
- version_stamp: false
270
+ version_stamp: false,
271
+ clear_button: true
271
272
  }
272
273
  ```
273
274
 
@@ -277,12 +278,13 @@ Supported keys:
277
278
  - `info_url`: show or hide the API document URL link
278
279
  - `doc_version`: show or hide the API document version label
279
280
  - `version_stamp`: show or hide the `OAS 2.0` version stamp
281
+ - `clear_button`: show or hide Swagger UI's "Clear" button that appears next to "Execute" after "Try it out". Hidden by default because the upstream button only resets internal request/response state and leaves user-typed input values on screen, which is confusing (see [swagger-api/swagger-ui#5283](https://github.com/swagger-api/swagger-ui/issues/5283)).
280
282
 
281
- By default, all of these options are `true`.
283
+ By default, all of these options are `true` except `clear_button`, which defaults to `false`.
282
284
 
283
285
  ### Updating Swagger UI from Dist
284
286
 
285
- To update Swagger UI from its [distribution](https://github.com/wordnik/swagger-ui), run `bundle exec rake swagger_ui:dist:update`. Examine the changes carefully.
287
+ To update Swagger UI from its [distribution](https://github.com/swagger-api/swagger-ui), run `bundle exec rake swagger_ui:dist:update`. Examine the changes carefully.
286
288
 
287
289
  NOTE: This action should be run part of this gem (not your application). In case if you want to
288
290
  make it up-to-date, clone the repo, run the rake task, examine the diff, fix any bugs, make sure
@@ -146,10 +146,27 @@ var initializeSwaggerPage = function () {
146
146
  },
147
147
  };
148
148
  };
149
+ // Swagger UI's "Clear" button (next to Execute) is confusing — it resets
150
+ // the internal request / response state but does not clear values still visible
151
+ // in the rendered input fields. Upstream issue swagger-api/swagger-ui#5283
152
+ // has acknowledged the UX problem since 2019 without a fix. Hide by default.
153
+ var hideClearButtonPlugin = function () {
154
+ return {
155
+ wrapComponents: {
156
+ clear: function () { return function () { return null; }; },
157
+ },
158
+ };
159
+ };
149
160
  var buildPlugins = function () {
150
161
  var configuredPlugins = options.swagger_ui_config && options.swagger_ui_config.plugins;
151
162
  var plugins = Array.isArray(configuredPlugins) ? configuredPlugins.slice() : [];
152
- var displayDefaults = { api_key_input: true, info_url: true, doc_version: true, version_stamp: true };
163
+ var displayDefaults = {
164
+ api_key_input: true,
165
+ info_url: true,
166
+ doc_version: true,
167
+ version_stamp: true,
168
+ clear_button: false,
169
+ };
153
170
  var display = Object.assign({}, displayDefaults, options.display || {});
154
171
  if (!display.info_url) {
155
172
  plugins.push(hideInfoUrlPlugin);
@@ -160,6 +177,9 @@ var initializeSwaggerPage = function () {
160
177
  if (!display.version_stamp) {
161
178
  plugins.push(hideVersionStampPlugin);
162
179
  }
180
+ if (!display.clear_button) {
181
+ plugins.push(hideClearButtonPlugin);
182
+ }
163
183
  return plugins;
164
184
  };
165
185
  applyTheme(getTheme());
@@ -1,2 +1,2 @@
1
- "use strict";var safeDecodeURIComponent=function(o){try{return decodeURIComponent(o)}catch{return o}},initializeSwaggerPage=function(){var o=document.documentElement.dataset.swaggerOptions;if(!(!o||typeof SwaggerUIBundle>"u"||typeof SwaggerUIStandalonePreset>"u")){var r=JSON.parse(o),p=document.getElementById("input_apiKey"),l=document.getElementById("spec-selector"),m=document.getElementById("spec-selector-wrapper"),u=document.getElementById("theme-toggle"),g=document.documentElement,_=function(){return r.theme==="dark"?"dark":"light"},v=function(e){g.dataset.theme=e,g.classList.toggle("dark-mode",e==="dark"),u&&(u.textContent=e==="dark"?"Light Mode":"Dark Mode",u.setAttribute("aria-pressed",String(e==="dark")))},y=function(){if(!p)return"";var e=p.value?p.value.trim():"";return e?r.api_auth==="basic"?"Basic "+btoa(e):r.api_auth==="bearer"?"Bearer "+e:r.api_auth==="token"?'Token token="'.concat(e,'"'):e:""},I=function(e){return e.headers||(e.headers={}),e.headers},h=function(e,n,a){var t=I(e);if(t instanceof Headers){t.set(n,a);return}t[n]=a},d=function(e){return e?/^https?:\/\//.test(e)?e:r.app_url+e:""},S=function(){return Array.isArray(r.urls)?r.urls.map(function(e,n){return typeof e=="string"?{name:e,url:d(e),default:!1}:{name:e.name||e.url||"Spec "+(n+1),url:d(e.url),default:!!e.default}}).filter(function(e){return!!e.url}):[]},k=function(e){if(!e.length)return null;for(var n=0;n<e.length;n+=1)if(e[n].default)return e[n];if(r.url){for(var a=d(r.url),t=0;t<e.length;t+=1)if(e[t].url===a)return e[t]}return e[0]},U=function(e,n){!l||!m||e.length<2||(e.forEach(function(a){var t=document.createElement("option");t.value=a.url,t.textContent=a.name,n&&a.url===n.url&&(t.selected=!0),l.appendChild(t)}),m.hidden=!1)},E=function(){return{wrapComponents:{InfoUrl:function(){return function(){return null}}}}},b=function(){return{wrapComponents:{VersionStamp:function(){return function(){return null}}}}},A=function(){return{wrapComponents:{OpenAPIVersion:function(){return function(){return null}}}}},B=function(){var e=r.swagger_ui_config&&r.swagger_ui_config.plugins,n=Array.isArray(e)?e.slice():[],a={api_key_input:!0,info_url:!0,doc_version:!0,version_stamp:!0},t=Object.assign({},a,r.display||{});return t.info_url||n.push(E),t.doc_version||n.push(b),t.version_stamp||n.push(A),n};v(_()),u&&u.addEventListener("click",function(){r.theme=g.dataset.theme==="dark"?"light":"dark",v(r.theme)});var s=S(),i=k(s),c=Object.assign({},r.swagger_ui_config||{},{dom_id:"#swagger-ui-container",deepLinking:!0,docExpansion:r.doc_expansion,supportedSubmitMethods:r.supported_submit_methods||[],validatorUrl:r.validator_url,layout:"BaseLayout",presets:[SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset],plugins:B(),requestInterceptor:function(e){var n=r.headers||{};Object.keys(n).forEach(function(f){h(e,f,n[f])});var a=y();if(!a)return e;if(r.api_key_type==="query"){var t=e.url.indexOf("?")===-1?"?":"&";return e.url+=t+encodeURIComponent(r.api_key_name)+"="+encodeURIComponent(a),e}return h(e,r.api_key_name,a),e}});s.length?(c.urls=s,i&&(c["urls.primaryName"]=i.name)):c.url=d(r.url),window.ui=SwaggerUIBundle(c),i&&(window.ui.specActions.updateUrl(i.url),window.ui.specActions.download(i.url)),U(s,i),l&&s.length>1&&l.addEventListener("change",function(e){var n=e.target,a=n.value;window.ui.specActions.updateUrl(a),window.ui.specActions.download(a)}),window.addEventListener("hashchange",function(){var e=window.location.hash;if(!(!e||e==="#")){var n=e.replace(/^#\/?/,"").split("/").filter(Boolean);if(n.length!==0){var a=safeDecodeURIComponent(n[0]),t=n.length>1?safeDecodeURIComponent(n[1]):null;window.ui.layoutActions.show(["operations-tag",a],!0),t&&window.ui.layoutActions.show(["operations",a,t],!0);var f=t?"operations-"+a+"-"+t:"operations-tag-"+a;requestAnimationFrame(function(){var w=document.getElementById(f);w&&w.scrollIntoView({behavior:"smooth",block:"start"})})}}})}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",initializeSwaggerPage):initializeSwaggerPage();
1
+ "use strict";var safeDecodeURIComponent=function(o){try{return decodeURIComponent(o)}catch{return o}},initializeSwaggerPage=function(){var o=document.documentElement.dataset.swaggerOptions;if(!(!o||typeof SwaggerUIBundle>"u"||typeof SwaggerUIStandalonePreset>"u")){var t=JSON.parse(o),p=document.getElementById("input_apiKey"),s=document.getElementById("spec-selector"),m=document.getElementById("spec-selector-wrapper"),u=document.getElementById("theme-toggle"),g=document.documentElement,_=function(){return t.theme==="dark"?"dark":"light"},v=function(e){g.dataset.theme=e,g.classList.toggle("dark-mode",e==="dark"),u&&(u.textContent=e==="dark"?"Light Mode":"Dark Mode",u.setAttribute("aria-pressed",String(e==="dark")))},y=function(){if(!p)return"";var e=p.value?p.value.trim():"";return e?t.api_auth==="basic"?"Basic "+btoa(e):t.api_auth==="bearer"?"Bearer "+e:t.api_auth==="token"?'Token token="'.concat(e,'"'):e:""},I=function(e){return e.headers||(e.headers={}),e.headers},h=function(e,n,a){var r=I(e);if(r instanceof Headers){r.set(n,a);return}r[n]=a},d=function(e){return e?/^https?:\/\//.test(e)?e:t.app_url+e:""},S=function(){return Array.isArray(t.urls)?t.urls.map(function(e,n){return typeof e=="string"?{name:e,url:d(e),default:!1}:{name:e.name||e.url||"Spec "+(n+1),url:d(e.url),default:!!e.default}}).filter(function(e){return!!e.url}):[]},k=function(e){if(!e.length)return null;for(var n=0;n<e.length;n+=1)if(e[n].default)return e[n];if(t.url){for(var a=d(t.url),r=0;r<e.length;r+=1)if(e[r].url===a)return e[r]}return e[0]},U=function(e,n){!s||!m||e.length<2||(e.forEach(function(a){var r=document.createElement("option");r.value=a.url,r.textContent=a.name,n&&a.url===n.url&&(r.selected=!0),s.appendChild(r)}),m.hidden=!1)},b=function(){return{wrapComponents:{InfoUrl:function(){return function(){return null}}}}},E=function(){return{wrapComponents:{VersionStamp:function(){return function(){return null}}}}},B=function(){return{wrapComponents:{OpenAPIVersion:function(){return function(){return null}}}}},A=function(){return{wrapComponents:{clear:function(){return function(){return null}}}}},C=function(){var e=t.swagger_ui_config&&t.swagger_ui_config.plugins,n=Array.isArray(e)?e.slice():[],a={api_key_input:!0,info_url:!0,doc_version:!0,version_stamp:!0,clear_button:!1},r=Object.assign({},a,t.display||{});return r.info_url||n.push(b),r.doc_version||n.push(E),r.version_stamp||n.push(B),r.clear_button||n.push(A),n};v(_()),u&&u.addEventListener("click",function(){t.theme=g.dataset.theme==="dark"?"light":"dark",v(t.theme)});var l=S(),i=k(l),c=Object.assign({},t.swagger_ui_config||{},{dom_id:"#swagger-ui-container",deepLinking:!0,docExpansion:t.doc_expansion,supportedSubmitMethods:t.supported_submit_methods||[],validatorUrl:t.validator_url,layout:"BaseLayout",presets:[SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset],plugins:C(),requestInterceptor:function(e){var n=t.headers||{};Object.keys(n).forEach(function(f){h(e,f,n[f])});var a=y();if(!a)return e;if(t.api_key_type==="query"){var r=e.url.indexOf("?")===-1?"?":"&";return e.url+=r+encodeURIComponent(t.api_key_name)+"="+encodeURIComponent(a),e}return h(e,t.api_key_name,a),e}});l.length?(c.urls=l,i&&(c["urls.primaryName"]=i.name)):c.url=d(t.url),window.ui=SwaggerUIBundle(c),i&&(window.ui.specActions.updateUrl(i.url),window.ui.specActions.download(i.url)),U(l,i),s&&l.length>1&&s.addEventListener("change",function(e){var n=e.target,a=n.value;window.ui.specActions.updateUrl(a),window.ui.specActions.download(a)}),window.addEventListener("hashchange",function(){var e=window.location.hash;if(!(!e||e==="#")){var n=e.replace(/^#\/?/,"").split("/").filter(Boolean);if(n.length!==0){var a=safeDecodeURIComponent(n[0]),r=n.length>1?safeDecodeURIComponent(n[1]):null;window.ui.layoutActions.show(["operations-tag",a],!0),r&&window.ui.layoutActions.show(["operations",a,r],!0);var f=r?"operations-"+a+"-"+r:"operations-tag-"+a;requestAnimationFrame(function(){var w=document.getElementById(f);w&&w.scrollIntoView({behavior:"smooth",block:"start"})})}}})}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",initializeSwaggerPage):initializeSwaggerPage();
2
2
  //# sourceMappingURL=index.min.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["index.js"],
4
- "sourcesContent": ["\"use strict\";\nvar safeDecodeURIComponent = function (value) {\n try {\n return decodeURIComponent(value);\n }\n catch (_a) {\n return value;\n }\n};\nvar initializeSwaggerPage = function () {\n var optionsElement = document.documentElement.dataset.swaggerOptions;\n if (!optionsElement ||\n typeof SwaggerUIBundle === \"undefined\" ||\n typeof SwaggerUIStandalonePreset === \"undefined\") {\n return;\n }\n var options = JSON.parse(optionsElement);\n var authInput = document.getElementById(\"input_apiKey\");\n var specSelector = document.getElementById(\"spec-selector\");\n var specSelectorWrapper = document.getElementById(\"spec-selector-wrapper\");\n var themeToggle = document.getElementById(\"theme-toggle\");\n var root = document.documentElement;\n var getTheme = function () {\n return options.theme === \"dark\" ? \"dark\" : \"light\";\n };\n var applyTheme = function (theme) {\n root.dataset.theme = theme;\n root.classList.toggle(\"dark-mode\", theme === \"dark\");\n if (!themeToggle) {\n return;\n }\n themeToggle.textContent = theme === \"dark\" ? \"Light Mode\" : \"Dark Mode\";\n themeToggle.setAttribute(\"aria-pressed\", String(theme === \"dark\"));\n };\n var getApiKeyValue = function () {\n if (!authInput) {\n return \"\";\n }\n var key = authInput.value ? authInput.value.trim() : \"\";\n if (!key) {\n return \"\";\n }\n if (options.api_auth === \"basic\") {\n return \"Basic \" + btoa(key);\n }\n if (options.api_auth === \"bearer\") {\n return \"Bearer \" + key;\n }\n if (options.api_auth === \"token\") {\n return \"Token token=\\\"\".concat(key, \"\\\"\");\n }\n return key;\n };\n var ensureRequestHeaders = function (request) {\n if (!request.headers) {\n request.headers = {};\n }\n return request.headers;\n };\n var setRequestHeader = function (request, key, value) {\n var headers = ensureRequestHeaders(request);\n if (headers instanceof Headers) {\n headers.set(key, value);\n return;\n }\n headers[key] = value;\n };\n var absoluteSpecUrl = function (url) {\n if (!url) {\n return \"\";\n }\n if (/^https?:\\/\\//.test(url)) {\n return url;\n }\n return options.app_url + url;\n };\n var normalizeSwaggerUrls = function () {\n if (!Array.isArray(options.urls)) {\n return [];\n }\n return options.urls\n .map(function (entry, index) {\n if (typeof entry === \"string\") {\n return { name: entry, url: absoluteSpecUrl(entry), default: false };\n }\n return {\n name: entry.name || entry.url || \"Spec \" + (index + 1),\n url: absoluteSpecUrl(entry.url),\n default: Boolean(entry.default),\n };\n })\n .filter(function (entry) { return Boolean(entry.url); });\n };\n var selectedSwaggerUrl = function (urls) {\n if (!urls.length) {\n return null;\n }\n for (var i = 0; i < urls.length; i += 1) {\n if (urls[i].default) {\n return urls[i];\n }\n }\n if (options.url) {\n var absoluteUrl = absoluteSpecUrl(options.url);\n for (var j = 0; j < urls.length; j += 1) {\n if (urls[j].url === absoluteUrl) {\n return urls[j];\n }\n }\n }\n return urls[0];\n };\n var setupSpecSelector = function (urls, selectedUrl) {\n if (!specSelector || !specSelectorWrapper || urls.length < 2) {\n return;\n }\n urls.forEach(function (entry) {\n var option = document.createElement(\"option\");\n option.value = entry.url;\n option.textContent = entry.name;\n if (selectedUrl && entry.url === selectedUrl.url) {\n option.selected = true;\n }\n specSelector.appendChild(option);\n });\n specSelectorWrapper.hidden = false;\n };\n var hideInfoUrlPlugin = function () {\n return {\n wrapComponents: {\n InfoUrl: function () { return function () { return null; }; },\n },\n };\n };\n var hideDocVersionPlugin = function () {\n return {\n wrapComponents: {\n VersionStamp: function () { return function () { return null; }; },\n },\n };\n };\n var hideVersionStampPlugin = function () {\n return {\n wrapComponents: {\n OpenAPIVersion: function () { return function () { return null; }; },\n },\n };\n };\n var buildPlugins = function () {\n var configuredPlugins = options.swagger_ui_config && options.swagger_ui_config.plugins;\n var plugins = Array.isArray(configuredPlugins) ? configuredPlugins.slice() : [];\n var displayDefaults = { api_key_input: true, info_url: true, doc_version: true, version_stamp: true };\n var display = Object.assign({}, displayDefaults, options.display || {});\n if (!display.info_url) {\n plugins.push(hideInfoUrlPlugin);\n }\n if (!display.doc_version) {\n plugins.push(hideDocVersionPlugin);\n }\n if (!display.version_stamp) {\n plugins.push(hideVersionStampPlugin);\n }\n return plugins;\n };\n applyTheme(getTheme());\n if (themeToggle) {\n themeToggle.addEventListener(\"click\", function () {\n options.theme = root.dataset.theme === \"dark\" ? \"light\" : \"dark\";\n applyTheme(options.theme);\n });\n }\n var swaggerUrls = normalizeSwaggerUrls();\n var selectedUrl = selectedSwaggerUrl(swaggerUrls);\n var bundleConfig = Object.assign({}, options.swagger_ui_config || {}, {\n dom_id: \"#swagger-ui-container\",\n deepLinking: true,\n docExpansion: options.doc_expansion,\n supportedSubmitMethods: options.supported_submit_methods || [],\n validatorUrl: options.validator_url,\n layout: \"BaseLayout\",\n presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],\n plugins: buildPlugins(),\n requestInterceptor: function (request) {\n var headers = options.headers || {};\n Object.keys(headers).forEach(function (key) {\n setRequestHeader(request, key, headers[key]);\n });\n var apiKeyValue = getApiKeyValue();\n if (!apiKeyValue) {\n return request;\n }\n if (options.api_key_type === \"query\") {\n var separator = request.url.indexOf(\"?\") === -1 ? \"?\" : \"&\";\n request.url +=\n separator +\n encodeURIComponent(options.api_key_name) +\n \"=\" +\n encodeURIComponent(apiKeyValue);\n return request;\n }\n setRequestHeader(request, options.api_key_name, apiKeyValue);\n return request;\n },\n });\n if (swaggerUrls.length) {\n bundleConfig.urls = swaggerUrls;\n if (selectedUrl) {\n bundleConfig[\"urls.primaryName\"] = selectedUrl.name;\n }\n }\n else {\n bundleConfig.url = absoluteSpecUrl(options.url);\n }\n window.ui = SwaggerUIBundle(bundleConfig);\n if (selectedUrl) {\n window.ui.specActions.updateUrl(selectedUrl.url);\n window.ui.specActions.download(selectedUrl.url);\n }\n setupSpecSelector(swaggerUrls, selectedUrl);\n if (specSelector && swaggerUrls.length > 1) {\n specSelector.addEventListener(\"change\", function (event) {\n var target = event.target;\n var url = target.value;\n window.ui.specActions.updateUrl(url);\n window.ui.specActions.download(url);\n });\n }\n // Listen for hash changes so that navigating to a deep-link URL in the same\n // tab (e.g. pasting a copied operation URL into the address bar) expands the\n // target operation without requiring a full page refresh.\n //\n // NOTE: We intentionally do NOT use `layoutActions.parseDeepLinkHash()` here.\n // That method is Swagger UI's built-in deep linking plugin action, designed to\n // run during initial spec load (inside the `onComplete` callback). When called\n // after spec rendering is complete, it fails to expand operations \u2014 likely\n // because it depends on internal state or lifecycle context that no longer applies.\n //\n // Instead, we directly call `layoutActions.show()` which reliably toggles the\n // visibility of tags/operations, then scroll into view manually.\n window.addEventListener(\"hashchange\", function () {\n var hash = window.location.hash;\n if (!hash || hash === \"#\") {\n return;\n }\n // Hash format used by Swagger UI deep linking: #/tag/operationId\n var parts = hash.replace(/^#\\/?/, \"\").split(\"/\").filter(Boolean);\n if (parts.length === 0) {\n return;\n }\n var tag = safeDecodeURIComponent(parts[0]);\n var operationId = parts.length > 1 ? safeDecodeURIComponent(parts[1]) : null;\n window.ui.layoutActions.show([\"operations-tag\", tag], true);\n if (operationId) {\n window.ui.layoutActions.show([\"operations\", tag, operationId], true);\n }\n // Scroll to the expanded element. Swagger UI uses id=\"operations-{tag}-{operationId}\"\n // for operations and id=\"operations-tag-{tag}\" for tag sections. Use a small delay\n // to allow the DOM to update after the layout action.\n var targetId = operationId\n ? \"operations-\" + tag + \"-\" + operationId\n : \"operations-tag-\" + tag;\n requestAnimationFrame(function () {\n var element = document.getElementById(targetId);\n if (element) {\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n }\n });\n });\n};\nif (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", initializeSwaggerPage);\n}\nelse {\n initializeSwaggerPage();\n}\n"],
5
- "mappings": "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",
6
- "names": ["value", "optionsElement", "options", "authInput", "specSelector", "specSelectorWrapper", "themeToggle", "root", "getTheme", "applyTheme", "theme", "getApiKeyValue", "key", "ensureRequestHeaders", "request", "setRequestHeader", "headers", "absoluteSpecUrl", "url", "normalizeSwaggerUrls", "entry", "index", "selectedSwaggerUrl", "urls", "i", "absoluteUrl", "j", "setupSpecSelector", "selectedUrl", "option", "hideInfoUrlPlugin", "hideDocVersionPlugin", "hideVersionStampPlugin", "buildPlugins", "configuredPlugins", "plugins", "displayDefaults", "display", "swaggerUrls", "bundleConfig", "apiKeyValue", "separator", "event", "target", "hash", "parts", "tag", "operationId", "targetId", "element"]
4
+ "sourcesContent": ["\"use strict\";\nvar safeDecodeURIComponent = function (value) {\n try {\n return decodeURIComponent(value);\n }\n catch (_a) {\n return value;\n }\n};\nvar initializeSwaggerPage = function () {\n var optionsElement = document.documentElement.dataset.swaggerOptions;\n if (!optionsElement ||\n typeof SwaggerUIBundle === \"undefined\" ||\n typeof SwaggerUIStandalonePreset === \"undefined\") {\n return;\n }\n var options = JSON.parse(optionsElement);\n var authInput = document.getElementById(\"input_apiKey\");\n var specSelector = document.getElementById(\"spec-selector\");\n var specSelectorWrapper = document.getElementById(\"spec-selector-wrapper\");\n var themeToggle = document.getElementById(\"theme-toggle\");\n var root = document.documentElement;\n var getTheme = function () {\n return options.theme === \"dark\" ? \"dark\" : \"light\";\n };\n var applyTheme = function (theme) {\n root.dataset.theme = theme;\n root.classList.toggle(\"dark-mode\", theme === \"dark\");\n if (!themeToggle) {\n return;\n }\n themeToggle.textContent = theme === \"dark\" ? \"Light Mode\" : \"Dark Mode\";\n themeToggle.setAttribute(\"aria-pressed\", String(theme === \"dark\"));\n };\n var getApiKeyValue = function () {\n if (!authInput) {\n return \"\";\n }\n var key = authInput.value ? authInput.value.trim() : \"\";\n if (!key) {\n return \"\";\n }\n if (options.api_auth === \"basic\") {\n return \"Basic \" + btoa(key);\n }\n if (options.api_auth === \"bearer\") {\n return \"Bearer \" + key;\n }\n if (options.api_auth === \"token\") {\n return \"Token token=\\\"\".concat(key, \"\\\"\");\n }\n return key;\n };\n var ensureRequestHeaders = function (request) {\n if (!request.headers) {\n request.headers = {};\n }\n return request.headers;\n };\n var setRequestHeader = function (request, key, value) {\n var headers = ensureRequestHeaders(request);\n if (headers instanceof Headers) {\n headers.set(key, value);\n return;\n }\n headers[key] = value;\n };\n var absoluteSpecUrl = function (url) {\n if (!url) {\n return \"\";\n }\n if (/^https?:\\/\\//.test(url)) {\n return url;\n }\n return options.app_url + url;\n };\n var normalizeSwaggerUrls = function () {\n if (!Array.isArray(options.urls)) {\n return [];\n }\n return options.urls\n .map(function (entry, index) {\n if (typeof entry === \"string\") {\n return { name: entry, url: absoluteSpecUrl(entry), default: false };\n }\n return {\n name: entry.name || entry.url || \"Spec \" + (index + 1),\n url: absoluteSpecUrl(entry.url),\n default: Boolean(entry.default),\n };\n })\n .filter(function (entry) { return Boolean(entry.url); });\n };\n var selectedSwaggerUrl = function (urls) {\n if (!urls.length) {\n return null;\n }\n for (var i = 0; i < urls.length; i += 1) {\n if (urls[i].default) {\n return urls[i];\n }\n }\n if (options.url) {\n var absoluteUrl = absoluteSpecUrl(options.url);\n for (var j = 0; j < urls.length; j += 1) {\n if (urls[j].url === absoluteUrl) {\n return urls[j];\n }\n }\n }\n return urls[0];\n };\n var setupSpecSelector = function (urls, selectedUrl) {\n if (!specSelector || !specSelectorWrapper || urls.length < 2) {\n return;\n }\n urls.forEach(function (entry) {\n var option = document.createElement(\"option\");\n option.value = entry.url;\n option.textContent = entry.name;\n if (selectedUrl && entry.url === selectedUrl.url) {\n option.selected = true;\n }\n specSelector.appendChild(option);\n });\n specSelectorWrapper.hidden = false;\n };\n var hideInfoUrlPlugin = function () {\n return {\n wrapComponents: {\n InfoUrl: function () { return function () { return null; }; },\n },\n };\n };\n var hideDocVersionPlugin = function () {\n return {\n wrapComponents: {\n VersionStamp: function () { return function () { return null; }; },\n },\n };\n };\n var hideVersionStampPlugin = function () {\n return {\n wrapComponents: {\n OpenAPIVersion: function () { return function () { return null; }; },\n },\n };\n };\n // Swagger UI's \"Clear\" button (next to Execute) is confusing \u2014 it resets\n // the internal request / response state but does not clear values still visible\n // in the rendered input fields. Upstream issue swagger-api/swagger-ui#5283\n // has acknowledged the UX problem since 2019 without a fix. Hide by default.\n var hideClearButtonPlugin = function () {\n return {\n wrapComponents: {\n clear: function () { return function () { return null; }; },\n },\n };\n };\n var buildPlugins = function () {\n var configuredPlugins = options.swagger_ui_config && options.swagger_ui_config.plugins;\n var plugins = Array.isArray(configuredPlugins) ? configuredPlugins.slice() : [];\n var displayDefaults = {\n api_key_input: true,\n info_url: true,\n doc_version: true,\n version_stamp: true,\n clear_button: false,\n };\n var display = Object.assign({}, displayDefaults, options.display || {});\n if (!display.info_url) {\n plugins.push(hideInfoUrlPlugin);\n }\n if (!display.doc_version) {\n plugins.push(hideDocVersionPlugin);\n }\n if (!display.version_stamp) {\n plugins.push(hideVersionStampPlugin);\n }\n if (!display.clear_button) {\n plugins.push(hideClearButtonPlugin);\n }\n return plugins;\n };\n applyTheme(getTheme());\n if (themeToggle) {\n themeToggle.addEventListener(\"click\", function () {\n options.theme = root.dataset.theme === \"dark\" ? \"light\" : \"dark\";\n applyTheme(options.theme);\n });\n }\n var swaggerUrls = normalizeSwaggerUrls();\n var selectedUrl = selectedSwaggerUrl(swaggerUrls);\n var bundleConfig = Object.assign({}, options.swagger_ui_config || {}, {\n dom_id: \"#swagger-ui-container\",\n deepLinking: true,\n docExpansion: options.doc_expansion,\n supportedSubmitMethods: options.supported_submit_methods || [],\n validatorUrl: options.validator_url,\n layout: \"BaseLayout\",\n presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],\n plugins: buildPlugins(),\n requestInterceptor: function (request) {\n var headers = options.headers || {};\n Object.keys(headers).forEach(function (key) {\n setRequestHeader(request, key, headers[key]);\n });\n var apiKeyValue = getApiKeyValue();\n if (!apiKeyValue) {\n return request;\n }\n if (options.api_key_type === \"query\") {\n var separator = request.url.indexOf(\"?\") === -1 ? \"?\" : \"&\";\n request.url +=\n separator +\n encodeURIComponent(options.api_key_name) +\n \"=\" +\n encodeURIComponent(apiKeyValue);\n return request;\n }\n setRequestHeader(request, options.api_key_name, apiKeyValue);\n return request;\n },\n });\n if (swaggerUrls.length) {\n bundleConfig.urls = swaggerUrls;\n if (selectedUrl) {\n bundleConfig[\"urls.primaryName\"] = selectedUrl.name;\n }\n }\n else {\n bundleConfig.url = absoluteSpecUrl(options.url);\n }\n window.ui = SwaggerUIBundle(bundleConfig);\n if (selectedUrl) {\n window.ui.specActions.updateUrl(selectedUrl.url);\n window.ui.specActions.download(selectedUrl.url);\n }\n setupSpecSelector(swaggerUrls, selectedUrl);\n if (specSelector && swaggerUrls.length > 1) {\n specSelector.addEventListener(\"change\", function (event) {\n var target = event.target;\n var url = target.value;\n window.ui.specActions.updateUrl(url);\n window.ui.specActions.download(url);\n });\n }\n // Listen for hash changes so that navigating to a deep-link URL in the same\n // tab (e.g. pasting a copied operation URL into the address bar) expands the\n // target operation without requiring a full page refresh.\n //\n // NOTE: We intentionally do NOT use `layoutActions.parseDeepLinkHash()` here.\n // That method is Swagger UI's built-in deep linking plugin action, designed to\n // run during initial spec load (inside the `onComplete` callback). When called\n // after spec rendering is complete, it fails to expand operations \u2014 likely\n // because it depends on internal state or lifecycle context that no longer applies.\n //\n // Instead, we directly call `layoutActions.show()` which reliably toggles the\n // visibility of tags/operations, then scroll into view manually.\n window.addEventListener(\"hashchange\", function () {\n var hash = window.location.hash;\n if (!hash || hash === \"#\") {\n return;\n }\n // Hash format used by Swagger UI deep linking: #/tag/operationId\n var parts = hash.replace(/^#\\/?/, \"\").split(\"/\").filter(Boolean);\n if (parts.length === 0) {\n return;\n }\n var tag = safeDecodeURIComponent(parts[0]);\n var operationId = parts.length > 1 ? safeDecodeURIComponent(parts[1]) : null;\n window.ui.layoutActions.show([\"operations-tag\", tag], true);\n if (operationId) {\n window.ui.layoutActions.show([\"operations\", tag, operationId], true);\n }\n // Scroll to the expanded element. Swagger UI uses id=\"operations-{tag}-{operationId}\"\n // for operations and id=\"operations-tag-{tag}\" for tag sections. Use a small delay\n // to allow the DOM to update after the layout action.\n var targetId = operationId\n ? \"operations-\" + tag + \"-\" + operationId\n : \"operations-tag-\" + tag;\n requestAnimationFrame(function () {\n var element = document.getElementById(targetId);\n if (element) {\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n }\n });\n });\n};\nif (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", initializeSwaggerPage);\n}\nelse {\n initializeSwaggerPage();\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["value", "optionsElement", "options", "authInput", "specSelector", "specSelectorWrapper", "themeToggle", "root", "getTheme", "applyTheme", "theme", "getApiKeyValue", "key", "ensureRequestHeaders", "request", "setRequestHeader", "headers", "absoluteSpecUrl", "url", "normalizeSwaggerUrls", "entry", "index", "selectedSwaggerUrl", "urls", "i", "absoluteUrl", "j", "setupSpecSelector", "selectedUrl", "option", "hideInfoUrlPlugin", "hideDocVersionPlugin", "hideVersionStampPlugin", "hideClearButtonPlugin", "buildPlugins", "configuredPlugins", "plugins", "displayDefaults", "display", "swaggerUrls", "bundleConfig", "apiKeyValue", "separator", "event", "target", "hash", "parts", "tag", "operationId", "targetId", "element"]
7
7
  }
@@ -1,6 +1,5 @@
1
1
  html {
2
2
  box-sizing: border-box;
3
- overflow: -moz-scrollbars-vertical;
4
3
  overflow-y: scroll;
5
4
  }
6
5
 
@@ -232,6 +231,10 @@ html[data-theme="dark"] .swagger-ui .model-box {
232
231
  border-color: #475569;
233
232
  }
234
233
 
234
+ .swagger-ui .model-box table.model tr.property-row > td {
235
+ vertical-align: baseline;
236
+ }
237
+
235
238
  @media (max-width: 767px) {
236
239
  .swagger-header {
237
240
  flex-direction: column;
@@ -17,6 +17,7 @@ interface SwaggerPageOptions {
17
17
  info_url: boolean;
18
18
  doc_version: boolean;
19
19
  version_stamp: boolean;
20
+ clear_button: boolean;
20
21
  };
21
22
  supported_submit_methods: string[];
22
23
  theme: string;
@@ -236,10 +237,28 @@ const initializeSwaggerPage = (): void => {
236
237
  };
237
238
  }
238
239
 
240
+ // Swagger UI's "Clear" button (next to Execute) is confusing — it resets
241
+ // the internal request / response state but does not clear values still visible
242
+ // in the rendered input fields. Upstream issue swagger-api/swagger-ui#5283
243
+ // has acknowledged the UX problem since 2019 without a fix. Hide by default.
244
+ const hideClearButtonPlugin = (): SwaggerPlugin => {
245
+ return {
246
+ wrapComponents: {
247
+ clear: () => () => null,
248
+ },
249
+ };
250
+ }
251
+
239
252
  const buildPlugins = (): unknown[] => {
240
253
  const configuredPlugins = options.swagger_ui_config && options.swagger_ui_config.plugins;
241
254
  const plugins = Array.isArray(configuredPlugins) ? configuredPlugins.slice() : [];
242
- const displayDefaults = { api_key_input: true, info_url: true, doc_version: true, version_stamp: true };
255
+ const displayDefaults = {
256
+ api_key_input: true,
257
+ info_url: true,
258
+ doc_version: true,
259
+ version_stamp: true,
260
+ clear_button: false,
261
+ };
243
262
  const display = Object.assign({}, displayDefaults, options.display || {});
244
263
 
245
264
  if (!display.info_url) {
@@ -254,6 +273,10 @@ const initializeSwaggerPage = (): void => {
254
273
  plugins.push(hideVersionStampPlugin);
255
274
  }
256
275
 
276
+ if (!display.clear_button) {
277
+ plugins.push(hideClearButtonPlugin);
278
+ }
279
+
257
280
  return plugins;
258
281
  }
259
282
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrapeSwaggerRails
4
- VERSION = '1.0.1'
4
+ VERSION = '1.0.2'
5
5
  SWAGGER_UI_VERSION = '5.32.6'
6
6
  end
@@ -51,7 +51,8 @@ module GrapeSwaggerRails
51
51
  api_key_input: true,
52
52
  info_url: true,
53
53
  doc_version: true,
54
- version_stamp: true
54
+ version_stamp: true,
55
+ clear_button: false
55
56
  }
56
57
  )
57
58
 
@@ -8,7 +8,14 @@ namespace :swagger_ui do
8
8
  namespace :dist do
9
9
  desc 'Update Swagger UI assets from swagger-api/swagger-ui.'
10
10
  task :update do
11
- version = ENV.fetch('SWAGGER_UI_VERSION', 'v5.32.5')
11
+ root = File.expand_path('../..', __dir__)
12
+ version_file = File.join(root, 'lib/grape-swagger-rails/version.rb')
13
+ match = File.read(version_file).match(/SWAGGER_UI_VERSION = '([^']+)'/)
14
+ raise "Could not find SWAGGER_UI_VERSION in #{version_file}" unless match
15
+
16
+ current_version = match[1]
17
+ version = ENV.fetch('SWAGGER_UI_VERSION', "v#{current_version}")
18
+ version = "v#{version}" unless version.start_with?('v')
12
19
 
13
20
  Dir.mktmpdir('swagger-ui') do |dir|
14
21
  puts "Cloning swagger-api/swagger-ui #{version} into #{dir} ..."
@@ -20,7 +27,6 @@ namespace :swagger_ui do
20
27
  branch: version
21
28
  )
22
29
 
23
- root = File.expand_path('../..', __dir__)
24
30
  dist = File.join(dir, 'swagger-ui', 'dist')
25
31
 
26
32
  raise "Missing dist directory at #{dist}" unless Dir.exist?(dist)
@@ -39,11 +45,22 @@ namespace :swagger_ui do
39
45
  File.join(root, 'app/assets/stylesheets/grape_swagger_rails/swagger-ui.css')
40
46
 
41
47
  semver = version.sub(/\Av/, '')
42
- version_file = File.join(root, 'lib/grape-swagger-rails/version.rb')
43
48
  content = File.read(version_file)
44
49
  updated = content.gsub(/SWAGGER_UI_VERSION = '[^']*'/, "SWAGGER_UI_VERSION = '#{semver}'")
45
50
  File.write(version_file, updated)
46
51
  puts "Updated SWAGGER_UI_VERSION to #{semver} in #{version_file}"
52
+
53
+ readme_file = File.join(root, 'README.md')
54
+ readme = File.read(readme_file)
55
+ compatibility_table = readme.match(/(## Compatibility.*?)(\n\nThe dummy app)/m)
56
+ raise 'Could not find README compatibility table' unless compatibility_table
57
+
58
+ updated_table = compatibility_table[1].gsub(
59
+ /^(\|\s*[^|\n]+\|\s*[^|\n]+\|\s*[^|\n]+\|\s*[^|\n]+\|\s*)\d+\.\d+\.\d+(\s*\|)$/m,
60
+ "\\1#{semver}\\2"
61
+ )
62
+ File.write(readme_file, readme.sub(compatibility_table[1], updated_table))
63
+ puts "Updated Swagger UI compatibility table to #{semver} in #{readme_file}"
47
64
  end
48
65
  end
49
66
  end
@@ -231,6 +231,32 @@ describe 'Swagger' do
231
231
  end
232
232
  end
233
233
 
234
+ describe 'display[:clear_button] option' do
235
+ include_context 'with isolated options'
236
+
237
+ it 'hides the Clear button by default after Execute' do
238
+ visit_swagger
239
+ open_operation('operations-tag-foos', 'operations-foos-getApiFoos')
240
+ execute_operation('operations-foos-getApiFoos')
241
+
242
+ within('#operations-foos-getApiFoos') do
243
+ expect(page).to have_css('.responses-wrapper')
244
+ expect(page).to have_no_css('.btn-clear')
245
+ end
246
+ end
247
+
248
+ it 'shows the Clear button when enabled' do
249
+ GrapeSwaggerRails.options.display = GrapeSwaggerRails.options.display.merge(clear_button: true)
250
+ visit_swagger
251
+ open_operation('operations-tag-foos', 'operations-foos-getApiFoos')
252
+ execute_operation('operations-foos-getApiFoos')
253
+
254
+ within('#operations-foos-getApiFoos') do
255
+ expect(page).to have_css('.btn-clear', text: 'Clear')
256
+ end
257
+ end
258
+ end
259
+
234
260
  describe 'same-session deep link navigation' do
235
261
  # Regression tests for: navigating to a Swagger deep-link URL in the same
236
262
  # tab/session should expand the target operation without a full page refresh.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape-swagger-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Logunov
@@ -83,6 +83,7 @@ files:
83
83
  - ".github/workflows/danger.yml"
84
84
  - ".github/workflows/frontend.yml"
85
85
  - ".github/workflows/rubocop.yml"
86
+ - ".github/workflows/swagger-ui-update.yml"
86
87
  - ".github/workflows/test.yml"
87
88
  - ".gitignore"
88
89
  - ".pnp.cjs"
@@ -171,7 +172,7 @@ licenses:
171
172
  metadata:
172
173
  bug_tracker_uri: https://github.com/ruby-grape/grape-swagger-rails/issues
173
174
  changelog_uri: https://github.com/ruby-grape/grape-swagger-rails/blob/master/CHANGELOG.md
174
- source_code_uri: https://github.com/ruby-grape/grape-swagger-rails/tree/v1.0.1
175
+ source_code_uri: https://github.com/ruby-grape/grape-swagger-rails/tree/v1.0.2
175
176
  rubygems_mfa_required: 'true'
176
177
  rdoc_options: []
177
178
  require_paths: