@scalar/api-client 3.21.2 → 3.21.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/style.css +18 -12
- package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +11 -0
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts +2 -0
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +3 -1
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/helpers/get-structured-body-rows.js +2 -1
- package/dist/v2/blocks/request-block/helpers/get-structured-body-rows.js.map +1 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts +2 -0
- package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.js +1 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.js.map +1 -1
- package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js +26 -3
- package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.d.ts +2 -0
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js +59 -42
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
- package/dist/v2/components/code-input/CodeInputLite.vue.d.ts +6 -2
- package/dist/v2/components/code-input/CodeInputLite.vue.d.ts.map +1 -1
- package/dist/v2/components/code-input/CodeInputLite.vue.js +1 -1
- package/dist/v2/components/code-input/CodeInputLite.vue.js.map +1 -1
- package/dist/v2/components/code-input/CodeInputLite.vue.script.js +3 -0
- package/dist/v2/components/code-input/CodeInputLite.vue.script.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInputSelect.vue.d.ts +4 -4
- package/dist/v2/components/data-table/DataTableInputSelect.vue.d.ts.map +1 -1
- package/dist/v2/components/data-table/DataTableInputSelect.vue.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInputSelect.vue.script.js +22 -16
- package/dist/v2/components/data-table/DataTableInputSelect.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/v2/features/localization/locales/ar.d.ts +2 -0
- package/dist/v2/features/localization/locales/ar.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/ar.js +2 -0
- package/dist/v2/features/localization/locales/ar.js.map +1 -1
- package/dist/v2/features/localization/locales/de.d.ts +2 -0
- package/dist/v2/features/localization/locales/de.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/de.js +2 -0
- package/dist/v2/features/localization/locales/de.js.map +1 -1
- package/dist/v2/features/localization/locales/es.d.ts +2 -0
- package/dist/v2/features/localization/locales/es.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/es.js +2 -0
- package/dist/v2/features/localization/locales/es.js.map +1 -1
- package/dist/v2/features/localization/locales/fr.d.ts +2 -0
- package/dist/v2/features/localization/locales/fr.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/fr.js +2 -0
- package/dist/v2/features/localization/locales/fr.js.map +1 -1
- package/dist/v2/features/localization/locales/pt.d.ts +2 -0
- package/dist/v2/features/localization/locales/pt.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/pt.js +2 -0
- package/dist/v2/features/localization/locales/pt.js.map +1 -1
- package/dist/v2/features/localization/locales/ru.d.ts +2 -0
- package/dist/v2/features/localization/locales/ru.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/ru.js +2 -0
- package/dist/v2/features/localization/locales/ru.js.map +1 -1
- package/dist/v2/features/localization/locales/zh-cn.d.ts +2 -0
- package/dist/v2/features/localization/locales/zh-cn.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/zh-cn.js +2 -0
- package/dist/v2/features/localization/locales/zh-cn.js.map +1 -1
- package/dist/v2/features/localization/translations.d.ts +2 -0
- package/dist/v2/features/localization/translations.d.ts.map +1 -1
- package/dist/v2/features/localization/translations.js +2 -0
- package/dist/v2/features/localization/translations.js.map +1 -1
- package/dist/v2/features/search/helpers/create-fuse-instance.js +1 -1
- package/dist/v2/features/search/helpers/create-fuse-instance.js.map +1 -1
- package/dist/vue-styles.css +11 -11
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/request-block/RequestBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ClientOptionGroup } from '@scalar/blocks/code-example'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body'\nimport { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\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 { getUniqueExampleName } from '@scalar/workspace-store/navigation'\nimport {\n filterGlobalCookie,\n getEnvironmentVariables,\n getResolvedUrl,\n getSchemaExampleFromBody,\n type MergedSecuritySchemes,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, provide, ref, useId, watch } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport RequestBody from '@/v2/blocks/request-block/components/RequestBody.vue'\nimport RequestCodeSnippet from '@/v2/blocks/request-block/components/RequestCodeSnippet.vue'\nimport RequestParams from '@/v2/blocks/request-block/components/RequestParams.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { createParameterHandlers } from '@/v2/blocks/request-block/helpers/create-parameter-handlers'\nimport { createParameterRows } from '@/v2/blocks/request-block/helpers/create-parameter-rows'\nimport { groupBy } from '@/v2/blocks/request-block/helpers/group-by'\nimport { groupGlobalCookies } from '@/v2/blocks/request-block/helpers/group-global-cookies'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport {\n COLLAPSIBLE_SECTION_HEADING_LEVEL,\n type CollapsibleSectionHeadingLevel,\n} from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\ntype Filter =\n | 'All'\n | 'Auth'\n | 'Variables'\n | 'Cookies'\n | 'Headers'\n | 'Query'\n | 'Body'\n\nexport type RequestBlockProps = {\n authMeta: AuthMeta\n clientOptions: ClientOptionGroup[]\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n exampleKey: string\n workspaceCookies: XScalarCookie[]\n documentCookies: XScalarCookie[]\n /** Slug of the document the operation belongs to */\n documentSlug: string\n layout: ClientLayout\n method: string\n operation: OperationObject\n /** Operation before downloaded examples are overlaid, for parameter edit targets. */\n sourceOperation?: OperationObject\n path: string\n plugins: ClientPlugin[]\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\n requestBodyCompositionSelection?: Record<string, number>\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n selectedSecurity: SelectedSecurity\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n server: ServerObject | null\n defaultHeaders: Record<string, string>\n /** Initial view for structured request bodies, from the `x-scalar-default-request-body-view` document extension */\n defaultRequestBodyView?: 'form' | 'raw'\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}\n\nconst {\n authMeta = { type: 'document' },\n clientOptions,\n environment,\n eventBus,\n exampleKey,\n workspaceCookies,\n documentCookies,\n documentSlug,\n layout,\n method,\n operation,\n sourceOperation,\n path,\n plugins,\n proxyUrl,\n requestBodyCompositionSelection,\n openapiVersion,\n securityRequirements,\n securitySchemes,\n selectedClient,\n selectedSecurity,\n selectedSecuritySchemes,\n server,\n defaultHeaders: autoGeneratedHeaders,\n defaultRequestBodyView = 'raw',\n} = defineProps<RequestBlockProps>()\n\nconst { translate } = useLocalization()\n\n/** Base name for examples created by the \"generate example from schema\" button */\nconst GENERATED_EXAMPLE_NAME = 'Generated from schema'\n\n/** Operation metadata used across event emissions */\nconst meta = computed(() => ({\n method,\n path,\n exampleKey,\n}))\n\nconst deletedExpandedParameterPaths = ref<Record<string, string[][]>>({})\n\n/** Renamed expanded rows, tracked as old-schema-path -> typed-value-path per parameter. */\nconst renamedExpandedParameterPaths = ref<\n Record<string, { from: string[]; to: string[] }[]>\n>({})\n\nconst getExpandedParameterKey = (parameter: {\n in: string\n name: string\n}): string => `${parameter.in}:${parameter.name}`\n\nconst getHiddenValuePaths = (parameter: {\n in: string\n name: string\n}): string[][] =>\n deletedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst getRenamedValuePaths = (parameter: {\n in: string\n name: string\n}): { from: string[]; to: string[] }[] =>\n renamedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst pathsEqual = (a: string[], b: string[]): boolean =>\n a.length === b.length && a.every((segment, index) => segment === b[index])\n\n/**\n * Hides the schema path of an expanded row so it does not reappear as an empty suggestion. Used\n * both when a row is deleted and when its key is renamed (the old key should not pop back up).\n */\nconst hideExpandedRowPath = (row: TableRow): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const key = getExpandedParameterKey(row.originalParameter)\n deletedExpandedParameterPaths.value = {\n ...deletedExpandedParameterPaths.value,\n [key]: [\n ...(deletedExpandedParameterPaths.value[key] ?? []),\n row.sourceParameterValuePath,\n ],\n }\n}\n\n/**\n * Records that an expanded row was renamed from its current value path to the typed one, so the\n * read side can render the renamed key in the original property's slot instead of appending it to\n * the end of the table. Repeated renames of the same row stay anchored to the original schema path.\n */\nconst recordExpandedRowRename = (\n row: TableRow,\n newValuePath: string[],\n): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const from = row.sourceParameterValuePath\n const key = getExpandedParameterKey(row.originalParameter)\n const existing = renamedExpandedParameterPaths.value[key] ?? []\n\n // If this row was already renamed, the row's current path is the previous target. Re-anchor that\n // entry to the new target so a second rename does not create an orphaned mapping.\n const chained = existing.find((entry) => pathsEqual(entry.to, from))\n const next = chained\n ? existing.map((entry) =>\n entry === chained ? { from: entry.from, to: newValuePath } : entry,\n )\n : [...existing, { from, to: newValuePath }]\n\n renamedExpandedParameterPaths.value = {\n ...renamedExpandedParameterPaths.value,\n [key]: next,\n }\n}\n\n/** Whole-query parameters share the Query section but retain their original identity. */\nconst hasQuerystringParameter = computed(\n () =>\n operation.parameters?.some(\n (parameter) => getResolvedRef(parameter)?.in === 'querystring',\n ) ?? false,\n)\n\n/** Parameters grouped by type (path, query, header, cookie) */\nconst sections = computed(() =>\n groupBy(\n operation.parameters?.flatMap((reference, index) => {\n const param = getResolvedRef(reference)\n if (!param) return []\n return createParameterRows(param, exampleKey, {\n hiddenValuePaths:\n param.in === 'query' ? getHiddenValuePaths(param) : [],\n renamedValuePaths:\n param.in === 'query' ? getRenamedValuePaths(param) : [],\n }).map((row) => ({\n ...row,\n // Overlays retain parameter order, but their downloaded values are read-only.\n originalParameter:\n getResolvedRef(sourceOperation?.parameters?.[index]) ?? param,\n in: param.in === 'querystring' ? 'query' : param.in,\n }))\n }) ?? [],\n 'in',\n ({ in: _in, ...row }) => {\n return row\n },\n ),\n)\n\n// Generate a reverse map for fast lookup of headers by the name\nconst headersMap = computed(() =>\n groupBy(\n sections.value.header?.map((it) => ({\n ...it,\n name: it.name.toLowerCase(),\n })) ?? [],\n 'name',\n ),\n)\n\nconst defaultHeaders = computed(() => {\n const disableParameters =\n operation['x-scalar-disable-parameters']?.['default-headers']?.[\n exampleKey\n ] ?? {}\n\n const isOverridden = (name: string) => {\n const header = headersMap.value[name.toLowerCase()]?.[0]\n\n if (!header) {\n return false\n }\n\n return !header.isDisabled\n }\n\n return Object.entries(autoGeneratedHeaders).map(([name, value]) => {\n return {\n name,\n value,\n schema: undefined,\n isOverridden: isOverridden(name),\n isReadonly: true,\n isDisabled: disableParameters[name.toLowerCase()] ?? false,\n } satisfies TableRow\n })\n})\n\nconst headers = computed(() => [\n ...defaultHeaders.value,\n ...(sections.value.header ?? []),\n])\n\n/** Resolved request URL, used to filter global cookies by their domain and path. */\nconst requestCookieUrl = computed(() => {\n const environmentVariables = getEnvironmentVariables(environment)\n const resolvedUrl = getResolvedUrl({ server, path })\n return replaceEnvVariables(resolvedUrl, environmentVariables)\n})\n\n/**\n * Global cookies grouped by name. Same-named cookies collapse into a single logical cookie so\n * duplicate names no longer share one disabled state (which made toggling one toggle them all).\n * A name with multiple values becomes a preset the user can switch between.\n */\nconst globalCookieGroups = computed(() =>\n groupGlobalCookies({\n sources: [\n { location: 'workspace', cookies: workspaceCookies },\n { location: 'document', cookies: documentCookies },\n ],\n // Keep domain/path filtering but ignore the disabled flag, so a disabled preset value stays\n // selectable in the switcher (it is only hidden from the request, not from the dropdown).\n shouldInclude: (cookie) =>\n filterGlobalCookie({\n cookie: { ...cookie, isDisabled: false },\n url: requestCookieUrl.value,\n disabledGlobalCookies: {},\n }),\n }),\n)\n\nconst defaultCookies = computed<TableRow[]>(() => {\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[\n exampleKey\n ] ?? {}\n\n return globalCookieGroups.value.map((group) => ({\n name: group.name,\n value: group.selectedValue,\n globalRoute: { page: group.location, path: 'cookies' } as const,\n isReadonly: true,\n isDisabled: disabledGlobalCookies[group.name.toLowerCase()] ?? false,\n presetOptions: group.isPreset ? group.options : undefined,\n }))\n})\n\n/**\n * Switch a grouped global cookie preset to the chosen value by enabling the matching sibling and\n * disabling the rest. Selection is written back to the source `x-scalar-cookies` list so it\n * persists, and the send path drops disabled cookies, so only the selected value is sent.\n */\nconst handleSelectCookiePreset = (index: number, value: string): void => {\n const group = globalCookieGroups.value[index]\n if (!group) {\n return\n }\n\n for (const sibling of group.siblings) {\n eventBus.emit('cookie:upsert:cookie', {\n collectionType: sibling.location,\n index: sibling.index,\n payload: { isDisabled: sibling.value !== value },\n })\n }\n}\n\nconst cookies = computed(() => [\n ...(defaultCookies.value ?? []),\n ...(sections.value.cookie ?? []),\n])\n\n/** Currently selected filter for the request sections */\nconst selectedFilter = ref<Filter>('All')\n\n/** Available operation sections */\nconst OPERATION_SECTIONS: readonly Filter[] = [\n 'Auth',\n 'Variables',\n 'Cookies',\n 'Headers',\n 'Query',\n 'Body',\n] as const\n\n/**\n * Pre-generated stable IDs for all possible filter sections.\n * These are created once at setup time to avoid regenerating IDs on re-render.\n */\nconst sectionIds: Record<Filter, string> = {\n All: useId(),\n Auth: useId(),\n Variables: useId(),\n Cookies: useId(),\n Headers: useId(),\n Query: useId(),\n Body: useId(),\n}\n\n/** Filters available based on operation state */\nconst filters = computed<Filter[]>(() => {\n const availableFilters = new Set<Filter>(['All', ...OPERATION_SECTIONS])\n\n if (!sections.value.path?.length) {\n availableFilters.delete('Variables')\n }\n if (!canMethodHaveBody(method)) {\n availableFilters.delete('Body')\n }\n if (isAuthHidden.value) {\n availableFilters.delete('Auth')\n }\n\n return [...availableFilters]\n})\n\n/**\n * Map available filters to their pre-generated stable IDs.\n * Only includes IDs for filters that are currently available.\n */\nconst filterIds = computed(() =>\n filters.value.reduce<Partial<Record<Filter, string>>>((ids, section) => {\n ids[section] = sectionIds[section]\n return ids\n }, {}),\n)\n\n/**\n * Hide auth selector in readonly mode when no security schemes are defined.\n * This keeps the UI clean when there are no authentication options available.\n */\nconst isAuthHidden = computed(\n () => layout === 'modal' && !Object.keys(securitySchemes ?? {}).length,\n)\n\n/**\n * Keep auth available for unauthenticated operations, but collapse it by default\n * in readonly modal layouts unless a requirement or manual selection exists.\n */\nconst isAuthDefaultOpen = computed(\n () =>\n layout !== 'modal' ||\n Boolean(\n securityRequirements?.length || selectedSecurity.selectedSchemes.length,\n ),\n)\n\n/** Get a sensible placeholder for the request name input */\nconst requestNamePlaceholder = computed(() => {\n if (operation.summary) {\n return operation.summary\n }\n const cleanPath = path.replace(REGEX.PROTOCOL, '')\n return cleanPath || translate('apiClient.requestBlock.requestName')\n})\n\n/** Check if the section should be shown based on the selected filter */\nconst isSectionVisible = (section: Filter): boolean => {\n return selectedFilter.value === 'All' || selectedFilter.value === section\n}\n\n/**\n * Reset filter to 'All' if Body filter is selected but method changes to one that cannot have a body.\n * This prevents showing an empty Body section when switching methods.\n */\nwatch(\n () => method,\n (newMethod) => {\n if (selectedFilter.value === 'Body' && !canMethodHaveBody(newMethod)) {\n selectedFilter.value = 'All'\n }\n },\n)\n\n// Expanded-row bookkeeping is keyed by `in:name`, which is not unique across operations or\n// examples. Reset both maps when the operation or example changes so stale delete/rename mappings\n// do not leak onto another request that happens to share a query parameter name.\nwatch(\n () => [method, path, exampleKey],\n () => {\n deletedExpandedParameterPaths.value = {}\n renamedExpandedParameterPaths.value = {}\n },\n)\n\n/** Handle operation summary updates */\nconst handleSummaryUpdate = (event: Event): void => {\n if (!(event.target instanceof HTMLInputElement)) {\n return\n }\n const summary = event.target.value\n eventBus.emit('operation:update:meta', {\n meta: meta.value,\n payload: { summary: summary.trim() },\n })\n}\n\n/** Parameter handlers */\nconst parameterHandlers = computed(() => ({\n path: createParameterHandlers('path', eventBus, meta.value, {\n context: sections.value.path ?? [],\n }),\n cookie: {\n ...createParameterHandlers('cookie', eventBus, meta.value, {\n context: cookies.value ?? [],\n globalParameters: defaultCookies.value.length,\n }),\n selectPreset: handleSelectCookiePreset,\n },\n header: createParameterHandlers('header', eventBus, meta.value, {\n context: headers.value,\n defaultParameters: defaultHeaders.value.length,\n }),\n query: createParameterHandlers('query', eventBus, meta.value, {\n context: sections.value.query ?? [],\n onDeleteExpandedRow: hideExpandedRowPath,\n onRenameExpandedRow: recordExpandedRowRename,\n }),\n}))\n\n/** Handle request body content type update */\nconst handleUpdateContentType = (payload: { value: string }): void =>\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType: payload.value },\n meta: meta.value,\n })\n\n/** Handle request body value update */\nconst handleUpdateBodyValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey =\n typeof payload === 'string'\n ? `update:requestBody:value-${contentType}`\n : undefined\n\n eventBus.emit(\n 'operation:update:requestBody:value',\n {\n payload,\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/** Handle request body value update */\nconst handleUpdateBodyFormValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey = `update:requestBody:${contentType}-form-value`\n\n eventBus.emit(\n 'operation:update:requestBody:formValue',\n {\n payload: payload.map((row) => unpackProxyObject(row, { depth: 1 })),\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/**\n * Create a new example seeded with values generated from the request body schema.\n *\n * Custom examples in the document otherwise hide the auto-generated fields entirely. Rather than\n * only rendering the generated body, we write it into a fresh example so the user can edit it and\n * so it survives an export of the document.\n */\nconst handleGenerateExample = ({\n contentType,\n}: {\n contentType: string\n}): void => {\n const requestBody = getResolvedRef(operation.requestBody)\n const codec = getStructuredBodyCodec(contentType)\n if (!requestBody || !codec) {\n return\n }\n\n const value = getSchemaExampleFromBody(\n requestBody,\n contentType,\n requestBodyCompositionSelection,\n )\n\n // A schema that generates nothing writable would leave the user on an empty new example.\n if (value === undefined || value === null) {\n return\n }\n\n const exampleName = getUniqueExampleName(operation, GENERATED_EXAMPLE_NAME)\n const exampleMeta = { path, method, exampleKey: exampleName }\n\n eventBus.emit('operation:create:draft-example', {\n documentName: documentSlug,\n meta: { path, method },\n exampleName,\n })\n\n // Carry over the content type the user was looking at, otherwise the new example opens on\n // whichever content type happens to come first on the request body.\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType },\n meta: exampleMeta,\n })\n\n eventBus.emit('operation:update:requestBody:value', {\n payload: codec.stringify(value),\n contentType,\n meta: exampleMeta,\n })\n\n // The modal selects the example after its creation hook rebuilds the sidebar.\n if (layout === 'modal') {\n return\n }\n\n eventBus.emit('ui:navigate', {\n page: 'example',\n documentSlug,\n path,\n method,\n exampleName,\n })\n}\n\nconst labelRequestNameId = useId()\n\n/**\n * Where the collapsible sections below sit in the heading outline.\n *\n * The modal renders the operation summary as a heading above them, so they are\n * its subsections. Every other layout shows the summary as an editable input\n * rather than a heading, which leaves the sections at the top level.\n */\nprovide(\n COLLAPSIBLE_SECTION_HEADING_LEVEL,\n computed<CollapsibleSectionHeadingLevel>(() =>\n layout === 'modal' && operation.summary ? 3 : 2,\n ),\n)\n\nconst globalCookies = computed(() => [...workspaceCookies, ...documentCookies])\n\n/** Allow updating the operation extensions for the plugins */\nconst updateOperationExtension = (\n payload: ApiReferenceEvents['operation:update:extension']['payload'],\n): void =>\n eventBus.emit('operation:update:extension', { payload, meta: meta.value })\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=\"\n translate('apiClient.requestBlock.label', {\n name: operation.summary ?? '',\n })\n \">\n <template #title>\n <div\n class=\"group pointer-events-none flex flex-1 items-center gap-1 lg:pe-24\">\n <label\n v-if=\"layout !== 'modal'\"\n class=\"pointer-events-auto absolute top-0 left-0 h-full w-full cursor-text opacity-0\"\n :for=\"labelRequestNameId\" />\n <input\n v-if=\"layout !== 'modal'\"\n :id=\"labelRequestNameId\"\n class=\"text-c-1 group-hover-input pointer-events-auto relative z-10 -ml-0.5 h-8 w-full rounded pl-1.25 has-[:focus-visible]:outline md:-ml-1.25\"\n :placeholder=\"requestNamePlaceholder\"\n :value=\"operation.summary\"\n @blur=\"handleSummaryUpdate\" />\n <!-- In the modal the summary is the title of everything below it, so\n it carries the heading role that lets screen reader users jump to\n it. An operation without a summary renders nothing, because an\n empty heading is worse than none. -->\n <h2\n v-else-if=\"operation.summary\"\n class=\"text-c-1 flex h-8 items-center\">\n {{ operation.summary }}\n </h2>\n <span\n v-else\n class=\"text-c-1 flex h-8 items-center\" />\n </div>\n <SectionFilter\n v-model=\"selectedFilter\"\n :filters=\"filters\"\n :labels=\"filterLabels\" />\n </template>\n\n <div\n :id=\"filterIds.All\"\n class=\"request-section-content custom-scroll relative flex flex-1 flex-col\"\n :role=\"selectedFilter === 'All' ? 'tabpanel' : 'none'\">\n <!-- Auth Selector -->\n <AuthSelector\n v-show=\"isSectionVisible('Auth') && !isAuthHidden\"\n :id=\"filterIds.Auth\"\n :createAnySecurityScheme=\"layout !== 'modal'\"\n :defaultOpen=\"isAuthDefaultOpen\"\n :environment\n :eventBus\n :meta=\"authMeta\"\n :options\n :proxyUrl\n :securityRequirements\n :securitySchemes\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n :title=\"translate('apiClient.requestBlock.authentication')\" />\n\n <!-- Variables (Path Parameters) -->\n <RequestParams\n v-show=\"isSectionVisible('Variables') && sections.path?.length\"\n :id=\"filterIds.Variables\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.path ?? []\"\n :showAddRowPlaceholder=\"false\"\n :title=\"translate('apiClient.requestBlock.variables')\"\n v-on=\"parameterHandlers.path\" />\n\n <!-- Cookies -->\n <RequestParams\n v-show=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"cookies ?? []\"\n :showAddRowPlaceholder=\"true\"\n :title=\"translate('apiClient.requestBlock.cookies')\"\n v-on=\"parameterHandlers.cookie\" />\n\n <!-- Headers -->\n <RequestParams\n v-show=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"headers ?? []\"\n :title=\"translate('apiClient.requestBlock.headers')\"\n v-on=\"parameterHandlers.header\" />\n\n <!-- Query Parameters -->\n <RequestParams\n v-show=\"isSectionVisible('Query')\"\n :id=\"filterIds.Query\"\n :description=\"\n hasQuerystringParameter\n ? translate('apiClient.requestBlock.queryStringDescription')\n : undefined\n \"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.query ?? []\"\n :showAddRowPlaceholder=\"!hasQuerystringParameter\"\n :title=\"\n hasQuerystringParameter\n ? translate('apiClient.requestBlock.queryString')\n : translate('apiClient.requestBlock.queryParameters')\n \"\n v-on=\"parameterHandlers.query\" />\n\n <!-- Request Body -->\n <RequestBody\n v-show=\"isSectionVisible('Body') && canMethodHaveBody(method)\"\n :id=\"filterIds.Body\"\n :defaultView=\"defaultRequestBodyView\"\n :environment\n :exampleKey\n :openapiVersion\n :requestBody=\"getResolvedRef(operation.requestBody)\"\n :requestBodyCompositionSelection\n :title=\"translate('apiClient.requestBlock.requestBody')\"\n @generate:example=\"handleGenerateExample\"\n @update:contentType=\"handleUpdateContentType\"\n @update:formValue=\"handleUpdateBodyFormValue\"\n @update:value=\"handleUpdateBodyValue\" />\n\n <!-- Inject request section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.request.component\"\n v-if=\"plugin?.components?.request\"\n v-show=\"selectedFilter === 'All'\"\n :operation\n v-bind=\"plugin.components.request.additionalProps\"\n @operation:update:extension=\"updateOperationExtension\" />\n </ScalarErrorBoundary>\n\n <!-- Spacer -->\n <div class=\"flex grow\" />\n <!-- Code Snippet -->\n <RequestCodeSnippet\n v-show=\"selectedFilter === 'All'\"\n :clientOptions\n :eventBus\n :globalCookies\n integration=\"client\"\n :method\n :openapiVersion\n :operation\n :path\n :requestBodyCompositionSelection\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"\n getResolvedRef(operation.requestBody)?.[\n 'x-scalar-selected-content-type'\n ]?.[exampleKey]\n \"\n :selectedExample=\"exampleKey\"\n :selectedServer=\"server ?? undefined\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.request-section-content {\n --scalar-border-width: 0.5px;\n}\n.request-section-content-filter {\n box-shadow: 0 -10px 0 10px var(--scalar-background-1);\n}\n.request-item:focus-within .request-meta-buttons {\n opacity: 1;\n}\n.group-hover-input {\n border-width: var(--scalar-border-width);\n border-color: transparent;\n}\n.group:hover .group-hover-input {\n background: color-mix(\n in srgb,\n var(--scalar-background-1),\n var(--scalar-background-2)\n );\n border-color: var(--scalar-border-color);\n}\n.group-hover-input:focus {\n background: transparent !important;\n border-color: var(--scalar-border-color) !important;\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RequestBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/request-block/RequestBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ClientOptionGroup } from '@scalar/blocks/code-example'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body'\nimport { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\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 { getUniqueExampleName } from '@scalar/workspace-store/navigation'\nimport {\n filterGlobalCookie,\n getEnvironmentVariables,\n getResolvedUrl,\n getSchemaExampleFromBody,\n type MergedSecuritySchemes,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, provide, ref, useId, watch } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport RequestBody from '@/v2/blocks/request-block/components/RequestBody.vue'\nimport RequestCodeSnippet from '@/v2/blocks/request-block/components/RequestCodeSnippet.vue'\nimport RequestParams from '@/v2/blocks/request-block/components/RequestParams.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { createParameterHandlers } from '@/v2/blocks/request-block/helpers/create-parameter-handlers'\nimport { createParameterRows } from '@/v2/blocks/request-block/helpers/create-parameter-rows'\nimport { groupBy } from '@/v2/blocks/request-block/helpers/group-by'\nimport { groupGlobalCookies } from '@/v2/blocks/request-block/helpers/group-global-cookies'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport {\n COLLAPSIBLE_SECTION_HEADING_LEVEL,\n type CollapsibleSectionHeadingLevel,\n} from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\ntype Filter =\n | 'All'\n | 'Auth'\n | 'Variables'\n | 'Cookies'\n | 'Headers'\n | 'Query'\n | 'Body'\n\nexport type RequestBlockProps = {\n authMeta: AuthMeta\n clientOptions: ClientOptionGroup[]\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n exampleKey: string\n workspaceCookies: XScalarCookie[]\n documentCookies: XScalarCookie[]\n /** Slug of the document the operation belongs to */\n documentSlug: string\n layout: ClientLayout\n method: string\n operation: OperationObject\n /** Operation before downloaded examples are overlaid, for parameter edit targets. */\n sourceOperation?: OperationObject\n path: string\n plugins: ClientPlugin[]\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\n requestBodyCompositionSelection?: Record<string, number>\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n selectedSecurity: SelectedSecurity\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n server: ServerObject | null\n defaultHeaders: Record<string, string>\n /** Initial view for structured request bodies, from the `x-scalar-default-request-body-view` document extension */\n defaultRequestBodyView?: 'form' | 'raw'\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}\n\nconst {\n authMeta = { type: 'document' },\n clientOptions,\n environment,\n eventBus,\n exampleKey,\n workspaceCookies,\n documentCookies,\n documentSlug,\n layout,\n method,\n operation,\n sourceOperation,\n path,\n plugins,\n proxyUrl,\n requestBodyCompositionSelection,\n openapiVersion,\n securityRequirements,\n securitySchemes,\n selectedClient,\n selectedSecurity,\n selectedSecuritySchemes,\n server,\n defaultHeaders: autoGeneratedHeaders,\n defaultRequestBodyView = 'raw',\n} = defineProps<RequestBlockProps>()\n\nconst { translate } = useLocalization()\n\n/** Base name for examples created by the \"generate example from schema\" button */\nconst GENERATED_EXAMPLE_NAME = 'Generated from schema'\n\n/** Operation metadata used across event emissions */\nconst meta = computed(() => ({\n method,\n path,\n exampleKey,\n}))\n\nconst deletedExpandedParameterPaths = ref<Record<string, string[][]>>({})\n\n/** Renamed expanded rows, tracked as old-schema-path -> typed-value-path per parameter. */\nconst renamedExpandedParameterPaths = ref<\n Record<string, { from: string[]; to: string[] }[]>\n>({})\n\nconst getExpandedParameterKey = (parameter: {\n in: string\n name: string\n}): string => `${parameter.in}:${parameter.name}`\n\nconst getHiddenValuePaths = (parameter: {\n in: string\n name: string\n}): string[][] =>\n deletedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst getRenamedValuePaths = (parameter: {\n in: string\n name: string\n}): { from: string[]; to: string[] }[] =>\n renamedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst pathsEqual = (a: string[], b: string[]): boolean =>\n a.length === b.length && a.every((segment, index) => segment === b[index])\n\n/**\n * Hides the schema path of an expanded row so it does not reappear as an empty suggestion. Used\n * both when a row is deleted and when its key is renamed (the old key should not pop back up).\n */\nconst hideExpandedRowPath = (row: TableRow): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const key = getExpandedParameterKey(row.originalParameter)\n deletedExpandedParameterPaths.value = {\n ...deletedExpandedParameterPaths.value,\n [key]: [\n ...(deletedExpandedParameterPaths.value[key] ?? []),\n row.sourceParameterValuePath,\n ],\n }\n}\n\n/**\n * Records that an expanded row was renamed from its current value path to the typed one, so the\n * read side can render the renamed key in the original property's slot instead of appending it to\n * the end of the table. Repeated renames of the same row stay anchored to the original schema path.\n */\nconst recordExpandedRowRename = (\n row: TableRow,\n newValuePath: string[],\n): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const from = row.sourceParameterValuePath\n const key = getExpandedParameterKey(row.originalParameter)\n const existing = renamedExpandedParameterPaths.value[key] ?? []\n\n // If this row was already renamed, the row's current path is the previous target. Re-anchor that\n // entry to the new target so a second rename does not create an orphaned mapping.\n const chained = existing.find((entry) => pathsEqual(entry.to, from))\n const next = chained\n ? existing.map((entry) =>\n entry === chained ? { from: entry.from, to: newValuePath } : entry,\n )\n : [...existing, { from, to: newValuePath }]\n\n renamedExpandedParameterPaths.value = {\n ...renamedExpandedParameterPaths.value,\n [key]: next,\n }\n}\n\n/** Whole-query parameters share the Query section but retain their original identity. */\nconst hasQuerystringParameter = computed(\n () =>\n operation.parameters?.some(\n (parameter) => getResolvedRef(parameter)?.in === 'querystring',\n ) ?? false,\n)\n\n/** Parameters grouped by type (path, query, header, cookie) */\nconst sections = computed(() =>\n groupBy(\n operation.parameters?.flatMap((reference, index) => {\n const param = getResolvedRef(reference)\n if (!param) return []\n return createParameterRows(param, exampleKey, {\n hiddenValuePaths:\n param.in === 'query' ? getHiddenValuePaths(param) : [],\n renamedValuePaths:\n param.in === 'query' ? getRenamedValuePaths(param) : [],\n }).map((row) => ({\n ...row,\n // Overlays retain parameter order, but their downloaded values are read-only.\n originalParameter:\n getResolvedRef(sourceOperation?.parameters?.[index]) ?? param,\n in: param.in === 'querystring' ? 'query' : param.in,\n }))\n }) ?? [],\n 'in',\n ({ in: _in, ...row }) => {\n return row\n },\n ),\n)\n\n// Generate a reverse map for fast lookup of headers by the name\nconst headersMap = computed(() =>\n groupBy(\n sections.value.header?.map((it) => ({\n ...it,\n name: it.name.toLowerCase(),\n })) ?? [],\n 'name',\n ),\n)\n\nconst defaultHeaders = computed(() => {\n const disableParameters =\n operation['x-scalar-disable-parameters']?.['default-headers']?.[\n exampleKey\n ] ?? {}\n\n const isOverridden = (name: string) => {\n const header = headersMap.value[name.toLowerCase()]?.[0]\n\n if (!header) {\n return false\n }\n\n return !header.isDisabled\n }\n\n return Object.entries(autoGeneratedHeaders).map(([name, value]) => {\n return {\n name,\n value,\n schema: undefined,\n isOverridden: isOverridden(name),\n isReadonly: true,\n isDisabled: disableParameters[name.toLowerCase()] ?? false,\n } satisfies TableRow\n })\n})\n\nconst headers = computed(() => [\n ...defaultHeaders.value,\n ...(sections.value.header ?? []),\n])\n\n/** Resolved request URL, used to filter global cookies by their domain and path. */\nconst requestCookieUrl = computed(() => {\n const environmentVariables = getEnvironmentVariables(environment)\n const resolvedUrl = getResolvedUrl({ server, path })\n return replaceEnvVariables(resolvedUrl, environmentVariables)\n})\n\n/**\n * Global cookies grouped by name. Same-named cookies collapse into a single logical cookie so\n * duplicate names no longer share one disabled state (which made toggling one toggle them all).\n * A name with multiple values becomes a preset the user can switch between.\n */\nconst globalCookieGroups = computed(() =>\n groupGlobalCookies({\n sources: [\n { location: 'workspace', cookies: workspaceCookies },\n { location: 'document', cookies: documentCookies },\n ],\n // Keep domain/path filtering but ignore the disabled flag, so a disabled preset value stays\n // selectable in the switcher (it is only hidden from the request, not from the dropdown).\n shouldInclude: (cookie) =>\n filterGlobalCookie({\n cookie: { ...cookie, isDisabled: false },\n url: requestCookieUrl.value,\n disabledGlobalCookies: {},\n }),\n }),\n)\n\nconst defaultCookies = computed<TableRow[]>(() => {\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[\n exampleKey\n ] ?? {}\n\n return globalCookieGroups.value.map((group) => ({\n name: group.name,\n value: group.selectedValue,\n globalRoute: { page: group.location, path: 'cookies' } as const,\n isReadonly: true,\n isDisabled: disabledGlobalCookies[group.name.toLowerCase()] ?? false,\n presetOptions: group.isPreset ? group.options : undefined,\n }))\n})\n\n/**\n * Switch a grouped global cookie preset to the chosen value by enabling the matching sibling and\n * disabling the rest. Selection is written back to the source `x-scalar-cookies` list so it\n * persists, and the send path drops disabled cookies, so only the selected value is sent.\n */\nconst handleSelectCookiePreset = (index: number, value: string): void => {\n const group = globalCookieGroups.value[index]\n if (!group) {\n return\n }\n\n for (const sibling of group.siblings) {\n eventBus.emit('cookie:upsert:cookie', {\n collectionType: sibling.location,\n index: sibling.index,\n payload: { isDisabled: sibling.value !== value },\n })\n }\n}\n\nconst cookies = computed(() => [\n ...(defaultCookies.value ?? []),\n ...(sections.value.cookie ?? []),\n])\n\n/** Currently selected filter for the request sections */\nconst selectedFilter = ref<Filter>('All')\n\n/** Available operation sections */\nconst OPERATION_SECTIONS: readonly Filter[] = [\n 'Auth',\n 'Variables',\n 'Cookies',\n 'Headers',\n 'Query',\n 'Body',\n] as const\n\n/**\n * Pre-generated stable IDs for all possible filter sections.\n * These are created once at setup time to avoid regenerating IDs on re-render.\n */\nconst sectionIds: Record<Filter, string> = {\n All: useId(),\n Auth: useId(),\n Variables: useId(),\n Cookies: useId(),\n Headers: useId(),\n Query: useId(),\n Body: useId(),\n}\n\n/** Filters available based on operation state */\nconst filters = computed<Filter[]>(() => {\n const availableFilters = new Set<Filter>(['All', ...OPERATION_SECTIONS])\n\n if (!sections.value.path?.length) {\n availableFilters.delete('Variables')\n }\n if (!canMethodHaveBody(method)) {\n availableFilters.delete('Body')\n }\n if (isAuthHidden.value) {\n availableFilters.delete('Auth')\n }\n\n return [...availableFilters]\n})\n\n/**\n * Map available filters to their pre-generated stable IDs.\n * Only includes IDs for filters that are currently available.\n */\nconst filterIds = computed(() =>\n filters.value.reduce<Partial<Record<Filter, string>>>((ids, section) => {\n ids[section] = sectionIds[section]\n return ids\n }, {}),\n)\n\n/**\n * Hide auth selector in readonly mode when no security schemes are defined.\n * This keeps the UI clean when there are no authentication options available.\n */\nconst isAuthHidden = computed(\n () => layout === 'modal' && !Object.keys(securitySchemes ?? {}).length,\n)\n\n/**\n * Keep auth available for unauthenticated operations, but collapse it by default\n * in readonly modal layouts unless a requirement or manual selection exists.\n */\nconst isAuthDefaultOpen = computed(\n () =>\n layout !== 'modal' ||\n Boolean(\n securityRequirements?.length || selectedSecurity.selectedSchemes.length,\n ),\n)\n\n/** Get a sensible placeholder for the request name input */\nconst requestNamePlaceholder = computed(() => {\n if (operation.summary) {\n return operation.summary\n }\n const cleanPath = path.replace(REGEX.PROTOCOL, '')\n return cleanPath || translate('apiClient.requestBlock.requestName')\n})\n\n/** Check if the section should be shown based on the selected filter */\nconst isSectionVisible = (section: Filter): boolean => {\n return selectedFilter.value === 'All' || selectedFilter.value === section\n}\n\n/**\n * Reset filter to 'All' if Body filter is selected but method changes to one that cannot have a body.\n * This prevents showing an empty Body section when switching methods.\n */\nwatch(\n () => method,\n (newMethod) => {\n if (selectedFilter.value === 'Body' && !canMethodHaveBody(newMethod)) {\n selectedFilter.value = 'All'\n }\n },\n)\n\n// Expanded-row bookkeeping is keyed by `in:name`, which is not unique across operations or\n// examples. Reset both maps when the operation or example changes so stale delete/rename mappings\n// do not leak onto another request that happens to share a query parameter name.\nwatch(\n () => [method, path, exampleKey],\n () => {\n deletedExpandedParameterPaths.value = {}\n renamedExpandedParameterPaths.value = {}\n },\n)\n\n/** Handle operation summary updates */\nconst handleSummaryUpdate = (event: Event): void => {\n if (!(event.target instanceof HTMLInputElement)) {\n return\n }\n const summary = event.target.value\n eventBus.emit('operation:update:meta', {\n meta: meta.value,\n payload: { summary: summary.trim() },\n })\n}\n\n/** Parameter handlers */\nconst parameterHandlers = computed(() => ({\n path: createParameterHandlers('path', eventBus, meta.value, {\n context: sections.value.path ?? [],\n }),\n cookie: {\n ...createParameterHandlers('cookie', eventBus, meta.value, {\n context: cookies.value ?? [],\n globalParameters: defaultCookies.value.length,\n }),\n selectPreset: handleSelectCookiePreset,\n },\n header: createParameterHandlers('header', eventBus, meta.value, {\n context: headers.value,\n defaultParameters: defaultHeaders.value.length,\n }),\n query: createParameterHandlers('query', eventBus, meta.value, {\n context: sections.value.query ?? [],\n onDeleteExpandedRow: hideExpandedRowPath,\n onRenameExpandedRow: recordExpandedRowRename,\n }),\n}))\n\n/** Handle request body content type update */\nconst handleUpdateContentType = (payload: { value: string }): void =>\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType: payload.value },\n meta: meta.value,\n })\n\n/** Handle request body value update */\nconst handleUpdateBodyValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey =\n typeof payload === 'string'\n ? `update:requestBody:value-${contentType}`\n : undefined\n\n eventBus.emit(\n 'operation:update:requestBody:value',\n {\n payload,\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/** Handle request body value update */\nconst handleUpdateBodyFormValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey = `update:requestBody:${contentType}-form-value`\n\n eventBus.emit(\n 'operation:update:requestBody:formValue',\n {\n payload: payload.map((row) => unpackProxyObject(row, { depth: 1 })),\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/**\n * Create a new example seeded with values generated from the request body schema.\n *\n * Custom examples in the document otherwise hide the auto-generated fields entirely. Rather than\n * only rendering the generated body, we write it into a fresh example so the user can edit it and\n * so it survives an export of the document.\n */\nconst handleGenerateExample = ({\n contentType,\n}: {\n contentType: string\n}): void => {\n const requestBody = getResolvedRef(operation.requestBody)\n const codec = getStructuredBodyCodec(contentType)\n if (!requestBody || !codec) {\n return\n }\n\n const value = getSchemaExampleFromBody(\n requestBody,\n contentType,\n requestBodyCompositionSelection,\n )\n\n // A schema that generates nothing writable would leave the user on an empty new example.\n if (value === undefined || value === null) {\n return\n }\n\n const exampleName = getUniqueExampleName(operation, GENERATED_EXAMPLE_NAME)\n const exampleMeta = { path, method, exampleKey: exampleName }\n\n eventBus.emit('operation:create:draft-example', {\n documentName: documentSlug,\n meta: { path, method },\n exampleName,\n })\n\n // Carry over the content type the user was looking at, otherwise the new example opens on\n // whichever content type happens to come first on the request body.\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType },\n meta: exampleMeta,\n })\n\n eventBus.emit('operation:update:requestBody:value', {\n payload: codec.stringify(value),\n contentType,\n meta: exampleMeta,\n })\n\n // The modal selects the example after its creation hook rebuilds the sidebar.\n if (layout === 'modal') {\n return\n }\n\n eventBus.emit('ui:navigate', {\n page: 'example',\n documentSlug,\n path,\n method,\n exampleName,\n })\n}\n\nconst labelRequestNameId = useId()\n\n/**\n * Where the collapsible sections below sit in the heading outline.\n *\n * The modal renders the operation summary as a heading above them, so they are\n * its subsections. Every other layout shows the summary as an editable input\n * rather than a heading, which leaves the sections at the top level.\n */\nprovide(\n COLLAPSIBLE_SECTION_HEADING_LEVEL,\n computed<CollapsibleSectionHeadingLevel>(() =>\n layout === 'modal' && operation.summary ? 3 : 2,\n ),\n)\n\nconst globalCookies = computed(() => [...workspaceCookies, ...documentCookies])\n\n/** Allow updating the operation extensions for the plugins */\nconst updateOperationExtension = (\n payload: ApiReferenceEvents['operation:update:extension']['payload'],\n): void =>\n eventBus.emit('operation:update:extension', { payload, meta: meta.value })\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=\"\n translate('apiClient.requestBlock.label', {\n name: operation.summary ?? '',\n })\n \">\n <template #title>\n <div\n class=\"group pointer-events-none flex flex-1 items-center gap-1 lg:pe-24\">\n <label\n v-if=\"layout !== 'modal'\"\n class=\"pointer-events-auto absolute top-0 left-0 h-full w-full cursor-text opacity-0\"\n :for=\"labelRequestNameId\" />\n <input\n v-if=\"layout !== 'modal'\"\n :id=\"labelRequestNameId\"\n class=\"text-c-1 group-hover-input pointer-events-auto relative z-10 -ml-0.5 h-8 w-full rounded pl-1.25 has-[:focus-visible]:outline md:-ml-1.25\"\n :placeholder=\"requestNamePlaceholder\"\n :value=\"operation.summary\"\n @blur=\"handleSummaryUpdate\" />\n <!-- In the modal the summary is the title of everything below it, so\n it carries the heading role that lets screen reader users jump to\n it. An operation without a summary renders nothing, because an\n empty heading is worse than none. -->\n <h2\n v-else-if=\"operation.summary\"\n class=\"text-c-1 flex h-8 items-center\">\n {{ operation.summary }}\n </h2>\n <span\n v-else\n class=\"text-c-1 flex h-8 items-center\" />\n </div>\n <SectionFilter\n v-model=\"selectedFilter\"\n :filters=\"filters\"\n :labels=\"filterLabels\" />\n </template>\n\n <div\n :id=\"filterIds.All\"\n class=\"request-section-content custom-scroll relative flex flex-1 flex-col\"\n :role=\"selectedFilter === 'All' ? 'tabpanel' : 'none'\">\n <!-- Auth Selector -->\n <AuthSelector\n v-show=\"isSectionVisible('Auth') && !isAuthHidden\"\n :id=\"filterIds.Auth\"\n :createAnySecurityScheme=\"layout !== 'modal'\"\n :defaultOpen=\"isAuthDefaultOpen\"\n :environment\n :eventBus\n :meta=\"authMeta\"\n :options\n :proxyUrl\n :securityRequirements\n :securitySchemes\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n :title=\"translate('apiClient.requestBlock.authentication')\" />\n\n <!-- Variables (Path Parameters) -->\n <RequestParams\n v-show=\"isSectionVisible('Variables') && sections.path?.length\"\n :id=\"filterIds.Variables\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.path ?? []\"\n :showAddRowPlaceholder=\"false\"\n :title=\"translate('apiClient.requestBlock.variables')\"\n v-on=\"parameterHandlers.path\" />\n\n <!-- Cookies -->\n <RequestParams\n v-show=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"cookies ?? []\"\n :showAddRowPlaceholder=\"true\"\n :title=\"translate('apiClient.requestBlock.cookies')\"\n v-on=\"parameterHandlers.cookie\" />\n\n <!-- Headers -->\n <RequestParams\n v-show=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"headers ?? []\"\n :title=\"translate('apiClient.requestBlock.headers')\"\n v-on=\"parameterHandlers.header\" />\n\n <!-- Query Parameters -->\n <RequestParams\n v-show=\"isSectionVisible('Query')\"\n :id=\"filterIds.Query\"\n :description=\"\n hasQuerystringParameter\n ? translate('apiClient.requestBlock.queryStringDescription')\n : undefined\n \"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.query ?? []\"\n :showAddRowPlaceholder=\"!hasQuerystringParameter\"\n :title=\"\n hasQuerystringParameter\n ? translate('apiClient.requestBlock.queryString')\n : translate('apiClient.requestBlock.queryParameters')\n \"\n v-on=\"parameterHandlers.query\" />\n\n <!-- Request Body -->\n <RequestBody\n v-show=\"isSectionVisible('Body') && canMethodHaveBody(method)\"\n :id=\"filterIds.Body\"\n :defaultView=\"defaultRequestBodyView\"\n :environment\n :exampleKey\n :openapiVersion\n :requestBody=\"getResolvedRef(operation.requestBody)\"\n :requestBodyCompositionSelection\n :title=\"translate('apiClient.requestBlock.requestBody')\"\n @generate:example=\"handleGenerateExample\"\n @update:contentType=\"handleUpdateContentType\"\n @update:formValue=\"handleUpdateBodyFormValue\"\n @update:value=\"handleUpdateBodyValue\" />\n\n <!-- Inject request section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.request.component\"\n v-if=\"plugin?.components?.request\"\n v-show=\"selectedFilter === 'All'\"\n :operation\n v-bind=\"plugin.components.request.additionalProps\"\n @operation:update:extension=\"updateOperationExtension\" />\n </ScalarErrorBoundary>\n\n <!-- Spacer -->\n <div class=\"flex grow\" />\n <!-- Code Snippet -->\n <RequestCodeSnippet\n v-show=\"selectedFilter === 'All'\"\n :clientOptions\n :eventBus\n :globalCookies\n integration=\"client\"\n :method\n :openapiVersion\n :operation\n :path\n :requestBodyCompositionSelection\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"\n getResolvedRef(operation.requestBody)?.[\n 'x-scalar-selected-content-type'\n ]?.[exampleKey]\n \"\n :selectedExample=\"exampleKey\"\n :selectedServer=\"server ?? undefined\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.request-section-content {\n --scalar-border-width: 0.5px;\n}\n.request-section-content-filter {\n box-shadow: 0 -10px 0 10px var(--scalar-background-1);\n}\n.request-item:focus-within .request-meta-buttons {\n opacity: 1;\n}\n.group-hover-input {\n border-width: var(--scalar-border-width);\n border-color: transparent;\n}\n.group:hover .group-hover-input {\n background: color-mix(\n in srgb,\n var(--scalar-background-1),\n var(--scalar-background-2)\n );\n border-color: var(--scalar-border-color);\n}\n.group-hover-input:focus {\n background: transparent !important;\n border-color: var(--scalar-border-color) !important;\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -28,6 +28,8 @@ export type TableRow = {
|
|
|
28
28
|
schema?: SchemaObject;
|
|
29
29
|
/** Preserve array values even while their JSON text is temporarily invalid. */
|
|
30
30
|
isArray?: boolean;
|
|
31
|
+
/** Text representation used by array enum controls. */
|
|
32
|
+
arrayEncoding?: 'json' | 'comma-separated';
|
|
31
33
|
/** Whether the parameter is required */
|
|
32
34
|
isRequired?: boolean;
|
|
33
35
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"names":[],"mappings":"AAkaA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAGxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAgBrE,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAA;IACd,iFAAiF;IACjF,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,kBAAkB,CAAA;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAC;AAwBF,MAAM,MAAM,QAAQ,GAAG;IACrB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3B,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAA;IAC/C,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,wEAAwE;IACxE,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAA;IAC1C,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,eAAe,CAAA;IACnC,2FAA2F;IAC3F,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAA;IACnC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,UAAU,EAAE,OAAO,CAAA;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC,CAAA;AA2sBD,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Text representation used by array enum controls. */\n arrayEncoding?: 'json' | 'comma-separated'\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<unknown[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return data.arrayEncoding === 'json'\n ? resolved.enum\n : resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n :arrayEncoding=\"data.arrayEncoding\"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""}
|
|
@@ -71,7 +71,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
71
71
|
if (__props.data.schema.enum) return __props.data.schema.enum.map((item) => String(item));
|
|
72
72
|
if ("items" in __props.data.schema) {
|
|
73
73
|
const resolved = resolve.schema(__props.data.schema.items);
|
|
74
|
-
if (resolved?.enum) return resolved.enum.map((item) => String(item));
|
|
74
|
+
if (resolved?.enum) return __props.data.arrayEncoding === "json" ? resolved.enum : resolved.enum.map((item) => String(item));
|
|
75
75
|
}
|
|
76
76
|
return [];
|
|
77
77
|
});
|
|
@@ -166,6 +166,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
166
166
|
}, null, 8, ["modelValue", "value"])) : (openBlock(), createBlock(unref(CodeInputLite_default), {
|
|
167
167
|
key: 1,
|
|
168
168
|
"aria-label": unref(translate)("apiClient.requestTableRow.valueLabel", { name: __props.label ?? "" }),
|
|
169
|
+
arrayEncoding: __props.data.arrayEncoding,
|
|
169
170
|
class: "pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10",
|
|
170
171
|
default: defaultValue.value,
|
|
171
172
|
disabled: __props.data.isReadonly,
|
|
@@ -220,6 +221,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
220
221
|
_: 1
|
|
221
222
|
}, 8, [
|
|
222
223
|
"aria-label",
|
|
224
|
+
"arrayEncoding",
|
|
223
225
|
"default",
|
|
224
226
|
"disabled",
|
|
225
227
|
"enum",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Text representation used by array enum controls. */\n arrayEncoding?: 'json' | 'comma-separated'\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<unknown[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return data.arrayEncoding === 'json'\n ? resolved.enum\n : resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n :arrayEncoding=\"data.arrayEncoding\"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CA,MAAM,OAAO;EAUb,MAAM,EAAE,cAAc,gBAAgB;EAyDtC,MAAM,OAAO,IAAY,QAAA,KAAK,QAAQ,EAAE;EACxC,MAAM,QAAQ,IAAmB,kBAAkB,QAAA,KAAK,KAAK,KAAK,EAAE;EACpE,MAAM,aAAa,IAAa,QAAA,KAAK,cAAc,KAAK;EAGxD,YACQ,QAAA,KAAK,OACV,YAAY;GAIX,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,QAAA,iBAAiB;GAChD,KAAK,QAAQ,WAAW;EAC1B,CACF;EACA,YACQ,QAAA,KAAK,QACV,aAAc,MAAM,QAAQ,kBAAkB,QAAQ,KAAK,EAC9D;EACA,YACQ,QAAA,KAAK,aACV,kBAAmB,WAAW,QAAQ,iBAAiB,KAC1D;;EAGA,MAAM,SAAS,eAAe,MAAM,iBAAiB,IAAI;;EAGzD,MAAM,eAAe,gBAEhB,OAAO,QACJ,YAAY,MAAM,KAAa,IAC9B,MAAM,UAAqB,EACpC;EAEA,MAAM,eAAe,eAAe,QAAA,KAAK,QAAQ,OAAiB;;EAGlE,MAAM,YAAY,eAA0B;GAC1C,IAAI,CAAC,QAAA,KAAK,QACR,OAAO,CAAC;GAIV,IAAI,QAAA,KAAK,OAAO,MACd,OAAO,QAAA,KAAK,OAAO,KAAK,KAAK,SAAS,OAAO,IAAI,CAAC;GAIpD,IAAI,WAAW,QAAA,KAAK,QAAQ;IAC1B,MAAM,WAAW,QAAQ,OAAO,QAAA,KAAK,OAAO,KAAK;IACjD,IAAI,UAAU,MACZ,OAAO,QAAA,KAAK,kBAAkB,SAC1B,SAAS,OACT,SAAS,KAAK,KAAK,SAAS,OAAO,IAAI,CAAC;GAEhD;GAEA,OAAO,CAAC;EACV,CAAC;EAED,MAAM,YAAY,eAChB,QAAA,KAAK,UAAU,UAAU,QAAA,KAAK,SAAS,QAAA,KAAK,OAAO,OAAO,KAAA,CAC5D;EAEA,MAAM,mBAAmB,eACvB,kBAAkB,QAAA,KAAK,QAAQ,MAAM,KAAK,CAC5C;;EAGA,MAAM,mBACJ,SACA,UAAsE,CAAC,MAC9D;GAET,IAAI,QAAQ,SAAS,KAAA,GACnB,KAAK,QAAQ,QAAQ;GAEvB,IAAI,QAAQ,UAAU,KAAA,GAAW;IAC/B,MAAM,QAAQ,QAAQ;IAItB,IAAI,QAAA,KAAK,qBACP,WAAW,QAAQ;GAEvB;GAGA,IAAI,QAAQ,eAAe,KAAA,GACzB,WAAW,QAAQ,QAAQ;GAG7B,IACE,QAAQ,SAAS,KAAA,MAChB,QAAA,mBAAmB,QAAA,KAAK,6BACzB,CAAC,QAAQ,2BACT,CAAC,QAAQ,WAET;GAIF,KAAK,aAAa;IAChB,MAAM,KAAK;IACX,OAAO,MAAM;IACb,YAAY,WAAW;IACvB,GAAI,QAAQ,0BACR,EAAE,yBAAyB,KAAK,IAChC,CAAC;GACP,CAAC;EACH;;;;;;;EAQA,MAAM,iBAAiB,YAA0B;GAC/C,IAAI,YAAY,QAAA,KAAK,MACnB;GAIF,IAAI,CAAC,WAAW,QAAA,KAAK,SAAS,CAAC,QAAA,mBAAmB,KAAK,UAAU,KAC/D;GAGF,gBACE;IAAE,MAAM;IAAS,YAAY,WAAW;GAAM,GAC9C;IACE,yBAAyB,QAAQ,QAAA,KAAK,wBAAwB;IAC9D,WAAW;GACb,CACF;EACF;;EAGA,MAAM,iBAAiB,UAA+B;GACpD,IACE,QAAA,mBACA,MAAM,QAAQ,YACb,MAAM,WAAW,MAAM,UAExB,cAAc,KAAK,KAAK;EAE5B;;uBAIE,YAiJe,MAAA,oBAAA,GAAA;IAhJZ,IAAI,QAAA,KAAK;IACT,OAAK,eAAA;YAAiB,iBAAA,MAAiB,OAAE;YAAyB,iBAAA,MAAiB,OAAE,SAAc,QAAA,eAAe,IAAI,QAAA,KAAK,IAAI;;;2BAa5D;KATpE,YASoE,MAAA,yBAAA,GAAA;MARjE,WAAoB,MAAA,SAAA,CAAS,CAAA,qCAAA,EAAA,MAAwD,QAAA,KAAK,QAAQ,MAAA,SAAA,CAAS,CAAA,+BAAA,EAAA,CAAA;MAK5G,OAAM;MACL,UAAU,QAAA,uBAAmB;MAC7B,YAAU,CAAG,WAAA;MACb,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAM,gBAAe,EAAA,YAAA,CAAgB,EAAC,CAAA;;;;;;KAG7D,YAcgB,MAAA,qBAAA,GAAA,MAAA;6BAD+C,CAZ7D,YAY6D,MAAA,qBAAA,GAAA;OAX1D,cAAuB,MAAA,SAAA,CAAS,CAAA,sCAAA,EAAA,MAA+C,QAAA,SAAK,GAAA,CAAA;OAGpF,UAAU,QAAA,KAAK;OACf,aAAa,QAAA;OACb,YAAY,KAAA;OACZ,aAAa,MAAA,SAAA,CAAS,CAAA,+BAAA;OACtB,UAAU,QAAQ,QAAA,KAAK,UAAU;OACjC,QAAI,OAAA,OAAA,OAAA,MAAG,MAAM,cAAc,CAAC;yBACX;OACjB,YAAQ,OAAA,OAAA,OAAA,MAAG,UAAU,KAAI,YAAa,KAAK;OAC3C,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAM,gBAAe,EAAA,MAAS,EAAC,CAAA;;;;;;;;;;;KAIxD,YAuEgB,MAAA,qBAAA,GAAA,MAAA;6BAhE0C,CAJhD,QAAA,KAAK,eAAe,UAAA,UAAA,GAD5B,YAKwD,MAAA,4BAAA,GAAA;;OAHrD,mBAAmB;OACnB,YAAY,aAAA;OACZ,OAAO,QAAA,KAAK;OACZ,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAM,KAAI,gBAAiB,CAAC;4DACnD,YA8DgB,MAAA,qBAAA,GAAA;;OA5Db,cAAuB,MAAA,SAAA,CAAS,CAAA,wCAAA,EAAA,MAA6D,QAAA,SAAK,GAAA,CAAA;OAKlG,eAAe,QAAA,KAAK;OACrB,OAAM;OACL,SAAS,aAAA;OACT,UAAU,QAAA,KAAK;OACf,MAAM,UAAA;OACN,aAAa,QAAA;OACb,UAAqB,QAAA,KAAK,QAAQ,UAAU,KAAK,YAAY,OAAO,OAAO,CAAA,KAAA,CAAA;OAG3E,aAAa,QAAA,KAAK;OAClB,YAAY,aAAA;OACZ,aAAa,MAAA,SAAA,CAAS,CAAA,iCAAA;OACtB,MAAM,UAAA;OACP,cAAA;OACC,YAAQ,OAAA,OAAA,OAAA,MAAG,UAAU,KAAI,YAAa,KAAK;OAC3C,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAM,gBAAe,EAAA,OAAU,EAAC,CAAA;;OAC1C,MAAI,cAiBE;QAfQ,QAAQ,QAAA,KAAK,QAAQ,MAAA,KAAK,KAAA,CAAoB,QAAA,KAAK,cAA4B,QAAA,KAAK,eAAU,QAAA,UAAA,GADrH,YAgBe,MAAA,YAAA,GAAA;;SAVZ,cAA2B,MAAA,SAAA,CAAS,CAAA,uCAAA,EAAA,MAAgE,QAAA,KAAK,QAAQ,MAAA,SAAA,CAAS,CAAA,+BAAA,EAAA,CAAA;SAK3H,OAAM;SACN,MAAK;SACL,SAAQ;SACP,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,WAAA;;gCACwB,CAApC,YAAoC,MAAA,eAAA,GAAA,EAAnB,OAAM,WAAU,CAAA,CAAA,CAAA;;;QAI3B,QAAA,KAAK,gBAAgB,KAAA,KAAA,UAAA,GAD7B,YAQgD,MAAA,gBAAA,GAAA;;SAN9C,OAAM;SACL,MAAM,MAAA,eAAA;SACN,OAAO,MAAA,SAAA,CAAS,CAAA,4CAAA;SACjB,MAAK;SACL,SAAQ;SACR,SAAQ;SACP,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,YAAa,QAAA,KAAK,WAAW;;QAGnC,QAAA,KAAK,cAAA,UAAA,GADb,YAGkB,6BAAA;;SADf,aAAa,MAAA,SAAA,CAAS,CAAA,wCAAA;SACtB,OAAO;wCAEG,QAAA,KAAK,UAAA,UAAA,GADlB,YAIW,6BAAA;;SAFR,aAAa,QAAA,KAAK;SAClB,QAAQ,QAAA,KAAK;SACb,OAAA,MAAA;;;;;;;;;;;;;;;;;;;;;;;KAOD,QAAA,oBAAA,UAAA,GADR,YAmCgB,MAAA,qBAAA,GAAA;;MAjCd,OAAM;;6BAgBK,CAfK,OAAA,SAAA,UAAA,GAAhB,mBAeW,UAAA,EAAA,KAAA,EAAA,GAAA,CAdT,mBAOM,OAPN,YAOM,CALJ,mBAIC,QAAA;OAHC,OAAM;OACL,OAAO,aAAA;yBACJ,aAAA,KAAY,GAAA,GAAA,UAAA,CAAA,CAAA,GAGpB,mBAKS,UAAA;OAJP,OAAM;OACN,MAAK;OACJ,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,YAAA;yBACT,MAAA,SAAA,CAAS,CAAA,kCAAA,CAAA,GAAA,CAAA,CAAA,GAAA,EAAA,MAAA,UAAA,GAId,mBAaM,OAbN,YAaM,CAZJ,YAWe,MAAA,YAAA,GAAA;OAVb,OAAM;OACN,MAAK;OACL,SAAQ;OACP,SAAK,OAAA,QAAA,OAAA,OAAA,WAAE,KAAI,YAAA;;8BACwD,CAApE,mBAAoE,QAAA,MAAA,gBAA3D,MAAA,SAAA,CAAS,CAAA,sCAAA,CAAA,GAAA,CAAA,GAClB,YAIoB,MAAA,UAAA,GAAA;QAHlB,OAAM;QACN,MAAK;QACL,MAAK;QACL,WAAU"}
|
|
@@ -23,7 +23,8 @@ var getStructuredBodyRows = (parsedValue, schema) => {
|
|
|
23
23
|
const row = {
|
|
24
24
|
name,
|
|
25
25
|
value: value === void 0 || value === null ? "" : stringifyValue(value),
|
|
26
|
-
isDisabled: false
|
|
26
|
+
isDisabled: false,
|
|
27
|
+
arrayEncoding: "json"
|
|
27
28
|
};
|
|
28
29
|
const leaf = leafByDottedName.get(name);
|
|
29
30
|
const propSchema = leaf?.schema ?? (objectSchema ? resolve.schema(objectSchema.properties?.[name]) : void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-structured-body-rows.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/get-structured-body-rows.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\n\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n type LeafRow,\n collectExampleRows,\n collectLeafProperties,\n stringifyValue,\n} from '@/v2/blocks/request-block/helpers/get-form-body-rows'\n\n/**\n * Build form-table rows for a structured (JSON/YAML) request body.\n *\n * The parsed body value is walked alongside the schema exactly like the multipart form\n * editor does: schema-declared properties first in schema order (nested objects flatten\n * into dotted-path leaves like `props.name`), example-only keys after in example order.\n * Each row is enriched with its leaf schema so the table shows enum dropdowns, required\n * badges, defaults, and validation per field.\n */\nexport const getStructuredBodyRows = (parsedValue: unknown, schema?: SchemaObject): TableRow[] => {\n const objectSchema = schema && isObjectSchema(schema) ? schema : undefined\n\n // Nothing to build rows from: neither a body object nor an object schema.\n if (!isObject(parsedValue) && !objectSchema) {\n return []\n }\n\n // Leaf index by dotted name so nested leaves keep their schema and required flag.\n const leafByDottedName = new Map<string, LeafRow>()\n if (objectSchema) {\n for (const leaf of collectLeafProperties(objectSchema)) {\n leafByDottedName.set(leaf.path.join('.'), leaf)\n }\n }\n const requiredSet = new Set(objectSchema?.required ?? [])\n\n return collectExampleRows(isObject(parsedValue) ? parsedValue : {}, objectSchema).map(({ path, value }) => {\n const name = path.join('.')\n\n // Missing values and explicit `null` render as empty inputs so the user can type a\n // value rather than seeing the string \"null\". Empty rows are omitted on fold-back.\n const rendered = value === undefined || value === null ? '' : stringifyValue(value)\n\n const row: TableRow = { name, value: rendered, isDisabled: false }\n\n const leaf = leafByDottedName.get(name)\n const propSchema = leaf?.schema ?? (objectSchema ? resolve.schema(objectSchema.properties?.[name]) : undefined)\n row.schema = propSchema\n row.description = propSchema?.description\n row.isRequired = leaf?.isRequired ?? requiredSet.has(name)\n\n return row\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,IAAa,yBAAyB,aAAsB,WAAsC;CAChG,MAAM,eAAe,UAAU,eAAe,MAAM,IAAI,SAAS,KAAA;CAGjE,IAAI,CAAC,SAAS,WAAW,KAAK,CAAC,cAC7B,OAAO,CAAC;CAIV,MAAM,mCAAmB,IAAI,IAAqB;CAClD,IAAI,cACF,KAAK,MAAM,QAAQ,sBAAsB,YAAY,GACnD,iBAAiB,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI;CAGlD,MAAM,cAAc,IAAI,IAAI,cAAc,YAAY,CAAC,CAAC;CAExD,OAAO,mBAAmB,SAAS,WAAW,IAAI,cAAc,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,EAAE,MAAM,YAAY;EACzG,MAAM,OAAO,KAAK,KAAK,GAAG;EAM1B,MAAM,MAAgB;GAAE;GAAM,OAFb,UAAU,KAAA,KAAa,UAAU,OAAO,KAAK,eAAe,KAAK;GAEnC,YAAY;
|
|
1
|
+
{"version":3,"file":"get-structured-body-rows.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/get-structured-body-rows.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\n\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n type LeafRow,\n collectExampleRows,\n collectLeafProperties,\n stringifyValue,\n} from '@/v2/blocks/request-block/helpers/get-form-body-rows'\n\n/**\n * Build form-table rows for a structured (JSON/YAML) request body.\n *\n * The parsed body value is walked alongside the schema exactly like the multipart form\n * editor does: schema-declared properties first in schema order (nested objects flatten\n * into dotted-path leaves like `props.name`), example-only keys after in example order.\n * Each row is enriched with its leaf schema so the table shows enum dropdowns, required\n * badges, defaults, and validation per field.\n */\nexport const getStructuredBodyRows = (parsedValue: unknown, schema?: SchemaObject): TableRow[] => {\n const objectSchema = schema && isObjectSchema(schema) ? schema : undefined\n\n // Nothing to build rows from: neither a body object nor an object schema.\n if (!isObject(parsedValue) && !objectSchema) {\n return []\n }\n\n // Leaf index by dotted name so nested leaves keep their schema and required flag.\n const leafByDottedName = new Map<string, LeafRow>()\n if (objectSchema) {\n for (const leaf of collectLeafProperties(objectSchema)) {\n leafByDottedName.set(leaf.path.join('.'), leaf)\n }\n }\n const requiredSet = new Set(objectSchema?.required ?? [])\n\n return collectExampleRows(isObject(parsedValue) ? parsedValue : {}, objectSchema).map(({ path, value }) => {\n const name = path.join('.')\n\n // Missing values and explicit `null` render as empty inputs so the user can type a\n // value rather than seeing the string \"null\". Empty rows are omitted on fold-back.\n const rendered = value === undefined || value === null ? '' : stringifyValue(value)\n\n const row: TableRow = { name, value: rendered, isDisabled: false, arrayEncoding: 'json' }\n\n const leaf = leafByDottedName.get(name)\n const propSchema = leaf?.schema ?? (objectSchema ? resolve.schema(objectSchema.properties?.[name]) : undefined)\n row.schema = propSchema\n row.description = propSchema?.description\n row.isRequired = leaf?.isRequired ?? requiredSet.has(name)\n\n return row\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,IAAa,yBAAyB,aAAsB,WAAsC;CAChG,MAAM,eAAe,UAAU,eAAe,MAAM,IAAI,SAAS,KAAA;CAGjE,IAAI,CAAC,SAAS,WAAW,KAAK,CAAC,cAC7B,OAAO,CAAC;CAIV,MAAM,mCAAmB,IAAI,IAAqB;CAClD,IAAI,cACF,KAAK,MAAM,QAAQ,sBAAsB,YAAY,GACnD,iBAAiB,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI;CAGlD,MAAM,cAAc,IAAI,IAAI,cAAc,YAAY,CAAC,CAAC;CAExD,OAAO,mBAAmB,SAAS,WAAW,IAAI,cAAc,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,EAAE,MAAM,YAAY;EACzG,MAAM,OAAO,KAAK,KAAK,GAAG;EAM1B,MAAM,MAAgB;GAAE;GAAM,OAFb,UAAU,KAAA,KAAa,UAAU,OAAO,KAAK,eAAe,KAAK;GAEnC,YAAY;GAAO,eAAe;EAAO;EAExF,MAAM,OAAO,iBAAiB,IAAI,IAAI;EACtC,MAAM,aAAa,MAAM,WAAW,eAAe,QAAQ,OAAO,aAAa,aAAa,KAAK,IAAI,KAAA;EACrG,IAAI,SAAS;EACb,IAAI,cAAc,YAAY;EAC9B,IAAI,aAAa,MAAM,cAAc,YAAY,IAAI,IAAI;EAEzD,OAAO;CACT,CAAC;AACH"}
|
|
@@ -6,6 +6,8 @@ import type { ClientLayout } from '../../../v2/types/layout';
|
|
|
6
6
|
type __VLS_Props = {
|
|
7
7
|
/** Wait for the selected external request example before sending. */
|
|
8
8
|
executionDisabled?: boolean;
|
|
9
|
+
/** Failure retained until the next request or operation change. */
|
|
10
|
+
requestError?: Error | null;
|
|
9
11
|
/** Preprocessed response */
|
|
10
12
|
response: ResponseInstance | null;
|
|
11
13
|
/** Original request as a [url, RequestInit] tuple */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ResponseBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"names":[],"mappings":"AA6VA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAA;AAK7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kDAAkD,CAAA;AAYxF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,KAAK,WAAW,GAAG;IACjB,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,mEAAmE;IACnE,YAAY,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IAC3B,4BAA4B;IAC5B,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACjC,qDAAqD;IACrD,cAAc,EAAE,cAAc,GAAG,IAAI,CAAA;IACrC,oBAAoB;IACpB,MAAM,EAAE,YAAY,CAAA;IACpB,yCAAyC;IACzC,sBAAsB,EAAE,MAAM,CAAA;IAC9B,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,6BAA6B;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,0BAA0B;IAC1B,QAAQ,EAAE,iBAAiB,CAAA;CAC5B,CAAC;AAgDF,QAAA,MAAM,gBAAgB,yCAA0C,CAAA;AAChE,KAAK,MAAM,GAAG,KAAK,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;AAwdvD,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;oPAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../_virtual/_plugin-vue_exp
|
|
|
2
2
|
import ResponseBlock_vue_vue_type_script_setup_true_lang_default from "./ResponseBlock.vue.script.js";
|
|
3
3
|
/* empty css */
|
|
4
4
|
//#region src/v2/blocks/response-block/ResponseBlock.vue
|
|
5
|
-
var ResponseBlock_default = /*#__PURE__*/ _plugin_vue_export_helper_default(ResponseBlock_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
5
|
+
var ResponseBlock_default = /*#__PURE__*/ _plugin_vue_export_helper_default(ResponseBlock_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-7f122fc4"]]);
|
|
6
6
|
//#endregion
|
|
7
7
|
export { ResponseBlock_default as default };
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResponseBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { RequestPayload } from '@scalar/workspace-store/request-example'\nimport { computed, ref, useId } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ResponseInstance } from '@/v2/blocks/operation-block/helpers/send-request'\nimport HeadersComponent from '@/v2/blocks/response-block/components/Headers.vue'\nimport ResponseBody from '@/v2/blocks/response-block/components/ResponseBody.vue'\nimport ResponseBodyStreaming from '@/v2/blocks/response-block/components/ResponseBodyStreaming.vue'\nimport ResponseBodyVirtual from '@/v2/blocks/response-block/components/ResponseBodyVirtual.vue'\nimport ResponseCookies from '@/v2/blocks/response-block/components/ResponseCookies.vue'\nimport ResponseEmpty from '@/v2/blocks/response-block/components/ResponseEmpty.vue'\nimport ResponseLoadingOverlay from '@/v2/blocks/response-block/components/ResponseLoadingOverlay.vue'\nimport ResponseMetaInformation from '@/v2/blocks/response-block/components/ResponseMetaInformation.vue'\nimport { textMediaTypes } from '@/v2/blocks/response-block/helpers/media-types'\nimport { parseSetCookie } from '@/v2/blocks/response-block/helpers/parse-set-cookie'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nconst { layout, totalPerformedRequests, response, requestPayload } =\n defineProps<{\n /** Wait for the selected external request example before sending. */\n executionDisabled?: boolean\n /** Preprocessed response */\n response: ResponseInstance | null\n /** Original request as a [url, RequestInit] tuple */\n requestPayload: RequestPayload | null\n /** Client layout */\n layout: ClientLayout\n /** Total number of performed requests */\n totalPerformedRequests: number\n /** Application version */\n appVersion: string\n /** Registered app plugins */\n plugins: ClientPlugin[]\n /** Workspace event bus */\n eventBus: WorkspaceEventBus\n }>()\n\nconst { translate } = useLocalization()\n\n// Headers\nconst responseHeaders = computed(() => {\n const headers = response?.headers\n\n return headers\n ? Object.keys(headers).map((key) => ({\n name: key,\n value: headers[key] ?? '',\n }))\n : []\n})\n\nconst responseContentType = computed(\n () => response?.headers['content-type'] ?? response?.headers['Content-Type'],\n)\n\n// Cookies\nconst responseCookies = computed(\n () =>\n response?.cookieHeaderKeys\n .map((setCookieValue) => parseSetCookie(setCookieValue))\n .filter(isDefined) ?? [],\n)\n\nconst responseSections = ['Cookies', 'Headers', 'Body'] as const\ntype Filter = 'All' | (typeof responseSections)[number]\nconst activeFilter = ref<Filter>('All')\n\nconst filters = computed<Filter[]>(() => ['All', ...responseSections])\n\nconst filterIds = computed<Record<Filter, string>>(() => ({\n All: useId(),\n Cookies: useId(),\n Headers: useId(),\n Body: useId(),\n}))\n\n/** Threshold for virtualizing response bodies in bytes */\nconst VIRTUALIZATION_THRESHOLD = 200_000\nconst shouldVirtualize = computed(() => {\n if (!response || !('size' in response)) {\n return false\n }\n\n // Get content type from headers\n const contentType =\n response.headers?.['content-type'] || response.headers?.['Content-Type']\n\n // If no content type or response size is small, don't virtualize\n if (!contentType || (response.size ?? 0) <= VIRTUALIZATION_THRESHOLD) {\n return false\n }\n\n // Do not virtualize html\n if (contentType.includes('text/html')) {\n return false\n }\n\n // Check if content type matches any text-based type\n const isTextBased = textMediaTypes.some((type) => contentType.includes(type))\n\n return isTextBased && (response.size ?? 0) > VIRTUALIZATION_THRESHOLD\n})\n\nconst requestHeaders = computed(() => {\n const headers = requestPayload?.[1]?.headers\n if (!headers) {\n return []\n }\n\n // Normalise via the Headers constructor, and then spread\n return [...new Headers(headers)].map(([name, value]) => ({\n name,\n value,\n required: false,\n }))\n})\n\nconst isSectionVisible = (\n section: (typeof responseSections)[number] | 'All',\n) => {\n if (activeFilter.value === 'All' || activeFilter.value === section) {\n return true\n }\n return false\n}\n\ndefineExpose({\n responseHeaders,\n responseCookies,\n requestHeaders,\n shouldVirtualize,\n activeFilter,\n filters,\n})\n\nconst filterLabels = computed(() => ({\n All: translate('apiClient.sectionFilter.all'),\n Auth: translate('apiClient.sectionFilter.auth'),\n Variables: translate('apiClient.sectionFilter.variables'),\n Cookies: translate('apiClient.sectionFilter.cookies'),\n Headers: translate('apiClient.sectionFilter.headers'),\n Query: translate('apiClient.sectionFilter.query'),\n Body: translate('apiClient.sectionFilter.body'),\n}))\n</script>\n<template>\n <!-- Bound the stacked response section so long bodies keep their own scroll area. -->\n <ViewLayoutSection\n :aria-label=\"translate('apiClient.responseBlock.response')\"\n class=\"max-xl:max-h-full\">\n <template #title>\n <div class=\"flex h-8 flex-1 items-center\">\n <div\n aria-live=\"polite\"\n class=\"flex items-center\"\n :class=\"{ 'animate-response-heading': response }\">\n <span class=\"response-heading pointer-events-none absolute\">{{\n translate('apiClient.responseBlock.response')\n }}</span>\n <ResponseMetaInformation\n v-if=\"response\"\n class=\"animate-response-children\"\n :eventBus=\"eventBus\"\n :response=\"response\" />\n </div>\n <SectionFilter\n v-model=\"activeFilter\"\n :filters=\"filters\"\n :labels=\"filterLabels\" />\n </div>\n </template>\n <div\n :id=\"filterIds.All\"\n class=\"custom-scroll response-section-content relative grid h-full justify-stretch\"\n :class=\"{\n 'content-start': response,\n }\"\n :role=\"activeFilter === 'All' && response ? 'tabpanel' : 'none'\">\n <template v-if=\"!response\">\n <ResponseEmpty\n :appVersion=\"appVersion\"\n :executionDisabled\n :layout=\"layout\"\n :totalPerformedRequests=\"totalPerformedRequests\"\n @addRequest=\"\n eventBus.emit('ui:open:command-palette', {\n action: 'create-request',\n payload: undefined,\n })\n \"\n @openCommandPalette=\"eventBus.emit('ui:open:command-palette')\"\n @sendRequest=\"eventBus.emit('operation:send:request:hotkey')\" />\n </template>\n <template v-else>\n <!-- Cookies section -->\n <ResponseCookies\n v-if=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n class=\"response-section-content-cookies\"\n :cookies=\"responseCookies\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n <!-- Request headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"requestHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.requestHeaders') }}\n </template>\n </HeadersComponent>\n <!-- Response headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.responseHeaders') }}\n </template>\n </HeadersComponent>\n\n <!-- Inject response section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.response.component\"\n v-if=\"plugin?.components?.response\"\n v-show=\"activeFilter === 'All'\"\n v-bind=\"plugin.components.response.additionalProps\" />\n </ScalarErrorBoundary>\n\n <template v-if=\"activeFilter === 'All' || activeFilter === 'Body'\">\n <!-- Streaming response body -->\n <ResponseBodyStreaming\n v-if=\"'reader' in response\"\n :id=\"filterIds.Body\"\n class=\"response-section-content-body\"\n :contentType=\"responseContentType\"\n :reader=\"response.reader\" />\n\n <!-- Virtualized Text for massive responses -->\n <ResponseBodyVirtual\n v-else-if=\"shouldVirtualize && typeof response?.data === 'string'\"\n :id=\"filterIds.Body\"\n :content=\"response!.data\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n\n <!-- Regular response body -->\n <ResponseBody\n v-else\n :id=\"filterIds.Body\"\n :active=\"true\"\n class=\"response-section-content-body\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n layout=\"client\"\n :plugins=\"plugins\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\"\n :title=\"translate('apiClient.responseBlock.body')\" />\n </template>\n </template>\n <ResponseLoadingOverlay :eventBus=\"eventBus\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.animate-response-heading .response-heading {\n animation: push-response 0.2s ease-in-out forwards;\n opacity: 1;\n}\n@keyframes push-response {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(-4px);\n }\n}\n.animate-response-heading .animate-response-children {\n animation: response-spans 0.2s ease-in-out forwards 0.05s;\n opacity: 0;\n}\n\n@keyframes response-spans {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ResponseBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/response-block/ResponseBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { RequestPayload } from '@scalar/workspace-store/request-example'\nimport { computed, ref, useId } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ResponseInstance } from '@/v2/blocks/operation-block/helpers/send-request'\nimport HeadersComponent from '@/v2/blocks/response-block/components/Headers.vue'\nimport ResponseBody from '@/v2/blocks/response-block/components/ResponseBody.vue'\nimport ResponseBodyStreaming from '@/v2/blocks/response-block/components/ResponseBodyStreaming.vue'\nimport ResponseBodyVirtual from '@/v2/blocks/response-block/components/ResponseBodyVirtual.vue'\nimport ResponseCookies from '@/v2/blocks/response-block/components/ResponseCookies.vue'\nimport ResponseEmpty from '@/v2/blocks/response-block/components/ResponseEmpty.vue'\nimport ResponseLoadingOverlay from '@/v2/blocks/response-block/components/ResponseLoadingOverlay.vue'\nimport ResponseMetaInformation from '@/v2/blocks/response-block/components/ResponseMetaInformation.vue'\nimport { textMediaTypes } from '@/v2/blocks/response-block/helpers/media-types'\nimport { parseSetCookie } from '@/v2/blocks/response-block/helpers/parse-set-cookie'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nconst {\n layout,\n totalPerformedRequests,\n response,\n requestPayload,\n requestError,\n} = defineProps<{\n /** Wait for the selected external request example before sending. */\n executionDisabled?: boolean\n /** Failure retained until the next request or operation change. */\n requestError?: Error | null\n /** Preprocessed response */\n response: ResponseInstance | null\n /** Original request as a [url, RequestInit] tuple */\n requestPayload: RequestPayload | null\n /** Client layout */\n layout: ClientLayout\n /** Total number of performed requests */\n totalPerformedRequests: number\n /** Application version */\n appVersion: string\n /** Registered app plugins */\n plugins: ClientPlugin[]\n /** Workspace event bus */\n eventBus: WorkspaceEventBus\n}>()\n\nconst { translate } = useLocalization()\n\n/** Browsers hide CORS details, so these messages warrant guidance, not a diagnosis. */\nconst showNetworkErrorHelp = computed<boolean>(\n () =>\n !isElectron() &&\n requestError?.name === 'TypeError' &&\n [\n 'Failed to fetch',\n 'Load failed',\n 'NetworkError when attempting to fetch resource.',\n ].includes(requestError.message),\n)\n\n// Headers\nconst responseHeaders = computed(() => {\n const headers = response?.headers\n\n return headers\n ? Object.keys(headers).map((key) => ({\n name: key,\n value: headers[key] ?? '',\n }))\n : []\n})\n\nconst responseContentType = computed(\n () => response?.headers['content-type'] ?? response?.headers['Content-Type'],\n)\n\n// Cookies\nconst responseCookies = computed(\n () =>\n response?.cookieHeaderKeys\n .map((setCookieValue) => parseSetCookie(setCookieValue))\n .filter(isDefined) ?? [],\n)\n\nconst responseSections = ['Cookies', 'Headers', 'Body'] as const\ntype Filter = 'All' | (typeof responseSections)[number]\nconst activeFilter = ref<Filter>('All')\n\nconst filters = computed<Filter[]>(() => ['All', ...responseSections])\n\nconst filterIds = computed<Record<Filter, string>>(() => ({\n All: useId(),\n Cookies: useId(),\n Headers: useId(),\n Body: useId(),\n}))\n\n/** Threshold for virtualizing response bodies in bytes */\nconst VIRTUALIZATION_THRESHOLD = 200_000\nconst shouldVirtualize = computed(() => {\n if (!response || !('size' in response)) {\n return false\n }\n\n // Get content type from headers\n const contentType =\n response.headers?.['content-type'] || response.headers?.['Content-Type']\n\n // If no content type or response size is small, don't virtualize\n if (!contentType || (response.size ?? 0) <= VIRTUALIZATION_THRESHOLD) {\n return false\n }\n\n // Do not virtualize html\n if (contentType.includes('text/html')) {\n return false\n }\n\n // Check if content type matches any text-based type\n const isTextBased = textMediaTypes.some((type) => contentType.includes(type))\n\n return isTextBased && (response.size ?? 0) > VIRTUALIZATION_THRESHOLD\n})\n\nconst requestHeaders = computed(() => {\n const headers = requestPayload?.[1]?.headers\n if (!headers) {\n return []\n }\n\n // Normalise via the Headers constructor, and then spread\n return [...new Headers(headers)].map(([name, value]) => ({\n name,\n value,\n required: false,\n }))\n})\n\nconst isSectionVisible = (\n section: (typeof responseSections)[number] | 'All',\n) => {\n if (activeFilter.value === 'All' || activeFilter.value === section) {\n return true\n }\n return false\n}\n\ndefineExpose({\n responseHeaders,\n responseCookies,\n requestHeaders,\n shouldVirtualize,\n activeFilter,\n filters,\n})\n\nconst filterLabels = computed(() => ({\n All: translate('apiClient.sectionFilter.all'),\n Auth: translate('apiClient.sectionFilter.auth'),\n Variables: translate('apiClient.sectionFilter.variables'),\n Cookies: translate('apiClient.sectionFilter.cookies'),\n Headers: translate('apiClient.sectionFilter.headers'),\n Query: translate('apiClient.sectionFilter.query'),\n Body: translate('apiClient.sectionFilter.body'),\n}))\n</script>\n<template>\n <!-- Bound the stacked response section so long bodies keep their own scroll area. -->\n <ViewLayoutSection\n :aria-label=\"translate('apiClient.responseBlock.response')\"\n class=\"max-xl:max-h-full\">\n <template #title>\n <div class=\"flex h-8 flex-1 items-center\">\n <div\n aria-live=\"polite\"\n class=\"flex items-center\"\n :class=\"{ 'animate-response-heading': response }\">\n <span class=\"response-heading pointer-events-none absolute\">{{\n translate('apiClient.responseBlock.response')\n }}</span>\n <ResponseMetaInformation\n v-if=\"response\"\n class=\"animate-response-children\"\n :eventBus=\"eventBus\"\n :response=\"response\" />\n </div>\n <SectionFilter\n v-model=\"activeFilter\"\n :filters=\"filters\"\n :labels=\"filterLabels\" />\n </div>\n </template>\n <div\n :id=\"filterIds.All\"\n class=\"custom-scroll response-section-content relative grid h-full justify-stretch\"\n :class=\"{\n 'content-start': response,\n }\"\n :role=\"activeFilter === 'All' && response ? 'tabpanel' : 'none'\">\n <div\n v-if=\"requestError\"\n class=\"flex flex-col gap-3 p-4 text-sm\"\n role=\"alert\">\n <h3 class=\"text-c-1 font-medium\">\n {{ translate('apiClient.responseBlock.requestFailed') }}\n </h3>\n <p class=\"text-c-2 break-words\">{{ requestError.message }}</p>\n <p\n v-if=\"showNetworkErrorHelp\"\n class=\"text-c-2 leading-relaxed\">\n {{ translate('apiClient.responseBlock.networkErrorHelp') }}\n </p>\n </div>\n <template v-else-if=\"!response\">\n <ResponseEmpty\n :appVersion=\"appVersion\"\n :executionDisabled\n :layout=\"layout\"\n :totalPerformedRequests=\"totalPerformedRequests\"\n @addRequest=\"\n eventBus.emit('ui:open:command-palette', {\n action: 'create-request',\n payload: undefined,\n })\n \"\n @openCommandPalette=\"eventBus.emit('ui:open:command-palette')\"\n @sendRequest=\"eventBus.emit('operation:send:request:hotkey')\" />\n </template>\n <template v-else>\n <!-- Cookies section -->\n <ResponseCookies\n v-if=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n class=\"response-section-content-cookies\"\n :cookies=\"responseCookies\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n <!-- Request headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"requestHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.requestHeaders') }}\n </template>\n </HeadersComponent>\n <!-- Response headers section -->\n <HeadersComponent\n v-if=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n class=\"response-section-content-headers\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\">\n <template #title>\n {{ translate('apiClient.responseBlock.responseHeaders') }}\n </template>\n </HeadersComponent>\n\n <!-- Inject response section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.response.component\"\n v-if=\"plugin?.components?.response\"\n v-show=\"activeFilter === 'All'\"\n v-bind=\"plugin.components.response.additionalProps\" />\n </ScalarErrorBoundary>\n\n <template v-if=\"activeFilter === 'All' || activeFilter === 'Body'\">\n <!-- Streaming response body -->\n <ResponseBodyStreaming\n v-if=\"'reader' in response\"\n :id=\"filterIds.Body\"\n class=\"response-section-content-body\"\n :contentType=\"responseContentType\"\n :reader=\"response.reader\" />\n\n <!-- Virtualized Text for massive responses -->\n <ResponseBodyVirtual\n v-else-if=\"shouldVirtualize && typeof response?.data === 'string'\"\n :id=\"filterIds.Body\"\n :content=\"response!.data\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\" />\n\n <!-- Regular response body -->\n <ResponseBody\n v-else\n :id=\"filterIds.Body\"\n :active=\"true\"\n class=\"response-section-content-body\"\n :data=\"response?.data\"\n :headers=\"responseHeaders\"\n layout=\"client\"\n :plugins=\"plugins\"\n :role=\"activeFilter === 'All' ? 'none' : 'tabpanel'\"\n :title=\"translate('apiClient.responseBlock.body')\" />\n </template>\n </template>\n <ResponseLoadingOverlay :eventBus=\"eventBus\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.animate-response-heading .response-heading {\n animation: push-response 0.2s ease-in-out forwards;\n opacity: 1;\n}\n@keyframes push-response {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(-4px);\n }\n}\n.animate-response-heading .animate-response-children {\n animation: response-spans 0.2s ease-in-out forwards 0.05s;\n opacity: 0;\n}\n\n@keyframes response-spans {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n</style>\n"],"mappings":""}
|