@scalar/api-client 3.21.2 → 3.21.4
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 +18 -0
- package/dist/style.css +18 -12
- 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 +11 -0
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js +3 -0
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts +2 -0
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +3 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/helpers/get-structured-body-rows.js +2 -1
- package/dist/v2/blocks/request-block/helpers/get-structured-body-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 +26 -3
- package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.d.ts +2 -0
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js +59 -42
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
- package/dist/v2/components/code-input/CodeInputLite.vue.d.ts +6 -2
- package/dist/v2/components/code-input/CodeInputLite.vue.d.ts.map +1 -1
- package/dist/v2/components/code-input/CodeInputLite.vue.js +1 -1
- package/dist/v2/components/code-input/CodeInputLite.vue.js.map +1 -1
- package/dist/v2/components/code-input/CodeInputLite.vue.script.js +3 -0
- package/dist/v2/components/code-input/CodeInputLite.vue.script.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInputSelect.vue.d.ts +4 -4
- package/dist/v2/components/data-table/DataTableInputSelect.vue.d.ts.map +1 -1
- package/dist/v2/components/data-table/DataTableInputSelect.vue.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInputSelect.vue.script.js +22 -16
- package/dist/v2/components/data-table/DataTableInputSelect.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/v2/features/localization/locales/ar.d.ts +2 -0
- package/dist/v2/features/localization/locales/ar.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/ar.js +2 -0
- package/dist/v2/features/localization/locales/ar.js.map +1 -1
- package/dist/v2/features/localization/locales/de.d.ts +2 -0
- package/dist/v2/features/localization/locales/de.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/de.js +2 -0
- package/dist/v2/features/localization/locales/de.js.map +1 -1
- package/dist/v2/features/localization/locales/es.d.ts +2 -0
- package/dist/v2/features/localization/locales/es.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/es.js +2 -0
- package/dist/v2/features/localization/locales/es.js.map +1 -1
- package/dist/v2/features/localization/locales/fr.d.ts +2 -0
- package/dist/v2/features/localization/locales/fr.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/fr.js +2 -0
- package/dist/v2/features/localization/locales/fr.js.map +1 -1
- package/dist/v2/features/localization/locales/pt.d.ts +2 -0
- package/dist/v2/features/localization/locales/pt.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/pt.js +2 -0
- package/dist/v2/features/localization/locales/pt.js.map +1 -1
- package/dist/v2/features/localization/locales/ru.d.ts +2 -0
- package/dist/v2/features/localization/locales/ru.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/ru.js +2 -0
- package/dist/v2/features/localization/locales/ru.js.map +1 -1
- package/dist/v2/features/localization/locales/zh-cn.d.ts +2 -0
- package/dist/v2/features/localization/locales/zh-cn.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/zh-cn.js +2 -0
- package/dist/v2/features/localization/locales/zh-cn.js.map +1 -1
- package/dist/v2/features/localization/translations.d.ts +2 -0
- package/dist/v2/features/localization/translations.d.ts.map +1 -1
- package/dist/v2/features/localization/translations.js +2 -0
- package/dist/v2/features/localization/translations.js.map +1 -1
- package/dist/v2/features/search/helpers/create-fuse-instance.js +1 -1
- package/dist/v2/features/search/helpers/create-fuse-instance.js.map +1 -1
- package/dist/vue-styles.css +11 -11
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestCodeSnippet.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n findClient,\n generateCodeSnippet,\n getClients,\n getCustomCodeSamples,\n getSecrets,\n type ClientOption,\n type CodeExampleProps,\n type CustomClientOption,\n} from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\n\nimport { DataTable, DataTableRow } from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n clientOptions,\n eventBus,\n operation,\n method,\n path,\n selectedContentType,\n selectedServer = null,\n selectedExample,\n securitySchemes,\n selectedClient,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n integration,\n} = defineProps<CodeExampleProps & { eventBus: WorkspaceEventBus }>()\n\nconst { translate } = useLocalization()\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(\n customCodeSamples.value.samples,\n clientOptions,\n customCodeSamples.value.label,\n ),\n)\n\n/**\n * The locally selected client which would include code samples from this operation only\n * Must be local state because it contains custom code samples from this operation only\n */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/**\n * Re-resolve the local client whenever the global selection or the available\n * clients change. Watching `clients` matters when navigating between operations:\n * the stored id stays the same, but the matching option (e.g. a custom sample)\n * differs per operation, so without this the snippet could go stale.\n */\nwatch([() => selectedClient, clients], ([newClient]) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes ?? []))\n\n/** Handle client change */\nconst handleClientChange = (option: ClientOption | undefined) => {\n localSelectedClient.value = option\n\n // Sync the selection globally (built-in client or custom sample keyed by language)\n if (option) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string | null>(() =>\n generateCodeSnippet({\n defaultDisabledParameters: true,\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExample,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n includeDefaultHeaders: integration === 'client',\n }),\n)\n\n/** Check if there are any clients available (built-in or custom code samples) */\nconst hasClients = computed(() =>\n clients.value.some((group) => group.options.length > 0),\n)\n</script>\n\n<template>\n <CollapsibleSection\n v-if=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>\n {{ translate('apiClient.requestCodeSnippet.codeSnippet') }}\n </template>\n\n <!-- Client selector -->\n <template #actions>\n <div class=\"flex flex-1\">\n <ScalarCombobox\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n @update:modelValue=\"\n (ev) => handleClientChange(ev as ClientOption | undefined)\n \">\n <template #default=\"{ open }\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"mt-0.25 size-3 transition-transform duration-100\"\n :class=\"open && 'rotate-180'\"\n weight=\"bold\" />\n </ScalarButton>\n </template>\n </ScalarCombobox>\n </div>\n </template>\n\n <!-- Code snippet -->\n <ScalarErrorBoundary>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableRow>\n <div class=\"overflow-hidden\">\n <div\n v-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ translate('apiClient.requestCodeSnippet.unavailable') }}\n </div>\n <ScalarCodeBlock\n v-else\n class=\"text-base\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"localSelectedClient?.lang ?? 'plaintext'\"\n lineNumbers />\n </div>\n </DataTableRow>\n </DataTable>\n </ScalarErrorBoundary>\n </CollapsibleSection>\n</template>\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"RequestCodeSnippet.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n findClient,\n generateCodeSnippet,\n getClients,\n getCustomCodeSamples,\n getSecrets,\n type ClientOption,\n type CodeExampleProps,\n type CustomClientOption,\n} from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\n\nimport { DataTable, DataTableRow } from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n clientOptions,\n eventBus,\n operation,\n method,\n path,\n selectedContentType,\n selectedServer = null,\n selectedExample,\n securitySchemes,\n selectedClient,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n integration,\n} = defineProps<CodeExampleProps & { eventBus: WorkspaceEventBus }>()\n\nconst { translate } = useLocalization()\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(\n customCodeSamples.value.samples,\n clientOptions,\n customCodeSamples.value.label,\n ),\n)\n\n/**\n * The locally selected client which would include code samples from this operation only\n * Must be local state because it contains custom code samples from this operation only\n */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/**\n * Re-resolve the local client whenever the global selection or the available\n * clients change. Watching `clients` matters when navigating between operations:\n * the stored id stays the same, but the matching option (e.g. a custom sample)\n * differs per operation, so without this the snippet could go stale.\n */\nwatch([() => selectedClient, clients], ([newClient]) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes ?? []))\n\n/** Handle client change */\nconst handleClientChange = (option: ClientOption | undefined) => {\n localSelectedClient.value = option\n\n // Sync the selection globally (built-in client or custom sample keyed by language)\n if (option) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string | null>(() =>\n generateCodeSnippet({\n defaultDisabledParameters: true,\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExample,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n includeDefaultHeaders: integration === 'client',\n }),\n)\n\n/** Check if there are any clients available (built-in or custom code samples) */\nconst hasClients = computed(() =>\n clients.value.some((group) => group.options.length > 0),\n)\n</script>\n\n<template>\n <CollapsibleSection\n v-if=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>\n {{ translate('apiClient.requestCodeSnippet.codeSnippet') }}\n </template>\n\n <!-- Client selector -->\n <template #actions>\n <div class=\"flex flex-1\">\n <ScalarCombobox\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n @update:modelValue=\"\n (ev) => handleClientChange(ev as ClientOption | undefined)\n \">\n <template #default=\"{ open }\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"mt-0.25 size-3 transition-transform duration-100\"\n :class=\"open && 'rotate-180'\"\n weight=\"bold\" />\n </ScalarButton>\n </template>\n </ScalarCombobox>\n </div>\n </template>\n\n <!-- Code snippet -->\n <ScalarErrorBoundary>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableRow>\n <div class=\"overflow-hidden\">\n <div\n v-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ translate('apiClient.requestCodeSnippet.unavailable') }}\n </div>\n <ScalarCodeBlock\n v-else\n class=\"text-base\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :label=\"translate('apiClient.requestCodeSnippet.codeSnippet')\"\n :lang=\"localSelectedClient?.lang ?? 'plaintext'\"\n lineNumbers />\n </div>\n </DataTableRow>\n </DataTable>\n </ScalarErrorBoundary>\n </CollapsibleSection>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCA,MAAM,EAAE,cAAc,gBAAgB;;EAGtC,MAAM,oBAAoB,eAAe,qBAAqB,QAAA,SAAS,CAAC;;EAGxE,MAAM,UAAU,eACd,WACE,kBAAkB,MAAM,SACxB,QAAA,eACA,kBAAkB,MAAM,KAC1B,CACF;;;;;EAMA,MAAM,sBAAsB,IAC1B,WAAW,QAAQ,OAAO,QAAA,cAAc,CAC1C;;;;;;;EAQA,MAAM,OAAO,QAAA,gBAAgB,OAAO,IAAI,CAAC,eAAe;GACtD,MAAM,SAAS,WAAW,QAAQ,OAAO,SAAS;GAClD,IAAI,QACF,oBAAoB,QAAQ;EAEhC,CAAC;;EAGD,MAAM,oBAAoB,eAAe,WAAW,QAAA,mBAAmB,CAAC,CAAC,CAAC;;EAG1E,MAAM,sBAAsB,WAAqC;GAC/D,oBAAoB,QAAQ;GAG5B,IAAI,QACF,QAAA,SAAS,KAAK,oCAAoC,OAAO,EAAE;EAE/D;;EAGA,MAAM,gBAAgB,eACpB,oBAAoB;GAClB,2BAA2B;GAC3B,UAAU,oBAAoB,OAAO;GACrC,mBAAmB,kBAAkB,MAAM;GAC3C,WAAQ,QAAA;GACR,QAAK,QAAA;GACL,MAAG,QAAA;GACH,aAAa,QAAA;GACb,QAAQ,QAAA;GACR,iBAAc,QAAA;GACd,SAAS,QAAA;GACT,eAAY,QAAA;GACZ,gBAAa,QAAA;GACb,iCAA8B,QAAA;GAC9B,uBAAuB,QAAA,gBAAgB;EACzC,CAAC,CACH;;EAGA,MAAM,aAAa,eACjB,QAAQ,MAAM,MAAM,UAAU,MAAM,QAAQ,SAAS,CAAC,CACxD;;UAKU,WAAA,SAAA,UAAA,GADR,YA2DqB,MAAA,0BAAA,GAAA;;IAzDnB,OAAM;IACL,aAAa;;IACH,OAAK,cAC6C,CAAA,gBAAA,gBAAxD,MAAA,SAAA,CAAS,CAAA,0CAAA,CAAA,GAAA,CAAA,CAAA,CAAA;IAIH,SAAO,cAsBV,CArBN,mBAqBM,OArBN,YAqBM,CApBJ,YAmBiB,MAAA,cAAA,GAAA;KAlBd,YAAY,oBAAA;KACZ,SAAS,QAAA;KACV,WAAU;KACT,uBAAiB,OAAA,OAAA,OAAA,MAAgB,OAAO,mBAAmB,EAAE;;KAGnD,SAAO,SAUD,EAVK,WAAI,CACxB,YASe,MAAA,YAAA,GAAA;MARb,OAAM;MACN,eAAY;MACZ,SAAQ;;6BACwB,CAAA,gBAAA,gBAA7B,oBAAA,OAAqB,KAAK,IAAG,KAChC,CAAA,GAAA,YAGkB,MAAA,mBAAA,GAAA;OAFhB,OAAK,eAAA,CAAC,oDACE,QAAI,YAAA,CAAA;OACZ,QAAO;;;;;;2BA+BG,CAvBtB,YAuBsB,MAAA,mBAAA,GAAA,MAAA;4BADR,CArBZ,YAqBY,MAAA,iBAAA,GAAA;MApBT,SAAS,CAAA,EAAA;MACV,gBAAA;;6BAkBe,CAjBf,YAiBe,MAAA,oBAAA,GAAA,MAAA;8BADP,CAfN,mBAeM,OAfN,YAeM,CAbI,cAAA,UAAa,QAAA,UAAA,GADrB,mBAKM,OALN,YAKM,gBADD,MAAA,SAAA,CAAS,CAAA,0CAAA,CAAA,GAAA,CAAA,MAAA,UAAA,GAEd,YAOgB,MAAA,eAAA,GAAA;;QALd,OAAM;QACL,SAAS,cAAA;QACT,iBAAiB,kBAAA;QACjB,OAAO,MAAA,SAAA,CAAS,CAAA,0CAAA;QAChB,MAAM,oBAAA,OAAqB,QAAI;QAChC,aAAA"}
|
|
@@ -28,6 +28,8 @@ export type TableRow = {
|
|
|
28
28
|
schema?: SchemaObject;
|
|
29
29
|
/** Preserve array values even while their JSON text is temporarily invalid. */
|
|
30
30
|
isArray?: boolean;
|
|
31
|
+
/** Text representation used by array enum controls. */
|
|
32
|
+
arrayEncoding?: 'json' | 'comma-separated';
|
|
31
33
|
/** Whether the parameter is required */
|
|
32
34
|
isRequired?: boolean;
|
|
33
35
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"names":[],"mappings":"AAkaA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAGxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAgBrE,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAA;IACd,iFAAiF;IACjF,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,kBAAkB,CAAA;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAC;AAwBF,MAAM,MAAM,QAAQ,GAAG;IACrB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3B,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAA;IAC/C,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,wEAAwE;IACxE,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAA;IAC1C,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,eAAe,CAAA;IACnC,2FAA2F;IAC3F,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAA;IACnC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,UAAU,EAAE,OAAO,CAAA;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC,CAAA;AA2sBD,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Text representation used by array enum controls. */\n arrayEncoding?: 'json' | 'comma-separated'\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<unknown[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return data.arrayEncoding === 'json'\n ? resolved.enum\n : resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n :arrayEncoding=\"data.arrayEncoding\"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""}
|
|
@@ -71,7 +71,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
71
71
|
if (__props.data.schema.enum) return __props.data.schema.enum.map((item) => String(item));
|
|
72
72
|
if ("items" in __props.data.schema) {
|
|
73
73
|
const resolved = resolve.schema(__props.data.schema.items);
|
|
74
|
-
if (resolved?.enum) return resolved.enum.map((item) => String(item));
|
|
74
|
+
if (resolved?.enum) return __props.data.arrayEncoding === "json" ? resolved.enum : resolved.enum.map((item) => String(item));
|
|
75
75
|
}
|
|
76
76
|
return [];
|
|
77
77
|
});
|
|
@@ -166,6 +166,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
166
166
|
}, null, 8, ["modelValue", "value"])) : (openBlock(), createBlock(unref(CodeInputLite_default), {
|
|
167
167
|
key: 1,
|
|
168
168
|
"aria-label": unref(translate)("apiClient.requestTableRow.valueLabel", { name: __props.label ?? "" }),
|
|
169
|
+
arrayEncoding: __props.data.arrayEncoding,
|
|
169
170
|
class: "pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10",
|
|
170
171
|
default: defaultValue.value,
|
|
171
172
|
disabled: __props.data.isReadonly,
|
|
@@ -220,6 +221,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
220
221
|
_: 1
|
|
221
222
|
}, 8, [
|
|
222
223
|
"aria-label",
|
|
224
|
+
"arrayEncoding",
|
|
223
225
|
"default",
|
|
224
226
|
"disabled",
|
|
225
227
|
"enum",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Text representation used by array enum controls. */\n arrayEncoding?: 'json' | 'comma-separated'\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<unknown[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return data.arrayEncoding === 'json'\n ? resolved.enum\n : resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n :arrayEncoding=\"data.arrayEncoding\"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":"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"}
|
|
@@ -23,7 +23,8 @@ var getStructuredBodyRows = (parsedValue, schema) => {
|
|
|
23
23
|
const row = {
|
|
24
24
|
name,
|
|
25
25
|
value: value === void 0 || value === null ? "" : stringifyValue(value),
|
|
26
|
-
isDisabled: false
|
|
26
|
+
isDisabled: false,
|
|
27
|
+
arrayEncoding: "json"
|
|
27
28
|
};
|
|
28
29
|
const leaf = leafByDottedName.get(name);
|
|
29
30
|
const propSchema = leaf?.schema ?? (objectSchema ? resolve.schema(objectSchema.properties?.[name]) : void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-structured-body-rows.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/get-structured-body-rows.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\n\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n type LeafRow,\n collectExampleRows,\n collectLeafProperties,\n stringifyValue,\n} from '@/v2/blocks/request-block/helpers/get-form-body-rows'\n\n/**\n * Build form-table rows for a structured (JSON/YAML) request body.\n *\n * The parsed body value is walked alongside the schema exactly like the multipart form\n * editor does: schema-declared properties first in schema order (nested objects flatten\n * into dotted-path leaves like `props.name`), example-only keys after in example order.\n * Each row is enriched with its leaf schema so the table shows enum dropdowns, required\n * badges, defaults, and validation per field.\n */\nexport const getStructuredBodyRows = (parsedValue: unknown, schema?: SchemaObject): TableRow[] => {\n const objectSchema = schema && isObjectSchema(schema) ? schema : undefined\n\n // Nothing to build rows from: neither a body object nor an object schema.\n if (!isObject(parsedValue) && !objectSchema) {\n return []\n }\n\n // Leaf index by dotted name so nested leaves keep their schema and required flag.\n const leafByDottedName = new Map<string, LeafRow>()\n if (objectSchema) {\n for (const leaf of collectLeafProperties(objectSchema)) {\n leafByDottedName.set(leaf.path.join('.'), leaf)\n }\n }\n const requiredSet = new Set(objectSchema?.required ?? [])\n\n return collectExampleRows(isObject(parsedValue) ? parsedValue : {}, objectSchema).map(({ path, value }) => {\n const name = path.join('.')\n\n // Missing values and explicit `null` render as empty inputs so the user can type a\n // value rather than seeing the string \"null\". Empty rows are omitted on fold-back.\n const rendered = value === undefined || value === null ? '' : stringifyValue(value)\n\n const row: TableRow = { name, value: rendered, isDisabled: false }\n\n const leaf = leafByDottedName.get(name)\n const propSchema = leaf?.schema ?? (objectSchema ? resolve.schema(objectSchema.properties?.[name]) : undefined)\n row.schema = propSchema\n row.description = propSchema?.description\n row.isRequired = leaf?.isRequired ?? requiredSet.has(name)\n\n return row\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,IAAa,yBAAyB,aAAsB,WAAsC;CAChG,MAAM,eAAe,UAAU,eAAe,MAAM,IAAI,SAAS,KAAA;CAGjE,IAAI,CAAC,SAAS,WAAW,KAAK,CAAC,cAC7B,OAAO,CAAC;CAIV,MAAM,mCAAmB,IAAI,IAAqB;CAClD,IAAI,cACF,KAAK,MAAM,QAAQ,sBAAsB,YAAY,GACnD,iBAAiB,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI;CAGlD,MAAM,cAAc,IAAI,IAAI,cAAc,YAAY,CAAC,CAAC;CAExD,OAAO,mBAAmB,SAAS,WAAW,IAAI,cAAc,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,EAAE,MAAM,YAAY;EACzG,MAAM,OAAO,KAAK,KAAK,GAAG;EAM1B,MAAM,MAAgB;GAAE;GAAM,OAFb,UAAU,KAAA,KAAa,UAAU,OAAO,KAAK,eAAe,KAAK;GAEnC,YAAY;
|
|
1
|
+
{"version":3,"file":"get-structured-body-rows.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/get-structured-body-rows.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\n\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n type LeafRow,\n collectExampleRows,\n collectLeafProperties,\n stringifyValue,\n} from '@/v2/blocks/request-block/helpers/get-form-body-rows'\n\n/**\n * Build form-table rows for a structured (JSON/YAML) request body.\n *\n * The parsed body value is walked alongside the schema exactly like the multipart form\n * editor does: schema-declared properties first in schema order (nested objects flatten\n * into dotted-path leaves like `props.name`), example-only keys after in example order.\n * Each row is enriched with its leaf schema so the table shows enum dropdowns, required\n * badges, defaults, and validation per field.\n */\nexport const getStructuredBodyRows = (parsedValue: unknown, schema?: SchemaObject): TableRow[] => {\n const objectSchema = schema && isObjectSchema(schema) ? schema : undefined\n\n // Nothing to build rows from: neither a body object nor an object schema.\n if (!isObject(parsedValue) && !objectSchema) {\n return []\n }\n\n // Leaf index by dotted name so nested leaves keep their schema and required flag.\n const leafByDottedName = new Map<string, LeafRow>()\n if (objectSchema) {\n for (const leaf of collectLeafProperties(objectSchema)) {\n leafByDottedName.set(leaf.path.join('.'), leaf)\n }\n }\n const requiredSet = new Set(objectSchema?.required ?? [])\n\n return collectExampleRows(isObject(parsedValue) ? parsedValue : {}, objectSchema).map(({ path, value }) => {\n const name = path.join('.')\n\n // Missing values and explicit `null` render as empty inputs so the user can type a\n // value rather than seeing the string \"null\". Empty rows are omitted on fold-back.\n const rendered = value === undefined || value === null ? '' : stringifyValue(value)\n\n const row: TableRow = { name, value: rendered, isDisabled: false, arrayEncoding: 'json' }\n\n const leaf = leafByDottedName.get(name)\n const propSchema = leaf?.schema ?? (objectSchema ? resolve.schema(objectSchema.properties?.[name]) : undefined)\n row.schema = propSchema\n row.description = propSchema?.description\n row.isRequired = leaf?.isRequired ?? requiredSet.has(name)\n\n return row\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,IAAa,yBAAyB,aAAsB,WAAsC;CAChG,MAAM,eAAe,UAAU,eAAe,MAAM,IAAI,SAAS,KAAA;CAGjE,IAAI,CAAC,SAAS,WAAW,KAAK,CAAC,cAC7B,OAAO,CAAC;CAIV,MAAM,mCAAmB,IAAI,IAAqB;CAClD,IAAI,cACF,KAAK,MAAM,QAAQ,sBAAsB,YAAY,GACnD,iBAAiB,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI;CAGlD,MAAM,cAAc,IAAI,IAAI,cAAc,YAAY,CAAC,CAAC;CAExD,OAAO,mBAAmB,SAAS,WAAW,IAAI,cAAc,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,EAAE,MAAM,YAAY;EACzG,MAAM,OAAO,KAAK,KAAK,GAAG;EAM1B,MAAM,MAAgB;GAAE;GAAM,OAFb,UAAU,KAAA,KAAa,UAAU,OAAO,KAAK,eAAe,KAAK;GAEnC,YAAY;GAAO,eAAe;EAAO;EAExF,MAAM,OAAO,iBAAiB,IAAI,IAAI;EACtC,MAAM,aAAa,MAAM,WAAW,eAAe,QAAQ,OAAO,aAAa,aAAa,KAAK,IAAI,KAAA;EACrG,IAAI,SAAS;EACb,IAAI,cAAc,YAAY;EAC9B,IAAI,aAAa,MAAM,cAAc,YAAY,IAAI,IAAI;EAEzD,OAAO;CACT,CAAC;AACH"}
|
|
@@ -6,6 +6,8 @@ import type { ClientLayout } from '../../../v2/types/layout';
|
|
|
6
6
|
type __VLS_Props = {
|
|
7
7
|
/** Wait for the selected external request example before sending. */
|
|
8
8
|
executionDisabled?: boolean;
|
|
9
|
+
/** Failure retained until the next request or operation change. */
|
|
10
|
+
requestError?: Error | null;
|
|
9
11
|
/** Preprocessed response */
|
|
10
12
|
response: ResponseInstance | null;
|
|
11
13
|
/** Original request as a [url, RequestInit] tuple */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ResponseBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"names":[],"mappings":"AA6VA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAA;AAK7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kDAAkD,CAAA;AAYxF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,KAAK,WAAW,GAAG;IACjB,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,mEAAmE;IACnE,YAAY,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IAC3B,4BAA4B;IAC5B,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACjC,qDAAqD;IACrD,cAAc,EAAE,cAAc,GAAG,IAAI,CAAA;IACrC,oBAAoB;IACpB,MAAM,EAAE,YAAY,CAAA;IACpB,yCAAyC;IACzC,sBAAsB,EAAE,MAAM,CAAA;IAC9B,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,6BAA6B;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,0BAA0B;IAC1B,QAAQ,EAAE,iBAAiB,CAAA;CAC5B,CAAC;AAgDF,QAAA,MAAM,gBAAgB,yCAA0C,CAAA;AAChE,KAAK,MAAM,GAAG,KAAK,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;AAwdvD,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;oPAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../_virtual/_plugin-vue_exp
|
|
|
2
2
|
import ResponseBlock_vue_vue_type_script_setup_true_lang_default from "./ResponseBlock.vue.script.js";
|
|
3
3
|
/* empty css */
|
|
4
4
|
//#region src/v2/blocks/response-block/ResponseBlock.vue
|
|
5
|
-
var ResponseBlock_default = /*#__PURE__*/ _plugin_vue_export_helper_default(ResponseBlock_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
5
|
+
var ResponseBlock_default = /*#__PURE__*/ _plugin_vue_export_helper_default(ResponseBlock_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-7f122fc4"]]);
|
|
6
6
|
//#endregion
|
|
7
7
|
export { ResponseBlock_default as default };
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { RequestPayload } from '@scalar/workspace-store/request-example'\nimport { computed, ref, useId } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ResponseInstance } from '@/v2/blocks/operation-block/helpers/send-request'\nimport HeadersComponent from '@/v2/blocks/response-block/components/Headers.vue'\nimport ResponseBody from '@/v2/blocks/response-block/components/ResponseBody.vue'\nimport ResponseBodyStreaming from '@/v2/blocks/response-block/components/ResponseBodyStreaming.vue'\nimport ResponseBodyVirtual from '@/v2/blocks/response-block/components/ResponseBodyVirtual.vue'\nimport ResponseCookies from '@/v2/blocks/response-block/components/ResponseCookies.vue'\nimport ResponseEmpty from '@/v2/blocks/response-block/components/ResponseEmpty.vue'\nimport ResponseLoadingOverlay from '@/v2/blocks/response-block/components/ResponseLoadingOverlay.vue'\nimport ResponseMetaInformation from '@/v2/blocks/response-block/components/ResponseMetaInformation.vue'\nimport { textMediaTypes } from '@/v2/blocks/response-block/helpers/media-types'\nimport { parseSetCookie } from '@/v2/blocks/response-block/helpers/parse-set-cookie'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nconst { layout, totalPerformedRequests, response, requestPayload } =\n defineProps<{\n /** Wait for the selected external request example before sending. */\n executionDisabled?: boolean\n /** Preprocessed response */\n response: ResponseInstance | null\n /** Original request as a [url, RequestInit] tuple */\n requestPayload: RequestPayload | null\n /** Client layout */\n layout: ClientLayout\n /** Total number of performed requests */\n totalPerformedRequests: number\n /** Application version */\n appVersion: string\n /** Registered app plugins */\n plugins: ClientPlugin[]\n /** Workspace event bus */\n eventBus: WorkspaceEventBus\n }>()\n\nconst { translate } = useLocalization()\n\n// Headers\nconst responseHeaders = computed(() => {\n const headers = response?.headers\n\n return headers\n ? Object.keys(headers).map((key) => ({\n name: key,\n value: headers[key] ?? '',\n }))\n : []\n})\n\nconst responseContentType = computed(\n () => response?.headers['content-type'] ?? response?.headers['Content-Type'],\n)\n\n// Cookies\nconst responseCookies = computed(\n () =>\n response?.cookieHeaderKeys\n .map((setCookieValue) => parseSetCookie(setCookieValue))\n .filter(isDefined) ?? [],\n)\n\nconst responseSections = ['Cookies', 'Headers', 'Body'] as const\ntype Filter = 'All' | (typeof responseSections)[number]\nconst activeFilter = ref<Filter>('All')\n\nconst filters = computed<Filter[]>(() => ['All', ...responseSections])\n\nconst filterIds = computed<Record<Filter, string>>(() => ({\n All: useId(),\n Cookies: useId(),\n Headers: useId(),\n Body: useId(),\n}))\n\n/** Threshold for virtualizing response bodies in bytes */\nconst VIRTUALIZATION_THRESHOLD = 200_000\nconst shouldVirtualize = computed(() => {\n if (!response || !('size' in response)) {\n return false\n }\n\n // Get content type from headers\n const contentType =\n response.headers?.['content-type'] || response.headers?.['Content-Type']\n\n // If no content type or response size is small, don't virtualize\n if (!contentType || (response.size ?? 0) <= VIRTUALIZATION_THRESHOLD) {\n return false\n }\n\n // Do not virtualize html\n if (contentType.includes('text/html')) {\n return false\n }\n\n // Check if content type matches any text-based type\n const isTextBased = textMediaTypes.some((type) => contentType.includes(type))\n\n return isTextBased && (response.size ?? 0) > VIRTUALIZATION_THRESHOLD\n})\n\nconst requestHeaders = computed(() => {\n const headers = requestPayload?.[1]?.headers\n if (!headers) {\n return []\n }\n\n // Normalise via the Headers constructor, and then spread\n return [...new Headers(headers)].map(([name, value]) => ({\n name,\n value,\n required: false,\n }))\n})\n\nconst isSectionVisible = (\n section: (typeof responseSections)[number] | 'All',\n) => {\n if (activeFilter.value === 'All' || activeFilter.value === section) {\n return true\n }\n return false\n}\n\ndefineExpose({\n responseHeaders,\n responseCookies,\n requestHeaders,\n shouldVirtualize,\n activeFilter,\n filters,\n})\n\nconst filterLabels = computed(() => ({\n All: translate('apiClient.sectionFilter.all'),\n Auth: translate('apiClient.sectionFilter.auth'),\n Variables: translate('apiClient.sectionFilter.variables'),\n Cookies: translate('apiClient.sectionFilter.cookies'),\n Headers: translate('apiClient.sectionFilter.headers'),\n Query: translate('apiClient.sectionFilter.query'),\n Body: translate('apiClient.sectionFilter.body'),\n}))\n</script>\n<template>\n <!-- Bound the stacked response section so long bodies keep their own scroll area. -->\n <ViewLayoutSection\n :aria-label=\"translate('apiClient.responseBlock.response')\"\n class=\"max-xl:max-h-full\">\n <template #title>\n <div class=\"flex h-8 flex-1 items-center\">\n <div\n aria-live=\"polite\"\n class=\"flex items-center\"\n :class=\"{ 'animate-response-heading': response }\">\n <span class=\"response-heading pointer-events-none absolute\">{{\n translate('apiClient.responseBlock.response')\n }}</span>\n <ResponseMetaInformation\n v-if=\"response\"\n class=\"animate-response-children\"\n :eventBus=\"eventBus\"\n :response=\"response\" />\n </div>\n <SectionFilter\n v-model=\"activeFilter\"\n :filters=\"filters\"\n :labels=\"filterLabels\" />\n </div>\n </template>\n <div\n :id=\"filterIds.All\"\n class=\"custom-scroll response-section-content relative grid h-full justify-stretch\"\n :class=\"{\n 'content-start': response,\n }\"\n :role=\"activeFilter === 'All' && response ? 'tabpanel' : 'none'\">\n <template v-if=\"!response\">\n <ResponseEmpty\n :appVersion=\"appVersion\"\n :executionDisabled\n :layout=\"layout\"\n :totalPerformedRequests=\"totalPerformedRequests\"\n @addRequest=\"\n eventBus.emit('ui:open:command-palette', {\n action: 'create-request',\n payload: undefined,\n })\n \"\n @openCommandPalette=\"eventBus.emit('ui:open:command-palette')\"\n @sendRequest=\"eventBus.emit('operation:send:request:hotkey')\" />\n </template>\n <template v-else>\n <!-- Cookies section -->\n <ResponseCookies\n v-if=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n class=\"response-section-content-cookies\"\n :cookies=\"responseCookies\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n <!-- Request headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"requestHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.requestHeaders') }}\n </template>\n </HeadersComponent>\n <!-- Response headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.responseHeaders') }}\n </template>\n </HeadersComponent>\n\n <!-- Inject response section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.response.component\"\n v-if=\"plugin?.components?.response\"\n v-show=\"activeFilter === 'All'\"\n v-bind=\"plugin.components.response.additionalProps\" />\n </ScalarErrorBoundary>\n\n <template v-if=\"activeFilter === 'All' || activeFilter === 'Body'\">\n <!-- Streaming response body -->\n <ResponseBodyStreaming\n v-if=\"'reader' in response\"\n :id=\"filterIds.Body\"\n class=\"response-section-content-body\"\n :contentType=\"responseContentType\"\n :reader=\"response.reader\" />\n\n <!-- Virtualized Text for massive responses -->\n <ResponseBodyVirtual\n v-else-if=\"shouldVirtualize && typeof response?.data === 'string'\"\n :id=\"filterIds.Body\"\n :content=\"response!.data\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n\n <!-- Regular response body -->\n <ResponseBody\n v-else\n :id=\"filterIds.Body\"\n :active=\"true\"\n class=\"response-section-content-body\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n layout=\"client\"\n :plugins=\"plugins\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\"\n :title=\"translate('apiClient.responseBlock.body')\" />\n </template>\n </template>\n <ResponseLoadingOverlay :eventBus=\"eventBus\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.animate-response-heading .response-heading {\n animation: push-response 0.2s ease-in-out forwards;\n opacity: 1;\n}\n@keyframes push-response {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(-4px);\n }\n}\n.animate-response-heading .animate-response-children {\n animation: response-spans 0.2s ease-in-out forwards 0.05s;\n opacity: 0;\n}\n\n@keyframes response-spans {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ResponseBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { RequestPayload } from '@scalar/workspace-store/request-example'\nimport { computed, ref, useId } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ResponseInstance } from '@/v2/blocks/operation-block/helpers/send-request'\nimport HeadersComponent from '@/v2/blocks/response-block/components/Headers.vue'\nimport ResponseBody from '@/v2/blocks/response-block/components/ResponseBody.vue'\nimport ResponseBodyStreaming from '@/v2/blocks/response-block/components/ResponseBodyStreaming.vue'\nimport ResponseBodyVirtual from '@/v2/blocks/response-block/components/ResponseBodyVirtual.vue'\nimport ResponseCookies from '@/v2/blocks/response-block/components/ResponseCookies.vue'\nimport ResponseEmpty from '@/v2/blocks/response-block/components/ResponseEmpty.vue'\nimport ResponseLoadingOverlay from '@/v2/blocks/response-block/components/ResponseLoadingOverlay.vue'\nimport ResponseMetaInformation from '@/v2/blocks/response-block/components/ResponseMetaInformation.vue'\nimport { textMediaTypes } from '@/v2/blocks/response-block/helpers/media-types'\nimport { parseSetCookie } from '@/v2/blocks/response-block/helpers/parse-set-cookie'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nconst {\n layout,\n totalPerformedRequests,\n response,\n requestPayload,\n requestError,\n} = defineProps<{\n /** Wait for the selected external request example before sending. */\n executionDisabled?: boolean\n /** Failure retained until the next request or operation change. */\n requestError?: Error | null\n /** Preprocessed response */\n response: ResponseInstance | null\n /** Original request as a [url, RequestInit] tuple */\n requestPayload: RequestPayload | null\n /** Client layout */\n layout: ClientLayout\n /** Total number of performed requests */\n totalPerformedRequests: number\n /** Application version */\n appVersion: string\n /** Registered app plugins */\n plugins: ClientPlugin[]\n /** Workspace event bus */\n eventBus: WorkspaceEventBus\n}>()\n\nconst { translate } = useLocalization()\n\n/** Browsers hide CORS details, so these messages warrant guidance, not a diagnosis. */\nconst showNetworkErrorHelp = computed<boolean>(\n () =>\n !isElectron() &&\n requestError?.name === 'TypeError' &&\n [\n 'Failed to fetch',\n 'Load failed',\n 'NetworkError when attempting to fetch resource.',\n ].includes(requestError.message),\n)\n\n// Headers\nconst responseHeaders = computed(() => {\n const headers = response?.headers\n\n return headers\n ? Object.keys(headers).map((key) => ({\n name: key,\n value: headers[key] ?? '',\n }))\n : []\n})\n\nconst responseContentType = computed(\n () => response?.headers['content-type'] ?? response?.headers['Content-Type'],\n)\n\n// Cookies\nconst responseCookies = computed(\n () =>\n response?.cookieHeaderKeys\n .map((setCookieValue) => parseSetCookie(setCookieValue))\n .filter(isDefined) ?? [],\n)\n\nconst responseSections = ['Cookies', 'Headers', 'Body'] as const\ntype Filter = 'All' | (typeof responseSections)[number]\nconst activeFilter = ref<Filter>('All')\n\nconst filters = computed<Filter[]>(() => ['All', ...responseSections])\n\nconst filterIds = computed<Record<Filter, string>>(() => ({\n All: useId(),\n Cookies: useId(),\n Headers: useId(),\n Body: useId(),\n}))\n\n/** Threshold for virtualizing response bodies in bytes */\nconst VIRTUALIZATION_THRESHOLD = 200_000\nconst shouldVirtualize = computed(() => {\n if (!response || !('size' in response)) {\n return false\n }\n\n // Get content type from headers\n const contentType =\n response.headers?.['content-type'] || response.headers?.['Content-Type']\n\n // If no content type or response size is small, don't virtualize\n if (!contentType || (response.size ?? 0) <= VIRTUALIZATION_THRESHOLD) {\n return false\n }\n\n // Do not virtualize html\n if (contentType.includes('text/html')) {\n return false\n }\n\n // Check if content type matches any text-based type\n const isTextBased = textMediaTypes.some((type) => contentType.includes(type))\n\n return isTextBased && (response.size ?? 0) > VIRTUALIZATION_THRESHOLD\n})\n\nconst requestHeaders = computed(() => {\n const headers = requestPayload?.[1]?.headers\n if (!headers) {\n return []\n }\n\n // Normalise via the Headers constructor, and then spread\n return [...new Headers(headers)].map(([name, value]) => ({\n name,\n value,\n required: false,\n }))\n})\n\nconst isSectionVisible = (\n section: (typeof responseSections)[number] | 'All',\n) => {\n if (activeFilter.value === 'All' || activeFilter.value === section) {\n return true\n }\n return false\n}\n\ndefineExpose({\n responseHeaders,\n responseCookies,\n requestHeaders,\n shouldVirtualize,\n activeFilter,\n filters,\n})\n\nconst filterLabels = computed(() => ({\n All: translate('apiClient.sectionFilter.all'),\n Auth: translate('apiClient.sectionFilter.auth'),\n Variables: translate('apiClient.sectionFilter.variables'),\n Cookies: translate('apiClient.sectionFilter.cookies'),\n Headers: translate('apiClient.sectionFilter.headers'),\n Query: translate('apiClient.sectionFilter.query'),\n Body: translate('apiClient.sectionFilter.body'),\n}))\n</script>\n<template>\n <!-- Bound the stacked response section so long bodies keep their own scroll area. -->\n <ViewLayoutSection\n :aria-label=\"translate('apiClient.responseBlock.response')\"\n class=\"max-xl:max-h-full\">\n <template #title>\n <div class=\"flex h-8 flex-1 items-center\">\n <div\n aria-live=\"polite\"\n class=\"flex items-center\"\n :class=\"{ 'animate-response-heading': response }\">\n <span class=\"response-heading pointer-events-none absolute\">{{\n translate('apiClient.responseBlock.response')\n }}</span>\n <ResponseMetaInformation\n v-if=\"response\"\n class=\"animate-response-children\"\n :eventBus=\"eventBus\"\n :response=\"response\" />\n </div>\n <SectionFilter\n v-model=\"activeFilter\"\n :filters=\"filters\"\n :labels=\"filterLabels\" />\n </div>\n </template>\n <div\n :id=\"filterIds.All\"\n class=\"custom-scroll response-section-content relative grid h-full justify-stretch\"\n :class=\"{\n 'content-start': response,\n }\"\n :role=\"activeFilter === 'All' && response ? 'tabpanel' : 'none'\">\n <div\n v-if=\"requestError\"\n class=\"flex flex-col gap-3 p-4 text-sm\"\n role=\"alert\">\n <h3 class=\"text-c-1 font-medium\">\n {{ translate('apiClient.responseBlock.requestFailed') }}\n </h3>\n <p class=\"text-c-2 break-words\">{{ requestError.message }}</p>\n <p\n v-if=\"showNetworkErrorHelp\"\n class=\"text-c-2 leading-relaxed\">\n {{ translate('apiClient.responseBlock.networkErrorHelp') }}\n </p>\n </div>\n <template v-else-if=\"!response\">\n <ResponseEmpty\n :appVersion=\"appVersion\"\n :executionDisabled\n :layout=\"layout\"\n :totalPerformedRequests=\"totalPerformedRequests\"\n @addRequest=\"\n eventBus.emit('ui:open:command-palette', {\n action: 'create-request',\n payload: undefined,\n })\n \"\n @openCommandPalette=\"eventBus.emit('ui:open:command-palette')\"\n @sendRequest=\"eventBus.emit('operation:send:request:hotkey')\" />\n </template>\n <template v-else>\n <!-- Cookies section -->\n <ResponseCookies\n v-if=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n class=\"response-section-content-cookies\"\n :cookies=\"responseCookies\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n <!-- Request headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"requestHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.requestHeaders') }}\n </template>\n </HeadersComponent>\n <!-- Response headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.responseHeaders') }}\n </template>\n </HeadersComponent>\n\n <!-- Inject response section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.response.component\"\n v-if=\"plugin?.components?.response\"\n v-show=\"activeFilter === 'All'\"\n v-bind=\"plugin.components.response.additionalProps\" />\n </ScalarErrorBoundary>\n\n <template v-if=\"activeFilter === 'All' || activeFilter === 'Body'\">\n <!-- Streaming response body -->\n <ResponseBodyStreaming\n v-if=\"'reader' in response\"\n :id=\"filterIds.Body\"\n class=\"response-section-content-body\"\n :contentType=\"responseContentType\"\n :reader=\"response.reader\" />\n\n <!-- Virtualized Text for massive responses -->\n <ResponseBodyVirtual\n v-else-if=\"shouldVirtualize && typeof response?.data === 'string'\"\n :id=\"filterIds.Body\"\n :content=\"response!.data\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n\n <!-- Regular response body -->\n <ResponseBody\n v-else\n :id=\"filterIds.Body\"\n :active=\"true\"\n class=\"response-section-content-body\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n layout=\"client\"\n :plugins=\"plugins\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\"\n :title=\"translate('apiClient.responseBlock.body')\" />\n </template>\n </template>\n <ResponseLoadingOverlay :eventBus=\"eventBus\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.animate-response-heading .response-heading {\n animation: push-response 0.2s ease-in-out forwards;\n opacity: 1;\n}\n@keyframes push-response {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(-4px);\n }\n}\n.animate-response-heading .animate-response-children {\n animation: response-spans 0.2s ease-in-out forwards 0.05s;\n opacity: 0;\n}\n\n@keyframes response-spans {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -13,16 +13,29 @@ import ResponseMetaInformation_default from "./components/ResponseMetaInformatio
|
|
|
13
13
|
import { parseSetCookie } from "./helpers/parse-set-cookie.js";
|
|
14
14
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, ref, renderList, resolveDynamicComponent, toDisplayString, unref, useId, vShow, withCtx, withDirectives } from "vue";
|
|
15
15
|
import { isDefined } from "@scalar/helpers/array/is-defined";
|
|
16
|
+
import { isElectron } from "@scalar/helpers/general/is-electron";
|
|
16
17
|
import { ScalarErrorBoundary } from "@scalar/components/error-boundary";
|
|
17
18
|
//#region src/v2/blocks/response-block/ResponseBlock.vue?vue&type=script&setup=true&lang.ts
|
|
18
19
|
var _hoisted_1 = { class: "flex h-8 flex-1 items-center" };
|
|
19
20
|
var _hoisted_2 = { class: "response-heading pointer-events-none absolute" };
|
|
20
21
|
var _hoisted_3 = ["id", "role"];
|
|
22
|
+
var _hoisted_4 = {
|
|
23
|
+
key: 0,
|
|
24
|
+
class: "flex flex-col gap-3 p-4 text-sm",
|
|
25
|
+
role: "alert"
|
|
26
|
+
};
|
|
27
|
+
var _hoisted_5 = { class: "text-c-1 font-medium" };
|
|
28
|
+
var _hoisted_6 = { class: "text-c-2 break-words" };
|
|
29
|
+
var _hoisted_7 = {
|
|
30
|
+
key: 0,
|
|
31
|
+
class: "text-c-2 leading-relaxed"
|
|
32
|
+
};
|
|
21
33
|
var VIRTUALIZATION_THRESHOLD = 2e5;
|
|
22
34
|
var ResponseBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
23
35
|
__name: "ResponseBlock",
|
|
24
36
|
props: {
|
|
25
37
|
executionDisabled: { type: Boolean },
|
|
38
|
+
requestError: {},
|
|
26
39
|
response: {},
|
|
27
40
|
requestPayload: {},
|
|
28
41
|
layout: {},
|
|
@@ -33,6 +46,12 @@ var ResponseBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
33
46
|
},
|
|
34
47
|
setup(__props, { expose: __expose }) {
|
|
35
48
|
const { translate } = useLocalization();
|
|
49
|
+
/** Browsers hide CORS details, so these messages warrant guidance, not a diagnosis. */
|
|
50
|
+
const showNetworkErrorHelp = computed(() => !isElectron() && __props.requestError?.name === "TypeError" && [
|
|
51
|
+
"Failed to fetch",
|
|
52
|
+
"Load failed",
|
|
53
|
+
"NetworkError when attempting to fetch resource."
|
|
54
|
+
].includes(__props.requestError.message));
|
|
36
55
|
const responseHeaders = computed(() => {
|
|
37
56
|
const headers = __props.response?.headers;
|
|
38
57
|
return headers ? Object.keys(headers).map((key) => ({
|
|
@@ -120,8 +139,12 @@ var ResponseBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
120
139
|
id: filterIds.value.All,
|
|
121
140
|
class: normalizeClass(["custom-scroll response-section-content relative grid h-full justify-stretch", { "content-start": __props.response }]),
|
|
122
141
|
role: activeFilter.value === "All" && __props.response ? "tabpanel" : "none"
|
|
123
|
-
}, [
|
|
124
|
-
|
|
142
|
+
}, [__props.requestError ? (openBlock(), createElementBlock("div", _hoisted_4, [
|
|
143
|
+
createElementVNode("h3", _hoisted_5, toDisplayString(unref(translate)("apiClient.responseBlock.requestFailed")), 1),
|
|
144
|
+
createElementVNode("p", _hoisted_6, toDisplayString(__props.requestError.message), 1),
|
|
145
|
+
showNetworkErrorHelp.value ? (openBlock(), createElementBlock("p", _hoisted_7, toDisplayString(unref(translate)("apiClient.responseBlock.networkErrorHelp")), 1)) : createCommentVNode("", true)
|
|
146
|
+
])) : !__props.response ? (openBlock(), createBlock(ResponseEmpty_default, {
|
|
147
|
+
key: 1,
|
|
125
148
|
appVersion: __props.appVersion,
|
|
126
149
|
executionDisabled: __props.executionDisabled,
|
|
127
150
|
layout: __props.layout,
|
|
@@ -137,7 +160,7 @@ var ResponseBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
137
160
|
"executionDisabled",
|
|
138
161
|
"layout",
|
|
139
162
|
"totalPerformedRequests"
|
|
140
|
-
])) : (openBlock(), createElementBlock(Fragment, { key:
|
|
163
|
+
])) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [
|
|
141
164
|
isSectionVisible("Cookies") ? (openBlock(), createBlock(ResponseCookies_default, {
|
|
142
165
|
key: 0,
|
|
143
166
|
id: filterIds.value.Cookies,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { RequestPayload } from '@scalar/workspace-store/request-example'\nimport { computed, ref, useId } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ResponseInstance } from '@/v2/blocks/operation-block/helpers/send-request'\nimport HeadersComponent from '@/v2/blocks/response-block/components/Headers.vue'\nimport ResponseBody from '@/v2/blocks/response-block/components/ResponseBody.vue'\nimport ResponseBodyStreaming from '@/v2/blocks/response-block/components/ResponseBodyStreaming.vue'\nimport ResponseBodyVirtual from '@/v2/blocks/response-block/components/ResponseBodyVirtual.vue'\nimport ResponseCookies from '@/v2/blocks/response-block/components/ResponseCookies.vue'\nimport ResponseEmpty from '@/v2/blocks/response-block/components/ResponseEmpty.vue'\nimport ResponseLoadingOverlay from '@/v2/blocks/response-block/components/ResponseLoadingOverlay.vue'\nimport ResponseMetaInformation from '@/v2/blocks/response-block/components/ResponseMetaInformation.vue'\nimport { textMediaTypes } from '@/v2/blocks/response-block/helpers/media-types'\nimport { parseSetCookie } from '@/v2/blocks/response-block/helpers/parse-set-cookie'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nconst { layout, totalPerformedRequests, response, requestPayload } =\n defineProps<{\n /** Wait for the selected external request example before sending. */\n executionDisabled?: boolean\n /** Preprocessed response */\n response: ResponseInstance | null\n /** Original request as a [url, RequestInit] tuple */\n requestPayload: RequestPayload | null\n /** Client layout */\n layout: ClientLayout\n /** Total number of performed requests */\n totalPerformedRequests: number\n /** Application version */\n appVersion: string\n /** Registered app plugins */\n plugins: ClientPlugin[]\n /** Workspace event bus */\n eventBus: WorkspaceEventBus\n }>()\n\nconst { translate } = useLocalization()\n\n// Headers\nconst responseHeaders = computed(() => {\n const headers = response?.headers\n\n return headers\n ? Object.keys(headers).map((key) => ({\n name: key,\n value: headers[key] ?? '',\n }))\n : []\n})\n\nconst responseContentType = computed(\n () => response?.headers['content-type'] ?? response?.headers['Content-Type'],\n)\n\n// Cookies\nconst responseCookies = computed(\n () =>\n response?.cookieHeaderKeys\n .map((setCookieValue) => parseSetCookie(setCookieValue))\n .filter(isDefined) ?? [],\n)\n\nconst responseSections = ['Cookies', 'Headers', 'Body'] as const\ntype Filter = 'All' | (typeof responseSections)[number]\nconst activeFilter = ref<Filter>('All')\n\nconst filters = computed<Filter[]>(() => ['All', ...responseSections])\n\nconst filterIds = computed<Record<Filter, string>>(() => ({\n All: useId(),\n Cookies: useId(),\n Headers: useId(),\n Body: useId(),\n}))\n\n/** Threshold for virtualizing response bodies in bytes */\nconst VIRTUALIZATION_THRESHOLD = 200_000\nconst shouldVirtualize = computed(() => {\n if (!response || !('size' in response)) {\n return false\n }\n\n // Get content type from headers\n const contentType =\n response.headers?.['content-type'] || response.headers?.['Content-Type']\n\n // If no content type or response size is small, don't virtualize\n if (!contentType || (response.size ?? 0) <= VIRTUALIZATION_THRESHOLD) {\n return false\n }\n\n // Do not virtualize html\n if (contentType.includes('text/html')) {\n return false\n }\n\n // Check if content type matches any text-based type\n const isTextBased = textMediaTypes.some((type) => contentType.includes(type))\n\n return isTextBased && (response.size ?? 0) > VIRTUALIZATION_THRESHOLD\n})\n\nconst requestHeaders = computed(() => {\n const headers = requestPayload?.[1]?.headers\n if (!headers) {\n return []\n }\n\n // Normalise via the Headers constructor, and then spread\n return [...new Headers(headers)].map(([name, value]) => ({\n name,\n value,\n required: false,\n }))\n})\n\nconst isSectionVisible = (\n section: (typeof responseSections)[number] | 'All',\n) => {\n if (activeFilter.value === 'All' || activeFilter.value === section) {\n return true\n }\n return false\n}\n\ndefineExpose({\n responseHeaders,\n responseCookies,\n requestHeaders,\n shouldVirtualize,\n activeFilter,\n filters,\n})\n\nconst filterLabels = computed(() => ({\n All: translate('apiClient.sectionFilter.all'),\n Auth: translate('apiClient.sectionFilter.auth'),\n Variables: translate('apiClient.sectionFilter.variables'),\n Cookies: translate('apiClient.sectionFilter.cookies'),\n Headers: translate('apiClient.sectionFilter.headers'),\n Query: translate('apiClient.sectionFilter.query'),\n Body: translate('apiClient.sectionFilter.body'),\n}))\n</script>\n<template>\n <!-- Bound the stacked response section so long bodies keep their own scroll area. -->\n <ViewLayoutSection\n :aria-label=\"translate('apiClient.responseBlock.response')\"\n class=\"max-xl:max-h-full\">\n <template #title>\n <div class=\"flex h-8 flex-1 items-center\">\n <div\n aria-live=\"polite\"\n class=\"flex items-center\"\n :class=\"{ 'animate-response-heading': response }\">\n <span class=\"response-heading pointer-events-none absolute\">{{\n translate('apiClient.responseBlock.response')\n }}</span>\n <ResponseMetaInformation\n v-if=\"response\"\n class=\"animate-response-children\"\n :eventBus=\"eventBus\"\n :response=\"response\" />\n </div>\n <SectionFilter\n v-model=\"activeFilter\"\n :filters=\"filters\"\n :labels=\"filterLabels\" />\n </div>\n </template>\n <div\n :id=\"filterIds.All\"\n class=\"custom-scroll response-section-content relative grid h-full justify-stretch\"\n :class=\"{\n 'content-start': response,\n }\"\n :role=\"activeFilter === 'All' && response ? 'tabpanel' : 'none'\">\n <template v-if=\"!response\">\n <ResponseEmpty\n :appVersion=\"appVersion\"\n :executionDisabled\n :layout=\"layout\"\n :totalPerformedRequests=\"totalPerformedRequests\"\n @addRequest=\"\n eventBus.emit('ui:open:command-palette', {\n action: 'create-request',\n payload: undefined,\n })\n \"\n @openCommandPalette=\"eventBus.emit('ui:open:command-palette')\"\n @sendRequest=\"eventBus.emit('operation:send:request:hotkey')\" />\n </template>\n <template v-else>\n <!-- Cookies section -->\n <ResponseCookies\n v-if=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n class=\"response-section-content-cookies\"\n :cookies=\"responseCookies\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n <!-- Request headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"requestHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.requestHeaders') }}\n </template>\n </HeadersComponent>\n <!-- Response headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.responseHeaders') }}\n </template>\n </HeadersComponent>\n\n <!-- Inject response section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.response.component\"\n v-if=\"plugin?.components?.response\"\n v-show=\"activeFilter === 'All'\"\n v-bind=\"plugin.components.response.additionalProps\" />\n </ScalarErrorBoundary>\n\n <template v-if=\"activeFilter === 'All' || activeFilter === 'Body'\">\n <!-- Streaming response body -->\n <ResponseBodyStreaming\n v-if=\"'reader' in response\"\n :id=\"filterIds.Body\"\n class=\"response-section-content-body\"\n :contentType=\"responseContentType\"\n :reader=\"response.reader\" />\n\n <!-- Virtualized Text for massive responses -->\n <ResponseBodyVirtual\n v-else-if=\"shouldVirtualize && typeof response?.data === 'string'\"\n :id=\"filterIds.Body\"\n :content=\"response!.data\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n\n <!-- Regular response body -->\n <ResponseBody\n v-else\n :id=\"filterIds.Body\"\n :active=\"true\"\n class=\"response-section-content-body\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n layout=\"client\"\n :plugins=\"plugins\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\"\n :title=\"translate('apiClient.responseBlock.body')\" />\n </template>\n </template>\n <ResponseLoadingOverlay :eventBus=\"eventBus\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.animate-response-heading .response-heading {\n animation: push-response 0.2s ease-in-out forwards;\n opacity: 1;\n}\n@keyframes push-response {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(-4px);\n }\n}\n.animate-response-heading .animate-response-children {\n animation: response-spans 0.2s ease-in-out forwards 0.05s;\n opacity: 0;\n}\n\n@keyframes response-spans {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ResponseBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { RequestPayload } from '@scalar/workspace-store/request-example'\nimport { computed, ref, useId } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ResponseInstance } from '@/v2/blocks/operation-block/helpers/send-request'\nimport HeadersComponent from '@/v2/blocks/response-block/components/Headers.vue'\nimport ResponseBody from '@/v2/blocks/response-block/components/ResponseBody.vue'\nimport ResponseBodyStreaming from '@/v2/blocks/response-block/components/ResponseBodyStreaming.vue'\nimport ResponseBodyVirtual from '@/v2/blocks/response-block/components/ResponseBodyVirtual.vue'\nimport ResponseCookies from '@/v2/blocks/response-block/components/ResponseCookies.vue'\nimport ResponseEmpty from '@/v2/blocks/response-block/components/ResponseEmpty.vue'\nimport ResponseLoadingOverlay from '@/v2/blocks/response-block/components/ResponseLoadingOverlay.vue'\nimport ResponseMetaInformation from '@/v2/blocks/response-block/components/ResponseMetaInformation.vue'\nimport { textMediaTypes } from '@/v2/blocks/response-block/helpers/media-types'\nimport { parseSetCookie } from '@/v2/blocks/response-block/helpers/parse-set-cookie'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nconst {\n layout,\n totalPerformedRequests,\n response,\n requestPayload,\n requestError,\n} = defineProps<{\n /** Wait for the selected external request example before sending. */\n executionDisabled?: boolean\n /** Failure retained until the next request or operation change. */\n requestError?: Error | null\n /** Preprocessed response */\n response: ResponseInstance | null\n /** Original request as a [url, RequestInit] tuple */\n requestPayload: RequestPayload | null\n /** Client layout */\n layout: ClientLayout\n /** Total number of performed requests */\n totalPerformedRequests: number\n /** Application version */\n appVersion: string\n /** Registered app plugins */\n plugins: ClientPlugin[]\n /** Workspace event bus */\n eventBus: WorkspaceEventBus\n}>()\n\nconst { translate } = useLocalization()\n\n/** Browsers hide CORS details, so these messages warrant guidance, not a diagnosis. */\nconst showNetworkErrorHelp = computed<boolean>(\n () =>\n !isElectron() &&\n requestError?.name === 'TypeError' &&\n [\n 'Failed to fetch',\n 'Load failed',\n 'NetworkError when attempting to fetch resource.',\n ].includes(requestError.message),\n)\n\n// Headers\nconst responseHeaders = computed(() => {\n const headers = response?.headers\n\n return headers\n ? Object.keys(headers).map((key) => ({\n name: key,\n value: headers[key] ?? '',\n }))\n : []\n})\n\nconst responseContentType = computed(\n () => response?.headers['content-type'] ?? response?.headers['Content-Type'],\n)\n\n// Cookies\nconst responseCookies = computed(\n () =>\n response?.cookieHeaderKeys\n .map((setCookieValue) => parseSetCookie(setCookieValue))\n .filter(isDefined) ?? [],\n)\n\nconst responseSections = ['Cookies', 'Headers', 'Body'] as const\ntype Filter = 'All' | (typeof responseSections)[number]\nconst activeFilter = ref<Filter>('All')\n\nconst filters = computed<Filter[]>(() => ['All', ...responseSections])\n\nconst filterIds = computed<Record<Filter, string>>(() => ({\n All: useId(),\n Cookies: useId(),\n Headers: useId(),\n Body: useId(),\n}))\n\n/** Threshold for virtualizing response bodies in bytes */\nconst VIRTUALIZATION_THRESHOLD = 200_000\nconst shouldVirtualize = computed(() => {\n if (!response || !('size' in response)) {\n return false\n }\n\n // Get content type from headers\n const contentType =\n response.headers?.['content-type'] || response.headers?.['Content-Type']\n\n // If no content type or response size is small, don't virtualize\n if (!contentType || (response.size ?? 0) <= VIRTUALIZATION_THRESHOLD) {\n return false\n }\n\n // Do not virtualize html\n if (contentType.includes('text/html')) {\n return false\n }\n\n // Check if content type matches any text-based type\n const isTextBased = textMediaTypes.some((type) => contentType.includes(type))\n\n return isTextBased && (response.size ?? 0) > VIRTUALIZATION_THRESHOLD\n})\n\nconst requestHeaders = computed(() => {\n const headers = requestPayload?.[1]?.headers\n if (!headers) {\n return []\n }\n\n // Normalise via the Headers constructor, and then spread\n return [...new Headers(headers)].map(([name, value]) => ({\n name,\n value,\n required: false,\n }))\n})\n\nconst isSectionVisible = (\n section: (typeof responseSections)[number] | 'All',\n) => {\n if (activeFilter.value === 'All' || activeFilter.value === section) {\n return true\n }\n return false\n}\n\ndefineExpose({\n responseHeaders,\n responseCookies,\n requestHeaders,\n shouldVirtualize,\n activeFilter,\n filters,\n})\n\nconst filterLabels = computed(() => ({\n All: translate('apiClient.sectionFilter.all'),\n Auth: translate('apiClient.sectionFilter.auth'),\n Variables: translate('apiClient.sectionFilter.variables'),\n Cookies: translate('apiClient.sectionFilter.cookies'),\n Headers: translate('apiClient.sectionFilter.headers'),\n Query: translate('apiClient.sectionFilter.query'),\n Body: translate('apiClient.sectionFilter.body'),\n}))\n</script>\n<template>\n <!-- Bound the stacked response section so long bodies keep their own scroll area. -->\n <ViewLayoutSection\n :aria-label=\"translate('apiClient.responseBlock.response')\"\n class=\"max-xl:max-h-full\">\n <template #title>\n <div class=\"flex h-8 flex-1 items-center\">\n <div\n aria-live=\"polite\"\n class=\"flex items-center\"\n :class=\"{ 'animate-response-heading': response }\">\n <span class=\"response-heading pointer-events-none absolute\">{{\n translate('apiClient.responseBlock.response')\n }}</span>\n <ResponseMetaInformation\n v-if=\"response\"\n class=\"animate-response-children\"\n :eventBus=\"eventBus\"\n :response=\"response\" />\n </div>\n <SectionFilter\n v-model=\"activeFilter\"\n :filters=\"filters\"\n :labels=\"filterLabels\" />\n </div>\n </template>\n <div\n :id=\"filterIds.All\"\n class=\"custom-scroll response-section-content relative grid h-full justify-stretch\"\n :class=\"{\n 'content-start': response,\n }\"\n :role=\"activeFilter === 'All' && response ? 'tabpanel' : 'none'\">\n <div\n v-if=\"requestError\"\n class=\"flex flex-col gap-3 p-4 text-sm\"\n role=\"alert\">\n <h3 class=\"text-c-1 font-medium\">\n {{ translate('apiClient.responseBlock.requestFailed') }}\n </h3>\n <p class=\"text-c-2 break-words\">{{ requestError.message }}</p>\n <p\n v-if=\"showNetworkErrorHelp\"\n class=\"text-c-2 leading-relaxed\">\n {{ translate('apiClient.responseBlock.networkErrorHelp') }}\n </p>\n </div>\n <template v-else-if=\"!response\">\n <ResponseEmpty\n :appVersion=\"appVersion\"\n :executionDisabled\n :layout=\"layout\"\n :totalPerformedRequests=\"totalPerformedRequests\"\n @addRequest=\"\n eventBus.emit('ui:open:command-palette', {\n action: 'create-request',\n payload: undefined,\n })\n \"\n @openCommandPalette=\"eventBus.emit('ui:open:command-palette')\"\n @sendRequest=\"eventBus.emit('operation:send:request:hotkey')\" />\n </template>\n <template v-else>\n <!-- Cookies section -->\n <ResponseCookies\n v-if=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n class=\"response-section-content-cookies\"\n :cookies=\"responseCookies\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n <!-- Request headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"requestHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.requestHeaders') }}\n </template>\n </HeadersComponent>\n <!-- Response headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.responseHeaders') }}\n </template>\n </HeadersComponent>\n\n <!-- Inject response section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.response.component\"\n v-if=\"plugin?.components?.response\"\n v-show=\"activeFilter === 'All'\"\n v-bind=\"plugin.components.response.additionalProps\" />\n </ScalarErrorBoundary>\n\n <template v-if=\"activeFilter === 'All' || activeFilter === 'Body'\">\n <!-- Streaming response body -->\n <ResponseBodyStreaming\n v-if=\"'reader' in response\"\n :id=\"filterIds.Body\"\n class=\"response-section-content-body\"\n :contentType=\"responseContentType\"\n :reader=\"response.reader\" />\n\n <!-- Virtualized Text for massive responses -->\n <ResponseBodyVirtual\n v-else-if=\"shouldVirtualize && typeof response?.data === 'string'\"\n :id=\"filterIds.Body\"\n :content=\"response!.data\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n\n <!-- Regular response body -->\n <ResponseBody\n v-else\n :id=\"filterIds.Body\"\n :active=\"true\"\n class=\"response-section-content-body\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n layout=\"client\"\n :plugins=\"plugins\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\"\n :title=\"translate('apiClient.responseBlock.body')\" />\n </template>\n </template>\n <ResponseLoadingOverlay :eventBus=\"eventBus\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.animate-response-heading .response-heading {\n animation: push-response 0.2s ease-in-out forwards;\n opacity: 1;\n}\n@keyframes push-response {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(-4px);\n }\n}\n.animate-response-heading .animate-response-children {\n animation: response-spans 0.2s ease-in-out forwards 0.05s;\n opacity: 0;\n}\n\n@keyframes response-spans {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -25,6 +25,8 @@ type __VLS_Props = {
|
|
|
25
25
|
* turns it off and the card is named as a group instead.
|
|
26
26
|
*/
|
|
27
27
|
heading?: boolean;
|
|
28
|
+
/** Hides a sole active required choice in the reference while preserving client controls. */
|
|
29
|
+
hideSingleRequiredScheme?: boolean;
|
|
28
30
|
/** Creates a static disclosure that cannot be collapsed */
|
|
29
31
|
isStatic?: boolean;
|
|
30
32
|
meta: AuthMeta;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthSelector.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AuthSelector.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue"],"names":[],"mappings":"AAuYA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;AAKnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,KAAK,EACV,QAAQ,EACR,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AAGvC,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,eAAe,EAEf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAIrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8DAA8D,CAAA;AACjG,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,gEAAgE,CAAA;AAMvE,KAAK,WAAW,GAAG;IACjB,WAAW,EAAE,kBAAkB,CAAA;IAC/B,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,gEAAgE;IAChE,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6FAA6F;IAC7F,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAClC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,oBAAoB,EAAE,eAAe,CAAC,UAAU,CAAC,CAAA;IACjD,eAAe,EAAE,qBAAqB,CAAA;IACtC,gBAAgB,EAAE,gBAAgB,GAAG,SAAS,CAAA;IAC9C,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,uDAAuD;IACvD,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,yFAAyF;IACzF,YAAY,CAAC,EAAE,SAAS,GAAG,UAAU,CAAA;CACtC,CAAC;AAyiBF,QAAA,MAAM,YAAY;;cAjgBqB,IAAI;cAAQ,MAAM;;;;oPAogBvD,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|