@scalar/api-client 3.21.0 → 3.21.1
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 +13 -0
- package/dist/style.css +22 -16
- 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 +4 -0
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts +2 -0
- package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/RequestBlock.vue.js +1 -1
- package/dist/v2/blocks/request-block/RequestBlock.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/RequestBlock.vue.script.js +7 -0
- package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts +4 -0
- package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.js +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js +8 -5
- package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.d.ts +2 -0
- package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.script.js +12 -4
- package/dist/v2/blocks/request-block/components/RequestBodyForm.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/RequestTable.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTable.vue.js +1 -1
- package/dist/v2/blocks/request-block/components/RequestTable.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js +1 -0
- package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js.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 +2 -2
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/helpers/get-form-body-rows.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js +5 -3
- package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js.map +1 -1
- 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 +4 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/vue-styles.css +16 -16
- package/package.json +11 -11
|
@@ -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) 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) {\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 /** 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-form-body-rows.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/get-form-body-rows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAG/G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0DAA0D,CAAA;AAExF,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,WAQ5C,CAAA;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,EAAE,YAAY,GAAG,SAAS,CAAA;IAChC,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,YAAY,EACpB,aAAY,MAAM,EAAO,EACzB,wBAAqB,KACpB,OAAO,EA6BT,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,OAAO,EAChB,QAAQ,YAAY,GAAG,SAAS,EAChC,aAAY,MAAM,EAAO,KACxB;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EAqCpC,CAAA;AAED,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,GAAI,KAAK,QAAQ,KAAG,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE,GAAG,SAG5E,CAAA;AAED,uGAAuG;AACvG,eAAO,MAAM,eAAe,GAC1B,SAAS,aAAa,GAAG,SAAS,GAAG,IAAI,EACzC,aAAa,MAAM,EACnB,iBAAiB,YAAY,KAC5B,QAAQ,
|
|
1
|
+
{"version":3,"file":"get-form-body-rows.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/get-form-body-rows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAG/G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0DAA0D,CAAA;AAExF,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,WAQ5C,CAAA;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,EAAE,YAAY,GAAG,SAAS,CAAA;IAChC,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,YAAY,EACpB,aAAY,MAAM,EAAO,EACzB,wBAAqB,KACpB,OAAO,EA6BT,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,OAAO,EAChB,QAAQ,YAAY,GAAG,SAAS,EAChC,aAAY,MAAM,EAAO,KACxB;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EAqCpC,CAAA;AAED,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,GAAI,KAAK,QAAQ,KAAG,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE,GAAG,SAG5E,CAAA;AAED,uGAAuG;AACvG,eAAO,MAAM,eAAe,GAC1B,SAAS,aAAa,GAAG,SAAS,GAAG,IAAI,EACzC,aAAa,MAAM,EACnB,iBAAiB,YAAY,KAC5B,QAAQ,EAyIV,CAAA"}
|
|
@@ -120,12 +120,14 @@ var getFormBodyRows = (example, contentType, formBodySchema) => {
|
|
|
120
120
|
if (Array.isArray(value)) return value.flatMap((exampleValue) => {
|
|
121
121
|
if (isObject(exampleValue)) {
|
|
122
122
|
const name = String(exampleValue.name);
|
|
123
|
-
|
|
123
|
+
return (contentType === "multipart/form-data" ? mapValue(name, exampleValue.value, Boolean(exampleValue.isDisabled), exampleValue.isArray === true) : [mapRow({
|
|
124
124
|
name,
|
|
125
125
|
value: exampleValue.value instanceof File ? exampleValue.value : String(exampleValue.value),
|
|
126
126
|
isDisabled: Boolean(exampleValue.isDisabled)
|
|
127
|
-
})
|
|
128
|
-
|
|
127
|
+
})]).map((row) => row.isDisabled && exampleValue.isDisabledByDefault === true ? {
|
|
128
|
+
...row,
|
|
129
|
+
isDisabledByDefault: true
|
|
130
|
+
} : row);
|
|
129
131
|
}
|
|
130
132
|
return {
|
|
131
133
|
name: "",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-form-body-rows.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/get-form-body-rows.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { coerceLeafValueToSchemaType } from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { ExampleObject, 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'\n\nexport const stringifyValue = (value: unknown) => {\n if (value instanceof File) {\n return value.name\n }\n if (typeof value === 'object' && value !== null) {\n return JSON.stringify(value)\n }\n return String(value)\n}\n\nexport type LeafRow = {\n path: string[]\n schema: SchemaObject | undefined\n isRequired: boolean\n}\n\n/**\n * Walk a (possibly nested) object schema and collect one entry per leaf property.\n *\n * A \"leaf\" is any property whose resolved schema is not an `{ type: 'object' }` schema\n * with named `properties` — i.e. primitives, arrays, files, and `additionalProperties`\n * placeholders all stop the recursion. Object properties recurse, so the widget example\n * (`file` + `props.{name,description,created_at}`) yields four leaves.\n */\nexport const collectLeafProperties = (\n schema: SchemaObject,\n parentPath: string[] = [],\n parentRequired = true,\n): LeafRow[] => {\n // Nothing to walk if this is not an object schema or has no declared properties.\n if (!isObjectSchema(schema) || !schema.properties) {\n return []\n }\n\n // `required` is a list of property names on *this* schema, so build it once per level.\n const requiredSet = new Set(schema.required ?? [])\n const leaves: LeafRow[] = []\n\n for (const [key, rawChildSchema] of objectEntries(schema.properties)) {\n const childSchema = resolve.schema(rawChildSchema)\n const path = [...parentPath, String(key)]\n\n // A leaf is only required when *every* ancestor was also required — a non-required\n // parent makes the whole subtree optional regardless of inner `required` lists.\n const isRequired = parentRequired && requiredSet.has(String(key))\n\n // Nested objects with named properties recurse so each leaf gets its own row;\n // everything else (primitives, arrays, files, additionalProperties placeholders)\n // is treated as a leaf and stops the descent.\n if (childSchema && isObjectSchema(childSchema) && childSchema.properties) {\n leaves.push(...collectLeafProperties(childSchema, path, isRequired))\n } else {\n leaves.push({ path, schema: childSchema, isRequired })\n }\n }\n\n return leaves\n}\n\n/**\n * Walk a schema + example together and collect one row per leaf, including example-only\n * keys that the schema does not declare. Schema-declared properties come first in schema\n * order; extras present in the example follow in example order at each level.\n *\n * Unlike `collectLeafProperties` (which is schema-only and feeds the dotted-name index),\n * this walker drives what the user actually sees in the form: a row for every leaf the\n * example contains, even when the schema is partial or out of date.\n */\nexport const collectExampleRows = (\n example: unknown,\n schema: SchemaObject | undefined,\n parentPath: string[] = [],\n): { path: string[]; value: unknown }[] => {\n const rows: { path: string[]; value: unknown }[] = []\n const exampleEntries = isObject(example) ? objectEntries(example) : []\n const exampleByKey = new Map<string, unknown>(exampleEntries.map(([key, value]) => [String(key), value]))\n const declaredKeys = new Set<string>()\n const schemaProperties = schema && isObjectSchema(schema) ? (schema.properties ?? {}) : {}\n\n // Schema-declared properties first, in schema order. Nested object schemas recurse so\n // each leaf gets its own row; otherwise the schema-declared key is a leaf and uses the\n // matching example value (or `undefined` when the example does not provide one).\n for (const [key, rawChildSchema] of objectEntries(schemaProperties)) {\n const keyStr = String(key)\n declaredKeys.add(keyStr)\n const childSchema = resolve.schema(rawChildSchema)\n const path = [...parentPath, keyStr]\n const exampleSubvalue = exampleByKey.get(keyStr)\n\n if (childSchema && isObjectSchema(childSchema) && childSchema.properties) {\n rows.push(...collectExampleRows(exampleSubvalue, childSchema, path))\n } else {\n rows.push({ path, value: exampleSubvalue })\n }\n }\n\n // Example-only properties at this level (preserve example order). Their inner shape is\n // not descended into — without a schema saying \"this is a nested object\" we have no\n // signal to flatten, so an object value becomes a single JSON-stringified row, matching\n // the schema-less fallback below.\n for (const [key, value] of exampleEntries) {\n const keyStr = String(key)\n if (declaredKeys.has(keyStr)) {\n continue\n }\n rows.push({ path: [...parentPath, keyStr], value })\n }\n\n return rows\n}\n\n/** Restore array values after text editing without parsing ordinary string fields. */\nexport const getFormBodyValue = (row: TableRow): string | File | unknown[] | undefined => {\n const value = coerceLeafValueToSchemaType(row.value, row.isArray ? { type: 'array' } : row.schema)\n return Array.isArray(value) ? value : (row.value ?? undefined)\n}\n\n/** Build the table rows for the form data, optionally enriched with schema (e.g. enum) per property */\nexport const getFormBodyRows = (\n example: ExampleObject | undefined | null,\n contentType: string,\n formBodySchema?: SchemaObject,\n): TableRow[] => {\n // Forms use structured data even when the raw example also supplies wire text.\n const value = example?.dataValue !== undefined ? example.dataValue : example?.value\n // We only need the rows for formData\n if (!value || (contentType !== 'multipart/form-data' && contentType !== 'application/x-www-form-urlencoded')) {\n return []\n }\n\n // Get all the schema properties if the schema is an object schema\n const schemaWithProperties = formBodySchema && isObjectSchema(formBodySchema) ? formBodySchema : undefined\n // The request builder preserves composed fields because members can make them required.\n // Keep those fields checked so the initial form matches the body that will be sent.\n const isComposed = Boolean(schemaWithProperties?.allOf || schemaWithProperties?.oneOf || schemaWithProperties?.anyOf)\n const requiredSet = schemaWithProperties ? new Set(schemaWithProperties.required ?? []) : undefined\n\n // Pre-compute the leaf-by-dotted-name index up front so both the array and the\n // schema-driven branches can pull each row's leaf schema and required flag without\n // re-walking the schema. Without this, edited rows lose the per-leaf `Required`\n // badge because a top-level `properties[name]` lookup misses dotted names.\n const leafByDottedName = new Map<string, LeafRow>()\n if (schemaWithProperties) {\n for (const leaf of collectLeafProperties(schemaWithProperties)) {\n leafByDottedName.set(leaf.path.join('.'), leaf)\n }\n }\n\n const mapRow = ({\n name,\n value,\n isDisabled,\n }: {\n name: string\n value: string | File\n isDisabled?: boolean\n }): TableRow => {\n const row: TableRow = { name, value, isDisabled: isDisabled ?? false }\n if (!schemaWithProperties || !name) {\n return row\n }\n // Prefer the pre-resolved leaf (handles dotted names like `props.name`); fall back\n // to a top-level property lookup so user-added rows keep working.\n const leaf = leafByDottedName.get(name)\n const propSchema = leaf?.schema ?? resolve.schema(schemaWithProperties.properties?.[name])\n row.schema = propSchema\n row.description = propSchema?.description\n row.isRequired = leaf?.isRequired ?? requiredSet?.has(name) ?? false\n\n // Top-level optional properties default to disabled (unchecked), matching how optional\n // parameters behave. Scoped to top-level declared properties on purpose: the send side\n // (`build-request-body`) only drops top-level optional keys, so auto-disabling a nested\n // leaf (e.g. `props.name`) would leave it unchecked yet still transmitted. `Object.hasOwn`\n // (not `in`) keeps example-only keys named like `Object.prototype` members enabled. An\n // explicit `isDisabled` (from a stored form-row array) always wins.\n if (\n isDisabled === undefined &&\n !isComposed &&\n schemaWithProperties.properties &&\n Object.hasOwn(schemaWithProperties.properties, name)\n ) {\n row.isDisabled = !row.isRequired\n // Mark the row as disabled by default (no explicit `isDisabled` was stored) so typing a\n // value auto-enables it in `RequestTableRow`, matching how optional parameters behave. An\n // explicit `isDisabled` from a stored form-row array skips this branch and keeps winning.\n row.isDisabledByDefault = row.isDisabled\n }\n return row\n }\n\n const mapValue = (name: string, value: unknown, isDisabled?: boolean, isArray?: boolean): TableRow[] => {\n // Uploaded files must never pass through JSON.stringify, which discards their bytes.\n if (\n contentType === 'multipart/form-data' &&\n Array.isArray(value) &&\n value.length > 0 &&\n value.every((item) => item instanceof File)\n ) {\n return value.map((file) => mapRow({ name, value: file, isDisabled }))\n }\n const row = mapRow({\n name,\n value: value instanceof File ? value : value == null ? '' : stringifyValue(value),\n isDisabled,\n })\n if (contentType === 'multipart/form-data' && (Array.isArray(value) || isArray)) {\n // Example-only arrays also need their type to survive a form-table round trip.\n row.isArray = true\n }\n return [row]\n }\n\n // We have form data stored as an array\n if (Array.isArray(value)) {\n return value.flatMap((exampleValue) => {\n if (isObject(exampleValue)) {\n const name = String(exampleValue.name)\n if (contentType !== 'multipart/form-data') {\n return mapRow({\n name,\n value: exampleValue.value instanceof File ? exampleValue.value : String(exampleValue.value),\n isDisabled: Boolean(exampleValue.isDisabled),\n })\n }\n return mapValue(name, exampleValue.value, Boolean(exampleValue.isDisabled), exampleValue.isArray === true)\n }\n return { name: '', value: exampleValue, isDisabled: false }\n })\n }\n\n // Schema-driven path: when the form body schema describes nested objects, emit one row\n // per leaf so users can edit individual fields. The dotted name (`props.name`) is folded\n // back into a single JSON multipart part by `build-request-body.ts` before the request is\n // sent. Gated to `multipart/form-data` because urlencoded has no regrouping step on send,\n // so dotted leaves would otherwise reach the wire as separate `props.name`-style fields.\n //\n // We walk the example alongside the schema so example-only properties (top-level extras\n // or undeclared keys inside a nested object) are still visible and editable instead of\n // being silently dropped to whatever the schema happens to declare.\n if (contentType === 'multipart/form-data' && schemaWithProperties && typeof value === 'object') {\n return collectExampleRows(value, schemaWithProperties).flatMap(({ path, value }) => mapValue(path.join('.'), value))\n }\n\n // We got an object try to convert it to an array of rows\n if (typeof value === 'object' && value) {\n return objectEntries(value).flatMap(([key, value]) =>\n contentType === 'multipart/form-data'\n ? mapValue(String(key), value)\n : mapRow({ name: String(key), value: stringifyValue(value) }),\n )\n }\n\n return []\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"get-form-body-rows.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/get-form-body-rows.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { coerceLeafValueToSchemaType } from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { ExampleObject, 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'\n\nexport const stringifyValue = (value: unknown) => {\n if (value instanceof File) {\n return value.name\n }\n if (typeof value === 'object' && value !== null) {\n return JSON.stringify(value)\n }\n return String(value)\n}\n\nexport type LeafRow = {\n path: string[]\n schema: SchemaObject | undefined\n isRequired: boolean\n}\n\n/**\n * Walk a (possibly nested) object schema and collect one entry per leaf property.\n *\n * A \"leaf\" is any property whose resolved schema is not an `{ type: 'object' }` schema\n * with named `properties` — i.e. primitives, arrays, files, and `additionalProperties`\n * placeholders all stop the recursion. Object properties recurse, so the widget example\n * (`file` + `props.{name,description,created_at}`) yields four leaves.\n */\nexport const collectLeafProperties = (\n schema: SchemaObject,\n parentPath: string[] = [],\n parentRequired = true,\n): LeafRow[] => {\n // Nothing to walk if this is not an object schema or has no declared properties.\n if (!isObjectSchema(schema) || !schema.properties) {\n return []\n }\n\n // `required` is a list of property names on *this* schema, so build it once per level.\n const requiredSet = new Set(schema.required ?? [])\n const leaves: LeafRow[] = []\n\n for (const [key, rawChildSchema] of objectEntries(schema.properties)) {\n const childSchema = resolve.schema(rawChildSchema)\n const path = [...parentPath, String(key)]\n\n // A leaf is only required when *every* ancestor was also required — a non-required\n // parent makes the whole subtree optional regardless of inner `required` lists.\n const isRequired = parentRequired && requiredSet.has(String(key))\n\n // Nested objects with named properties recurse so each leaf gets its own row;\n // everything else (primitives, arrays, files, additionalProperties placeholders)\n // is treated as a leaf and stops the descent.\n if (childSchema && isObjectSchema(childSchema) && childSchema.properties) {\n leaves.push(...collectLeafProperties(childSchema, path, isRequired))\n } else {\n leaves.push({ path, schema: childSchema, isRequired })\n }\n }\n\n return leaves\n}\n\n/**\n * Walk a schema + example together and collect one row per leaf, including example-only\n * keys that the schema does not declare. Schema-declared properties come first in schema\n * order; extras present in the example follow in example order at each level.\n *\n * Unlike `collectLeafProperties` (which is schema-only and feeds the dotted-name index),\n * this walker drives what the user actually sees in the form: a row for every leaf the\n * example contains, even when the schema is partial or out of date.\n */\nexport const collectExampleRows = (\n example: unknown,\n schema: SchemaObject | undefined,\n parentPath: string[] = [],\n): { path: string[]; value: unknown }[] => {\n const rows: { path: string[]; value: unknown }[] = []\n const exampleEntries = isObject(example) ? objectEntries(example) : []\n const exampleByKey = new Map<string, unknown>(exampleEntries.map(([key, value]) => [String(key), value]))\n const declaredKeys = new Set<string>()\n const schemaProperties = schema && isObjectSchema(schema) ? (schema.properties ?? {}) : {}\n\n // Schema-declared properties first, in schema order. Nested object schemas recurse so\n // each leaf gets its own row; otherwise the schema-declared key is a leaf and uses the\n // matching example value (or `undefined` when the example does not provide one).\n for (const [key, rawChildSchema] of objectEntries(schemaProperties)) {\n const keyStr = String(key)\n declaredKeys.add(keyStr)\n const childSchema = resolve.schema(rawChildSchema)\n const path = [...parentPath, keyStr]\n const exampleSubvalue = exampleByKey.get(keyStr)\n\n if (childSchema && isObjectSchema(childSchema) && childSchema.properties) {\n rows.push(...collectExampleRows(exampleSubvalue, childSchema, path))\n } else {\n rows.push({ path, value: exampleSubvalue })\n }\n }\n\n // Example-only properties at this level (preserve example order). Their inner shape is\n // not descended into — without a schema saying \"this is a nested object\" we have no\n // signal to flatten, so an object value becomes a single JSON-stringified row, matching\n // the schema-less fallback below.\n for (const [key, value] of exampleEntries) {\n const keyStr = String(key)\n if (declaredKeys.has(keyStr)) {\n continue\n }\n rows.push({ path: [...parentPath, keyStr], value })\n }\n\n return rows\n}\n\n/** Restore array values after text editing without parsing ordinary string fields. */\nexport const getFormBodyValue = (row: TableRow): string | File | unknown[] | undefined => {\n const value = coerceLeafValueToSchemaType(row.value, row.isArray ? { type: 'array' } : row.schema)\n return Array.isArray(value) ? value : (row.value ?? undefined)\n}\n\n/** Build the table rows for the form data, optionally enriched with schema (e.g. enum) per property */\nexport const getFormBodyRows = (\n example: ExampleObject | undefined | null,\n contentType: string,\n formBodySchema?: SchemaObject,\n): TableRow[] => {\n // Forms use structured data even when the raw example also supplies wire text.\n const value = example?.dataValue !== undefined ? example.dataValue : example?.value\n // We only need the rows for formData\n if (!value || (contentType !== 'multipart/form-data' && contentType !== 'application/x-www-form-urlencoded')) {\n return []\n }\n\n // Get all the schema properties if the schema is an object schema\n const schemaWithProperties = formBodySchema && isObjectSchema(formBodySchema) ? formBodySchema : undefined\n // The request builder preserves composed fields because members can make them required.\n // Keep those fields checked so the initial form matches the body that will be sent.\n const isComposed = Boolean(schemaWithProperties?.allOf || schemaWithProperties?.oneOf || schemaWithProperties?.anyOf)\n const requiredSet = schemaWithProperties ? new Set(schemaWithProperties.required ?? []) : undefined\n\n // Pre-compute the leaf-by-dotted-name index up front so both the array and the\n // schema-driven branches can pull each row's leaf schema and required flag without\n // re-walking the schema. Without this, edited rows lose the per-leaf `Required`\n // badge because a top-level `properties[name]` lookup misses dotted names.\n const leafByDottedName = new Map<string, LeafRow>()\n if (schemaWithProperties) {\n for (const leaf of collectLeafProperties(schemaWithProperties)) {\n leafByDottedName.set(leaf.path.join('.'), leaf)\n }\n }\n\n const mapRow = ({\n name,\n value,\n isDisabled,\n }: {\n name: string\n value: string | File\n isDisabled?: boolean\n }): TableRow => {\n const row: TableRow = { name, value, isDisabled: isDisabled ?? false }\n if (!schemaWithProperties || !name) {\n return row\n }\n // Prefer the pre-resolved leaf (handles dotted names like `props.name`); fall back\n // to a top-level property lookup so user-added rows keep working.\n const leaf = leafByDottedName.get(name)\n const propSchema = leaf?.schema ?? resolve.schema(schemaWithProperties.properties?.[name])\n row.schema = propSchema\n row.description = propSchema?.description\n row.isRequired = leaf?.isRequired ?? requiredSet?.has(name) ?? false\n\n // Top-level optional properties default to disabled (unchecked), matching how optional\n // parameters behave. Scoped to top-level declared properties on purpose: the send side\n // (`build-request-body`) only drops top-level optional keys, so auto-disabling a nested\n // leaf (e.g. `props.name`) would leave it unchecked yet still transmitted. `Object.hasOwn`\n // (not `in`) keeps example-only keys named like `Object.prototype` members enabled. An\n // explicit `isDisabled` (from a stored form-row array) always wins.\n if (\n isDisabled === undefined &&\n !isComposed &&\n schemaWithProperties.properties &&\n Object.hasOwn(schemaWithProperties.properties, name)\n ) {\n row.isDisabled = !row.isRequired\n // Mark the row as disabled by default (no explicit `isDisabled` was stored) so typing a\n // value auto-enables it in `RequestTableRow`, matching how optional parameters behave. An\n // explicit `isDisabled` from a stored form-row array skips this branch and keeps winning.\n row.isDisabledByDefault = row.isDisabled\n }\n return row\n }\n\n const mapValue = (name: string, value: unknown, isDisabled?: boolean, isArray?: boolean): TableRow[] => {\n // Uploaded files must never pass through JSON.stringify, which discards their bytes.\n if (\n contentType === 'multipart/form-data' &&\n Array.isArray(value) &&\n value.length > 0 &&\n value.every((item) => item instanceof File)\n ) {\n return value.map((file) => mapRow({ name, value: file, isDisabled }))\n }\n const row = mapRow({\n name,\n value: value instanceof File ? value : value == null ? '' : stringifyValue(value),\n isDisabled,\n })\n if (contentType === 'multipart/form-data' && (Array.isArray(value) || isArray)) {\n // Example-only arrays also need their type to survive a form-table round trip.\n row.isArray = true\n }\n return [row]\n }\n\n // We have form data stored as an array\n if (Array.isArray(value)) {\n return value.flatMap((exampleValue) => {\n if (isObject(exampleValue)) {\n const name = String(exampleValue.name)\n const rows =\n contentType === 'multipart/form-data'\n ? mapValue(name, exampleValue.value, Boolean(exampleValue.isDisabled), exampleValue.isArray === true)\n : [\n mapRow({\n name,\n value: exampleValue.value instanceof File ? exampleValue.value : String(exampleValue.value),\n isDisabled: Boolean(exampleValue.isDisabled),\n }),\n ]\n // An untouched optional row stays eligible for auto-enabling after another row is edited.\n return rows.map((row) =>\n row.isDisabled && exampleValue.isDisabledByDefault === true ? { ...row, isDisabledByDefault: true } : row,\n )\n }\n return { name: '', value: exampleValue, isDisabled: false }\n })\n }\n\n // Schema-driven path: when the form body schema describes nested objects, emit one row\n // per leaf so users can edit individual fields. The dotted name (`props.name`) is folded\n // back into a single JSON multipart part by `build-request-body.ts` before the request is\n // sent. Gated to `multipart/form-data` because urlencoded has no regrouping step on send,\n // so dotted leaves would otherwise reach the wire as separate `props.name`-style fields.\n //\n // We walk the example alongside the schema so example-only properties (top-level extras\n // or undeclared keys inside a nested object) are still visible and editable instead of\n // being silently dropped to whatever the schema happens to declare.\n if (contentType === 'multipart/form-data' && schemaWithProperties && typeof value === 'object') {\n return collectExampleRows(value, schemaWithProperties).flatMap(({ path, value }) => mapValue(path.join('.'), value))\n }\n\n // We got an object try to convert it to an array of rows\n if (typeof value === 'object' && value) {\n return objectEntries(value).flatMap(([key, value]) =>\n contentType === 'multipart/form-data'\n ? mapValue(String(key), value)\n : mapRow({ name: String(key), value: stringifyValue(value) }),\n )\n }\n\n return []\n}\n"],"mappings":"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"}
|
|
@@ -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":"AA2TA,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;IACf,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,OAAO,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;AA+BJ,QAAA,MAAM,gBAAgB,yCAA0C,CAAA;AAChE,KAAK,MAAM,GAAG,KAAK,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;AAubvD,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-2694e1a2"]]);
|
|
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 <ViewLayoutSection\n :aria-label=\"translate('apiClient.responseBlock.response')\">\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 :filterIds=\"filterIds\"\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 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 :filterIds=\"filterIds\"\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":""}
|
|
@@ -94,7 +94,10 @@ var ResponseBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
94
94
|
Body: translate("apiClient.sectionFilter.body")
|
|
95
95
|
}));
|
|
96
96
|
return (_ctx, _cache) => {
|
|
97
|
-
return openBlock(), createBlock(ViewLayoutSection_default, {
|
|
97
|
+
return openBlock(), createBlock(ViewLayoutSection_default, {
|
|
98
|
+
"aria-label": unref(translate)("apiClient.responseBlock.response"),
|
|
99
|
+
class: "max-xl:max-h-full"
|
|
100
|
+
}, {
|
|
98
101
|
title: withCtx(() => [createElementVNode("div", _hoisted_1, [createElementVNode("div", {
|
|
99
102
|
"aria-live": "polite",
|
|
100
103
|
class: normalizeClass(["flex items-center", { "animate-response-heading": __props.response }])
|
|
@@ -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 <ViewLayoutSection\n :aria-label=\"translate('apiClient.responseBlock.response')\">\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 :filterIds=\"filterIds\"\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 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 :filterIds=\"filterIds\"\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n type ScalarButton as ScalarButtonType,\n} from '@scalar/components/button'\nimport { ScalarComboboxMultiselect } from '@scalar/components/combobox'\nimport type { Icon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarListboxCheckbox } from '@scalar/components/listbox'\nimport { useModal } from '@scalar/components/modal'\nimport { ScalarIconCaretDown, ScalarIconTrash } from '@scalar/icons'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n isAuthOptional,\n type MergedSecuritySchemes,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n OpenApiDocument,\n SecurityRequirementObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, useId } from 'vue'\n\nimport DeleteRequestAuthModal from '@/v2/blocks/scalar-auth-selector-block/components/DeleteRequestAuthModal.vue'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport {\n formatComplexScheme,\n formatScheme,\n getSecuritySchemeOptions,\n type SecuritySchemeOption,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/security-scheme'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestAuthDataTable from './RequestAuthDataTable.vue'\n\nconst {\n environment,\n eventBus,\n createAnySecurityScheme = false,\n canDeleteSchemes = true,\n defaultOpen = true,\n isStatic = false,\n meta,\n proxyUrl,\n securityRequirements,\n securitySchemes,\n selectedSecurity,\n server,\n title,\n options,\n documentType,\n} = defineProps<{\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n /** Allows adding authentication which is not in the document */\n createAnySecurityScheme?: boolean\n /**\n * Whether schemes can be deleted from the selector. Enabled for the editable client, disabled in\n * the read-only reference where the schemes come from the document and cannot be removed.\n */\n canDeleteSchemes?: boolean\n /** Whether the authentication disclosure should start expanded */\n defaultOpen?: boolean\n /** Creates a static disclosure that cannot be collapsed */\n isStatic?: boolean\n meta: AuthMeta\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n selectedSecurity: SelectedSecurity | undefined\n server: ServerObject | null\n title: string\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n /** Type of the document the schemes belong to, used to label the missing-type warning */\n documentType?: 'openapi' | 'asyncapi'\n}>()\n\nconst { translate, translations } = useLocalization()\n\nconst titleId = useId()\nconst comboboxButtonRef = ref<typeof ScalarButtonType | null>(null)\nconst isDisclosureOpen = ref(false)\n\nconst deleteModal = useModal()\nconst schemeToDelete = ref<{\n label: string\n payload: SecurityRequirementObject\n} | null>(null)\n\n/**\n * Determines if authentication is required or optional\n *\n * Auth is optional when there is an empty security requirement and no complex requirements.\n * Complex requirements have multiple auth schemes combined (e.g., API key + OAuth).\n */\nconst authIndicator = computed<{ icon: Icon; text: string } | null>(() => {\n if (!securityRequirements?.length) {\n return null\n }\n\n const isOptional = isAuthOptional(securityRequirements)\n\n return {\n icon: isOptional ? 'Unlock' : 'Lock',\n text: isOptional\n ? translate('apiClient.authSelector.optional')\n : translate('apiClient.authSelector.required'),\n }\n})\n\n/** All available auth scheme options for the dropdown */\nconst availableSchemeOptions = computed(() =>\n getSecuritySchemeOptions(\n securityRequirements ?? [],\n securitySchemes ?? {},\n selectedSecurity?.selectedSchemes ?? [],\n createAnySecurityScheme,\n translations.value.apiClient,\n ),\n)\n\n/** Currently active auth schemes selected for this operation or collection */\nconst activeSchemeOptions = computed<SecuritySchemeOption[]>(() => {\n const schemes = selectedSecurity?.selectedSchemes\n if (!schemes?.length) {\n return []\n }\n\n return schemes.flatMap((requirement) => {\n const schemeNames = Object.keys(requirement)\n\n if (schemeNames.length === 0) {\n return []\n }\n\n // Complex auth requirement with multiple schemes\n if (schemeNames.length > 1) {\n return formatComplexScheme(requirement)\n }\n\n // Simple auth requirement with single scheme\n const schemeName = schemeNames[0]\n if (!schemeName) {\n return []\n }\n\n const scheme = getResolvedRef(securitySchemes?.[schemeName])\n if (!scheme) {\n return []\n }\n\n return formatScheme({\n name: schemeName,\n value: requirement,\n })\n })\n})\n\n/**\n * Opens the combobox dropdown when clicking the auth indicator badge.\n * Prevents the disclosure from toggling if it is already open.\n */\nconst handleAuthIndicatorClick = (event: Event): void => {\n if (isDisclosureOpen.value) {\n event.stopPropagation()\n }\n comboboxButtonRef.value?.$el.click()\n}\n\n/**\n * Updates the selected auth schemes.\n * Separates existing schemes from newly created ones for the event payload.\n */\nconst handleSchemeSelection = (selected: SecuritySchemeOption[]): void => {\n const existingSchemes = selected\n .filter((option) => option.payload === undefined)\n .map((option) => unpackProxyObject(option.value, { depth: 2 }))\n\n const newSchemes = selected\n .filter((option) => option.payload !== undefined)\n .map((option) => ({\n name: option.label,\n scheme: option.payload!,\n }))\n\n eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: existingSchemes,\n newSchemes,\n meta,\n })\n}\n\n/** Shows the delete confirmation modal for the selected scheme */\nconst handleDeleteRequest = (option: {\n label: string\n value: SecurityRequirementObject\n}): void => {\n schemeToDelete.value = { label: option.label, payload: option.value }\n deleteModal.show()\n}\n\n/** Deletes the selected auth scheme after confirmation */\nconst handleDeleteConfirm = (): void => {\n if (!schemeToDelete.value) {\n return\n }\n\n eventBus.emit('auth:delete:security-scheme', {\n names: Object.keys(schemeToDelete.value.payload),\n })\n\n schemeToDelete.value = null\n deleteModal.hide()\n}\n\ndefineExpose({\n authIndicator,\n selectedSchemeOptions: activeSchemeOptions,\n schemeOptions: availableSchemeOptions,\n})\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params relative\"\n :defaultOpen\n :isStatic=\"isStatic\"\n :itemCount=\"activeSchemeOptions.length\"\n @update:modelValue=\"(open) => (isDisclosureOpen = open)\">\n <template #title>\n <div\n :id=\"titleId\"\n class=\"inline-flex items-center gap-0.5 leading-[20px]\">\n <span>{{ title }}</span>\n\n <span\n v-if=\"authIndicator\"\n class=\"text-c-3 hover:bg-b-3 hover:text-c-1 -my-0.5 -mr-1 cursor-pointer rounded px-1 py-0.5 leading-[normal] font-normal\"\n :class=\"{ 'text-c-1': authIndicator.icon === 'Lock' }\"\n data-testid=\"auth-indicator\"\n @click=\"handleAuthIndicatorClick\">\n {{ authIndicator.text }}\n </span>\n </div>\n </template>\n\n <!-- Auth Dropdown (hidden when only one scheme is available) -->\n <template #actions>\n <ScalarComboboxMultiselect\n class=\"w-72 text-xs\"\n :modelValue=\"activeSchemeOptions\"\n multiple\n :options=\"availableSchemeOptions\"\n placement=\"bottom-end\"\n teleport\n @delete=\"handleDeleteRequest\"\n @update:modelValue=\"handleSchemeSelection\">\n <ScalarButton\n ref=\"comboboxButtonRef\"\n :aria-describedby=\"titleId\"\n class=\"group/combobox-button hover:text-c-1 text-c-2 flex h-fit w-full items-center gap-1 px-0.75 py-0.25 text-base font-normal\"\n variant=\"ghost\">\n <!-- Single auth scheme selected -->\n <template v-if=\"activeSchemeOptions.length === 1\">\n {{\n translate('apiClient.authSelector.selectedType', {\n type: activeSchemeOptions[0]?.label ?? '',\n })\n }}\n </template>\n\n <!-- Multiple auth schemes selected -->\n <template v-else-if=\"activeSchemeOptions.length > 1\">\n {{ translate('apiClient.authSelector.multipleTypes') }}\n </template>\n\n <!-- No auth schemes selected -->\n <template v-else>\n {{ translate('apiClient.authSelector.selectType') }}\n </template>\n\n <ScalarIconCaretDown\n class=\"size-3 shrink-0 transition-transform duration-100 group-aria-expanded/combobox-button:rotate-180\"\n weight=\"bold\" />\n </ScalarButton>\n\n <template #option=\"{ option, selected }\">\n <ScalarListboxCheckbox\n multiselect\n :selected=\"selected\" />\n <div class=\"min-w-0 flex-1 truncate\">\n {{ option.label }}\n </div>\n <ScalarIconButton\n v-if=\"option.isDeletable && canDeleteSchemes\"\n class=\"-m-0.5 shrink-0 p-0.5 opacity-0 group-hover/item:opacity-100\"\n :icon=\"ScalarIconTrash\"\n :label=\"\n translate('apiClient.authSelector.deleteScheme', {\n name: option.label,\n })\n \"\n size=\"xs\"\n @click.stop=\"handleDeleteRequest(option)\" />\n </template>\n </ScalarComboboxMultiselect>\n </template>\n\n <!-- Auth Table -->\n <RequestAuthDataTable\n :activeAuthIndex=\"selectedSecurity?.selectedIndex ?? 0\"\n :documentType\n :environment\n :eventBus\n :isStatic\n :meta\n :options\n :proxyUrl\n :securitySchemes\n :selectedSchemeOptions=\"activeSchemeOptions\"\n :server />\n\n <!-- Delete Auth Modal -->\n <DeleteRequestAuthModal\n v-if=\"schemeToDelete\"\n :label=\"schemeToDelete.label\"\n :scheme=\"schemeToDelete\"\n :state=\"deleteModal\"\n @close=\"deleteModal.hide()\"\n @delete=\"handleDeleteConfirm\" />\n </CollapsibleSection>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuthSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n type ScalarButton as ScalarButtonType,\n} from '@scalar/components/button'\nimport { ScalarComboboxMultiselect } from '@scalar/components/combobox'\nimport type { Icon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarListboxCheckbox } from '@scalar/components/listbox'\nimport { useModal } from '@scalar/components/modal'\nimport { ScalarIconCaretDown, ScalarIconTrash } from '@scalar/icons'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n isAuthOptional,\n type MergedSecuritySchemes,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n OpenApiDocument,\n SecurityRequirementObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, useId } from 'vue'\n\nimport DeleteRequestAuthModal from '@/v2/blocks/scalar-auth-selector-block/components/DeleteRequestAuthModal.vue'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport {\n formatComplexScheme,\n formatScheme,\n getSecuritySchemeOptions,\n type SecuritySchemeOption,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/security-scheme'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestAuthDataTable from './RequestAuthDataTable.vue'\n\nconst {\n environment,\n eventBus,\n createAnySecurityScheme = false,\n canDeleteSchemes = true,\n defaultOpen = true,\n isStatic = false,\n meta,\n proxyUrl,\n securityRequirements,\n securitySchemes,\n selectedSecurity,\n server,\n title,\n options,\n documentType,\n} = defineProps<{\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n /** Allows adding authentication which is not in the document */\n createAnySecurityScheme?: boolean\n /**\n * Whether schemes can be deleted from the selector. Enabled for the editable client, disabled in\n * the read-only reference where the schemes come from the document and cannot be removed.\n */\n canDeleteSchemes?: boolean\n /** Whether the authentication disclosure should start expanded */\n defaultOpen?: boolean\n /** Creates a static disclosure that cannot be collapsed */\n isStatic?: boolean\n meta: AuthMeta\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n selectedSecurity: SelectedSecurity | undefined\n server: ServerObject | null\n title: string\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n /** Type of the document the schemes belong to, used to label the missing-type warning */\n documentType?: 'openapi' | 'asyncapi'\n}>()\n\nconst { translate, translations } = useLocalization()\n\nconst titleId = useId()\nconst comboboxButtonRef = ref<typeof ScalarButtonType | null>(null)\nconst isDisclosureOpen = ref(false)\n\nconst deleteModal = useModal()\nconst schemeToDelete = ref<{\n label: string\n payload: SecurityRequirementObject\n} | null>(null)\n\n/**\n * Determines if authentication is required or optional\n *\n * Auth is optional when there is an empty security requirement and no complex requirements.\n * Complex requirements have multiple auth schemes combined (e.g., API key + OAuth).\n */\nconst authIndicator = computed<{ icon: Icon; text: string } | null>(() => {\n if (!securityRequirements?.length) {\n return null\n }\n\n const isOptional = isAuthOptional(securityRequirements)\n\n return {\n icon: isOptional ? 'Unlock' : 'Lock',\n text: isOptional\n ? translate('apiClient.authSelector.optional')\n : translate('apiClient.authSelector.required'),\n }\n})\n\n/** All available auth scheme options for the dropdown */\nconst availableSchemeOptions = computed(() =>\n getSecuritySchemeOptions(\n securityRequirements ?? [],\n securitySchemes ?? {},\n selectedSecurity?.selectedSchemes ?? [],\n createAnySecurityScheme,\n translations.value.apiClient,\n ),\n)\n\n/** Currently active auth schemes selected for this operation or collection */\nconst activeSchemeOptions = computed<SecuritySchemeOption[]>(() => {\n const schemes = selectedSecurity?.selectedSchemes\n if (!schemes?.length) {\n return []\n }\n\n return schemes.flatMap((requirement) => {\n const schemeNames = Object.keys(requirement)\n\n if (schemeNames.length === 0) {\n return []\n }\n\n // Complex auth requirement with multiple schemes\n if (schemeNames.length > 1) {\n return formatComplexScheme(requirement)\n }\n\n // Simple auth requirement with single scheme\n const schemeName = schemeNames[0]\n if (!schemeName) {\n return []\n }\n\n const scheme = getResolvedRef(securitySchemes?.[schemeName])\n if (!scheme) {\n return []\n }\n\n return formatScheme({\n name: schemeName,\n value: requirement,\n })\n })\n})\n\n/**\n * Opens the combobox dropdown when clicking the auth indicator badge.\n * Prevents the disclosure from toggling if it is already open.\n */\nconst handleAuthIndicatorClick = (event: Event): void => {\n if (isDisclosureOpen.value) {\n event.stopPropagation()\n }\n comboboxButtonRef.value?.$el.click()\n}\n\n/**\n * Updates the selected auth schemes.\n * Separates existing schemes from newly created ones for the event payload.\n */\nconst handleSchemeSelection = (selected: SecuritySchemeOption[]): void => {\n const existingSchemes = selected\n .filter((option) => option.payload === undefined)\n .map((option) => unpackProxyObject(option.value, { depth: 2 }))\n\n const newSchemes = selected\n .filter((option) => option.payload !== undefined)\n .map((option) => ({\n name: option.label,\n scheme: option.payload!,\n }))\n\n eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: existingSchemes,\n newSchemes,\n meta,\n })\n}\n\n/** Shows the delete confirmation modal for the selected scheme */\nconst handleDeleteRequest = (option: {\n label: string\n value: SecurityRequirementObject\n}): void => {\n schemeToDelete.value = { label: option.label, payload: option.value }\n deleteModal.show()\n}\n\n/** Deletes the selected auth scheme after confirmation */\nconst handleDeleteConfirm = (): void => {\n if (!schemeToDelete.value) {\n return\n }\n\n eventBus.emit('auth:delete:security-scheme', {\n names: Object.keys(schemeToDelete.value.payload),\n })\n\n schemeToDelete.value = null\n deleteModal.hide()\n}\n\ndefineExpose({\n authIndicator,\n selectedSchemeOptions: activeSchemeOptions,\n schemeOptions: availableSchemeOptions,\n})\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params relative\"\n :defaultOpen\n :isStatic=\"isStatic\"\n :itemCount=\"activeSchemeOptions.length\"\n @update:modelValue=\"(open) => (isDisclosureOpen = open)\">\n <template #title>\n <div\n :id=\"titleId\"\n class=\"inline-flex items-center gap-0.5 leading-[20px]\">\n <span>{{ title }}</span>\n\n <span\n v-if=\"authIndicator\"\n class=\"text-c-3 hover:bg-b-3 hover:text-c-1 -my-0.5 -mr-1 cursor-pointer rounded px-1 py-0.5 leading-[normal] font-normal\"\n :class=\"{ 'text-c-1': authIndicator.icon === 'Lock' }\"\n data-testid=\"auth-indicator\"\n @click=\"handleAuthIndicatorClick\">\n {{ authIndicator.text }}\n </span>\n </div>\n </template>\n\n <!-- Auth Dropdown (hidden when only one scheme is available) -->\n <template #actions>\n <ScalarComboboxMultiselect\n class=\"w-72 text-xs\"\n :modelValue=\"activeSchemeOptions\"\n multiple\n :options=\"availableSchemeOptions\"\n placement=\"bottom-end\"\n teleport\n @delete=\"handleDeleteRequest\"\n @update:modelValue=\"handleSchemeSelection\">\n <ScalarButton\n ref=\"comboboxButtonRef\"\n :aria-describedby=\"titleId\"\n class=\"group/combobox-button hover:text-c-1 text-c-2 flex h-fit w-full items-center gap-1 px-0.75 py-0.25 text-base font-normal\"\n variant=\"ghost\">\n <!-- Single auth scheme selected -->\n <template v-if=\"activeSchemeOptions.length === 1\">\n {{\n translate('apiClient.authSelector.selectedType', {\n type: activeSchemeOptions[0]?.label ?? '',\n })\n }}\n </template>\n\n <!-- Multiple auth schemes selected -->\n <template v-else-if=\"activeSchemeOptions.length > 1\">\n {{ translate('apiClient.authSelector.multipleTypes') }}\n </template>\n\n <!-- No auth schemes selected -->\n <template v-else>\n {{ translate('apiClient.authSelector.selectType') }}\n </template>\n\n <ScalarIconCaretDown\n class=\"size-3 shrink-0 transition-transform duration-100 group-aria-expanded/combobox-button:rotate-180\"\n weight=\"bold\" />\n </ScalarButton>\n\n <template #option=\"{ option, selected }\">\n <ScalarListboxCheckbox\n multiselect\n :selected=\"selected\" />\n <div class=\"min-w-0 flex-1 truncate\">\n {{ option.label }}\n </div>\n <ScalarIconButton\n v-if=\"option.isDeletable && canDeleteSchemes\"\n class=\"-m-0.5 shrink-0 p-0.5 opacity-0 group-hover/item:opacity-100\"\n :icon=\"ScalarIconTrash\"\n :label=\"\n translate('apiClient.authSelector.deleteScheme', {\n name: option.label,\n })\n \"\n size=\"xs\"\n @click.stop=\"handleDeleteRequest(option)\" />\n </template>\n </ScalarComboboxMultiselect>\n </template>\n\n <!-- Auth Table -->\n <RequestAuthDataTable\n :activeAuthIndex=\"selectedSecurity?.selectedIndex ?? 0\"\n :documentType\n :environment\n :eventBus\n :isStatic\n :meta\n :options\n :proxyUrl\n :securitySchemes\n :selectedSchemeOptions=\"activeSchemeOptions\"\n :server />\n\n <!-- Delete Auth Modal -->\n <DeleteRequestAuthModal\n v-if=\"schemeToDelete\"\n :label=\"schemeToDelete.label\"\n :scheme=\"schemeToDelete\"\n :state=\"deleteModal\"\n @close=\"deleteModal.hide()\"\n @delete=\"handleDeleteConfirm\" />\n </CollapsibleSection>\n</template>\n"],"mappings":"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"}
|
package/dist/v2/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/v2/constants.ts
|
|
2
2
|
/** The version number taken from the package.json. Consumers can override at build time via define (e.g. OVERRIDE_PACKAGE_VERSION: JSON.stringify('1.2.3')). */
|
|
3
|
-
var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "3.21.
|
|
3
|
+
var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "3.21.1";
|
|
4
4
|
//#endregion
|
|
5
5
|
export { APP_VERSION };
|
|
6
6
|
|
package/dist/vue-styles.css
CHANGED
|
@@ -419,20 +419,20 @@ to {
|
|
|
419
419
|
background: color-mix(in srgb, var(--scalar-background-3), transparent 40%);
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
-
[data-v-
|
|
422
|
+
[data-v-e29008b7] .code-input-lite__editor {
|
|
423
423
|
background-color: transparent;
|
|
424
424
|
font-family: var(--scalar-font);
|
|
425
425
|
font-size: var(--scalar-small);
|
|
426
426
|
padding: 5px 8px;
|
|
427
427
|
}
|
|
428
|
-
[data-v-
|
|
428
|
+
[data-v-e29008b7] .scalar-pill:not(:last-of-type) {
|
|
429
429
|
margin-right: 0.15em;
|
|
430
430
|
}
|
|
431
|
-
[data-v-
|
|
431
|
+
[data-v-e29008b7] .scalar-pill:not(:first-of-type) {
|
|
432
432
|
margin-left: 0.5px;
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
-
[data-v-
|
|
435
|
+
[data-v-42eb1913] .cm-content {
|
|
436
436
|
font-size: var(--scalar-small);
|
|
437
437
|
}
|
|
438
438
|
|
|
@@ -481,20 +481,20 @@ input[data-v-135d11b9]::placeholder {
|
|
|
481
481
|
scrollbar-width: none;
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
-
.request-section-content[data-v-
|
|
484
|
+
.request-section-content[data-v-1bb88607] {
|
|
485
485
|
--scalar-border-width: 0.5px;
|
|
486
486
|
}
|
|
487
|
-
.request-section-content-filter[data-v-
|
|
487
|
+
.request-section-content-filter[data-v-1bb88607] {
|
|
488
488
|
box-shadow: 0 -10px 0 10px var(--scalar-background-1);
|
|
489
489
|
}
|
|
490
|
-
.request-item:focus-within .request-meta-buttons[data-v-
|
|
490
|
+
.request-item:focus-within .request-meta-buttons[data-v-1bb88607] {
|
|
491
491
|
opacity: 1;
|
|
492
492
|
}
|
|
493
|
-
.group-hover-input[data-v-
|
|
493
|
+
.group-hover-input[data-v-1bb88607] {
|
|
494
494
|
border-width: var(--scalar-border-width);
|
|
495
495
|
border-color: transparent;
|
|
496
496
|
}
|
|
497
|
-
.group:hover .group-hover-input[data-v-
|
|
497
|
+
.group:hover .group-hover-input[data-v-1bb88607] {
|
|
498
498
|
background: color-mix(
|
|
499
499
|
in srgb,
|
|
500
500
|
var(--scalar-background-1),
|
|
@@ -502,7 +502,7 @@ input[data-v-135d11b9]::placeholder {
|
|
|
502
502
|
);
|
|
503
503
|
border-color: var(--scalar-border-color);
|
|
504
504
|
}
|
|
505
|
-
.group-hover-input[data-v-
|
|
505
|
+
.group-hover-input[data-v-1bb88607]:focus {
|
|
506
506
|
background: transparent !important;
|
|
507
507
|
border-color: var(--scalar-border-color) !important;
|
|
508
508
|
}
|
|
@@ -582,11 +582,11 @@ input[data-v-135d11b9]::placeholder {
|
|
|
582
582
|
opacity: 0;
|
|
583
583
|
}
|
|
584
584
|
|
|
585
|
-
.animate-response-heading .response-heading[data-v-
|
|
586
|
-
animation: push-response-
|
|
585
|
+
.animate-response-heading .response-heading[data-v-2694e1a2] {
|
|
586
|
+
animation: push-response-2694e1a2 0.2s ease-in-out forwards;
|
|
587
587
|
opacity: 1;
|
|
588
588
|
}
|
|
589
|
-
@keyframes push-response-
|
|
589
|
+
@keyframes push-response-2694e1a2 {
|
|
590
590
|
from {
|
|
591
591
|
opacity: 1;
|
|
592
592
|
transform: translateY(0);
|
|
@@ -596,11 +596,11 @@ to {
|
|
|
596
596
|
transform: translateY(-4px);
|
|
597
597
|
}
|
|
598
598
|
}
|
|
599
|
-
.animate-response-heading .animate-response-children[data-v-
|
|
600
|
-
animation: response-spans-
|
|
599
|
+
.animate-response-heading .animate-response-children[data-v-2694e1a2] {
|
|
600
|
+
animation: response-spans-2694e1a2 0.2s ease-in-out forwards 0.05s;
|
|
601
601
|
opacity: 0;
|
|
602
602
|
}
|
|
603
|
-
@keyframes response-spans-
|
|
603
|
+
@keyframes response-spans-2694e1a2 {
|
|
604
604
|
from {
|
|
605
605
|
opacity: 0;
|
|
606
606
|
transform: translateY(4px);
|