@scalar/api-client 3.20.0 → 3.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/components/HttpMethod/HttpMethod.vue.d.ts +2 -2
  3. package/dist/components/HttpMethod/HttpMethod.vue.d.ts.map +1 -1
  4. package/dist/components/HttpMethod/HttpMethod.vue.js +1 -1
  5. package/dist/components/HttpMethod/HttpMethod.vue.js.map +1 -1
  6. package/dist/components/HttpMethod/HttpMethod.vue.script.js +15 -7
  7. package/dist/components/HttpMethod/HttpMethod.vue.script.js.map +1 -1
  8. package/dist/style.css +47 -42
  9. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts +1 -2
  10. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
  11. package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
  12. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +11 -0
  13. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
  14. package/dist/v2/blocks/operation-block/components/Header.vue.d.ts +1 -2
  15. package/dist/v2/blocks/operation-block/components/Header.vue.d.ts.map +1 -1
  16. package/dist/v2/blocks/operation-block/components/Header.vue.js +1 -1
  17. package/dist/v2/blocks/operation-block/components/Header.vue.js.map +1 -1
  18. package/dist/v2/blocks/operation-block/components/Header.vue.script.js.map +1 -1
  19. package/dist/v2/blocks/operation-block/components/OpenApiClientButton.vue.d.ts.map +1 -1
  20. package/dist/v2/blocks/operation-block/components/OpenApiClientButton.vue.js +1 -1
  21. package/dist/v2/blocks/operation-block/components/OpenApiClientButton.vue.js.map +1 -1
  22. package/dist/v2/blocks/operation-block/components/OpenApiClientButton.vue.script.js +2 -1
  23. package/dist/v2/blocks/operation-block/components/OpenApiClientButton.vue.script.js.map +1 -1
  24. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-response.d.ts +1 -2
  25. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-response.d.ts.map +1 -1
  26. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-response.js.map +1 -1
  27. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts +1 -2
  28. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts.map +1 -1
  29. package/dist/v2/blocks/operation-block/helpers/send-request.js.map +1 -1
  30. package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts +3 -2
  31. package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts.map +1 -1
  32. package/dist/v2/blocks/request-block/RequestBlock.vue.js +1 -1
  33. package/dist/v2/blocks/request-block/RequestBlock.vue.js.map +1 -1
  34. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js +17 -2
  35. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
  36. package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts +4 -0
  37. package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts.map +1 -1
  38. package/dist/v2/blocks/request-block/components/RequestBody.vue.js +1 -1
  39. package/dist/v2/blocks/request-block/components/RequestBody.vue.js.map +1 -1
  40. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js +8 -5
  41. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js.map +1 -1
  42. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.d.ts +2 -0
  43. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.d.ts.map +1 -1
  44. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.js.map +1 -1
  45. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.script.js +12 -4
  46. package/dist/v2/blocks/request-block/components/RequestBodyForm.vue.script.js.map +1 -1
  47. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.d.ts.map +1 -1
  48. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.js.map +1 -1
  49. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js +13 -3
  50. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js.map +1 -1
  51. package/dist/v2/blocks/request-block/components/RequestParams.vue.d.ts +2 -0
  52. package/dist/v2/blocks/request-block/components/RequestParams.vue.d.ts.map +1 -1
  53. package/dist/v2/blocks/request-block/components/RequestParams.vue.js.map +1 -1
  54. package/dist/v2/blocks/request-block/components/RequestParams.vue.script.js +7 -2
  55. package/dist/v2/blocks/request-block/components/RequestParams.vue.script.js.map +1 -1
  56. package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts +4 -4
  57. package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts.map +1 -1
  58. package/dist/v2/blocks/request-block/components/RequestTable.vue.js +1 -1
  59. package/dist/v2/blocks/request-block/components/RequestTable.vue.js.map +1 -1
  60. package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js +1 -0
  61. package/dist/v2/blocks/request-block/components/RequestTable.vue.script.js.map +1 -1
  62. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts +4 -4
  63. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
  64. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +2 -2
  65. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
  66. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.d.ts.map +1 -1
  67. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js +14 -6
  68. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js.map +1 -1
  69. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.d.ts.map +1 -1
  70. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js +5 -3
  71. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js.map +1 -1
  72. package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts.map +1 -1
  73. package/dist/v2/blocks/response-block/ResponseBlock.vue.js +1 -1
  74. package/dist/v2/blocks/response-block/ResponseBlock.vue.js.map +1 -1
  75. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js +4 -1
  76. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
  77. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts +2 -3
  78. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts.map +1 -1
  79. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js +1 -1
  80. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js.map +1 -1
  81. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js +2 -2
  82. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js.map +1 -1
  83. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.d.ts +1 -2
  84. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.d.ts.map +1 -1
  85. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.js +1 -1
  86. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.js.map +1 -1
  87. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.script.js.map +1 -1
  88. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue.d.ts.map +1 -1
  89. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue.js.map +1 -1
  90. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue.script.js +7 -6
  91. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue.script.js.map +1 -1
  92. package/dist/v2/components/data-table/DataTable.vue.d.ts.map +1 -1
  93. package/dist/v2/components/data-table/DataTable.vue.js.map +1 -1
  94. package/dist/v2/components/data-table/DataTable.vue.script.js +2 -1
  95. package/dist/v2/components/data-table/DataTable.vue.script.js.map +1 -1
  96. package/dist/v2/constants.js +1 -1
  97. package/dist/v2/features/localization/locales/ar.d.ts +4 -0
  98. package/dist/v2/features/localization/locales/ar.d.ts.map +1 -1
  99. package/dist/v2/features/localization/locales/ar.js +8 -2
  100. package/dist/v2/features/localization/locales/ar.js.map +1 -1
  101. package/dist/v2/features/localization/locales/de.d.ts +4 -0
  102. package/dist/v2/features/localization/locales/de.d.ts.map +1 -1
  103. package/dist/v2/features/localization/locales/de.js +8 -2
  104. package/dist/v2/features/localization/locales/de.js.map +1 -1
  105. package/dist/v2/features/localization/locales/es.d.ts +4 -0
  106. package/dist/v2/features/localization/locales/es.d.ts.map +1 -1
  107. package/dist/v2/features/localization/locales/es.js +8 -2
  108. package/dist/v2/features/localization/locales/es.js.map +1 -1
  109. package/dist/v2/features/localization/locales/fr.d.ts +4 -0
  110. package/dist/v2/features/localization/locales/fr.d.ts.map +1 -1
  111. package/dist/v2/features/localization/locales/fr.js +8 -2
  112. package/dist/v2/features/localization/locales/fr.js.map +1 -1
  113. package/dist/v2/features/localization/locales/pt.d.ts +4 -0
  114. package/dist/v2/features/localization/locales/pt.d.ts.map +1 -1
  115. package/dist/v2/features/localization/locales/pt.js +8 -2
  116. package/dist/v2/features/localization/locales/pt.js.map +1 -1
  117. package/dist/v2/features/localization/locales/ru.d.ts +4 -0
  118. package/dist/v2/features/localization/locales/ru.d.ts.map +1 -1
  119. package/dist/v2/features/localization/locales/ru.js +8 -2
  120. package/dist/v2/features/localization/locales/ru.js.map +1 -1
  121. package/dist/v2/features/localization/locales/zh-cn.d.ts +4 -0
  122. package/dist/v2/features/localization/locales/zh-cn.d.ts.map +1 -1
  123. package/dist/v2/features/localization/locales/zh-cn.js +8 -2
  124. package/dist/v2/features/localization/locales/zh-cn.js.map +1 -1
  125. package/dist/v2/features/localization/translations.d.ts +4 -0
  126. package/dist/v2/features/localization/translations.d.ts.map +1 -1
  127. package/dist/v2/features/localization/translations.js +8 -2
  128. package/dist/v2/features/localization/translations.js.map +1 -1
  129. package/dist/v2/features/modal/Modal.vue.d.ts +1 -2
  130. package/dist/v2/features/modal/Modal.vue.d.ts.map +1 -1
  131. package/dist/v2/features/modal/Modal.vue.js.map +1 -1
  132. package/dist/v2/features/modal/Modal.vue.script.js.map +1 -1
  133. package/dist/v2/features/modal/helpers/resolve-route-parameters.d.ts +2 -3
  134. package/dist/v2/features/modal/helpers/resolve-route-parameters.d.ts.map +1 -1
  135. package/dist/v2/features/modal/helpers/resolve-route-parameters.js +8 -7
  136. package/dist/v2/features/modal/helpers/resolve-route-parameters.js.map +1 -1
  137. package/dist/v2/features/modal/hooks/use-modal-sidebar.d.ts +2 -3
  138. package/dist/v2/features/modal/hooks/use-modal-sidebar.d.ts.map +1 -1
  139. package/dist/v2/features/modal/hooks/use-modal-sidebar.js.map +1 -1
  140. package/dist/v2/features/operation/Operation.vue.d.ts +1 -2
  141. package/dist/v2/features/operation/Operation.vue.d.ts.map +1 -1
  142. package/dist/v2/features/operation/Operation.vue.js.map +1 -1
  143. package/dist/v2/features/operation/Operation.vue.script.js.map +1 -1
  144. package/dist/v2/helpers/generate-location-id.d.ts +1 -2
  145. package/dist/v2/helpers/generate-location-id.d.ts.map +1 -1
  146. package/dist/v2/helpers/generate-location-id.js.map +1 -1
  147. package/dist/vue-styles.css +40 -40
  148. package/package.json +11 -11
@@ -1 +1 @@
1
- {"version":3,"file":"RequestParams.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestParams.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarTooltip } from '@scalar/components/tooltip'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed } from 'vue'\n\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTable from './RequestTable.vue'\nimport type { TableRow, TableRowUpsertPayload } from './RequestTableRow.vue'\n\nconst {\n rows,\n exampleKey,\n environment,\n title,\n globalRoute,\n showAddRowPlaceholder = true,\n eventBus,\n} = defineProps<{\n rows: TableRow[]\n exampleKey: string\n title: string\n label?: string\n invalidParams?: Set<string>\n globalRoute?: string\n showAddRowPlaceholder?: boolean\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsert',\n index: number,\n payload: ApiReferenceEvents['operation:upsert:parameter']['payload'] & {\n shouldRenameExpandedRow?: boolean\n },\n ): void\n (e: 'delete', payload: { index: number }): void\n (e: 'deleteAll'): void\n /** Select a value for a grouped global cookie preset at the given row index. */\n (e: 'selectPreset', index: number, value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst showTooltip = computed(() => rows.length > 1)\n\n/** Needed for type guard */\nconst handleUpserRow = (index: number, payload: TableRowUpsertPayload) => {\n const { value, ...rest } = payload\n\n // Type guard here as we cannot add files to params\n if (value instanceof File) {\n return\n }\n\n emit('upsert', index, { ...rest, value: value ?? '' })\n}\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params\"\n :itemCount=\"rows.length\">\n <template #title>{{ title }}</template>\n <template #actions>\n <div\n class=\"text-c-2 request-meta-buttons flex whitespace-nowrap opacity-0 group-hover/params:opacity-100 has-[:focus-visible]:opacity-100\">\n <ScalarTooltip\n v-if=\"showTooltip\"\n :content=\"\n translate('apiClient.requestParams.clearOptionalParameters')\n \"\n placement=\"left\">\n <ScalarButton\n :aria-label=\"\n translate('apiClient.requestParams.clearAll', { title })\n \"\n class=\"pr-0.75 pl-1 transition-none\"\n size=\"sm\"\n variant=\"ghost\"\n @click.stop=\"emit('deleteAll')\">\n {{ translate('apiClient.requestParams.clear') }}\n </ScalarButton>\n </ScalarTooltip>\n </div>\n </template>\n <RequestTable\n class=\"flex-1\"\n :columns=\"['32px', '', '']\"\n :data=\"rows\"\n :environment=\"environment\"\n :exampleKey=\"exampleKey\"\n :globalRoute=\"globalRoute\"\n :invalidParams=\"invalidParams\"\n :label=\"label\"\n :showAddRowPlaceholder=\"showAddRowPlaceholder\"\n @deleteRow=\"(index) => emit('delete', { index })\"\n @navigate=\"(route) => eventBus.emit('ui:navigate', route)\"\n @selectPreset=\"(index, value) => emit('selectPreset', index, value)\"\n @upsertRow=\"handleUpserRow\" />\n </CollapsibleSection>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RequestParams.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestParams.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarTooltip } from '@scalar/components/tooltip'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed } from 'vue'\n\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTable from './RequestTable.vue'\nimport type { TableRow, TableRowUpsertPayload } from './RequestTableRow.vue'\n\nconst {\n rows,\n exampleKey,\n environment,\n title,\n globalRoute,\n showAddRowPlaceholder = true,\n eventBus,\n} = defineProps<{\n rows: TableRow[]\n exampleKey: string\n title: string\n label?: string\n /** Explain restrictions on parameter editing when needed. */\n description?: string\n invalidParams?: Set<string>\n globalRoute?: string\n showAddRowPlaceholder?: boolean\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsert',\n index: number,\n payload: ApiReferenceEvents['operation:upsert:parameter']['payload'] & {\n shouldRenameExpandedRow?: boolean\n },\n ): void\n (e: 'delete', payload: { index: number }): void\n (e: 'deleteAll'): void\n /** Select a value for a grouped global cookie preset at the given row index. */\n (e: 'selectPreset', index: number, value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst showTooltip = computed(() => rows.length > 1)\n\n/** Needed for type guard */\nconst handleUpserRow = (index: number, payload: TableRowUpsertPayload) => {\n const { value, ...rest } = payload\n\n // Type guard here as we cannot add files to params\n if (value instanceof File) {\n return\n }\n\n emit('upsert', index, { ...rest, value: value ?? '' })\n}\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params\"\n :itemCount=\"rows.length\">\n <template #title>{{ title }}</template>\n <template #actions>\n <div\n class=\"text-c-2 request-meta-buttons flex whitespace-nowrap opacity-0 group-hover/params:opacity-100 has-[:focus-visible]:opacity-100\">\n <ScalarTooltip\n v-if=\"showTooltip\"\n :content=\"\n translate('apiClient.requestParams.clearOptionalParameters')\n \"\n placement=\"left\">\n <ScalarButton\n :aria-label=\"\n translate('apiClient.requestParams.clearAll', { title })\n \"\n class=\"pr-0.75 pl-1 transition-none\"\n size=\"sm\"\n variant=\"ghost\"\n @click.stop=\"emit('deleteAll')\">\n {{ translate('apiClient.requestParams.clear') }}\n </ScalarButton>\n </ScalarTooltip>\n </div>\n </template>\n <p\n v-if=\"description\"\n class=\"text-c-2 px-3 py-2 text-sm\">\n {{ description }}\n </p>\n <RequestTable\n class=\"flex-1\"\n :columns=\"['32px', '', '']\"\n :data=\"rows\"\n :environment=\"environment\"\n :exampleKey=\"exampleKey\"\n :globalRoute=\"globalRoute\"\n :invalidParams=\"invalidParams\"\n :label=\"label\"\n :showAddRowPlaceholder=\"showAddRowPlaceholder\"\n @deleteRow=\"(index) => emit('delete', { index })\"\n @navigate=\"(route) => eventBus.emit('ui:navigate', route)\"\n @selectPreset=\"(index, value) => emit('selectPreset', index, value)\"\n @upsertRow=\"handleUpserRow\" />\n </CollapsibleSection>\n</template>\n"],"mappings":""}
@@ -1,11 +1,15 @@
1
1
  import { useLocalization } from "../../../features/localization/index.js";
2
2
  import RequestTable_default from "./RequestTable.vue.js";
3
3
  import CollapsibleSection_default from "../../../components/layout/CollapsibleSection.vue.js";
4
- import { computed, createBlock, createCommentVNode, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, toDisplayString, unref, withCtx, withModifiers } from "vue";
4
+ import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, toDisplayString, unref, withCtx, withModifiers } from "vue";
5
5
  import { ScalarButton } from "@scalar/components/button";
6
6
  import { ScalarTooltip } from "@scalar/components/tooltip";
7
7
  //#region src/v2/blocks/request-block/components/RequestParams.vue?vue&type=script&setup=true&lang.ts
8
8
  var _hoisted_1 = { class: "text-c-2 request-meta-buttons flex whitespace-nowrap opacity-0 group-hover/params:opacity-100 has-[:focus-visible]:opacity-100" };
9
+ var _hoisted_2 = {
10
+ key: 0,
11
+ class: "text-c-2 px-3 py-2 text-sm"
12
+ };
9
13
  var RequestParams_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
10
14
  __name: "RequestParams",
11
15
  props: {
@@ -13,6 +17,7 @@ var RequestParams_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
13
17
  exampleKey: {},
14
18
  title: {},
15
19
  label: {},
20
+ description: {},
16
21
  invalidParams: {},
17
22
  globalRoute: {},
18
23
  showAddRowPlaceholder: {
@@ -64,7 +69,7 @@ var RequestParams_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
64
69
  }, 8, ["aria-label"])]),
65
70
  _: 1
66
71
  }, 8, ["content"])) : createCommentVNode("", true)])]),
67
- default: withCtx(() => [createVNode(RequestTable_default, {
72
+ default: withCtx(() => [__props.description ? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString(__props.description), 1)) : createCommentVNode("", true), createVNode(RequestTable_default, {
68
73
  class: "flex-1",
69
74
  columns: [
70
75
  "32px",
@@ -1 +1 @@
1
- {"version":3,"file":"RequestParams.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestParams.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarTooltip } from '@scalar/components/tooltip'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed } from 'vue'\n\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTable from './RequestTable.vue'\nimport type { TableRow, TableRowUpsertPayload } from './RequestTableRow.vue'\n\nconst {\n rows,\n exampleKey,\n environment,\n title,\n globalRoute,\n showAddRowPlaceholder = true,\n eventBus,\n} = defineProps<{\n rows: TableRow[]\n exampleKey: string\n title: string\n label?: string\n invalidParams?: Set<string>\n globalRoute?: string\n showAddRowPlaceholder?: boolean\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsert',\n index: number,\n payload: ApiReferenceEvents['operation:upsert:parameter']['payload'] & {\n shouldRenameExpandedRow?: boolean\n },\n ): void\n (e: 'delete', payload: { index: number }): void\n (e: 'deleteAll'): void\n /** Select a value for a grouped global cookie preset at the given row index. */\n (e: 'selectPreset', index: number, value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst showTooltip = computed(() => rows.length > 1)\n\n/** Needed for type guard */\nconst handleUpserRow = (index: number, payload: TableRowUpsertPayload) => {\n const { value, ...rest } = payload\n\n // Type guard here as we cannot add files to params\n if (value instanceof File) {\n return\n }\n\n emit('upsert', index, { ...rest, value: value ?? '' })\n}\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params\"\n :itemCount=\"rows.length\">\n <template #title>{{ title }}</template>\n <template #actions>\n <div\n class=\"text-c-2 request-meta-buttons flex whitespace-nowrap opacity-0 group-hover/params:opacity-100 has-[:focus-visible]:opacity-100\">\n <ScalarTooltip\n v-if=\"showTooltip\"\n :content=\"\n translate('apiClient.requestParams.clearOptionalParameters')\n \"\n placement=\"left\">\n <ScalarButton\n :aria-label=\"\n translate('apiClient.requestParams.clearAll', { title })\n \"\n class=\"pr-0.75 pl-1 transition-none\"\n size=\"sm\"\n variant=\"ghost\"\n @click.stop=\"emit('deleteAll')\">\n {{ translate('apiClient.requestParams.clear') }}\n </ScalarButton>\n </ScalarTooltip>\n </div>\n </template>\n <RequestTable\n class=\"flex-1\"\n :columns=\"['32px', '', '']\"\n :data=\"rows\"\n :environment=\"environment\"\n :exampleKey=\"exampleKey\"\n :globalRoute=\"globalRoute\"\n :invalidParams=\"invalidParams\"\n :label=\"label\"\n :showAddRowPlaceholder=\"showAddRowPlaceholder\"\n @deleteRow=\"(index) => emit('delete', { index })\"\n @navigate=\"(route) => eventBus.emit('ui:navigate', route)\"\n @selectPreset=\"(index, value) => emit('selectPreset', index, value)\"\n @upsertRow=\"handleUpserRow\" />\n </CollapsibleSection>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCA,MAAM,OAAO;EAcb,MAAM,EAAE,cAAc,gBAAgB;EAEtC,MAAM,cAAc,eAAe,QAAA,KAAK,SAAS,CAAC;;EAGlD,MAAM,kBAAkB,OAAe,YAAmC;GACxE,MAAM,EAAE,OAAO,GAAG,SAAS;GAG3B,IAAI,iBAAiB,MACnB;GAGF,KAAK,UAAU,OAAO;IAAE,GAAG;IAAM,OAAO,SAAS;GAAG,CAAC;EACvD;;uBAGE,YAwCqB,MAAA,0BAAA,GAAA;IAvCnB,OAAM;IACL,WAAW,QAAA,KAAK;;IACN,OAAK,cAAY,CAAA,gBAAA,gBAAR,QAAA,KAAK,GAAA,CAAA,CAAA,CAAA;IACd,SAAO,cAoBV,CAnBN,mBAmBM,OAnBN,YAmBM,CAhBI,YAAA,SAAA,UAAA,GADR,YAgBgB,MAAA,aAAA,GAAA;;KAdb,SAAsB,MAAA,SAAA,CAAS,CAAA,iDAAA;KAGhC,WAAU;;4BAUK,CATf,YASe,MAAA,YAAA,GAAA;MARZ,cAA2B,MAAA,SAAA,CAAS,CAAA,oCAAA,EAAA,OAAuC,QAAA,MAAK,CAAA;MAGjF,OAAM;MACN,MAAK;MACL,SAAQ;MACP,SAAK,OAAA,OAAA,OAAA,KAAA,eAAA,WAAO,KAAI,WAAA,GAAA,CAAA,MAAA,CAAA;;6BAC+B,CAAA,gBAAA,gBAA7C,MAAA,SAAA,CAAS,CAAA,+BAAA,CAAA,GAAA,CAAA,CAAA,CAAA;;;;;2BAkBY,CAbhC,YAagC,sBAAA;KAZ9B,OAAM;KACL,SAAS;MAAA;MAAA;MAAA;KAAA;KACT,MAAM,QAAA;KACN,aAAa,QAAA;KACb,YAAY,QAAA;KACZ,aAAa,QAAA;KACb,eAAe,QAAA;KACf,OAAO,QAAA;KACP,uBAAuB,QAAA;KACvB,aAAS,OAAA,OAAA,OAAA,MAAG,UAAU,KAAI,UAAA,EAAa,MAAK,CAAA;KAC5C,YAAQ,OAAA,OAAA,OAAA,MAAG,UAAU,QAAA,SAAS,KAAI,eAAgB,KAAK;KACvD,gBAAY,OAAA,OAAA,OAAA,MAAG,OAAO,UAAU,KAAI,gBAAiB,OAAO,KAAK;KACjE,aAAW"}
1
+ {"version":3,"file":"RequestParams.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestParams.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarTooltip } from '@scalar/components/tooltip'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed } from 'vue'\n\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTable from './RequestTable.vue'\nimport type { TableRow, TableRowUpsertPayload } from './RequestTableRow.vue'\n\nconst {\n rows,\n exampleKey,\n environment,\n title,\n globalRoute,\n showAddRowPlaceholder = true,\n eventBus,\n} = defineProps<{\n rows: TableRow[]\n exampleKey: string\n title: string\n label?: string\n /** Explain restrictions on parameter editing when needed. */\n description?: string\n invalidParams?: Set<string>\n globalRoute?: string\n showAddRowPlaceholder?: boolean\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsert',\n index: number,\n payload: ApiReferenceEvents['operation:upsert:parameter']['payload'] & {\n shouldRenameExpandedRow?: boolean\n },\n ): void\n (e: 'delete', payload: { index: number }): void\n (e: 'deleteAll'): void\n /** Select a value for a grouped global cookie preset at the given row index. */\n (e: 'selectPreset', index: number, value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst showTooltip = computed(() => rows.length > 1)\n\n/** Needed for type guard */\nconst handleUpserRow = (index: number, payload: TableRowUpsertPayload) => {\n const { value, ...rest } = payload\n\n // Type guard here as we cannot add files to params\n if (value instanceof File) {\n return\n }\n\n emit('upsert', index, { ...rest, value: value ?? '' })\n}\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params\"\n :itemCount=\"rows.length\">\n <template #title>{{ title }}</template>\n <template #actions>\n <div\n class=\"text-c-2 request-meta-buttons flex whitespace-nowrap opacity-0 group-hover/params:opacity-100 has-[:focus-visible]:opacity-100\">\n <ScalarTooltip\n v-if=\"showTooltip\"\n :content=\"\n translate('apiClient.requestParams.clearOptionalParameters')\n \"\n placement=\"left\">\n <ScalarButton\n :aria-label=\"\n translate('apiClient.requestParams.clearAll', { title })\n \"\n class=\"pr-0.75 pl-1 transition-none\"\n size=\"sm\"\n variant=\"ghost\"\n @click.stop=\"emit('deleteAll')\">\n {{ translate('apiClient.requestParams.clear') }}\n </ScalarButton>\n </ScalarTooltip>\n </div>\n </template>\n <p\n v-if=\"description\"\n class=\"text-c-2 px-3 py-2 text-sm\">\n {{ description }}\n </p>\n <RequestTable\n class=\"flex-1\"\n :columns=\"['32px', '', '']\"\n :data=\"rows\"\n :environment=\"environment\"\n :exampleKey=\"exampleKey\"\n :globalRoute=\"globalRoute\"\n :invalidParams=\"invalidParams\"\n :label=\"label\"\n :showAddRowPlaceholder=\"showAddRowPlaceholder\"\n @deleteRow=\"(index) => emit('delete', { index })\"\n @navigate=\"(route) => eventBus.emit('ui:navigate', route)\"\n @selectPreset=\"(index, value) => emit('selectPreset', index, value)\"\n @upsertRow=\"handleUpserRow\" />\n </CollapsibleSection>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsCA,MAAM,OAAO;EAcb,MAAM,EAAE,cAAc,gBAAgB;EAEtC,MAAM,cAAc,eAAe,QAAA,KAAK,SAAS,CAAC;;EAGlD,MAAM,kBAAkB,OAAe,YAAmC;GACxE,MAAM,EAAE,OAAO,GAAG,SAAS;GAG3B,IAAI,iBAAiB,MACnB;GAGF,KAAK,UAAU,OAAO;IAAE,GAAG;IAAM,OAAO,SAAS;GAAG,CAAC;EACvD;;uBAGE,YA6CqB,MAAA,0BAAA,GAAA;IA5CnB,OAAM;IACL,WAAW,QAAA,KAAK;;IACN,OAAK,cAAY,CAAA,gBAAA,gBAAR,QAAA,KAAK,GAAA,CAAA,CAAA,CAAA;IACd,SAAO,cAoBV,CAnBN,mBAmBM,OAnBN,YAmBM,CAhBI,YAAA,SAAA,UAAA,GADR,YAgBgB,MAAA,aAAA,GAAA;;KAdb,SAAsB,MAAA,SAAA,CAAS,CAAA,iDAAA;KAGhC,WAAU;;4BAUK,CATf,YASe,MAAA,YAAA,GAAA;MARZ,cAA2B,MAAA,SAAA,CAAS,CAAA,oCAAA,EAAA,OAAuC,QAAA,MAAK,CAAA;MAGjF,OAAM;MACN,MAAK;MACL,SAAQ;MACP,SAAK,OAAA,OAAA,OAAA,KAAA,eAAA,WAAO,KAAI,WAAA,GAAA,CAAA,MAAA,CAAA;;6BAC+B,CAAA,gBAAA,gBAA7C,MAAA,SAAA,CAAS,CAAA,+BAAA,CAAA,GAAA,CAAA,CAAA,CAAA;;;;;2BAShB,CAHI,QAAA,eAAA,UAAA,GADR,mBAII,KAJJ,YAII,gBADC,QAAA,WAAW,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,GAEhB,YAagC,sBAAA;KAZ9B,OAAM;KACL,SAAS;MAAA;MAAA;MAAA;KAAA;KACT,MAAM,QAAA;KACN,aAAa,QAAA;KACb,YAAY,QAAA;KACZ,aAAa,QAAA;KACb,eAAe,QAAA;KACf,OAAO,QAAA;KACP,uBAAuB,QAAA;KACvB,aAAS,OAAA,OAAA,OAAA,MAAG,UAAU,KAAI,UAAA,EAAa,MAAK,CAAA;KAC5C,YAAQ,OAAA,OAAA,OAAA,MAAG,UAAU,QAAA,SAAS,KAAI,eAAgB,KAAK;KACvD,gBAAY,OAAA,OAAA,OAAA,MAAG,OAAO,UAAU,KAAI,gBAAiB,OAAO,KAAK;KACjE,aAAW"}
@@ -30,13 +30,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
30
30
  page: "example";
31
31
  documentSlug?: string;
32
32
  path: string;
33
- method: import("@scalar/helpers/http/http-methods").HttpMethod;
33
+ method: string;
34
34
  exampleName: string;
35
35
  } | {
36
36
  page: "operation";
37
37
  path: "overview" | "servers" | "authentication" | "editor";
38
38
  operationPath: string;
39
- method: import("@scalar/helpers/http/http-methods").HttpMethod;
39
+ method: string;
40
40
  documentSlug?: string;
41
41
  })) | undefined>) => any;
42
42
  upsertRow: (index: number, payload: TableRowUpsertPayload) => any;
@@ -61,13 +61,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
61
61
  page: "example";
62
62
  documentSlug?: string;
63
63
  path: string;
64
- method: import("@scalar/helpers/http/http-methods").HttpMethod;
64
+ method: string;
65
65
  exampleName: string;
66
66
  } | {
67
67
  page: "operation";
68
68
  path: "overview" | "servers" | "authentication" | "editor";
69
69
  operationPath: string;
70
- method: import("@scalar/helpers/http/http-methods").HttpMethod;
70
+ method: string;
71
71
  documentSlug?: string;
72
72
  })) | undefined>) => any) | undefined;
73
73
  onUpsertRow?: ((index: number, payload: TableRowUpsertPayload) => any) | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"RequestTable.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTable.vue"],"names":[],"mappings":"AAwNA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAwB,EACtB,KAAK,QAAQ,EACb,KAAK,qBAAqB,EAC3B,MAAM,0DAA0D,CAAA;AAQjE,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,uFAAuF;IACvF,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,WAAW,EAAE,kBAAkB,CAAA;CAChC,CAAC;AAuUF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"RequestTable.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTable.vue"],"names":[],"mappings":"AA4NA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAwB,EACtB,KAAK,QAAQ,EACb,KAAK,qBAAqB,EAC3B,MAAM,0DAA0D,CAAA;AAQjE,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,uFAAuF;IACvF,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,WAAW,EAAE,kBAAkB,CAAA;CAChC,CAAC;AA2UF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_
2
2
  import RequestTable_vue_vue_type_script_setup_true_lang_default from "./RequestTable.vue.script.js";
3
3
  /* empty css */
4
4
  //#region src/v2/blocks/request-block/components/RequestTable.vue
5
- var RequestTable_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RequestTable_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-bb7a09e9"]]);
5
+ var RequestTable_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RequestTable_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e29008b7"]]);
6
6
  //#endregion
7
7
  export { RequestTable_default as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"RequestTable.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed } from 'vue'\n\nimport RequestTableRow, {\n type TableRow,\n type TableRowUpsertPayload,\n} from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n data,\n hasCheckboxDisabled,\n deferKeyUpdates,\n showUploadButton,\n showAddRowPlaceholder = true,\n environment,\n} = defineProps<{\n data: TableRow[]\n /** Save key edits on blur so changing a body name does not replace the focused row. */\n deferKeyUpdates?: boolean\n /** Hide the enabled column */\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n showUploadButton?: boolean\n showAddRowPlaceholder?: boolean\n environment: XScalarEnvironment\n}>()\n\n/**\n * Make this component more generic that can be used also for the operation body\n */\nconst emit = defineEmits<{\n (e: 'upsertRow', index: number, payload: TableRowUpsertPayload): void\n (e: 'deleteRow', index: number): void\n\n /**\n * File upload events\n *\n * Each row has its own upload button, so we need to know which row to update\n * when the file is selected.\n */\n (e: 'uploadFile', index: number): void\n (e: 'removeFile', index: number): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset at the given row index. */\n (e: 'selectPreset', index: number, value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst columns = computed(() => {\n if (showUploadButton) {\n return ['36px', '', '', 'minmax(0, 1fr)']\n }\n return ['36px', '', '']\n})\n\n/** Add the last empty row (for ui purposes only) */\nconst displayData = computed(() => {\n if (!showAddRowPlaceholder) {\n return data\n }\n\n const last = data.at(-1)\n\n if (!last || last.name !== '' || last.value !== '') {\n return [...data, { name: '', value: '', isDisabled: true }]\n }\n\n return data\n})\n\n/**\n * Stable identity key for each row so Vue never reuses a RequestTableRow instance for a different\n * parameter or the appended placeholder row. Parameter rows are keyed by their parameter identity —\n * the name plus the value path for expanded object parameters. The parts are combined through\n * JSON.stringify so the name/path boundary is unambiguous (for example `ab` + `['c']` never\n * collides with `a` + `['bc']`). Form rows use the name and its occurrence so repeated\n * multipart fields remain distinct while unrelated rows can move without losing their identity.\n */\nconst getRowKey = (row: TableRow, index: number): string => {\n if (row.originalParameter) {\n return JSON.stringify([\n row.originalParameter.name,\n ...(row.sourceParameterValuePath ?? []),\n ])\n }\n\n const occurrence = displayData.value\n .slice(0, index)\n .filter(\n (other) => !other.originalParameter && other.name === row.name,\n ).length\n return `row:${JSON.stringify([row.name, occurrence])}`\n}\n\n/** Keep an edited row mounted when saving it changes its parameter identity. */\ntype DisplayRow = {\n data: TableRow\n identity: string\n key: symbol\n}\n\nconst pendingUpdates = new Map<symbol, TableRowUpsertPayload>()\n\nconst matchesPendingUpdate = (key: symbol, row: TableRow): boolean => {\n const update = pendingUpdates.get(key)\n return update?.name === row.name && update.value === row.value\n}\n\n// A saved parameter inherits the editor's key. The next placeholder gets a fresh key,\n// so it cannot retain the previous placeholder's text or focused input.\nconst keyedRows = computed<DisplayRow[]>((previous = []) => {\n const available = new Set(previous)\n // Reserve identities still present in the store before transferring an edited key.\n // The appended placeholder is excluded so a newly saved row can inherit its editor.\n const savedIdentities = new Set(data.map(getRowKey))\n const rows = displayData.value.map((row, index) => {\n const identity = getRowKey(row, index)\n const existing = [...available].find((entry) => entry.identity === identity)\n const pending = [...available].find(\n (entry) =>\n !savedIdentities.has(entry.identity) &&\n !entry.data.sourceParameterValuePath &&\n matchesPendingUpdate(entry.key, row),\n )\n const match = existing ?? pending\n\n if (match) {\n available.delete(match)\n if (matchesPendingUpdate(match.key, row)) {\n pendingUpdates.delete(match.key)\n }\n }\n\n return { data: row, identity, key: match?.key ?? Symbol() }\n })\n\n for (const removed of available) {\n pendingUpdates.delete(removed.key)\n }\n\n return rows\n})\n\nconst handleUpsertRow = (\n row: DisplayRow,\n index: number,\n payload: TableRowUpsertPayload,\n): void => {\n // The store may debounce the save. Transfer this key only when the saved row arrives.\n pendingUpdates.set(row.key, payload)\n emit('upsertRow', index, payload)\n}\n</script>\n<template>\n <DataTable\n class=\"group/table flex-1\"\n :columns=\"columns\">\n <DataTableRow class=\"sr-only !block\">\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.enabled') }}\n </DataTableHeader>\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.key') }}\n </DataTableHeader>\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.value') }}\n </DataTableHeader>\n </DataTableRow>\n\n <RequestTableRow\n v-for=\"(row, index) in keyedRows\"\n :key=\"row.key\"\n :data=\"row.data\"\n :deferKeyUpdates=\"deferKeyUpdates\"\n :environment=\"environment\"\n :hasCheckboxDisabled=\"hasCheckboxDisabled\"\n :invalidParams=\"invalidParams\"\n :label=\"label\"\n :showUploadButton=\"showUploadButton\"\n @deleteRow=\"emit('deleteRow', index)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @removeFile=\"emit('removeFile', index)\"\n @selectPreset=\"(value) => emit('selectPreset', index, value)\"\n @uploadFile=\"emit('uploadFile', index)\"\n @upsertRow=\"(payload) => handleUpsertRow(row, index, payload)\" />\n </DataTable>\n</template>\n<style scoped>\n:deep(.code-input-lite__editor) {\n background-color: transparent;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n}\n:deep(.scalar-pill:not(:last-of-type)) {\n margin-right: 0.15em;\n}\n:deep(.scalar-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"RequestTable.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed } from 'vue'\n\nimport RequestTableRow, {\n type TableRow,\n type TableRowUpsertPayload,\n} from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n data,\n hasCheckboxDisabled,\n deferKeyUpdates,\n showUploadButton,\n showAddRowPlaceholder = true,\n environment,\n} = defineProps<{\n data: TableRow[]\n /** Save key edits on blur so changing a body name does not replace the focused row. */\n deferKeyUpdates?: boolean\n /** Hide the enabled column */\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n showUploadButton?: boolean\n showAddRowPlaceholder?: boolean\n environment: XScalarEnvironment\n}>()\n\n/**\n * Make this component more generic that can be used also for the operation body\n */\nconst emit = defineEmits<{\n (e: 'upsertRow', index: number, payload: TableRowUpsertPayload): void\n (e: 'deleteRow', index: number): void\n\n /**\n * File upload events\n *\n * Each row has its own upload button, so we need to know which row to update\n * when the file is selected.\n */\n (e: 'uploadFile', index: number): void\n (e: 'removeFile', index: number): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset at the given row index. */\n (e: 'selectPreset', index: number, value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst columns = computed(() => {\n if (showUploadButton) {\n return ['36px', '', '', 'minmax(0, 1fr)']\n }\n return ['36px', '', '']\n})\n\n/** Add the last empty row (for ui purposes only) */\nconst displayData = computed(() => {\n if (!showAddRowPlaceholder) {\n return data\n }\n\n const last = data.at(-1)\n\n if (!last || last.name !== '' || last.value !== '') {\n return [...data, { name: '', value: '', isDisabled: true }]\n }\n\n return data\n})\n\n/**\n * Stable identity key for each row so Vue never reuses a RequestTableRow instance for a different\n * parameter or the appended placeholder row. Parameter rows are keyed by their parameter identity —\n * the name plus the value path for expanded object parameters. The parts are combined through\n * JSON.stringify so the name/path boundary is unambiguous (for example `ab` + `['c']` never\n * collides with `a` + `['bc']`). Form rows use the name and its occurrence so repeated\n * multipart fields remain distinct while unrelated rows can move without losing their identity.\n */\nconst getRowKey = (row: TableRow, index: number): string => {\n // Body edits retain their row when blur commits a rename after focus moves into the value.\n if (deferKeyUpdates) {\n return `body:${index}`\n }\n if (row.originalParameter) {\n return JSON.stringify([\n row.originalParameter.name,\n ...(row.sourceParameterValuePath ?? []),\n ])\n }\n\n const occurrence = displayData.value\n .slice(0, index)\n .filter(\n (other) => !other.originalParameter && other.name === row.name,\n ).length\n return `row:${JSON.stringify([row.name, occurrence])}`\n}\n\n/** Keep an edited row mounted when saving it changes its parameter identity. */\ntype DisplayRow = {\n data: TableRow\n identity: string\n key: symbol\n}\n\nconst pendingUpdates = new Map<symbol, TableRowUpsertPayload>()\n\nconst matchesPendingUpdate = (key: symbol, row: TableRow): boolean => {\n const update = pendingUpdates.get(key)\n return update?.name === row.name && update.value === row.value\n}\n\n// A saved parameter inherits the editor's key. The next placeholder gets a fresh key,\n// so it cannot retain the previous placeholder's text or focused input.\nconst keyedRows = computed<DisplayRow[]>((previous = []) => {\n const available = new Set(previous)\n // Reserve identities still present in the store before transferring an edited key.\n // The appended placeholder is excluded so a newly saved row can inherit its editor.\n const savedIdentities = new Set(data.map(getRowKey))\n const rows = displayData.value.map((row, index) => {\n const identity = getRowKey(row, index)\n const existing = [...available].find((entry) => entry.identity === identity)\n const pending = [...available].find(\n (entry) =>\n !savedIdentities.has(entry.identity) &&\n !entry.data.sourceParameterValuePath &&\n matchesPendingUpdate(entry.key, row),\n )\n const match = existing ?? pending\n\n if (match) {\n available.delete(match)\n if (matchesPendingUpdate(match.key, row)) {\n pendingUpdates.delete(match.key)\n }\n }\n\n return { data: row, identity, key: match?.key ?? Symbol() }\n })\n\n for (const removed of available) {\n pendingUpdates.delete(removed.key)\n }\n\n return rows\n})\n\nconst handleUpsertRow = (\n row: DisplayRow,\n index: number,\n payload: TableRowUpsertPayload,\n): void => {\n // The store may debounce the save. Transfer this key only when the saved row arrives.\n pendingUpdates.set(row.key, payload)\n emit('upsertRow', index, payload)\n}\n</script>\n<template>\n <DataTable\n class=\"group/table flex-1\"\n :columns=\"columns\">\n <DataTableRow class=\"sr-only !block\">\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.enabled') }}\n </DataTableHeader>\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.key') }}\n </DataTableHeader>\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.value') }}\n </DataTableHeader>\n </DataTableRow>\n\n <RequestTableRow\n v-for=\"(row, index) in keyedRows\"\n :key=\"row.key\"\n :data=\"row.data\"\n :deferKeyUpdates=\"deferKeyUpdates\"\n :environment=\"environment\"\n :hasCheckboxDisabled=\"hasCheckboxDisabled\"\n :invalidParams=\"invalidParams\"\n :label=\"label\"\n :showUploadButton=\"showUploadButton\"\n @deleteRow=\"emit('deleteRow', index)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @removeFile=\"emit('removeFile', index)\"\n @selectPreset=\"(value) => emit('selectPreset', index, value)\"\n @uploadFile=\"emit('uploadFile', index)\"\n @upsertRow=\"(payload) => handleUpsertRow(row, index, payload)\" />\n </DataTable>\n</template>\n<style scoped>\n:deep(.code-input-lite__editor) {\n background-color: transparent;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n}\n:deep(.scalar-pill:not(:last-of-type)) {\n margin-right: 0.15em;\n}\n:deep(.scalar-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n</style>\n"],"mappings":""}
@@ -67,6 +67,7 @@ var RequestTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
67
67
  * multipart fields remain distinct while unrelated rows can move without losing their identity.
68
68
  */
69
69
  const getRowKey = (row, index) => {
70
+ if (__props.deferKeyUpdates) return `body:${index}`;
70
71
  if (row.originalParameter) return JSON.stringify([row.originalParameter.name, ...row.sourceParameterValuePath ?? []]);
71
72
  const occurrence = displayData.value.slice(0, index).filter((other) => !other.originalParameter && other.name === row.name).length;
72
73
  return `row:${JSON.stringify([row.name, occurrence])}`;
@@ -1 +1 @@
1
- {"version":3,"file":"RequestTable.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed } from 'vue'\n\nimport RequestTableRow, {\n type TableRow,\n type TableRowUpsertPayload,\n} from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n data,\n hasCheckboxDisabled,\n deferKeyUpdates,\n showUploadButton,\n showAddRowPlaceholder = true,\n environment,\n} = defineProps<{\n data: TableRow[]\n /** Save key edits on blur so changing a body name does not replace the focused row. */\n deferKeyUpdates?: boolean\n /** Hide the enabled column */\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n showUploadButton?: boolean\n showAddRowPlaceholder?: boolean\n environment: XScalarEnvironment\n}>()\n\n/**\n * Make this component more generic that can be used also for the operation body\n */\nconst emit = defineEmits<{\n (e: 'upsertRow', index: number, payload: TableRowUpsertPayload): void\n (e: 'deleteRow', index: number): void\n\n /**\n * File upload events\n *\n * Each row has its own upload button, so we need to know which row to update\n * when the file is selected.\n */\n (e: 'uploadFile', index: number): void\n (e: 'removeFile', index: number): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset at the given row index. */\n (e: 'selectPreset', index: number, value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst columns = computed(() => {\n if (showUploadButton) {\n return ['36px', '', '', 'minmax(0, 1fr)']\n }\n return ['36px', '', '']\n})\n\n/** Add the last empty row (for ui purposes only) */\nconst displayData = computed(() => {\n if (!showAddRowPlaceholder) {\n return data\n }\n\n const last = data.at(-1)\n\n if (!last || last.name !== '' || last.value !== '') {\n return [...data, { name: '', value: '', isDisabled: true }]\n }\n\n return data\n})\n\n/**\n * Stable identity key for each row so Vue never reuses a RequestTableRow instance for a different\n * parameter or the appended placeholder row. Parameter rows are keyed by their parameter identity —\n * the name plus the value path for expanded object parameters. The parts are combined through\n * JSON.stringify so the name/path boundary is unambiguous (for example `ab` + `['c']` never\n * collides with `a` + `['bc']`). Form rows use the name and its occurrence so repeated\n * multipart fields remain distinct while unrelated rows can move without losing their identity.\n */\nconst getRowKey = (row: TableRow, index: number): string => {\n if (row.originalParameter) {\n return JSON.stringify([\n row.originalParameter.name,\n ...(row.sourceParameterValuePath ?? []),\n ])\n }\n\n const occurrence = displayData.value\n .slice(0, index)\n .filter(\n (other) => !other.originalParameter && other.name === row.name,\n ).length\n return `row:${JSON.stringify([row.name, occurrence])}`\n}\n\n/** Keep an edited row mounted when saving it changes its parameter identity. */\ntype DisplayRow = {\n data: TableRow\n identity: string\n key: symbol\n}\n\nconst pendingUpdates = new Map<symbol, TableRowUpsertPayload>()\n\nconst matchesPendingUpdate = (key: symbol, row: TableRow): boolean => {\n const update = pendingUpdates.get(key)\n return update?.name === row.name && update.value === row.value\n}\n\n// A saved parameter inherits the editor's key. The next placeholder gets a fresh key,\n// so it cannot retain the previous placeholder's text or focused input.\nconst keyedRows = computed<DisplayRow[]>((previous = []) => {\n const available = new Set(previous)\n // Reserve identities still present in the store before transferring an edited key.\n // The appended placeholder is excluded so a newly saved row can inherit its editor.\n const savedIdentities = new Set(data.map(getRowKey))\n const rows = displayData.value.map((row, index) => {\n const identity = getRowKey(row, index)\n const existing = [...available].find((entry) => entry.identity === identity)\n const pending = [...available].find(\n (entry) =>\n !savedIdentities.has(entry.identity) &&\n !entry.data.sourceParameterValuePath &&\n matchesPendingUpdate(entry.key, row),\n )\n const match = existing ?? pending\n\n if (match) {\n available.delete(match)\n if (matchesPendingUpdate(match.key, row)) {\n pendingUpdates.delete(match.key)\n }\n }\n\n return { data: row, identity, key: match?.key ?? Symbol() }\n })\n\n for (const removed of available) {\n pendingUpdates.delete(removed.key)\n }\n\n return rows\n})\n\nconst handleUpsertRow = (\n row: DisplayRow,\n index: number,\n payload: TableRowUpsertPayload,\n): void => {\n // The store may debounce the save. Transfer this key only when the saved row arrives.\n pendingUpdates.set(row.key, payload)\n emit('upsertRow', index, payload)\n}\n</script>\n<template>\n <DataTable\n class=\"group/table flex-1\"\n :columns=\"columns\">\n <DataTableRow class=\"sr-only !block\">\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.enabled') }}\n </DataTableHeader>\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.key') }}\n </DataTableHeader>\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.value') }}\n </DataTableHeader>\n </DataTableRow>\n\n <RequestTableRow\n v-for=\"(row, index) in keyedRows\"\n :key=\"row.key\"\n :data=\"row.data\"\n :deferKeyUpdates=\"deferKeyUpdates\"\n :environment=\"environment\"\n :hasCheckboxDisabled=\"hasCheckboxDisabled\"\n :invalidParams=\"invalidParams\"\n :label=\"label\"\n :showUploadButton=\"showUploadButton\"\n @deleteRow=\"emit('deleteRow', index)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @removeFile=\"emit('removeFile', index)\"\n @selectPreset=\"(value) => emit('selectPreset', index, value)\"\n @uploadFile=\"emit('uploadFile', index)\"\n @upsertRow=\"(payload) => handleUpsertRow(row, index, payload)\" />\n </DataTable>\n</template>\n<style scoped>\n:deep(.code-input-lite__editor) {\n background-color: transparent;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n}\n:deep(.scalar-pill:not(:last-of-type)) {\n margin-right: 0.15em;\n}\n:deep(.scalar-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"RequestTable.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed } from 'vue'\n\nimport RequestTableRow, {\n type TableRow,\n type TableRowUpsertPayload,\n} from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n data,\n hasCheckboxDisabled,\n deferKeyUpdates,\n showUploadButton,\n showAddRowPlaceholder = true,\n environment,\n} = defineProps<{\n data: TableRow[]\n /** Save key edits on blur so changing a body name does not replace the focused row. */\n deferKeyUpdates?: boolean\n /** Hide the enabled column */\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n showUploadButton?: boolean\n showAddRowPlaceholder?: boolean\n environment: XScalarEnvironment\n}>()\n\n/**\n * Make this component more generic that can be used also for the operation body\n */\nconst emit = defineEmits<{\n (e: 'upsertRow', index: number, payload: TableRowUpsertPayload): void\n (e: 'deleteRow', index: number): void\n\n /**\n * File upload events\n *\n * Each row has its own upload button, so we need to know which row to update\n * when the file is selected.\n */\n (e: 'uploadFile', index: number): void\n (e: 'removeFile', index: number): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset at the given row index. */\n (e: 'selectPreset', index: number, value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nconst columns = computed(() => {\n if (showUploadButton) {\n return ['36px', '', '', 'minmax(0, 1fr)']\n }\n return ['36px', '', '']\n})\n\n/** Add the last empty row (for ui purposes only) */\nconst displayData = computed(() => {\n if (!showAddRowPlaceholder) {\n return data\n }\n\n const last = data.at(-1)\n\n if (!last || last.name !== '' || last.value !== '') {\n return [...data, { name: '', value: '', isDisabled: true }]\n }\n\n return data\n})\n\n/**\n * Stable identity key for each row so Vue never reuses a RequestTableRow instance for a different\n * parameter or the appended placeholder row. Parameter rows are keyed by their parameter identity —\n * the name plus the value path for expanded object parameters. The parts are combined through\n * JSON.stringify so the name/path boundary is unambiguous (for example `ab` + `['c']` never\n * collides with `a` + `['bc']`). Form rows use the name and its occurrence so repeated\n * multipart fields remain distinct while unrelated rows can move without losing their identity.\n */\nconst getRowKey = (row: TableRow, index: number): string => {\n // Body edits retain their row when blur commits a rename after focus moves into the value.\n if (deferKeyUpdates) {\n return `body:${index}`\n }\n if (row.originalParameter) {\n return JSON.stringify([\n row.originalParameter.name,\n ...(row.sourceParameterValuePath ?? []),\n ])\n }\n\n const occurrence = displayData.value\n .slice(0, index)\n .filter(\n (other) => !other.originalParameter && other.name === row.name,\n ).length\n return `row:${JSON.stringify([row.name, occurrence])}`\n}\n\n/** Keep an edited row mounted when saving it changes its parameter identity. */\ntype DisplayRow = {\n data: TableRow\n identity: string\n key: symbol\n}\n\nconst pendingUpdates = new Map<symbol, TableRowUpsertPayload>()\n\nconst matchesPendingUpdate = (key: symbol, row: TableRow): boolean => {\n const update = pendingUpdates.get(key)\n return update?.name === row.name && update.value === row.value\n}\n\n// A saved parameter inherits the editor's key. The next placeholder gets a fresh key,\n// so it cannot retain the previous placeholder's text or focused input.\nconst keyedRows = computed<DisplayRow[]>((previous = []) => {\n const available = new Set(previous)\n // Reserve identities still present in the store before transferring an edited key.\n // The appended placeholder is excluded so a newly saved row can inherit its editor.\n const savedIdentities = new Set(data.map(getRowKey))\n const rows = displayData.value.map((row, index) => {\n const identity = getRowKey(row, index)\n const existing = [...available].find((entry) => entry.identity === identity)\n const pending = [...available].find(\n (entry) =>\n !savedIdentities.has(entry.identity) &&\n !entry.data.sourceParameterValuePath &&\n matchesPendingUpdate(entry.key, row),\n )\n const match = existing ?? pending\n\n if (match) {\n available.delete(match)\n if (matchesPendingUpdate(match.key, row)) {\n pendingUpdates.delete(match.key)\n }\n }\n\n return { data: row, identity, key: match?.key ?? Symbol() }\n })\n\n for (const removed of available) {\n pendingUpdates.delete(removed.key)\n }\n\n return rows\n})\n\nconst handleUpsertRow = (\n row: DisplayRow,\n index: number,\n payload: TableRowUpsertPayload,\n): void => {\n // The store may debounce the save. Transfer this key only when the saved row arrives.\n pendingUpdates.set(row.key, payload)\n emit('upsertRow', index, payload)\n}\n</script>\n<template>\n <DataTable\n class=\"group/table flex-1\"\n :columns=\"columns\">\n <DataTableRow class=\"sr-only !block\">\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.enabled') }}\n </DataTableHeader>\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.key') }}\n </DataTableHeader>\n <DataTableHeader>\n {{ label }}\n {{ translate('apiClient.requestTable.value') }}\n </DataTableHeader>\n </DataTableRow>\n\n <RequestTableRow\n v-for=\"(row, index) in keyedRows\"\n :key=\"row.key\"\n :data=\"row.data\"\n :deferKeyUpdates=\"deferKeyUpdates\"\n :environment=\"environment\"\n :hasCheckboxDisabled=\"hasCheckboxDisabled\"\n :invalidParams=\"invalidParams\"\n :label=\"label\"\n :showUploadButton=\"showUploadButton\"\n @deleteRow=\"emit('deleteRow', index)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @removeFile=\"emit('removeFile', index)\"\n @selectPreset=\"(value) => emit('selectPreset', index, value)\"\n @uploadFile=\"emit('uploadFile', index)\"\n @upsertRow=\"(payload) => handleUpsertRow(row, index, payload)\" />\n </DataTable>\n</template>\n<style scoped>\n:deep(.code-input-lite__editor) {\n background-color: transparent;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n}\n:deep(.scalar-pill:not(:last-of-type)) {\n margin-right: 0.15em;\n}\n:deep(.scalar-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n</style>\n"],"mappings":"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"}
@@ -72,13 +72,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
72
72
  page: "example";
73
73
  documentSlug?: string;
74
74
  path: string;
75
- method: import("@scalar/helpers/http/http-methods").HttpMethod;
75
+ method: string;
76
76
  exampleName: string;
77
77
  } | {
78
78
  page: "operation";
79
79
  path: "overview" | "servers" | "authentication" | "editor";
80
80
  operationPath: string;
81
- method: import("@scalar/helpers/http/http-methods").HttpMethod;
81
+ method: string;
82
82
  documentSlug?: string;
83
83
  })) | undefined>) => any;
84
84
  upsertRow: (payload: TableRowUpsertPayload) => any;
@@ -103,13 +103,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
103
103
  page: "example";
104
104
  documentSlug?: string;
105
105
  path: string;
106
- method: import("@scalar/helpers/http/http-methods").HttpMethod;
106
+ method: string;
107
107
  exampleName: string;
108
108
  } | {
109
109
  page: "operation";
110
110
  path: "overview" | "servers" | "authentication" | "editor";
111
111
  operationPath: string;
112
- method: import("@scalar/helpers/http/http-methods").HttpMethod;
112
+ method: string;
113
113
  documentSlug?: string;
114
114
  })) | undefined>) => any) | undefined;
115
115
  onUpsertRow?: ((payload: TableRowUpsertPayload) => any) | undefined;
@@ -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) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""}
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":""}
@@ -55,7 +55,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
55
55
  const value = ref(unpackProxyObject(__props.data.value) ?? "");
56
56
  const isDisabled = ref(__props.data.isDisabled ?? false);
57
57
  watch(() => __props.data.name, (newName) => {
58
- if (!newName && name.value) return;
58
+ if (!newName && name.value && !__props.deferKeyUpdates) return;
59
59
  name.value = newName ?? "";
60
60
  });
61
61
  watch(() => __props.data.value, (newValue) => value.value = unpackProxyObject(newValue) ?? "");
@@ -101,7 +101,7 @@ var RequestTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
101
101
  */
102
102
  const handleKeyBlur = (newName) => {
103
103
  if (newName === __props.data.name) return;
104
- if (!newName && __props.data.name) return;
104
+ if (!newName && __props.data.name && (!__props.deferKeyUpdates || name.value !== "")) return;
105
105
  handleUpdateRow({
106
106
  name: newName,
107
107
  isDisabled: isDisabled.value
@@ -1 +1 @@
1
- {"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInputLite } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableInputSelect,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { useLocalization } from '@/v2/features/localization'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n deferKeyUpdates,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n /** Keep key edits local until blur when the row identity depends on its name. */\n deferKeyUpdates?: boolean\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'upsertRow', payload: TableRowUpsertPayload): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n /** Select a value for a grouped global cookie preset. */\n (e: 'selectPreset', value: string): void\n}>()\n\nconst { translate } = useLocalization()\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** Whether an optional parameter is disabled because it has no explicit x-disabled value */\n isDisabledByDefault?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Preserve array values even while their JSON text is temporarily invalid. */\n isArray?: boolean\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n /** Path to a value inside the original parameter example for expanded object parameters */\n sourceParameterValuePath?: string[]\n /**\n * Selectable values for a grouped global cookie preset. When set, the value cell renders a\n * dropdown to switch between predefined values (for example a `Culture` cookie with `PL`/`EN`)\n * instead of an editable input.\n */\n presetOptions?: string[]\n}\n\nexport type TableRowUpsertPayload = {\n name: string\n value: string | File\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => {\n // Do not overwrite a valid local name with an empty incoming prop — this\n // can happen when the placeholder row (appended by displayData) is briefly\n // mapped onto this component instance before Vue re-keys the list.\n if (!newName && name.value && !deferKeyUpdates) return\n name.value = newName ?? ''\n },\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n options: { shouldRenameExpandedRow?: boolean; commitKey?: boolean } = {},\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n\n // Optional parameters start unchecked, but entering a value expresses intent to send it.\n // Explicit x-disabled values stay unchanged so a deliberate opt-out is preserved.\n if (data.isDisabledByDefault) {\n isDisabled.value = false\n }\n }\n\n // Is disabled should only be updated when explicitly provided in the payload\n if (payload.isDisabled !== undefined) {\n isDisabled.value = payload.isDisabled\n }\n\n if (\n payload.name !== undefined &&\n (deferKeyUpdates || data.sourceParameterValuePath) &&\n !options.shouldRenameExpandedRow &&\n !options.commitKey\n ) {\n return\n }\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n ...(options.shouldRenameExpandedRow\n ? { shouldRenameExpandedRow: true }\n : {}),\n })\n}\n\n/**\n * Commit a key edit when the input loses focus. Body and expanded-object rows defer their rename to blur (see\n * handleUpdateRow), so we only emit when the key actually changed. Focusing and blurring the field\n * without typing should not re-emit the row or silently reset its disabled state. The current\n * disabled state is passed through so a renamed row keeps it.\n */\nconst handleKeyBlur = (newName: string): void => {\n if (newName === data.name) {\n return\n }\n // Do not emit an update that would blank the parameter name — this can fire\n // when CodeInputLite blurs before it has rendered its initial value.\n if (!newName && data.name && (!deferKeyUpdates || name.value !== '')) {\n return\n }\n\n handleUpdateRow(\n { name: newName, isDisabled: isDisabled.value },\n {\n shouldRenameExpandedRow: Boolean(data.sourceParameterValuePath),\n commitKey: true,\n },\n )\n}\n\n/** Save a pending body key before the send shortcut reaches the request handler. */\nconst handleKeydown = (event: KeyboardEvent): void => {\n if (\n deferKeyUpdates &&\n event.key === 'Enter' &&\n (event.metaKey || event.ctrlKey)\n ) {\n handleKeyBlur(name.value)\n }\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n :ariaLabel=\"\n translate('apiClient.requestTableRow.include', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInputLite\n :aria-label=\"\n translate('apiClient.requestTableRow.keyLabel', { name: label ?? '' })\n \"\n :disabled=\"data.isReadonly\"\n :environment=\"environment\"\n :modelValue=\"name\"\n :placeholder=\"translate('apiClient.requestTableRow.key')\"\n :required=\"Boolean(data.isRequired)\"\n @blur=\"(v) => handleKeyBlur(v)\"\n @keydown.capture=\"handleKeydown\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <!-- Preset switcher for grouped global cookies that share a name -->\n <DataTableInputSelect\n v-if=\"data.presetOptions?.length\"\n :canAddCustomValue=\"false\"\n :modelValue=\"displayValue\"\n :value=\"data.presetOptions\"\n @update:modelValue=\"(v) => emit('selectPreset', v)\" />\n <CodeInputLite\n v-else\n :aria-label=\"\n translate('apiClient.requestTableRow.valueLabel', {\n name: label ?? '',\n })\n \"\n class=\"pr-6 group-hover:pr-10 group-has-[.code-input-lite__editor:focus]:pr-10\"\n :default=\"defaultValue\"\n :disabled=\"data.isReadonly\"\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n :modelValue=\"displayValue\"\n :placeholder=\"translate('apiClient.requestTableRow.value')\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n :aria-label=\"\n translate('apiClient.requestTableRow.deleteRow', {\n name: data.name || translate('apiClient.requestTableRow.row'),\n })\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.code-input-lite__editor:focus]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n :label=\"translate('apiClient.requestTableRow.globalCookieHint')\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n :description=\"translate('apiClient.requestTableRow.readOnlyHint')\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInputLite>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span\n class=\"truncate\"\n :title=\"displayValue\"\n >{{ displayValue }}</span\n >\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n {{ translate('apiClient.requestTableRow.delete') }}\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>{{ translate('apiClient.requestTableRow.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-parameter-rows.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/create-parameter-rows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,8DAA8D,CAAA;AAGrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAA;AAkWjE;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,eAAe,EAC1B,YAAY,MAAM,EAClB,UAAS;IACP,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,EAAE,CAAA;IACtC,iBAAiB,CAAC,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CAC3D,KACL,QAAQ,EAuDV,CAAA"}
1
+ {"version":3,"file":"create-parameter-rows.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/create-parameter-rows.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,8DAA8D,CAAA;AAGrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAA;AAkWjE;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,eAAe,EAC1B,YAAY,MAAM,EAClB,UAAS;IACP,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,EAAE,CAAA;IACtC,iBAAiB,CAAC,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CAC3D,KACL,QAAQ,EAsFV,CAAA"}
@@ -1,9 +1,11 @@
1
1
  import { getParameterSchema } from "./get-parameter-schema.js";
2
2
  import { getValueAtPath } from "@scalar/helpers/object/get-value-at-path";
3
- import { deSerializeParameter, getExample, isParamDisabled } from "@scalar/workspace-store/request-example";
3
+ import { deSerializeParameter, isParamDisabled } from "@scalar/workspace-store/request-example";
4
4
  import { getResolvedRef } from "@scalar/workspace-store/helpers/get-resolved-ref";
5
5
  import { isObject } from "@scalar/helpers/object/is-object";
6
6
  import { isArraySchema, isObjectSchema } from "@scalar/workspace-store/schemas/v3.2/strict/type-guards";
7
+ import { getParameterExample } from "@scalar/workspace-store/helpers/get-parameter-example";
8
+ import { getQuerystringParameter, serializeQuerystringParameter } from "@scalar/workspace-store/helpers/querystring-parameter";
7
9
  //#region src/v2/blocks/request-block/helpers/create-parameter-rows.ts
8
10
  var isParameterWithSchema = (parameter) => "schema" in parameter && parameter.schema !== void 0;
9
11
  var resolveSchema = (schema) => {
@@ -188,14 +190,20 @@ var getUnmappedValueRows = ({ parameter, value, schemaRows, mode, isDisabled, is
188
190
  * through as a single row.
189
191
  */
190
192
  var createParameterRows = (parameter, exampleKey, options = {}) => {
191
- const example = getExample(parameter, exampleKey, void 0);
193
+ const selected = getParameterExample(parameter, exampleKey);
194
+ const { example } = selected;
195
+ const displayValue = selected.value === null && example?.dataValue === null ? "null" : selected.value;
192
196
  const isDisabled = isParamDisabled(parameter, example);
193
197
  const isDisabledByDefault = !parameter.required && parameter.in !== "path" && example?.["x-disabled"] === void 0;
194
198
  const schema = getParameterSchema(parameter);
195
- const mode = getExpansionMode(parameter, schema);
196
- if (mode === null || !schema || !isObjectSchema(schema)) return [toSingleParameterRow(parameter, schema, example?.value, isDisabled, isDisabledByDefault)];
197
- const value = example?.value === void 0 ? void 0 : deSerializeParameter(example.value, parameter);
198
- if (!schema.properties) return [toSingleParameterRow(parameter, schema, example?.value, isDisabled, isDisabledByDefault)];
199
+ if (parameter.in === "querystring") {
200
+ const querystring = getQuerystringParameter(parameter, exampleKey, { includeDisabled: true });
201
+ return [toSingleParameterRow(parameter, void 0, querystring ? serializeQuerystringParameter(querystring) : "", isDisabled, isDisabledByDefault)];
202
+ }
203
+ const mode = selected.serialized ? null : getExpansionMode(parameter, schema);
204
+ if (mode === null || !schema || !isObjectSchema(schema)) return [toSingleParameterRow(parameter, selected.serialized ? void 0 : schema, displayValue, isDisabled, isDisabledByDefault)];
205
+ const value = selected.value === void 0 ? void 0 : deSerializeParameter(selected.value, parameter);
206
+ if (!schema.properties) return [toSingleParameterRow(parameter, selected.serialized ? void 0 : schema, displayValue, isDisabled, isDisabledByDefault)];
199
207
  const hiddenValuePaths = new Set(options.hiddenValuePaths?.map(toPathKey) ?? []);
200
208
  const renamedValuePaths = new Map((options.renamedValuePaths ?? []).map(({ from, to }) => [toPathKey(from), to]));
201
209
  const renameTargetPaths = new Set((options.renamedValuePaths ?? []).map(({ to }) => toPathKey(to)));