openapi-explorer 1.0.571 → 1.1.578
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.
- package/dist/browser/openapi-explorer.min.js +6 -6
- package/dist/browser/openapi-explorer.min.js.map +1 -1
- package/dist/es/components/api-request.js +98 -44
- package/dist/es/components/request-form-table.js +77 -11
- package/dist/es/utils/schema-utils.js +4 -1
- package/dist/lib/components/api-request.js +97 -43
- package/dist/lib/components/request-form-table.js +80 -11
- package/dist/lib/utils/schema-utils.js +5 -0
- package/package.json +1 -1
|
@@ -43,6 +43,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
43
43
|
|
|
44
44
|
constructor() {
|
|
45
45
|
super();
|
|
46
|
+
this.duplicatedRowsByKey = {};
|
|
46
47
|
this.storedParamValues = {};
|
|
47
48
|
this.responseMessage = '';
|
|
48
49
|
this.responseStatus = '';
|
|
@@ -51,7 +52,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
51
52
|
this.responseUrl = '';
|
|
52
53
|
this.responseElapsedMs = 0;
|
|
53
54
|
this.curlSyntax = '';
|
|
54
|
-
this.activeResponseTab = '
|
|
55
|
+
this.activeResponseTab = 'curl'; // allowed values: response, headers, curl
|
|
55
56
|
|
|
56
57
|
this.selectedRequestBodyType = '';
|
|
57
58
|
this.selectedRequestBodyExample = '';
|
|
@@ -160,6 +161,10 @@ class ApiRequest extends _lit.LitElement {
|
|
|
160
161
|
attribute: 'fetch-credentials'
|
|
161
162
|
},
|
|
162
163
|
// properties for internal tracking
|
|
164
|
+
duplicatedRowsByKey: {
|
|
165
|
+
type: Object
|
|
166
|
+
},
|
|
167
|
+
// Tracking duplicated rows in form table
|
|
163
168
|
activeResponseTab: {
|
|
164
169
|
type: String
|
|
165
170
|
},
|
|
@@ -183,13 +188,8 @@ class ApiRequest extends _lit.LitElement {
|
|
|
183
188
|
}
|
|
184
189
|
|
|
185
190
|
updated(changedProperties) {
|
|
186
|
-
|
|
187
|
-
this.selectedRequestBodyType = '';
|
|
188
|
-
this.selectedRequestBodyExample = '';
|
|
189
|
-
} // In focused mode after rendering the request component, update the text-areas(which contains examples) using the original values from hidden textareas.
|
|
191
|
+
// In focused mode after rendering the request component, update the text-areas(which contains examples) using the original values from hidden textareas.
|
|
190
192
|
// This is done coz, user may update the dom by editing the textarea's and once the DOM is updated externally change detection wont happen, therefore update the values manually
|
|
191
|
-
|
|
192
|
-
|
|
193
193
|
if (this.renderStyle !== 'focused') {
|
|
194
194
|
return;
|
|
195
195
|
} // dont update example as only tabs is switched
|
|
@@ -257,7 +257,10 @@ class ApiRequest extends _lit.LitElement {
|
|
|
257
257
|
|
|
258
258
|
tableRows.push((0, _lit.html)` <tr> <td colspan="1" style="width:160px;min-width:50px;vertical-align:top"> <div class="param-name ${paramSchema.deprecated ? 'deprecated' : ''}" style="margin-top:1rem"> ${param.name}${!paramSchema.deprecated && param.required ? (0, _lit.html)`<span style="color:var(--red)">*</span>` : ''} </div> <div class="param-type" style="margin-bottom:1rem"> ${paramSchema.type === 'array' ? `${paramSchema.arrayType}` : `${paramSchema.format ? paramSchema.format : paramSchema.type}`}${!paramSchema.deprecated && param.required ? (0, _lit.html)`<span style="opacity:0">*</span>` : ''} </div> </td> <td colspan="2" style="min-width:160px;vertical-align:top"> ${this.allowTry === 'true' ? paramSchema.type === 'array' && (0, _lit.html)` <div style="margin-top:1rem;margin-bottom:1rem"> <tag-input class="request-param" style="width:100%" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" data-array="true" placeholder="add-multiple ↩" @change="${e => {
|
|
259
259
|
this.storedParamValues[param.name] = e.detail.value;
|
|
260
|
-
|
|
260
|
+
this.computeCurlSyntax();
|
|
261
|
+
}}" .value="${(_this$storedParamValu = this.storedParamValues[param.name]) !== null && _this$storedParamValu !== void 0 ? _this$storedParamValu : this.fillRequestWithDefault === 'true' && Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}"></tag-input> </div>` || paramSchema.type === 'object' && (0, _lit.html)` <textarea class="textarea small request-param" part="textarea small textarea-param" rows="3" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" spellcheck="false" placeholder="${paramSchema.example || defaultVal || ''}" style="width:100%;margin-top:1rem;margin-bottom:1rem" .value="${this.fillRequestWithDefault === 'true' ? defaultVal : ''}"></textarea>` || (0, _lit.html)` <input type="${paramSchema.format === 'password' ? 'password' : 'text'}" spellcheck="false" style="width:100%;margin-top:1rem;margin-bottom:1rem" @input="${() => {
|
|
262
|
+
this.computeCurlSyntax();
|
|
263
|
+
}}" placeholder="${paramSchema.example || defaultVal || ''}" class="request-param" part="textbox textbox-param" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-array="false" @keyup="${this.requestParamFunction}" .value="${this.fillRequestWithDefault === 'true' ? defaultVal : ''}">` : ''} ${this.exampleListTemplate.call(this, param, paramSchema.type)} </td> ${this.renderStyle === 'focused' ? (0, _lit.html)` <td colspan="2" style="vertical-align:top"> ${param.description ? (0, _lit.html)` <div class="param-description" style="margin-top:1rem"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(param.description))} </div>` : ''} ${paramSchema.default || paramSchema.s || paramSchema.allowedValues || paramSchema.pattern ? (0, _lit.html)` <div class="param-constraint" style="margin-top:1rem"> ${paramSchema.constraints.length ? (0, _lit.html)`<span style="font-weight:700">Constraints: </span>${paramSchema.constraints.join(', ')}<br>` : ''} ${paramSchema.pattern ? (0, _lit.html)` <div class="tooltip tooltip-replace" style="cursor:pointer;max-width:100%;display:flex"> <div style="white-space:nowrap;font-weight:700;margin-right:2px">Pattern: </div> <div style="white-space:nowrap;text-overflow:ellipsis;max-width:100%;overflow:hidden">${paramSchema.pattern}</div> <br> <div class="tooltip-text" style="position:absolute;display:block">${paramSchema.pattern}</div> </div> ` : ''} ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => (0, _lit.html)` ${i > 0 ? '|' : (0, _lit.html)`<span style="font-weight:700">Allowed: </span>`} ${(0, _lit.html)` <a part="anchor anchor-param-constraint" class="${this.allowTry === 'true' ? '' : 'inactive-link'}" data-type="${paramSchema.type === 'array' ? 'array' : 'string'}" data-enum="${v.trim()}" @click="${e => {
|
|
261
264
|
const inputEl = e.target.closest('table').querySelector(`[data-pname="${param.name}"]`);
|
|
262
265
|
|
|
263
266
|
if (inputEl) {
|
|
@@ -330,6 +333,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
330
333
|
resetRequestBodySelection() {
|
|
331
334
|
this.selectedRequestBodyType = '';
|
|
332
335
|
this.selectedRequestBodyExample = '';
|
|
336
|
+
this.computeCurlSyntax();
|
|
333
337
|
this.clearResponseData();
|
|
334
338
|
} // Request-Body Event Handlers
|
|
335
339
|
|
|
@@ -341,6 +345,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
341
345
|
const exampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param');
|
|
342
346
|
const userInputExampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param-user-input');
|
|
343
347
|
userInputExampleTextareaEl.value = exampleTextareaEl.value;
|
|
348
|
+
this.computeCurlSyntax();
|
|
344
349
|
}, 0, exampleDropdownEl);
|
|
345
350
|
}
|
|
346
351
|
|
|
@@ -355,6 +360,8 @@ class ApiRequest extends _lit.LitElement {
|
|
|
355
360
|
const userInputExampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param-user-input');
|
|
356
361
|
userInputExampleTextareaEl.value = exampleTextareaEl.value;
|
|
357
362
|
}
|
|
363
|
+
|
|
364
|
+
this.computeCurlSyntax();
|
|
358
365
|
}, 0, mimeDropdownEl);
|
|
359
366
|
}
|
|
360
367
|
|
|
@@ -432,7 +439,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
432
439
|
}
|
|
433
440
|
}
|
|
434
441
|
|
|
435
|
-
return (0, _lit.html)` <div class="request-body-container" data-selected-request-body-type="${this.selectedRequestBodyType}"> <div class="table-title top-gap row">
|
|
442
|
+
return (0, _lit.html)` <div class="request-body-container" data-selected-request-body-type="${this.selectedRequestBodyType}"> <div class="table-title top-gap row"> ${(0, _languages.getI18nText)('operations.request-body')} ${this.request_body.required ? (0, _lit.html)`<span class="mono-font" style="color:var(--red)">*</span>` : ''} <span style="font-weight:400;margin-left:5px"> ${this.selectedRequestBodyType}</span> <span style="flex:1"></span> ${reqBodyTypeSelectorHtml} </div> ${this.request_body.description ? (0, _lit.html)`<div class="m-markdown" style="margin-bottom:12px">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(this.request_body.description))}</div>` : ''} ${reqBodySchemaHtml || reqBodyDefaultHtml ? (0, _lit.html)` <div class="tab-panel col" style="border-width:0 0 1px 0"> <div class="tab-buttons row" @click="${e => {
|
|
436
443
|
if (e.target.tagName.toLowerCase() === 'button') {
|
|
437
444
|
this.activeSchemaTab = e.target.dataset.tab;
|
|
438
445
|
}
|
|
@@ -453,14 +460,16 @@ class ApiRequest extends _lit.LitElement {
|
|
|
453
460
|
|
|
454
461
|
|
|
455
462
|
apiResponseTabTemplate() {
|
|
463
|
+
const curlSyntax = this.curlSyntax || this.computeCurlSyntax() || '';
|
|
464
|
+
const hasResponse = this.responseMessage !== '';
|
|
456
465
|
const responseFormat = this.responseHeaders.includes('json') ? 'json' : this.responseHeaders.includes('html') || this.responseHeaders.includes('xml') ? 'html' : '';
|
|
457
|
-
return (0, _lit.html)` <div class="row" style="font-size:var(--font-size-small);margin:5px 0"> ${this.responseMessage ? (0, _lit.html)`<div class="response-message ${this.responseStatus}">Response Status: ${this.responseMessage} ${this.responseElapsedMs ? (0, _lit.html)`<span><br>Execution Time: ${this.responseElapsedMs}ms</span>` : ''} </div>` : ''} <div style="flex:1"></div>
|
|
466
|
+
return (0, _lit.html)` <div class="row" style="font-size:var(--font-size-small);margin:5px 0"> ${this.responseMessage ? (0, _lit.html)`<div class="response-message ${this.responseStatus}">Response Status: ${this.responseMessage} ${this.responseElapsedMs ? (0, _lit.html)`<span><br>Execution Time: ${this.responseElapsedMs}ms</span>` : ''} </div>` : ''} <div style="flex:1"></div> ${!hasResponse ? '' : (0, _lit.html)`<button class="m-btn" part="btn btn-outline" @click="${this.clearResponseData}">CLEAR RESPONSE</button>`} </div> <div class="tab-panel col" style="border-width:0 0 1px 0"> <div id="tab_buttons" class="tab-buttons row" @click="${e => {
|
|
458
467
|
if (e.target.classList.contains('tab-btn') === false) {
|
|
459
468
|
return;
|
|
460
469
|
}
|
|
461
470
|
|
|
462
471
|
this.activeResponseTab = e.target.dataset.tab;
|
|
463
|
-
}}"> <button class="tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}" data-tab="response">${(0, _languages.getI18nText)('operations.response')}</button> <button class="tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}" data-tab="headers">${(0, _languages.getI18nText)('operations.response-headers')}</button
|
|
472
|
+
}}"> <br> <div style="width:100%"> ${!hasResponse ? '' : (0, _lit.html)` <button class="tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}" data-tab="response">${(0, _languages.getI18nText)('operations.response')}</button> <button class="tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}" data-tab="headers">${(0, _languages.getI18nText)('operations.response-headers')}</button>`} <button class="tab-btn ${!hasResponse || this.activeResponseTab === 'curl' ? 'active' : ''}" data-tab="curl">FULL REQUEST</button> </div> </div> ${this.responseIsBlob ? (0, _lit.html)` <div class="tab-content col" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> <button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.downloadResponseBlob}" part="btn btn-outline">DOWNLOAD</button> ${this.responseBlobType === 'view' ? (0, _lit.html)`<button class="m-btn thin-border mar-top-8" style="width:135px" @click="${this.viewResponseBlob}" part="btn btn-outline">VIEW (NEW TAB)</button>` : ''} </div>` : (0, _lit.html)` <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'response' ? 'flex' : 'none'}"> ${this.responseText ? (0, _lit.html)`<button class="m-btn outline-primary toolbar-copy-btn" @click="${e => {
|
|
464
473
|
(0, _commonUtils.copyToClipboard)(this.responseText, e);
|
|
465
474
|
}}" part="btn btn-fill">${(0, _languages.getI18nText)('operations.copy')}</button>` : ''} <pre style="min-height:60px" @copy="${() => {
|
|
466
475
|
(0, _commonUtils.copyToClipboard)(window.getSelection().toString());
|
|
@@ -468,14 +477,14 @@ class ApiRequest extends _lit.LitElement {
|
|
|
468
477
|
</pre> </div>`} <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'}"> <button class="m-btn outline-primary toolbar-copy-btn" @click="${e => {
|
|
469
478
|
(0, _commonUtils.copyToClipboard)(this.responseHeaders, e);
|
|
470
479
|
}}" part="btn btn-fill">${(0, _languages.getI18nText)('operations.copy')}</button> <pre><code>${(0, _unsafeHtml.unsafeHTML)(_prismjs.default.highlight(this.responseHeaders, _prismjs.default.languages.css, 'css'))}</code></pre> </div> <div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'}"> <button class="m-btn outline-primary toolbar-copy-btn" @click="${e => {
|
|
471
|
-
(0, _commonUtils.copyToClipboard)(
|
|
480
|
+
(0, _commonUtils.copyToClipboard)(curlSyntax, e);
|
|
472
481
|
}}" part="btn btn-fill">${(0, _languages.getI18nText)('operations.copy')}</button> <pre class="fs-exclude" data-hj-suppress data-sl="mask">
|
|
473
|
-
<code>${(0, _unsafeHtml.unsafeHTML)(_prismjs.default.highlight(
|
|
482
|
+
<code>${(0, _unsafeHtml.unsafeHTML)(_prismjs.default.highlight(curlSyntax.trim(), _prismjs.default.languages.shell, 'shell'))}</code>
|
|
474
483
|
</pre> </div> </div>`;
|
|
475
484
|
}
|
|
476
485
|
|
|
477
486
|
apiCallTemplate() {
|
|
478
|
-
return (0, _lit.html)` <div style="display:flex;align-items:flex-end;margin:16px 0;font-size:var(--font-size-small)"> ${this.parameters.length > 0 || this.request_body ? (0, _lit.html)` <button class="m-btn thin-border" part="btn btn-outline" style="margin-right:5px" @click="${this.onClearRequestData}"> ${(0, _languages.getI18nText)('operations.clear')} </button>` : ''} <button class="m-btn primary btn-execute thin-border" part="btn btn-fill btn-try" @click="${this.onTryClick}">${(0, _languages.getI18nText)('operations.execute')}</button> </div> ${this.
|
|
487
|
+
return (0, _lit.html)` <div style="display:flex;align-items:flex-end;margin:16px 0;font-size:var(--font-size-small)"> ${this.parameters.length > 0 || this.request_body ? (0, _lit.html)` <button class="m-btn thin-border" part="btn btn-outline" style="margin-right:5px" @click="${this.onClearRequestData}"> ${(0, _languages.getI18nText)('operations.clear')} </button>` : ''} <button class="m-btn primary btn-execute thin-border" part="btn btn-fill btn-try" @click="${this.onTryClick}">${(0, _languages.getI18nText)('operations.execute')}</button> </div> ${this.apiResponseTabTemplate()} `;
|
|
479
488
|
}
|
|
480
489
|
/* eslint-enable indent */
|
|
481
490
|
|
|
@@ -499,12 +508,10 @@ class ApiRequest extends _lit.LitElement {
|
|
|
499
508
|
}
|
|
500
509
|
};
|
|
501
510
|
this.dispatchEvent(new CustomEvent('event', event));
|
|
511
|
+
this.computeCurlSyntax();
|
|
502
512
|
}
|
|
503
513
|
|
|
504
|
-
|
|
505
|
-
const tryBtnEl = this.querySelectorAll('.btn-execute')[0];
|
|
506
|
-
let curlData = '';
|
|
507
|
-
let curlForm = '';
|
|
514
|
+
recomputeFetchOptions() {
|
|
508
515
|
const closestRespContainer = this.closest('.expanded-req-resp-container, .req-resp-container');
|
|
509
516
|
const respEl = closestRespContainer && closestRespContainer.getElementsByTagName('api-response')[0];
|
|
510
517
|
const acceptHeader = respEl === null || respEl === void 0 ? void 0 : respEl.selectedMimeType;
|
|
@@ -624,14 +631,21 @@ class ApiRequest extends _lit.LitElement {
|
|
|
624
631
|
fetchOptions.headers.append(el.dataset.pname, el.value);
|
|
625
632
|
}
|
|
626
633
|
}); // Request Body Params
|
|
634
|
+
// url-encoded Form Params (dynamic) - Parse JSON and generate Params
|
|
635
|
+
|
|
636
|
+
const formUrlDynamicTextAreaEl = requestPanelEl.querySelector("[data-ptype='dynamic-form']"); // url-encoded Form Params (regular)
|
|
637
|
+
|
|
638
|
+
const rawFormInputEls = [...requestPanelEl.querySelectorAll("[data-ptype='form-input']")];
|
|
639
|
+
const patternPropertyKeyEls = [...requestPanelEl.querySelectorAll("[data-ptype='pattern-property-key']")];
|
|
640
|
+
const patternPropertyInputEls = rawFormInputEls.filter(el => (0, _schemaUtils.isPatternProperty)(el.dataset.pname));
|
|
641
|
+
const formInputEls = rawFormInputEls.filter(el => !(0, _schemaUtils.isPatternProperty)(el.dataset.pname));
|
|
642
|
+
let curlData = '';
|
|
643
|
+
let curlForm = '';
|
|
627
644
|
|
|
628
645
|
if (requestBodyContainerEl) {
|
|
629
646
|
const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;
|
|
630
647
|
|
|
631
648
|
if (requestBodyType.includes('form-urlencoded')) {
|
|
632
|
-
// url-encoded Form Params (dynamic) - Parse JSON and generate Params
|
|
633
|
-
const formUrlDynamicTextAreaEl = requestPanelEl.querySelector("[data-ptype='dynamic-form']");
|
|
634
|
-
|
|
635
649
|
if (formUrlDynamicTextAreaEl) {
|
|
636
650
|
const val = formUrlDynamicTextAreaEl.value;
|
|
637
651
|
const formUrlDynParams = new URLSearchParams();
|
|
@@ -658,17 +672,23 @@ class ApiRequest extends _lit.LitElement {
|
|
|
658
672
|
curlData = ` \\\n -d ${formUrlDynParams.toString()}`;
|
|
659
673
|
}
|
|
660
674
|
} else {
|
|
661
|
-
// url-encoded Form Params (regular)
|
|
662
|
-
const formUrlEls = [...requestPanelEl.querySelectorAll("[data-ptype='form-urlencode']")];
|
|
663
675
|
const formUrlParams = new URLSearchParams();
|
|
664
|
-
|
|
676
|
+
patternPropertyInputEls.concat(formInputEls).forEach((el, counter) => {
|
|
677
|
+
var _patternPropertyKeyEl;
|
|
678
|
+
|
|
679
|
+
const keyName = ((_patternPropertyKeyEl = patternPropertyKeyEls[counter]) === null || _patternPropertyKeyEl === void 0 ? void 0 : _patternPropertyKeyEl.value) || el.dataset.pname;
|
|
680
|
+
|
|
681
|
+
if (el.type === 'file') {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
|
|
665
685
|
if (el.dataset.array === 'false') {
|
|
666
686
|
if (el.value) {
|
|
667
|
-
formUrlParams.append(
|
|
687
|
+
formUrlParams.append(keyName, el.value);
|
|
668
688
|
}
|
|
669
689
|
} else {
|
|
670
690
|
const vals = el.value && Array.isArray(el.value) ? el.value.join(',') : '';
|
|
671
|
-
formUrlParams.append(
|
|
691
|
+
formUrlParams.append(keyName, vals);
|
|
672
692
|
}
|
|
673
693
|
});
|
|
674
694
|
fetchOptions.body = formUrlParams;
|
|
@@ -676,21 +696,24 @@ class ApiRequest extends _lit.LitElement {
|
|
|
676
696
|
}
|
|
677
697
|
} else if (requestBodyType.includes('form-data')) {
|
|
678
698
|
const formDataParams = new FormData();
|
|
679
|
-
|
|
680
|
-
|
|
699
|
+
patternPropertyInputEls.concat(formInputEls).forEach((el, counter) => {
|
|
700
|
+
var _patternPropertyKeyEl2;
|
|
701
|
+
|
|
702
|
+
const keyName = ((_patternPropertyKeyEl2 = patternPropertyKeyEls[counter]) === null || _patternPropertyKeyEl2 === void 0 ? void 0 : _patternPropertyKeyEl2.value) || el.dataset.pname;
|
|
703
|
+
|
|
681
704
|
if (el.dataset.array === 'false') {
|
|
682
705
|
if (el.type === 'file' && el.files[0]) {
|
|
683
|
-
formDataParams.append(
|
|
684
|
-
curlForm += ` \\\n -F "${
|
|
706
|
+
formDataParams.append(keyName, el.files[0], el.files[0].name);
|
|
707
|
+
curlForm += ` \\\n -F "${keyName}=@${el.files[0].name}"`;
|
|
685
708
|
} else if (el.value) {
|
|
686
|
-
formDataParams.append(
|
|
687
|
-
curlForm += ` \\\n -F "${
|
|
709
|
+
formDataParams.append(keyName, el.value);
|
|
710
|
+
curlForm += ` \\\n -F "${keyName}=${el.value}"`;
|
|
688
711
|
}
|
|
689
712
|
} else if (el.value && Array.isArray(el.value)) {
|
|
690
713
|
el.value.forEach(v => {
|
|
691
|
-
curlForm += ` \\\n -F "${
|
|
714
|
+
curlForm += ` \\\n -F "${keyName}[]=${v}"`;
|
|
692
715
|
});
|
|
693
|
-
formDataParams.append(
|
|
716
|
+
formDataParams.append(keyName, el.value.join(','));
|
|
694
717
|
}
|
|
695
718
|
});
|
|
696
719
|
fetchOptions.body = formDataParams;
|
|
@@ -729,16 +752,46 @@ class ApiRequest extends _lit.LitElement {
|
|
|
729
752
|
}
|
|
730
753
|
}
|
|
731
754
|
|
|
755
|
+
if (this.fetchCredentials) {
|
|
756
|
+
fetchOptions.credentials = this.fetchCredentials;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return {
|
|
760
|
+
fetchOptions,
|
|
761
|
+
fetchUrl,
|
|
762
|
+
curlParts: {
|
|
763
|
+
data: curlData,
|
|
764
|
+
form: curlForm
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
computeCurlSyntax(headerOverride) {
|
|
770
|
+
const {
|
|
771
|
+
fetchOptions,
|
|
772
|
+
fetchUrl,
|
|
773
|
+
curlParts
|
|
774
|
+
} = this.recomputeFetchOptions();
|
|
775
|
+
const curl = `curl -X ${this.method.toUpperCase()} "${fetchUrl.toString()}"`;
|
|
776
|
+
const headers = headerOverride !== null && headerOverride !== void 0 ? headerOverride : fetchOptions.headers;
|
|
777
|
+
const curlHeaders = [...headers.entries()].reduce((acc, [key, value]) => `${acc} \\\n -H "${key}: ${value}"`, '');
|
|
778
|
+
this.curlSyntax = `${curl}${curlHeaders}${curlParts.data}${curlParts.form}`;
|
|
779
|
+
this.requestUpdate();
|
|
780
|
+
} // onExecuteButtonClicked
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
async onTryClick() {
|
|
784
|
+
const tryBtnEl = this.querySelectorAll('.btn-execute')[0];
|
|
785
|
+
const {
|
|
786
|
+
fetchOptions,
|
|
787
|
+
fetchUrl
|
|
788
|
+
} = this.recomputeFetchOptions();
|
|
732
789
|
this.responseIsBlob = false;
|
|
733
790
|
this.respContentDisposition = '';
|
|
734
791
|
|
|
735
792
|
if (this.responseBlobUrl) {
|
|
736
793
|
URL.revokeObjectURL(this.responseBlobUrl);
|
|
737
794
|
this.responseBlobUrl = '';
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
if (this.fetchCredentials) {
|
|
741
|
-
fetchOptions.credentials = this.fetchCredentials;
|
|
742
795
|
} // Options is legacy usage, documentation has been updated to reference properties of the fetch option directly, but older usages may still be using options
|
|
743
796
|
|
|
744
797
|
|
|
@@ -764,9 +817,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
764
817
|
body: fetchRequest.body || fetchOptions.body
|
|
765
818
|
};
|
|
766
819
|
const fetchRequestObject = new Request(fetchRequest.url, newFetchOptions);
|
|
767
|
-
|
|
768
|
-
const curlHeaders = [...newFetchOptions.headers.entries()].reduce((acc, [key, value]) => `${acc} \\\n -H "${key}: ${value}"`, '');
|
|
769
|
-
this.curlSyntax = `${curl}${curlHeaders}${curlData}${curlForm}`;
|
|
820
|
+
this.computeCurlSyntax(newFetchOptions.headers);
|
|
770
821
|
let fetchResponse;
|
|
771
822
|
|
|
772
823
|
try {
|
|
@@ -780,6 +831,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
780
831
|
this.responseUrl = '';
|
|
781
832
|
this.responseHeaders = '';
|
|
782
833
|
this.responseText = '⌛';
|
|
834
|
+
this.activeResponseTab = 'response';
|
|
783
835
|
this.requestUpdate();
|
|
784
836
|
const awaiter = new Promise(resolve => setTimeout(resolve, 200));
|
|
785
837
|
fetchResponse = await fetch(fetchRequestObject);
|
|
@@ -886,7 +938,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
886
938
|
}
|
|
887
939
|
}
|
|
888
940
|
|
|
889
|
-
onAddRemoveFileInput(e, pname
|
|
941
|
+
onAddRemoveFileInput(e, pname) {
|
|
890
942
|
if (e.target.tagName.toLowerCase() !== 'button') {
|
|
891
943
|
return;
|
|
892
944
|
}
|
|
@@ -908,7 +960,7 @@ class ApiRequest extends _lit.LitElement {
|
|
|
908
960
|
newInputEl.type = 'file';
|
|
909
961
|
newInputEl.setAttribute('class', 'file-input');
|
|
910
962
|
newInputEl.setAttribute('data-pname', pname);
|
|
911
|
-
newInputEl.setAttribute('data-ptype',
|
|
963
|
+
newInputEl.setAttribute('data-ptype', 'form-input');
|
|
912
964
|
newInputEl.setAttribute('data-array', 'false');
|
|
913
965
|
newInputEl.setAttribute('data-file-array', 'true'); // Remover Button
|
|
914
966
|
|
|
@@ -918,6 +970,8 @@ class ApiRequest extends _lit.LitElement {
|
|
|
918
970
|
newInputContainerEl.appendChild(newInputEl);
|
|
919
971
|
newInputContainerEl.appendChild(newRemoveBtnEl);
|
|
920
972
|
el.insertBefore(newInputContainerEl, e.target); // el.appendChild(newInputContainerEl);
|
|
973
|
+
|
|
974
|
+
this.computeCurlSyntax();
|
|
921
975
|
}
|
|
922
976
|
|
|
923
977
|
downloadResponseBlob() {
|
|
@@ -9,6 +9,12 @@ var _marked = require("marked");
|
|
|
9
9
|
|
|
10
10
|
var _unsafeHtml = require("lit/directives/unsafe-html.js");
|
|
11
11
|
|
|
12
|
+
var _schemaUtils = require("../utils/schema-utils");
|
|
13
|
+
|
|
14
|
+
var _map = require("lit/directives/map.js");
|
|
15
|
+
|
|
16
|
+
var _range = require("lit/directives/range.js");
|
|
17
|
+
|
|
12
18
|
/* eslint-disable indent */
|
|
13
19
|
function generateFormRows(data, options, dataType = 'object', key = '', description = '', schemaLevel = 0) {
|
|
14
20
|
const newSchemaLevel = data['::type'] && data['::type'].startsWith('xxx-of') ? schemaLevel : schemaLevel + 1;
|
|
@@ -52,6 +58,20 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
|
|
|
52
58
|
|
|
53
59
|
|
|
54
60
|
const parsedData = JSON.parse(data);
|
|
61
|
+
return generatePrimitiveRow.call(this, parsedData, {
|
|
62
|
+
key,
|
|
63
|
+
keyLabel,
|
|
64
|
+
keyDescr,
|
|
65
|
+
description,
|
|
66
|
+
dataType,
|
|
67
|
+
isRequired,
|
|
68
|
+
options
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function generatePrimitiveRow(rowData, parentRecursionOptions) {
|
|
73
|
+
var _this$duplicatedRowsB;
|
|
74
|
+
|
|
55
75
|
const {
|
|
56
76
|
type,
|
|
57
77
|
format,
|
|
@@ -64,13 +84,46 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
|
|
|
64
84
|
schemaDescription,
|
|
65
85
|
schemaTitle,
|
|
66
86
|
deprecated
|
|
67
|
-
} =
|
|
87
|
+
} = rowData;
|
|
88
|
+
const {
|
|
89
|
+
key,
|
|
90
|
+
keyLabel,
|
|
91
|
+
keyDescr,
|
|
92
|
+
description,
|
|
93
|
+
dataType,
|
|
94
|
+
isRequired,
|
|
95
|
+
options
|
|
96
|
+
} = parentRecursionOptions;
|
|
68
97
|
|
|
69
98
|
if (readOrWriteOnly === '🆁') {
|
|
70
99
|
return undefined;
|
|
71
100
|
}
|
|
72
101
|
|
|
73
|
-
|
|
102
|
+
const elementId = this.elementId || `${this.method}-${this.path}`;
|
|
103
|
+
const duplicateRowGeneratorKey = `${elementId}-${key}`;
|
|
104
|
+
|
|
105
|
+
const rowGenerator = e => {
|
|
106
|
+
var _e$target$dataset, _e$target$dataset2;
|
|
107
|
+
|
|
108
|
+
if (((_e$target$dataset = e.target.dataset) === null || _e$target$dataset === void 0 ? void 0 : _e$target$dataset.ptype) !== 'pattern-property-key' && !(0, _schemaUtils.isPatternProperty)((_e$target$dataset2 = e.target.dataset) === null || _e$target$dataset2 === void 0 ? void 0 : _e$target$dataset2.pname)) {
|
|
109
|
+
return;
|
|
110
|
+
} // If the row key has a value then add another row
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
const patternPropertyKeyEls = [...this.querySelectorAll("[data-ptype='pattern-property-key']")];
|
|
114
|
+
const patternPropertyInputEls = [...this.querySelectorAll("[data-ptype='form-input']")].filter(el => (0, _schemaUtils.isPatternProperty)(el.dataset.pname)); // If there is still some row that either has an empty key or an empty value, then skip adding a new row
|
|
115
|
+
|
|
116
|
+
if (patternPropertyKeyEls.some((keyElement, index) => !keyElement.value || !patternPropertyInputEls[index].value)) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (e.target.value) {
|
|
121
|
+
this.duplicatedRowsByKey[duplicateRowGeneratorKey] = (this.duplicatedRowsByKey[duplicateRowGeneratorKey] || 1) + 1;
|
|
122
|
+
this.requestUpdate();
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return (0, _map.map)((0, _range.range)(((_this$duplicatedRowsB = this.duplicatedRowsByKey) === null || _this$duplicatedRowsB === void 0 ? void 0 : _this$duplicatedRowsB[duplicateRowGeneratorKey]) || 1), () => (0, _lit.html)` <tr> ${inputFieldKeyLabel.call(this, key.startsWith('::OPTION'), keyLabel, keyDescr, dataType, deprecated, isRequired, schemaTitle, format || type, rowGenerator)} ${dataType === 'array' ? getArrayFormField.call(this, keyLabel, example, defaultValue, format, rowGenerator) : ''} ${dataType !== 'array' ? getPrimitiveFormField.call(this, keyLabel, example, defaultValue, format, options, rowGenerator) : ''} <td> ${description ? (0, _lit.html)`<div class="param-description">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(description))}</div>` : ''} ${defaultValue || constraints || allowedValues || pattern ? (0, _lit.html)` <div class="param-constraint"> ${pattern ? (0, _lit.html)`<span style="font-weight:700">Pattern: </span>${pattern}<br>` : ''} ${constraints.length ? (0, _lit.html)`<span style="font-weight:700">Constraints: </span>${constraints.join(', ')}<br>` : ''} ${allowedValues === null || allowedValues === void 0 ? void 0 : allowedValues.split('┃').filter(v => v !== '').map((v, i) => (0, _lit.html)` ${i > 0 ? '|' : (0, _lit.html)`<span style="font-weight:700">Allowed: </span>`} ${(0, _lit.html)` <a part="anchor anchor-param-constraint" data-type="${type === 'array' ? type : 'string'}" data-enum="${v.trim()}" @click="${e => {
|
|
74
127
|
const inputEl = e.target.closest('table').querySelector(`[data-pname="${keyLabel}"]`);
|
|
75
128
|
|
|
76
129
|
if (inputEl) {
|
|
@@ -82,7 +135,17 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
|
|
|
82
135
|
if (inputEl) {
|
|
83
136
|
inputEl.value = e.target.dataset.exampleType === 'array' ? e.target.dataset.example.split('~|~') : e.target.dataset.example;
|
|
84
137
|
}
|
|
85
|
-
}}"> ${type === 'array' ? example.join(', ') : example} </a> ${type === 'array' ? '] ' : ''} </span>` : ''} </td> </tr>` : ''}
|
|
138
|
+
}}"> ${type === 'array' ? example.join(', ') : example} </a> ${type === 'array' ? '] ' : ''} </span>` : ''} </td> </tr>` : ''}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function inputFieldKeyLabel(isOption, keyLabel, keyDescription, dataType, deprecated, isRequired, schemaTitle, format, rowGenerator) {
|
|
142
|
+
if ((0, _schemaUtils.isPatternProperty)(keyLabel)) {
|
|
143
|
+
return (0, _lit.html)` <td style="width:160px;min-width:100px"> <div class="param-name ${deprecated ? 'deprecated' : ''}"> <input placeholder="${keyLabel}" @change="${e => {
|
|
144
|
+
rowGenerator(e);
|
|
145
|
+
}}" .value="${''}" spellcheck="false" type="${format === 'binary' ? 'file' : format === 'password' ? 'password' : 'text'}" part="textbox textbox-param" style="width:100%" data-ptype="pattern-property-key" data-pname="${keyLabel}" data-default="${''}" data-array="false"> </div></td>`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return (0, _lit.html)` <td style="width:160px;min-width:100px"> <div class="param-name ${deprecated ? 'deprecated' : ''}"> ${!deprecated && isRequired ? (0, _lit.html)`<span class="key-label">${keyLabel}</span><span style="color:var(--red)">*</span>` : isOption ? (0, _lit.html)`<span class="xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescription}</span>` : (0, _lit.html)`${keyLabel ? (0, _lit.html)`<span class="key-label"> ${keyLabel}</span>` : (0, _lit.html)`<span class="xxx-of-descr">${schemaTitle}</span>`}`} </div> <div class="param-type"> ${dataType === 'array' ? (0, _lit.html)`[<span>${format}</span>]` : `${format}`} </div> </td>`;
|
|
86
149
|
} // function getObjectFormField(keyLabel, example, defaultValue, format, options) {
|
|
87
150
|
// return html`
|
|
88
151
|
// <td>
|
|
@@ -93,30 +156,36 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
|
|
|
93
156
|
// part = "textarea textarea-param"
|
|
94
157
|
// style = "width:100%; border:none; resize:vertical;"
|
|
95
158
|
// data-array = "false"
|
|
96
|
-
// data-ptype = "
|
|
159
|
+
// data-ptype = "form-input"
|
|
97
160
|
// data-pname = "${keyLabel}"
|
|
98
161
|
// data-default = "${defaultValue || ''}"
|
|
99
162
|
// spellcheck = "false"
|
|
100
163
|
// .value="${options.fillRequestWithDefault === 'true' ? defaultValue : ''}"
|
|
101
164
|
// ></textarea>
|
|
102
165
|
// <!-- This textarea(hidden) is to store the original example value, in focused mode on navbar change it is used to update the example text -->
|
|
103
|
-
// <textarea data-pname = "hidden-${keyLabel}" data-ptype = "
|
|
166
|
+
// <textarea data-pname = "hidden-${keyLabel}" data-ptype = "hidden-form-input" class="is-hidden" style="display:none" .value="${defaultValue}"></textarea>
|
|
104
167
|
// </div>
|
|
105
168
|
// </div>
|
|
106
169
|
// </td>`;
|
|
107
170
|
// }
|
|
108
171
|
|
|
109
172
|
|
|
110
|
-
function getArrayFormField(keyLabel, example, defaultValue, format,
|
|
173
|
+
function getArrayFormField(keyLabel, example, defaultValue, format, rowGenerator) {
|
|
111
174
|
if (format === 'binary') {
|
|
112
|
-
return (0, _lit.html)`<td style="min-width:100px"> <div class="file-input-container col" style="align-items:flex-end" @click="${e => this.onAddRemoveFileInput(e, keyLabel
|
|
175
|
+
return (0, _lit.html)`<td style="min-width:100px"> <div class="file-input-container col" style="align-items:flex-end" @click="${e => this.onAddRemoveFileInput(e, keyLabel)}"> <div class="input-set row"> <input @change="${e => {
|
|
176
|
+
rowGenerator(e);
|
|
177
|
+
}}" type="file" part="file-input" class="file-input" data-pname="${keyLabel}" data-ptype="form-input" data-array="false" data-file-array="true"> <button class="file-input-remove-btn"> ✕ </button> </div> <button class="m-btn primary file-input-add-btn" part="btn btn-fill" style="margin:2px 25px 0 0;padding:2px 6px">ADD</button> </div> </td>`;
|
|
113
178
|
}
|
|
114
179
|
|
|
115
|
-
return (0, _lit.html)`<td style="min-width:100px"> <tag-input
|
|
180
|
+
return (0, _lit.html)`<td style="min-width:100px"> <tag-input @change="${e => {
|
|
181
|
+
rowGenerator(e);
|
|
182
|
+
}}" style="width:100%" data-ptype="form-input" data-pname="${keyLabel}" data-default="${defaultValue || ''}" data-array="true" placeholder="${(Array.isArray(example) ? example[0] : example) || defaultValue || 'add-multiple ↩'}" .value="${defaultValue || ''}"></tag-input> </td>`;
|
|
116
183
|
}
|
|
117
184
|
|
|
118
|
-
function getPrimitiveFormField(keyLabel, example, defaultValue, format, options) {
|
|
119
|
-
return (0, _lit.html)`<td style="min-width:100px"> <input placeholder="${example || defaultValue || ''}"
|
|
185
|
+
function getPrimitiveFormField(keyLabel, example, defaultValue, format, options, rowGenerator) {
|
|
186
|
+
return (0, _lit.html)`<td style="min-width:100px"> <input placeholder="${example || defaultValue || ''}" @change="${e => {
|
|
187
|
+
rowGenerator(e);
|
|
188
|
+
}}" .value="${options.fillRequestWithDefault && defaultValue || ''}" spellcheck="false" type="${format === 'binary' ? 'file' : format === 'password' ? 'password' : 'text'}" part="textbox textbox-param" style="width:100%" data-ptype="form-input" data-pname="${keyLabel}" data-default="${defaultValue || ''}" data-array="false"> </td>`;
|
|
120
189
|
}
|
|
121
190
|
|
|
122
191
|
function getRequestFormTable(data, mimeType) {
|
|
@@ -124,5 +193,5 @@ function getRequestFormTable(data, mimeType) {
|
|
|
124
193
|
mimeType: mimeType,
|
|
125
194
|
fillRequestWithDefault: this.fillRequestWithDefault === 'true'
|
|
126
195
|
};
|
|
127
|
-
return (0, _lit.html)` <table role="presentation" class="request-form-table" style="border:1px solid var(--light-border-color);width:100%"> ${data ? (0, _lit.html)`${generateFormRows.call(this, data['::type'] === 'array' ? data['::props'] : data, options, data['::type'])}` : ''} </table>`;
|
|
196
|
+
return (0, _lit.html)` <table id="request-form-table" role="presentation" class="request-form-table" style="border:1px solid var(--light-border-color);width:100%"> ${data ? (0, _lit.html)`${generateFormRows.call(this, data['::type'] === 'array' ? data['::props'] : data, options, data['::type'])}` : ''} </table>`;
|
|
128
197
|
}
|
|
@@ -5,6 +5,7 @@ exports.generateExample = generateExample;
|
|
|
5
5
|
exports.getExampleValuesFromSchema = getExampleValuesFromSchema;
|
|
6
6
|
exports.getSampleValueByType = getSampleValueByType;
|
|
7
7
|
exports.getTypeInfo = getTypeInfo;
|
|
8
|
+
exports.isPatternProperty = isPatternProperty;
|
|
8
9
|
exports.schemaInObjectNotation = schemaInObjectNotation;
|
|
9
10
|
|
|
10
11
|
var _lodash = _interopRequireDefault(require("lodash.clonedeep"));
|
|
@@ -402,6 +403,10 @@ function getSimpleValueResult(schema, config, namespace, prefix, xmlAttributes,
|
|
|
402
403
|
const value = getSampleValueByType(schema, config.propertyName, config.skipExampleStrings);
|
|
403
404
|
return [value];
|
|
404
405
|
}
|
|
406
|
+
|
|
407
|
+
function isPatternProperty(label) {
|
|
408
|
+
return label.match(/^<any-key>|<pattern:/);
|
|
409
|
+
}
|
|
405
410
|
/**
|
|
406
411
|
* For changing OpenAPI-Schema to an Object Notation,
|
|
407
412
|
* This Object would further be an input to UI Components to generate an Object-Tree
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openapi-explorer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.578",
|
|
4
4
|
"description": "OpenAPI Explorer - API viewer with dynamically generated components, documentation, and interaction console",
|
|
5
5
|
"author": "Rhosys Developers <developers@rhosys.ch>",
|
|
6
6
|
"type": "module",
|