@scalar/api-client 3.19.2 → 3.19.3
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/CHANGELOG.md +19 -0
- package/dist/style.css +26 -26
- package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts +8 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +38 -3
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/operation-block/components/Header.vue.d.ts +2 -0
- package/dist/v2/blocks/operation-block/components/Header.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/components/Header.vue.js +1 -1
- package/dist/v2/blocks/operation-block/components/Header.vue.js.map +1 -1
- package/dist/v2/blocks/operation-block/components/Header.vue.script.js +5 -2
- package/dist/v2/blocks/operation-block/components/Header.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/helpers/create-parameter-rows.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js +1 -1
- package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js.map +1 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts +2 -0
- package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.js +1 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.js.map +1 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js +3 -0
- package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.d.ts +2 -0
- package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.d.ts.map +1 -1
- package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.js +1 -1
- package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.js.map +1 -1
- package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.script.js +4 -1
- package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts +2 -0
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js +3 -2
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/v2/features/modal/Modal.vue.d.ts.map +1 -1
- package/dist/v2/features/modal/Modal.vue.js.map +1 -1
- package/dist/v2/features/modal/Modal.vue.script.js +2 -0
- package/dist/v2/features/modal/Modal.vue.script.js.map +1 -1
- package/dist/v2/features/operation/Operation.vue.d.ts +2 -0
- package/dist/v2/features/operation/Operation.vue.d.ts.map +1 -1
- package/dist/v2/features/operation/Operation.vue.js.map +1 -1
- package/dist/v2/features/operation/Operation.vue.script.js +29 -7
- package/dist/v2/features/operation/Operation.vue.script.js.map +1 -1
- package/dist/vue-styles.css +26 -26
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @scalar/api-client
|
|
2
2
|
|
|
3
|
+
## 3.19.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#10255](https://github.com/scalar/scalar/pull/10255): fix(api-client): auto-enable optional header/query/cookie rows that have a pre-populated value
|
|
8
|
+
|
|
9
|
+
Optional parameters (headers, query params, cookies) start disabled by default. When the API
|
|
10
|
+
description provides a default or enum value for such a parameter (e.g. `x-scenario-id` with an enum),
|
|
11
|
+
the row was rendered with its checkbox unchecked even though a value was already selected — so the
|
|
12
|
+
parameter was silently dropped from every request until the user manually checked it.
|
|
13
|
+
|
|
14
|
+
The fix auto-enables any row that is only disabled by default (no explicit `x-disabled: true`) and
|
|
15
|
+
already carries a non-empty value, mirroring the existing behaviour when a user types a value into
|
|
16
|
+
a previously-empty row.
|
|
17
|
+
|
|
18
|
+
Use the same enablement rules for the parameter editor, outgoing requests, and generated code snippets.
|
|
19
|
+
|
|
20
|
+
- [#10240](https://github.com/scalar/scalar/pull/10240): Load external examples on demand when their selected preview is visible or Test Request opens, instead of downloading every payload while loading the API description. Share and cache downloads, preserve relative URL origins, and show loading and retry states while preventing incomplete requests from being sent.
|
|
21
|
+
|
|
3
22
|
## 3.19.2
|
|
4
23
|
|
|
5
24
|
## 3.19.1
|
package/dist/style.css
CHANGED
|
@@ -6563,7 +6563,7 @@ input[data-v-a6f4752a]::placeholder {
|
|
|
6563
6563
|
flex-grow: 1;
|
|
6564
6564
|
}
|
|
6565
6565
|
|
|
6566
|
-
.scalar-version-number[data-v-
|
|
6566
|
+
.scalar-version-number[data-v-1c2fb5fe] {
|
|
6567
6567
|
transform: skew(0deg, 13deg);
|
|
6568
6568
|
width: 76px;
|
|
6569
6569
|
height: 76px;
|
|
@@ -6583,7 +6583,7 @@ input[data-v-a6f4752a]::placeholder {
|
|
|
6583
6583
|
text-transform: initial;
|
|
6584
6584
|
text-decoration-color: var(--scalar-color-3);
|
|
6585
6585
|
}
|
|
6586
|
-
.scalar-version-number a[data-v-
|
|
6586
|
+
.scalar-version-number a[data-v-1c2fb5fe] {
|
|
6587
6587
|
font-weight: bold;
|
|
6588
6588
|
font-weight: bold;
|
|
6589
6589
|
background: var(--scalar-background-2);
|
|
@@ -6592,7 +6592,7 @@ input[data-v-a6f4752a]::placeholder {
|
|
|
6592
6592
|
text-decoration: none;
|
|
6593
6593
|
border: 0.5px solid var(--scalar-border-color);
|
|
6594
6594
|
}
|
|
6595
|
-
.gitbook-show[data-v-
|
|
6595
|
+
.gitbook-show[data-v-1c2fb5fe] {
|
|
6596
6596
|
display: none;
|
|
6597
6597
|
}
|
|
6598
6598
|
|
|
@@ -6603,11 +6603,11 @@ input[data-v-a6f4752a]::placeholder {
|
|
|
6603
6603
|
opacity: 0;
|
|
6604
6604
|
}
|
|
6605
6605
|
|
|
6606
|
-
.animate-response-heading .response-heading[data-v-
|
|
6607
|
-
animation: push-response-
|
|
6606
|
+
.animate-response-heading .response-heading[data-v-e6c572c3] {
|
|
6607
|
+
animation: push-response-e6c572c3 0.2s ease-in-out forwards;
|
|
6608
6608
|
opacity: 1;
|
|
6609
6609
|
}
|
|
6610
|
-
@keyframes push-response-
|
|
6610
|
+
@keyframes push-response-e6c572c3 {
|
|
6611
6611
|
from {
|
|
6612
6612
|
opacity: 1;
|
|
6613
6613
|
transform: translateY(0);
|
|
@@ -6617,11 +6617,11 @@ to {
|
|
|
6617
6617
|
transform: translateY(-4px);
|
|
6618
6618
|
}
|
|
6619
6619
|
}
|
|
6620
|
-
.animate-response-heading .animate-response-children[data-v-
|
|
6621
|
-
animation: response-spans-
|
|
6620
|
+
.animate-response-heading .animate-response-children[data-v-e6c572c3] {
|
|
6621
|
+
animation: response-spans-e6c572c3 0.2s ease-in-out forwards 0.05s;
|
|
6622
6622
|
opacity: 0;
|
|
6623
6623
|
}
|
|
6624
|
-
@keyframes response-spans-
|
|
6624
|
+
@keyframes response-spans-e6c572c3 {
|
|
6625
6625
|
from {
|
|
6626
6626
|
opacity: 0;
|
|
6627
6627
|
transform: translateY(4px);
|
|
@@ -6649,21 +6649,21 @@ to {
|
|
|
6649
6649
|
background: var(--scalar-background-2);
|
|
6650
6650
|
}
|
|
6651
6651
|
|
|
6652
|
-
[data-v-
|
|
6652
|
+
[data-v-3f5b6752] .cm-editor {
|
|
6653
6653
|
height: 100%;
|
|
6654
6654
|
outline: none;
|
|
6655
6655
|
width: 100%;
|
|
6656
6656
|
}
|
|
6657
|
-
[data-v-
|
|
6657
|
+
[data-v-3f5b6752] .cm-line {
|
|
6658
6658
|
padding: 0;
|
|
6659
6659
|
}
|
|
6660
|
-
[data-v-
|
|
6660
|
+
[data-v-3f5b6752] .cm-content {
|
|
6661
6661
|
padding: 0;
|
|
6662
6662
|
display: flex;
|
|
6663
6663
|
align-items: center;
|
|
6664
6664
|
font-size: var(--scalar-small);
|
|
6665
6665
|
}
|
|
6666
|
-
.scroll-timeline-x[data-v-
|
|
6666
|
+
.scroll-timeline-x[data-v-3f5b6752] {
|
|
6667
6667
|
-ms-overflow-style: none;
|
|
6668
6668
|
/* Fade the URL at the viewport edges. Mask lives on the scrollport (this
|
|
6669
6669
|
element) rather than on `.cm-scroller`, whose width follows the URL's
|
|
@@ -6676,31 +6676,31 @@ to {
|
|
|
6676
6676
|
transparent 100%
|
|
6677
6677
|
);
|
|
6678
6678
|
}
|
|
6679
|
-
.scroll-timeline-x-hidden[data-v-
|
|
6679
|
+
.scroll-timeline-x-hidden[data-v-3f5b6752] {
|
|
6680
6680
|
overflow-x: auto;
|
|
6681
6681
|
}
|
|
6682
|
-
.scroll-timeline-x-hidden[data-v-
|
|
6682
|
+
.scroll-timeline-x-hidden[data-v-3f5b6752] .cm-scroller {
|
|
6683
6683
|
scrollbar-width: none;
|
|
6684
6684
|
-ms-overflow-style: none;
|
|
6685
6685
|
padding-right: 20px;
|
|
6686
6686
|
overflow: auto;
|
|
6687
6687
|
}
|
|
6688
|
-
.scroll-timeline-x-hidden[data-v-
|
|
6688
|
+
.scroll-timeline-x-hidden[data-v-3f5b6752]::-webkit-scrollbar {
|
|
6689
6689
|
width: 0;
|
|
6690
6690
|
height: 0;
|
|
6691
6691
|
display: none;
|
|
6692
6692
|
}
|
|
6693
|
-
.scroll-timeline-x-hidden[data-v-
|
|
6693
|
+
.scroll-timeline-x-hidden[data-v-3f5b6752] .cm-scroller::-webkit-scrollbar {
|
|
6694
6694
|
width: 0;
|
|
6695
6695
|
height: 0;
|
|
6696
6696
|
display: none;
|
|
6697
6697
|
}
|
|
6698
|
-
.scroll-timeline-x-address[data-v-
|
|
6698
|
+
.scroll-timeline-x-address[data-v-3f5b6752] {
|
|
6699
6699
|
line-height: 27px;
|
|
6700
6700
|
scrollbar-width: none; /* Firefox */
|
|
6701
6701
|
}
|
|
6702
6702
|
/* make clickable are to left of send button */
|
|
6703
|
-
.scroll-timeline-x-address[data-v-
|
|
6703
|
+
.scroll-timeline-x-address[data-v-3f5b6752]:after {
|
|
6704
6704
|
content: '';
|
|
6705
6705
|
position: absolute;
|
|
6706
6706
|
height: 100%;
|
|
@@ -6708,12 +6708,12 @@ to {
|
|
|
6708
6708
|
right: 0;
|
|
6709
6709
|
cursor: text;
|
|
6710
6710
|
}
|
|
6711
|
-
.scroll-timeline-x-address[data-v-
|
|
6711
|
+
.scroll-timeline-x-address[data-v-3f5b6752]:empty:before {
|
|
6712
6712
|
content: 'Enter URL or cURL request';
|
|
6713
6713
|
color: var(--scalar-color-3);
|
|
6714
6714
|
pointer-events: none;
|
|
6715
6715
|
}
|
|
6716
|
-
.address-bar-bg-states[data-v-
|
|
6716
|
+
.address-bar-bg-states[data-v-3f5b6752] {
|
|
6717
6717
|
--scalar-address-bar-bg: color-mix(
|
|
6718
6718
|
in srgb,
|
|
6719
6719
|
var(--scalar-background-1),
|
|
@@ -6721,22 +6721,22 @@ to {
|
|
|
6721
6721
|
);
|
|
6722
6722
|
background: var(--scalar-address-bar-bg);
|
|
6723
6723
|
}
|
|
6724
|
-
.address-bar-bg-states[data-v-
|
|
6724
|
+
.address-bar-bg-states[data-v-3f5b6752]:has(.cm-focused) {
|
|
6725
6725
|
--scalar-address-bar-bg: var(--scalar-background-1);
|
|
6726
6726
|
border-color: var(--scalar-border-color);
|
|
6727
6727
|
outline-width: 1px;
|
|
6728
6728
|
outline-style: solid;
|
|
6729
6729
|
}
|
|
6730
|
-
.address-bar-bg-states:has(.cm-focused) .fade-left[data-v-
|
|
6731
|
-
.address-bar-bg-states:has(.cm-focused) .fade-right[data-v-
|
|
6730
|
+
.address-bar-bg-states:has(.cm-focused) .fade-left[data-v-3f5b6752],
|
|
6731
|
+
.address-bar-bg-states:has(.cm-focused) .fade-right[data-v-3f5b6752] {
|
|
6732
6732
|
--scalar-address-bar-bg: var(--scalar-background-1);
|
|
6733
6733
|
}
|
|
6734
6734
|
|
|
6735
|
-
.app-exit-button[data-v-
|
|
6735
|
+
.app-exit-button[data-v-57d0a8d2] {
|
|
6736
6736
|
color: white;
|
|
6737
6737
|
background: rgba(0, 0, 0, 0.1);
|
|
6738
6738
|
}
|
|
6739
|
-
.app-exit-button[data-v-
|
|
6739
|
+
.app-exit-button[data-v-57d0a8d2]:hover {
|
|
6740
6740
|
background: rgba(255, 255, 255, 0.1);
|
|
6741
6741
|
}
|
|
6742
6742
|
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
@@ -28,6 +28,9 @@ import type { ClientLayout } from '../../../v2/types/layout';
|
|
|
28
28
|
declare const _default: typeof __VLS_export;
|
|
29
29
|
export default _default;
|
|
30
30
|
export type OperationBlockProps = {
|
|
31
|
+
/** Keep execution and editing unavailable until the selected payload is ready. */
|
|
32
|
+
externalExamplesPending?: boolean;
|
|
33
|
+
externalExamplesFailed?: boolean;
|
|
31
34
|
/** Event bus */
|
|
32
35
|
eventBus: WorkspaceEventBus;
|
|
33
36
|
/** Application version */
|
|
@@ -99,5 +102,9 @@ export type OperationBlockProps = {
|
|
|
99
102
|
/** Subset of config options for the modal */
|
|
100
103
|
options?: ModalProps['options'];
|
|
101
104
|
};
|
|
102
|
-
declare const __VLS_export: import("vue").DefineComponent<OperationBlockProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}
|
|
105
|
+
declare const __VLS_export: import("vue").DefineComponent<OperationBlockProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
106
|
+
"retry:externalExamples": () => any;
|
|
107
|
+
}, string, import("vue").PublicProps, Readonly<OperationBlockProps> & Readonly<{
|
|
108
|
+
"onRetry:externalExamples"?: (() => any) | undefined;
|
|
109
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
103
110
|
//# sourceMappingURL=OperationBlock.vue.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OperationBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"names":[],"mappings":"AAyxBA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAA;AACrF,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iDAAiD,CAAA;AACnF,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAML,KAAK,qBAAqB,EAE1B,KAAK,0BAA0B,EAChC,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AACxG,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uDAAuD,CAAA;AA0B5F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD;;;;;;;;;;;;GAYG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAMzC,MAAM,MAAM,mBAAmB,GAAG;IAChC,kFAAkF;IAClF,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,gBAAgB;IAChB,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,uBAAuB;IACvB,QAAQ,EAAE,eAAe,CAAA;IACzB,4BAA4B;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,wBAAwB;IACxB,gBAAgB,EAAE,aAAa,EAAE,CAAA;IACjC,uBAAuB;IACvB,eAAe,EAAE,aAAa,EAAE,CAAA;IAChC,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,6BAA6B;IAC7B,MAAM,EAAE,cAAc,CAAA;IACtB,oDAAoD;IACpD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,mBAAmB;IACnB,WAAW,EAAE,gBAAgB,CAAA;IAC7B,oCAAoC;IACpC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB,oBAAoB;IACpB,MAAM,EAAE,YAAY,CAAA;IACpB,gCAAgC;IAChC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,gCAAgC;IAChC,cAAc,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC,yBAAyB,CAAC,CAAA;IACtE,mDAAmD;IACnD,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,sCAAsC;IACtC,UAAU,EAAE,UAAU,CAAA;IACtB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oBAAoB;IACpB,MAAM,CAAC,EAAE,SAAS,GAAG,eAAe,CAAA;IACpC,uBAAuB;IACvB,SAAS,EAAE,eAAe,CAAA;IAC1B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;IAClB,2CAA2C;IAC3C,QAAQ,EAAE,QAAQ,CAAA;IAClB,wCAAwC;IACxC,eAAe,EAAE,qBAAqB,CAAA;IACtC,qBAAqB;IACrB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,uBAAuB;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,qCAAqC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,8CAA8C;IAC9C,WAAW,EAAE,kBAAkB,CAAA;IAC/B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB,kCAAkC;IAClC,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,0CAA0C;IAC1C,uBAAuB,EAAE,0BAA0B,EAAE,CAAA;IACrD,4BAA4B;IAC5B,oBAAoB,EAAE,eAAe,CAAC,UAAU,CAAC,CAAA;IACjD,sBAAsB;IACtB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD,6CAA6C;IAC7C,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;CAChC,CAAA;AACD,QAAA,MAAM,YAAY;;;;kFA0zBd,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Openapi document slug */\n documentSlug: string\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: HttpMethodType\n /** Whether `path` identifies an OpenAPI webhook. */\n isWebhook?: boolean\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { generateClientOptions } from '@scalar/blocks/code-example'\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport {\n executeHook,\n executeResponseHook,\n type ClientPlugin,\n} from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useClipboard } from '@scalar/use-hooks/useClipboard'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n resolveExecutableRequestUrl,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.2/strict/operation'\nimport { computed, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getCookieRequestUrl,\n getResponseCookieActions,\n} from '@/v2/blocks/operation-block/helpers/persist-response-cookies'\nimport { getEnvironmentPersistenceActions } from '@/v2/blocks/operation-block/helpers/persist-script-environment'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n documentSlug,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n layout,\n method,\n isWebhook = false,\n operation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n servers,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\nconst { copyToClipboard } = useClipboard()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/**\n * A webhook has no OpenAPI server, so its destination is the full URL the user\n * enters at runtime. The field holds that whole URL (not a server-relative path),\n * and the request is sent to it directly with no separate server base.\n */\nconst webhookUrl = ref('')\n\nwatch(\n [() => path, () => method, () => isWebhook],\n () => {\n webhookUrl.value = ''\n },\n { immediate: true },\n)\n\nconst requestPath = computed(() => (isWebhook ? webhookUrl.value : path))\nconst requestServer = computed<ServerObject | null>(() =>\n isWebhook ? null : server,\n)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/**\n * Persist server-set cookies from a response into the document cookie jar.\n *\n * Scalar keeps its own cookie jar because browsers hide `Set-Cookie` from `fetch`.\n * Mirroring browser behavior, cookies are stored scoped to the request host and\n * path and removed when the server expires them, so a value like a Django CSRF\n * token stays available for later PUT/PATCH requests after a page reload.\n */\nconst persistResponseCookies = (sendResult: {\n response: ResponseInstance\n requestPayload: RequestPayload\n}) => {\n const actions = getResponseCookieActions({\n cookieHeaderKeys: sendResult.response.cookieHeaderKeys ?? [],\n documentCookies,\n requestUrl: getCookieRequestUrl(String(sendResult.requestPayload[0])),\n })\n\n for (const action of actions) {\n if (action.type === 'delete') {\n eventBus.emit('cookie:delete:cookie', {\n collectionType: 'document',\n cookieName: action.cookieName,\n index: action.index,\n })\n continue\n }\n\n eventBus.emit('cookie:upsert:cookie', {\n collectionType: 'document',\n payload: action.cookie,\n ...(action.index === undefined ? {} : { index: action.index }),\n })\n }\n}\n\n/**\n * Copy the executable URL — same pipeline as Send (`requestFactory` +\n * `resolveExecutableRequestUrl`), including security query params.\n */\nconst copyAddressBarUrl = async (): Promise<void> => {\n const { request } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies: [...workspaceCookies, ...documentCookies],\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n await copyToClipboard(\n resolveExecutableRequestUrl(request, getEnvironmentVariables(environment)),\n )\n}\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n eventBus.flushDebouncedEmits?.()\n\n if (isWebhook && !requestPath.value.trim()) {\n toast('Webhook URL required. Enter a destination first.', 'error')\n return\n }\n\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast('Path parameters must have values.', 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Seed the script variable store with the active environment so pm.environment.get()\n // and pm.variables.get() resolve to the same values as {{…}} placeholders. Without\n // seeding, the store starts empty and every scripted read returns undefined.\n const seededEnvironment = getEnvironmentVariables(environment)\n variablesStore.setEnvironment?.(\n Object.entries(seededEnvironment).map(([key, value]) => ({ key, value })),\n )\n\n // Snapshot the persistence target at request start, alongside the seed. Persistence runs after\n // the request completes (awaits below), and the environment props are reactive — if the active\n // environment is switched mid-flight, or a concurrent request splices these arrays, reading\n // them at persist time would apply the script's writes to the wrong environment or resolve\n // workspace/document indexes against a shifted list. Copy the arrays (not just the reference)\n // so the seeded values and these targets stay fixed to the same point in time.\n const persistenceTarget = activeEnvironment\n ? {\n environmentName: activeEnvironment,\n mergedVariables: [...environment.variables],\n documentVariables: [\n ...(document['x-scalar-environments']?.[activeEnvironment]\n ?.variables ?? []),\n ],\n environmentExistsOnDocument: Boolean(\n document['x-scalar-environments']?.[activeEnvironment],\n ),\n }\n : null\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n server: requestServer.value,\n customFetch: toValue(options)?.customFetch,\n },\n 'beforeRequest',\n plugins,\n )\n\n // Persist environment variables set by scripts (pm.environment.set / unset) back to the active\n // environment so they survive to the next request, mirroring the Environment tab. Scope and\n // index are resolved from the seed-time environment so updates mutate in place. Defined here so\n // it can run on every exit path after the pre-request scripts — including a build failure or a\n // failed send — so a pre-request set, like a token stored before a flaky call, is not lost.\n const persistScriptEnvironment = () => {\n if (!persistenceTarget) {\n return\n }\n\n const environmentActions = getEnvironmentPersistenceActions({\n ...persistenceTarget,\n seededVariables: seededEnvironment,\n scriptVariables: variablesStore.getEnvironment(),\n })\n\n for (const action of environmentActions) {\n if (action.type === 'delete') {\n eventBus.emit('environment:delete:environment-variable', {\n environmentName: action.environmentName,\n index: action.index,\n collectionType: action.collectionType,\n })\n } else {\n eventBus.emit('environment:upsert:environment-variable', {\n environmentName: action.environmentName,\n variable: action.variable,\n index: action.index,\n collectionType: action.collectionType,\n })\n }\n }\n }\n\n // Resolve {{…}} placeholders from the script store so pre-request pm.environment.set() and\n // unset() take effect on this request. The store was seeded from the active environment, so\n // it already holds every value spreading seededEnvironment would add — minus the keys a script\n // unset, which must stay dropped (an object spread cannot remove them again).\n const envVariables = variablesStore.getVariables()\n\n // Build the fetch Request after hooks may have mutated the factory\n const built = buildRequest(requestBuilder, {\n envVariables,\n allowMissingRequestServerBase: layout === 'modal',\n })\n if (!built.ok) {\n // Save any pre-request script writes before bailing out on a build failure.\n persistScriptEnvironment()\n toast(built.message ?? built.error, 'error')\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = built.data.controller\n\n // Build the fetch Request once so the requestBuilt hook observes the exact bytes that are\n // sent. Rebuilding it later would generate a different multipart boundary, which breaks\n // plugins that hash the body (for example, request signing).\n const request = buildSafeBodyRequest(...built.data.requestPayload)\n\n // Execute the requestBuilt hook (plugins receive the exact fetch Request that will be sent)\n await executeHook(\n {\n request,\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'requestBuilt',\n plugins,\n )\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: built.data.isUsingProxy,\n requestPayload: built.data.requestPayload,\n request,\n plugins,\n customFetch: toValue(options)?.customFetch,\n onResponseReceived: async (response, responseDuration) => {\n const result = await executeResponseHook(\n {\n response,\n responseDuration,\n requestBuilder,\n request: buildSafeBodyRequest(...built.data.requestPayload),\n document,\n operation,\n variablesStore,\n },\n plugins,\n )\n return result.response\n },\n })\n\n // Save script environment writes (pre-request and, on success, post-response) back to the\n // active environment. Runs even when the send fails so a pre-request set is not lost.\n persistScriptEnvironment()\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Persist server-set cookies into the document jar so values like a CSRF token\n // survive a page reload and get replayed on the next request, like a browser would.\n persistResponseCookies(sendResult)\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n eventBus.on('copy-url:address-bar', copyAddressBarUrl)\n\n // Let plugins warm up per-operation resources (e.g. the scripts sandbox) so the first request\n // does not pay their cold-start cost.\n void executeHook({ document, operation }, 'onRequestMount', plugins)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n eventBus.off('copy-url:address-bar', copyAddressBarUrl)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as HttpMethodType,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\nconst handleNavigateSettings = () => {\n eventBus.emit('ui:navigate', {\n page: 'operation',\n path: 'overview',\n operationPath: path,\n method,\n })\n}\n\n/**\n * When the path, method, or example key changes, restore the response panel\n * for the new operation from the best available source:\n *\n * 1. `responseCache` — in-memory, populated on every successful send.\n * Has the live response object (including streams) so it wins.\n * 2. `history` — persisted in the workspace store. Used as a fallback when\n * the in-memory cache is empty (page reload, fresh app session, etc.)\n * so navigating to an operation that has been called before shows the\n * last response instead of an empty panel.\n * 3. Otherwise clear.\n *\n * Only the response is restored from history — the user's request inputs are\n * left alone, so we never silently overwrite an in-progress draft.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n const cached = responseCache.get(\n getOperationExampleKey(newMethod, newPath, newExampleKey),\n )\n\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n // History is keyed only by document/path/method but each entry carries\n // the example it came from, so we walk from the end and pick the most\n // recent entry that matches the active example. Otherwise a cache miss\n // on example B would restore example A's response. Only runs on a\n // cache miss — the common case (in-session navigation) skips it.\n const latest = (() => {\n for (let i = history.length - 1; i >= 0; i--) {\n const entry = history[i]\n if (entry?.meta.example === newExampleKey) {\n return entry\n }\n }\n return undefined\n })()\n\n if (latest) {\n response.value = harToFetchResponse({\n harResponse: latest.response,\n url: latest.request.url,\n method: newMethod,\n path: newPath,\n duration: latest.time,\n })\n requestPayload.value = null\n } else {\n response.value = null\n requestPayload.value = null\n }\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentSlug\n :documentUrl\n :environment\n :environments\n :eventBus\n :exampleKey\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :isWebhook\n :layout\n :method\n :path=\"requestPath\"\n :server=\"requestServer\"\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @navigate:settings=\"handleNavigateSettings\"\n @select:history:item=\"handleSelectHistoryItem\"\n @update:webhook-url=\"(value) => (webhookUrl = value)\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <RequestBlock\n :authMeta\n :clientOptions\n :defaultHeaders\n :defaultRequestBodyView=\"\n document['x-scalar-default-request-body-view']\n \"\n :documentCookies\n :documentSlug\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :operation\n :options=\"toValue(options)\"\n :path=\"requestPath\"\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server=\"requestServer\"\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :layout\n :plugins\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"OperationBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Keep execution and editing unavailable until the selected payload is ready. */\n externalExamplesPending?: boolean\n externalExamplesFailed?: boolean\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Openapi document slug */\n documentSlug: string\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: HttpMethodType\n /** Whether `path` identifies an OpenAPI webhook. */\n isWebhook?: boolean\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { generateClientOptions } from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport {\n executeHook,\n executeResponseHook,\n type ClientPlugin,\n} from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useClipboard } from '@scalar/use-hooks/useClipboard'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n resolveExecutableRequestUrl,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.2/strict/operation'\nimport { computed, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getCookieRequestUrl,\n getResponseCookieActions,\n} from '@/v2/blocks/operation-block/helpers/persist-response-cookies'\nimport { getEnvironmentPersistenceActions } from '@/v2/blocks/operation-block/helpers/persist-script-environment'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n externalExamplesPending = false,\n externalExamplesFailed = false,\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n documentSlug,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n layout,\n method,\n isWebhook = false,\n operation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n servers,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\ndefineEmits<{ (e: 'retry:externalExamples'): void }>()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\nconst { copyToClipboard } = useClipboard()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/**\n * A webhook has no OpenAPI server, so its destination is the full URL the user\n * enters at runtime. The field holds that whole URL (not a server-relative path),\n * and the request is sent to it directly with no separate server base.\n */\nconst webhookUrl = ref('')\n\nwatch(\n [() => path, () => method, () => isWebhook],\n () => {\n webhookUrl.value = ''\n },\n { immediate: true },\n)\n\nconst requestPath = computed(() => (isWebhook ? webhookUrl.value : path))\nconst requestServer = computed<ServerObject | null>(() =>\n isWebhook ? null : server,\n)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/**\n * Persist server-set cookies from a response into the document cookie jar.\n *\n * Scalar keeps its own cookie jar because browsers hide `Set-Cookie` from `fetch`.\n * Mirroring browser behavior, cookies are stored scoped to the request host and\n * path and removed when the server expires them, so a value like a Django CSRF\n * token stays available for later PUT/PATCH requests after a page reload.\n */\nconst persistResponseCookies = (sendResult: {\n response: ResponseInstance\n requestPayload: RequestPayload\n}) => {\n const actions = getResponseCookieActions({\n cookieHeaderKeys: sendResult.response.cookieHeaderKeys ?? [],\n documentCookies,\n requestUrl: getCookieRequestUrl(String(sendResult.requestPayload[0])),\n })\n\n for (const action of actions) {\n if (action.type === 'delete') {\n eventBus.emit('cookie:delete:cookie', {\n collectionType: 'document',\n cookieName: action.cookieName,\n index: action.index,\n })\n continue\n }\n\n eventBus.emit('cookie:upsert:cookie', {\n collectionType: 'document',\n payload: action.cookie,\n ...(action.index === undefined ? {} : { index: action.index }),\n })\n }\n}\n\n/**\n * Copy the executable URL — same pipeline as Send (`requestFactory` +\n * `resolveExecutableRequestUrl`), including security query params.\n */\nconst copyAddressBarUrl = async (): Promise<void> => {\n const { request } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies: [...workspaceCookies, ...documentCookies],\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n await copyToClipboard(\n resolveExecutableRequestUrl(request, getEnvironmentVariables(environment)),\n )\n}\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n if (externalExamplesPending) return\n eventBus.flushDebouncedEmits?.()\n\n if (isWebhook && !requestPath.value.trim()) {\n toast('Webhook URL required. Enter a destination first.', 'error')\n return\n }\n\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast('Path parameters must have values.', 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Seed the script variable store with the active environment so pm.environment.get()\n // and pm.variables.get() resolve to the same values as {{…}} placeholders. Without\n // seeding, the store starts empty and every scripted read returns undefined.\n const seededEnvironment = getEnvironmentVariables(environment)\n variablesStore.setEnvironment?.(\n Object.entries(seededEnvironment).map(([key, value]) => ({ key, value })),\n )\n\n // Snapshot the persistence target at request start, alongside the seed. Persistence runs after\n // the request completes (awaits below), and the environment props are reactive — if the active\n // environment is switched mid-flight, or a concurrent request splices these arrays, reading\n // them at persist time would apply the script's writes to the wrong environment or resolve\n // workspace/document indexes against a shifted list. Copy the arrays (not just the reference)\n // so the seeded values and these targets stay fixed to the same point in time.\n const persistenceTarget = activeEnvironment\n ? {\n environmentName: activeEnvironment,\n mergedVariables: [...environment.variables],\n documentVariables: [\n ...(document['x-scalar-environments']?.[activeEnvironment]\n ?.variables ?? []),\n ],\n environmentExistsOnDocument: Boolean(\n document['x-scalar-environments']?.[activeEnvironment],\n ),\n }\n : null\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n server: requestServer.value,\n customFetch: toValue(options)?.customFetch,\n },\n 'beforeRequest',\n plugins,\n )\n\n // Persist environment variables set by scripts (pm.environment.set / unset) back to the active\n // environment so they survive to the next request, mirroring the Environment tab. Scope and\n // index are resolved from the seed-time environment so updates mutate in place. Defined here so\n // it can run on every exit path after the pre-request scripts — including a build failure or a\n // failed send — so a pre-request set, like a token stored before a flaky call, is not lost.\n const persistScriptEnvironment = () => {\n if (!persistenceTarget) {\n return\n }\n\n const environmentActions = getEnvironmentPersistenceActions({\n ...persistenceTarget,\n seededVariables: seededEnvironment,\n scriptVariables: variablesStore.getEnvironment(),\n })\n\n for (const action of environmentActions) {\n if (action.type === 'delete') {\n eventBus.emit('environment:delete:environment-variable', {\n environmentName: action.environmentName,\n index: action.index,\n collectionType: action.collectionType,\n })\n } else {\n eventBus.emit('environment:upsert:environment-variable', {\n environmentName: action.environmentName,\n variable: action.variable,\n index: action.index,\n collectionType: action.collectionType,\n })\n }\n }\n }\n\n // Resolve {{…}} placeholders from the script store so pre-request pm.environment.set() and\n // unset() take effect on this request. The store was seeded from the active environment, so\n // it already holds every value spreading seededEnvironment would add — minus the keys a script\n // unset, which must stay dropped (an object spread cannot remove them again).\n const envVariables = variablesStore.getVariables()\n\n // Build the fetch Request after hooks may have mutated the factory\n const built = buildRequest(requestBuilder, {\n envVariables,\n allowMissingRequestServerBase: layout === 'modal',\n })\n if (!built.ok) {\n // Save any pre-request script writes before bailing out on a build failure.\n persistScriptEnvironment()\n toast(built.message ?? built.error, 'error')\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = built.data.controller\n\n // Build the fetch Request once so the requestBuilt hook observes the exact bytes that are\n // sent. Rebuilding it later would generate a different multipart boundary, which breaks\n // plugins that hash the body (for example, request signing).\n const request = buildSafeBodyRequest(...built.data.requestPayload)\n\n // Execute the requestBuilt hook (plugins receive the exact fetch Request that will be sent)\n await executeHook(\n {\n request,\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'requestBuilt',\n plugins,\n )\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: built.data.isUsingProxy,\n requestPayload: built.data.requestPayload,\n request,\n plugins,\n customFetch: toValue(options)?.customFetch,\n onResponseReceived: async (response, responseDuration) => {\n const result = await executeResponseHook(\n {\n response,\n responseDuration,\n requestBuilder,\n request: buildSafeBodyRequest(...built.data.requestPayload),\n document,\n operation,\n variablesStore,\n },\n plugins,\n )\n return result.response\n },\n })\n\n // Save script environment writes (pre-request and, on success, post-response) back to the\n // active environment. Runs even when the send fails so a pre-request set is not lost.\n persistScriptEnvironment()\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Persist server-set cookies into the document jar so values like a CSRF token\n // survive a page reload and get replayed on the next request, like a browser would.\n persistResponseCookies(sendResult)\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n eventBus.on('copy-url:address-bar', copyAddressBarUrl)\n\n // Let plugins warm up per-operation resources (e.g. the scripts sandbox) so the first request\n // does not pay their cold-start cost.\n void executeHook({ document, operation }, 'onRequestMount', plugins)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n eventBus.off('copy-url:address-bar', copyAddressBarUrl)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as HttpMethodType,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\nconst handleNavigateSettings = () => {\n eventBus.emit('ui:navigate', {\n page: 'operation',\n path: 'overview',\n operationPath: path,\n method,\n })\n}\n\n/**\n * When the path, method, or example key changes, restore the response panel\n * for the new operation from the best available source:\n *\n * 1. `responseCache` — in-memory, populated on every successful send.\n * Has the live response object (including streams) so it wins.\n * 2. `history` — persisted in the workspace store. Used as a fallback when\n * the in-memory cache is empty (page reload, fresh app session, etc.)\n * so navigating to an operation that has been called before shows the\n * last response instead of an empty panel.\n * 3. Otherwise clear.\n *\n * Only the response is restored from history — the user's request inputs are\n * left alone, so we never silently overwrite an in-progress draft.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n const cached = responseCache.get(\n getOperationExampleKey(newMethod, newPath, newExampleKey),\n )\n\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n // History is keyed only by document/path/method but each entry carries\n // the example it came from, so we walk from the end and pick the most\n // recent entry that matches the active example. Otherwise a cache miss\n // on example B would restore example A's response. Only runs on a\n // cache miss — the common case (in-session navigation) skips it.\n const latest = (() => {\n for (let i = history.length - 1; i >= 0; i--) {\n const entry = history[i]\n if (entry?.meta.example === newExampleKey) {\n return entry\n }\n }\n return undefined\n })()\n\n if (latest) {\n response.value = harToFetchResponse({\n harResponse: latest.response,\n url: latest.request.url,\n method: newMethod,\n path: newPath,\n duration: latest.time,\n })\n requestPayload.value = null\n } else {\n response.value = null\n requestPayload.value = null\n }\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentSlug\n :documentUrl\n :environment\n :environments\n :eventBus\n :exampleKey\n :executionDisabled=\"externalExamplesPending\"\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :isWebhook\n :layout\n :method\n :path=\"requestPath\"\n :server=\"requestServer\"\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @navigate:settings=\"handleNavigateSettings\"\n @select:history:item=\"handleSelectHistoryItem\"\n @update:webhook-url=\"(value) => (webhookUrl = value)\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <ViewLayoutSection\n v-if=\"externalExamplesPending\"\n aria-label=\"Request\">\n <template #title>Request</template>\n <div\n class=\"text-c-2 p-4\"\n role=\"status\">\n <template v-if=\"externalExamplesFailed\">\n Could not load this example.\n <ScalarButton\n size=\"sm\"\n variant=\"ghost\"\n @click=\"$emit('retry:externalExamples')\">\n Retry\n </ScalarButton>\n </template>\n <template v-else>Loading example…</template>\n </div>\n </ViewLayoutSection>\n <RequestBlock\n v-else\n :authMeta\n :clientOptions\n :defaultHeaders\n :defaultRequestBodyView=\"\n document['x-scalar-default-request-body-view']\n \"\n :documentCookies\n :documentSlug\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :operation\n :options=\"toValue(options)\"\n :path=\"requestPath\"\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server=\"requestServer\"\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :executionDisabled=\"externalExamplesPending\"\n :layout\n :plugins\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ViewLayout_default from "../../../components/ViewLayout/ViewLayout.vue.js";
|
|
2
2
|
import ViewLayoutContent_default from "../../../components/ViewLayout/ViewLayoutContent.vue.js";
|
|
3
|
+
import ViewLayoutSection_default from "../../../components/ViewLayout/ViewLayoutSection.vue.js";
|
|
3
4
|
import { sendRequest } from "./helpers/send-request.js";
|
|
4
5
|
import { harToFetchRequest } from "./helpers/har-to-fetch-request.js";
|
|
5
6
|
import { harToFetchResponse } from "./helpers/har-to-fetch-response.js";
|
|
@@ -10,7 +11,8 @@ import { validatePathParameters } from "./helpers/validate-path-parameters.js";
|
|
|
10
11
|
import RequestBlock_default from "../request-block/RequestBlock.vue.js";
|
|
11
12
|
import ResponseBlock_default from "../response-block/ResponseBlock.vue.js";
|
|
12
13
|
import Header_default from "./components/Header.vue.js";
|
|
13
|
-
import { computed, createElementBlock, createElementVNode, createVNode, defineComponent, onBeforeUnmount, onMounted, openBlock, ref, toValue, unref, watch, withCtx } from "vue";
|
|
14
|
+
import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, onBeforeUnmount, onMounted, openBlock, ref, toValue, unref, watch, withCtx } from "vue";
|
|
15
|
+
import { ScalarButton } from "@scalar/components/button";
|
|
14
16
|
import { buildRequest, createVariablesStoreForRequest, getEnvironmentVariables, requestFactory, resolveExecutableRequestUrl } from "@scalar/workspace-store/request-example";
|
|
15
17
|
import { ERRORS } from "@scalar/helpers/errors/normalize-error";
|
|
16
18
|
import { isElectron } from "@scalar/helpers/general/is-electron";
|
|
@@ -23,9 +25,21 @@ import { useToasts } from "@scalar/use-toasts";
|
|
|
23
25
|
//#region src/v2/blocks/operation-block/OperationBlock.vue?vue&type=script&setup=true&lang.ts
|
|
24
26
|
var _hoisted_1 = { class: "bg-b-1 flex h-full flex-col" };
|
|
25
27
|
var _hoisted_2 = { class: "lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0" };
|
|
28
|
+
var _hoisted_3 = {
|
|
29
|
+
class: "text-c-2 p-4",
|
|
30
|
+
role: "status"
|
|
31
|
+
};
|
|
26
32
|
var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
27
33
|
name: "OperationBlock",
|
|
28
34
|
props: {
|
|
35
|
+
externalExamplesPending: {
|
|
36
|
+
type: Boolean,
|
|
37
|
+
default: false
|
|
38
|
+
},
|
|
39
|
+
externalExamplesFailed: {
|
|
40
|
+
type: Boolean,
|
|
41
|
+
default: false
|
|
42
|
+
},
|
|
29
43
|
eventBus: {},
|
|
30
44
|
appVersion: {},
|
|
31
45
|
document: {},
|
|
@@ -65,6 +79,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
65
79
|
requestBodyCompositionSelection: {},
|
|
66
80
|
options: {}
|
|
67
81
|
},
|
|
82
|
+
emits: ["retry:externalExamples"],
|
|
68
83
|
setup(__props) {
|
|
69
84
|
/** Hoist up client generation so it doesn't get re-generated on every operation */
|
|
70
85
|
const clientOptions = computed(() => generateClientOptions(__props.httpClients));
|
|
@@ -143,6 +158,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
143
158
|
};
|
|
144
159
|
/** Execute the current operation example */
|
|
145
160
|
const handleExecute = async () => {
|
|
161
|
+
if (__props.externalExamplesPending) return;
|
|
146
162
|
__props.eventBus.flushDebouncedEmits?.();
|
|
147
163
|
if (__props.isWebhook && !requestPath.value.trim()) {
|
|
148
164
|
toast("Webhook URL required. Enter a destination first.", "error");
|
|
@@ -397,6 +413,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
397
413
|
environments: __props.environments,
|
|
398
414
|
eventBus: __props.eventBus,
|
|
399
415
|
exampleKey: __props.exampleKey,
|
|
416
|
+
executionDisabled: __props.externalExamplesPending,
|
|
400
417
|
hideClientButton: __props.hideClientButton,
|
|
401
418
|
history: operationHistory.value,
|
|
402
419
|
integration: __props.integration,
|
|
@@ -420,6 +437,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
420
437
|
"environments",
|
|
421
438
|
"eventBus",
|
|
422
439
|
"exampleKey",
|
|
440
|
+
"executionDisabled",
|
|
423
441
|
"hideClientButton",
|
|
424
442
|
"history",
|
|
425
443
|
"integration",
|
|
@@ -433,7 +451,22 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
433
451
|
"source"
|
|
434
452
|
])]), createVNode(ViewLayout_default, { class: "border-t" }, {
|
|
435
453
|
default: withCtx(() => [createVNode(ViewLayoutContent_default, { class: "flex-1" }, {
|
|
436
|
-
default: withCtx(() => [
|
|
454
|
+
default: withCtx(() => [__props.externalExamplesPending ? (openBlock(), createBlock(ViewLayoutSection_default, {
|
|
455
|
+
key: 0,
|
|
456
|
+
"aria-label": "Request"
|
|
457
|
+
}, {
|
|
458
|
+
title: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode("Request", -1)])]),
|
|
459
|
+
default: withCtx(() => [createElementVNode("div", _hoisted_3, [__props.externalExamplesFailed ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[4] || (_cache[4] = createTextVNode(" Could not load this example. ", -1)), createVNode(unref(ScalarButton), {
|
|
460
|
+
size: "sm",
|
|
461
|
+
variant: "ghost",
|
|
462
|
+
onClick: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("retry:externalExamples"))
|
|
463
|
+
}, {
|
|
464
|
+
default: withCtx(() => [..._cache[3] || (_cache[3] = [createTextVNode(" Retry ", -1)])]),
|
|
465
|
+
_: 1
|
|
466
|
+
})], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode("Loading example…")], 64))])]),
|
|
467
|
+
_: 1
|
|
468
|
+
})) : (openBlock(), createBlock(unref(RequestBlock_default), {
|
|
469
|
+
key: 1,
|
|
437
470
|
authMeta: __props.authMeta,
|
|
438
471
|
clientOptions: clientOptions.value,
|
|
439
472
|
defaultHeaders: __props.defaultHeaders,
|
|
@@ -483,9 +516,10 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
483
516
|
"selectedSecuritySchemes",
|
|
484
517
|
"server",
|
|
485
518
|
"workspaceCookies"
|
|
486
|
-
]), createVNode(unref(ResponseBlock_default), {
|
|
519
|
+
])), createVNode(unref(ResponseBlock_default), {
|
|
487
520
|
appVersion: __props.appVersion,
|
|
488
521
|
eventBus: __props.eventBus,
|
|
522
|
+
executionDisabled: __props.externalExamplesPending,
|
|
489
523
|
layout: __props.layout,
|
|
490
524
|
plugins: __props.plugins,
|
|
491
525
|
requestPayload: requestPayload.value,
|
|
@@ -494,6 +528,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
494
528
|
}, null, 8, [
|
|
495
529
|
"appVersion",
|
|
496
530
|
"eventBus",
|
|
531
|
+
"executionDisabled",
|
|
497
532
|
"layout",
|
|
498
533
|
"plugins",
|
|
499
534
|
"requestPayload",
|