@scalar/api-client 3.6.0 → 3.6.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 (65) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/style.css +31 -14
  3. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
  4. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
  5. package/dist/v2/constants.js +1 -1
  6. package/dist/v2/features/app/App.vue.d.ts.map +1 -1
  7. package/dist/v2/features/app/App.vue.js.map +1 -1
  8. package/dist/v2/features/app/App.vue.script.js +30 -28
  9. package/dist/v2/features/app/App.vue.script.js.map +1 -1
  10. package/dist/v2/features/app/components/AppHeader.vue.d.ts.map +1 -1
  11. package/dist/v2/features/app/components/AppHeader.vue.js.map +1 -1
  12. package/dist/v2/features/app/components/AppHeader.vue.script.js +3 -2
  13. package/dist/v2/features/app/components/AppHeader.vue.script.js.map +1 -1
  14. package/dist/v2/features/app/components/AppHeaderActions.vue.d.ts.map +1 -1
  15. package/dist/v2/features/app/components/AppHeaderActions.vue.js.map +1 -1
  16. package/dist/v2/features/app/components/AppHeaderActions.vue.script.js +12 -10
  17. package/dist/v2/features/app/components/AppHeaderActions.vue.script.js.map +1 -1
  18. package/dist/v2/features/app/components/AppSidebar.vue.d.ts +0 -2
  19. package/dist/v2/features/app/components/AppSidebar.vue.d.ts.map +1 -1
  20. package/dist/v2/features/app/components/AppSidebar.vue.js +1 -1
  21. package/dist/v2/features/app/components/AppSidebar.vue.js.map +1 -1
  22. package/dist/v2/features/app/components/AppSidebar.vue.script.js +3 -7
  23. package/dist/v2/features/app/components/AppSidebar.vue.script.js.map +1 -1
  24. package/dist/v2/features/app/components/DesktopTabs.vue.d.ts.map +1 -1
  25. package/dist/v2/features/app/components/DesktopTabs.vue.js.map +1 -1
  26. package/dist/v2/features/app/components/DesktopTabs.vue.script.js +2 -2
  27. package/dist/v2/features/app/components/DesktopTabs.vue.script.js.map +1 -1
  28. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts.map +1 -1
  29. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js +1 -1
  30. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js.map +1 -1
  31. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js +1 -1
  32. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js.map +1 -1
  33. package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.d.ts.map +1 -1
  34. package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.js.map +1 -1
  35. package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.script.js +35 -17
  36. package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.script.js.map +1 -1
  37. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.d.ts.map +1 -1
  38. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.js.map +1 -1
  39. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js +15 -13
  40. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js.map +1 -1
  41. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.d.ts.map +1 -1
  42. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.js +1 -1
  43. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.js.map +1 -1
  44. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.script.js +51 -39
  45. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.script.js.map +1 -1
  46. package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.d.ts.map +1 -1
  47. package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.js.map +1 -1
  48. package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.script.js +5 -5
  49. package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.script.js.map +1 -1
  50. package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.d.ts.map +1 -1
  51. package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.js.map +1 -1
  52. package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.script.js +44 -42
  53. package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.script.js.map +1 -1
  54. package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.d.ts.map +1 -1
  55. package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.js.map +1 -1
  56. package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.script.js +33 -17
  57. package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.script.js.map +1 -1
  58. package/dist/v2/features/command-palette/helpers/load-document-from-source.d.ts.map +1 -1
  59. package/dist/v2/features/command-palette/helpers/load-document-from-source.js +3 -2
  60. package/dist/v2/features/command-palette/helpers/load-document-from-source.js.map +1 -1
  61. package/dist/v2/helpers/is-url.d.ts.map +1 -1
  62. package/dist/v2/helpers/is-url.js +2 -1
  63. package/dist/v2/helpers/is-url.js.map +1 -1
  64. package/dist/vue-styles.css +6 -6
  65. package/package.json +8 -8
@@ -2,14 +2,19 @@ import HttpMethod_default from "../../../blocks/operation-code-sample/components
2
2
  import CommandActionForm_default from "./CommandActionForm.vue.js";
3
3
  import CommandActionInput_default from "./CommandActionInput.vue.js";
4
4
  import { getOperationFromCurl } from "../helpers/get-operation-from-curl.js";
5
- import { computed, createBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, toDisplayString, unref, withCtx } from "vue";
5
+ import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, toDisplayString, unref, withCtx } from "vue";
6
6
  import { ScalarButton, ScalarIcon, ScalarListbox } from "@scalar/components";
7
- import { useRouter } from "vue-router";
8
7
  //#region src/v2/features/command-palette/components/CommandPaletteImportCurl.vue?vue&type=script&setup=true&lang.ts
9
- var _hoisted_1 = { class: "flex flex-1 flex-col gap-2" };
10
- var _hoisted_2 = { class: "flex h-9 flex-row items-center gap-2 rounded border p-[3px] text-sm" };
11
- var _hoisted_3 = { class: "scroll-timeline-x whitespace-nowrap" };
12
- var _hoisted_4 = { class: "flex items-center gap-2" };
8
+ var _hoisted_1 = {
9
+ key: 0,
10
+ class: "text-red px-2 pb-1 text-xs",
11
+ "data-testid": "command-palette-import-curl-error",
12
+ role: "alert"
13
+ };
14
+ var _hoisted_2 = { class: "flex flex-1 flex-col gap-2" };
15
+ var _hoisted_3 = { class: "flex h-9 flex-row items-center gap-2 rounded border p-[3px] text-sm" };
16
+ var _hoisted_4 = { class: "scroll-timeline-x whitespace-nowrap" };
17
+ var _hoisted_5 = { class: "flex items-center gap-2" };
13
18
  var CommandPaletteImportCurl_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
14
19
  name: "CommandPaletteImportCurl",
15
20
  props: {
@@ -20,7 +25,6 @@ var CommandPaletteImportCurl_vue_vue_type_script_setup_true_lang_default = /* @_
20
25
  emits: ["close", "back"],
21
26
  setup(__props, { emit: __emit }) {
22
27
  const emit = __emit;
23
- const router = useRouter();
24
28
  const exampleKey = ref("");
25
29
  /** Trimmed version of the example key for validation and submission */
26
30
  const exampleKeyTrimmed = computed(() => exampleKey.value.trim());
@@ -33,18 +37,25 @@ var CommandPaletteImportCurl_vue_vue_type_script_setup_true_lang_default = /* @_
33
37
  })));
34
38
  const selectedDocument = ref(documents.value[0]);
35
39
  /**
36
- * Check if the form should be disabled.
37
- * Disabled when:
38
- * - Example key is empty
39
- * - No document is selected
40
- * - An operation with the same path and method already exists in the selected document
40
+ * Validation message surfaced under the input.
41
+ *
42
+ * Resolves to `null` when the form is valid; otherwise to a human-readable
43
+ * reason the user can act on. Empty input is the default state so we keep
44
+ * the field free of error styling `isDisabled` still blocks submission
45
+ * there, matching the {@link CommandPaletteOpenApiDocument} pattern.
41
46
  */
42
- const isDisabled = computed(() => {
43
- if (!exampleKeyTrimmed.value || !selectedDocument.value) return true;
44
- if (__props.workspaceStore.workspace.documents[selectedDocument.value.id]?.paths?.[path]?.[method]) return true;
45
- return false;
47
+ const errorMessage = computed(() => {
48
+ if (!exampleKeyTrimmed.value || !selectedDocument.value) return null;
49
+ if (__props.workspaceStore.workspace.documents[selectedDocument.value.id]?.paths?.[path]?.[method]) return `A ${method.toUpperCase()} operation at "${path}" already exists in "${selectedDocument.value.label}". Importing this cURL would conflict with it.`;
50
+ return null;
46
51
  });
47
52
  /**
53
+ * Submit is blocked while required fields are missing or a duplicate exists.
54
+ * The inline `errorMessage` makes the duplicate case explicit so the user
55
+ * understands why import is unavailable rather than seeing a silent disable.
56
+ */
57
+ const isDisabled = computed(() => !exampleKeyTrimmed.value || !selectedDocument.value || errorMessage.value !== null);
58
+ /**
48
59
  * Handle the import submission.
49
60
  * Creates a new operation in the selected document from the parsed cURL command.
50
61
  */
@@ -60,19 +71,16 @@ var CommandPaletteImportCurl_vue_vue_type_script_setup_true_lang_default = /* @_
60
71
  operation: result.operation,
61
72
  exampleKey: exampleKeyTrimmed.value,
62
73
  callback: (success) => {
63
- if (success) {
64
- __props.workspaceStore.buildSidebar(documentName.id);
65
- const path = result.path.startsWith("/") ? result.path : `/${result.path}`;
66
- router.push({
67
- name: "example",
68
- params: {
69
- documentSlug: documentName.id,
70
- pathEncoded: encodeURIComponent(path),
71
- method: result.method,
72
- exampleName: exampleKeyTrimmed.value
73
- }
74
- });
75
- }
74
+ if (!success) return;
75
+ __props.workspaceStore.buildSidebar(documentName.id);
76
+ const normalizedPath = result.path.startsWith("/") ? result.path : `/${result.path}`;
77
+ __props.eventBus.emit("ui:navigate", {
78
+ page: "example",
79
+ documentSlug: documentName.id,
80
+ path: normalizedPath,
81
+ method: result.method,
82
+ exampleName: exampleKeyTrimmed.value
83
+ });
76
84
  }
77
85
  });
78
86
  emit("close");
@@ -86,7 +94,7 @@ var CommandPaletteImportCurl_vue_vue_type_script_setup_true_lang_default = /* @_
86
94
  disabled: isDisabled.value,
87
95
  onSubmit: handleImportClick
88
96
  }, {
89
- options: withCtx(() => [createElementVNode("div", _hoisted_4, [createVNode(unref(ScalarListbox), {
97
+ options: withCtx(() => [createElementVNode("div", _hoisted_5, [createVNode(unref(ScalarListbox), {
90
98
  modelValue: selectedDocument.value,
91
99
  "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => selectedDocument.value = $event),
92
100
  options: documents.value
@@ -105,15 +113,19 @@ var CommandPaletteImportCurl_vue_vue_type_script_setup_true_lang_default = /* @_
105
113
  _: 1
106
114
  }, 8, ["modelValue", "options"])])]),
107
115
  submit: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode("Import Request", -1)])]),
108
- default: withCtx(() => [createVNode(CommandActionInput_default, {
109
- modelValue: exampleKey.value,
110
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => exampleKey.value = $event),
111
- placeholder: "Curl example key (e.g., example-1)",
112
- onDelete: handleBack
113
- }, null, 8, ["modelValue"]), createElementVNode("div", _hoisted_1, [createElementVNode("div", _hoisted_2, [createVNode(HttpMethod_default, {
114
- class: "border-r-1 px-1",
115
- method: unref(method)
116
- }, null, 8, ["method"]), createElementVNode("span", _hoisted_3, toDisplayString(unref(operation).servers?.[0]?.url || "") + toDisplayString(unref(path)), 1)])])]),
116
+ default: withCtx(() => [
117
+ createVNode(CommandActionInput_default, {
118
+ modelValue: exampleKey.value,
119
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => exampleKey.value = $event),
120
+ placeholder: "Curl example key (e.g., example-1)",
121
+ onDelete: handleBack
122
+ }, null, 8, ["modelValue"]),
123
+ errorMessage.value ? (openBlock(), createElementBlock("p", _hoisted_1, toDisplayString(errorMessage.value), 1)) : createCommentVNode("", true),
124
+ createElementVNode("div", _hoisted_2, [createElementVNode("div", _hoisted_3, [createVNode(HttpMethod_default, {
125
+ class: "border-r-1 px-1",
126
+ method: unref(method)
127
+ }, null, 8, ["method"]), createElementVNode("span", _hoisted_4, toDisplayString(unref(operation).servers?.[0]?.url || "") + toDisplayString(unref(path)), 1)])])
128
+ ]),
117
129
  _: 1
118
130
  }, 8, ["disabled"]);
119
131
  };
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteImportCurl.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImportCurl.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Import cURL Component\n *\n * Provides a form for importing API requests from cURL commands.\n * Parses the cURL command to extract the HTTP method, URL, path, headers,\n * and body, then creates a new operation in the selected document.\n *\n * Validates that no conflicting operation exists at the same path/method.\n *\n * @example\n * <CommandPaletteImportCurl\n * :workspaceStore=\"workspaceStore\"\n * :eventBus=\"eventBus\"\n * :curl=\"curlCommand\"\n * @close=\"handleClose\"\n * @back=\"handleBack\"\n * />\n */\nexport default {\n name: 'CommandPaletteImportCurl',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarIcon,\n ScalarListbox,\n type ScalarComboboxOption,\n} from '@scalar/components'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport CommandActionForm from '@/v2/features/command-palette/components/CommandActionForm.vue'\nimport CommandActionInput from '@/v2/features/command-palette/components/CommandActionInput.vue'\nimport { getOperationFromCurl } from '@/v2/features/command-palette/helpers/get-operation-from-curl'\n\nconst { workspaceStore, inputValue, eventBus } = defineProps<{\n /** The workspace store for accessing documents and operations */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting operation creation events */\n eventBus: WorkspaceEventBus\n /** The cURL command string to parse and import */\n inputValue: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the import is complete */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst router = useRouter()\n\nconst exampleKey = ref('')\n\n/** Trimmed version of the example key for validation and submission */\nconst exampleKeyTrimmed = computed<string>(() => exampleKey.value.trim())\n\n/** Parse the cURL command to extract path, method, and operation details */\nconst { path, method, operation } = getOperationFromCurl(inputValue)\n\n/** List of all available documents (collections) in the workspace */\nconst documents = computed(() =>\n Object.keys(workspaceStore.workspace.documents).map((document) => ({\n id: document,\n label: document,\n })),\n)\n\nconst selectedDocument = ref<ScalarComboboxOption | undefined>(\n documents.value[0],\n)\n\n/**\n * Check if the form should be disabled.\n * Disabled when:\n * - Example key is empty\n * - No document is selected\n * - An operation with the same path and method already exists in the selected document\n */\nconst isDisabled = computed<boolean>(() => {\n if (!exampleKeyTrimmed.value || !selectedDocument.value) {\n return true\n }\n\n /** Prevent creating duplicate operations at the same path/method */\n const document = workspaceStore.workspace.documents[selectedDocument.value.id]\n if (document?.paths?.[path]?.[method]) {\n return true\n }\n\n return false\n})\n\n/**\n * Handle the import submission.\n * Creates a new operation in the selected document from the parsed cURL command.\n */\nconst handleImportClick = (): void => {\n const documentName = selectedDocument.value\n\n if (isDisabled.value || !documentName) {\n return\n }\n\n /** Re-parse with the example key to include it in the operation */\n const result = getOperationFromCurl(inputValue, exampleKeyTrimmed.value)\n\n eventBus.emit('operation:create:operation', {\n documentName: documentName.id,\n path: result.path,\n method: result.method,\n operation: result.operation,\n exampleKey: exampleKeyTrimmed.value,\n callback: (success) => {\n if (success) {\n // build the sidebar\n workspaceStore.buildSidebar(documentName.id)\n\n const path = result.path.startsWith('/')\n ? result.path\n : `/${result.path}`\n\n // navigate to the operation\n router.push({\n name: 'example',\n params: {\n documentSlug: documentName.id,\n pathEncoded: encodeURIComponent(path),\n method: result.method,\n exampleName: exampleKeyTrimmed.value,\n },\n })\n }\n },\n })\n\n emit('close')\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n @submit=\"handleImportClick\">\n <!-- Example key input -->\n <CommandActionInput\n v-model=\"exampleKey\"\n placeholder=\"Curl example key (e.g., example-1)\"\n @delete=\"handleBack\" />\n\n <!-- Preview of the parsed cURL request (method + URL + path) -->\n <div class=\"flex flex-1 flex-col gap-2\">\n <div\n class=\"flex h-9 flex-row items-center gap-2 rounded border p-[3px] text-sm\">\n <HttpMethod\n class=\"border-r-1 px-1\"\n :method=\"method\" />\n <span class=\"scroll-timeline-x whitespace-nowrap\">\n {{ operation.servers?.[0]?.url || '' }}{{ path }}\n </span>\n </div>\n </div>\n\n <!-- Document selector -->\n <template #options>\n <div class=\"flex items-center gap-2\">\n <ScalarListbox\n v-model=\"selectedDocument\"\n :options=\"documents\">\n <ScalarButton\n class=\"hover:bg-b-2 max-h-8 w-full justify-between gap-1 p-2 text-xs\"\n variant=\"outlined\">\n <span\n class=\"whitespace-nowrap\"\n :class=\"selectedDocument ? 'text-c-1' : 'text-c-3'\">\n {{\n selectedDocument ? selectedDocument.label : 'Select Collection'\n }}\n </span>\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </div>\n </template>\n\n <template #submit>Import Request</template>\n </CommandActionForm>\n</template>\n<style scoped>\n/**\n * Custom horizontal scroll for the URL preview.\n * Hides scrollbar for a cleaner appearance while maintaining scroll functionality.\n */\n.scroll-timeline-x {\n overflow: auto;\n scroll-timeline: --scroll-timeline x;\n /* Firefox support */\n scroll-timeline: --scroll-timeline horizontal;\n /* Hide scrollbar in IE and Edge */\n -ms-overflow-style: none;\n /* Hide scrollbar in Firefox */\n scrollbar-width: none;\n}\n\n/* Hide scrollbar in Chrome, Safari, and Opera */\n.scroll-timeline-x::-webkit-scrollbar {\n display: none;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;CAoBE,MAAM;;;;;;;;EA8BR,MAAM,OAAO;EAOb,MAAM,SAAS,WAAU;EAEzB,MAAM,aAAa,IAAI,GAAE;;EAGzB,MAAM,oBAAoB,eAAuB,WAAW,MAAM,MAAM,CAAA;;EAGxE,MAAM,EAAE,MAAM,QAAQ,cAAc,qBAAqB,QAAA,WAAU;;EAGnE,MAAM,YAAY,eAChB,OAAO,KAAK,QAAA,eAAe,UAAU,UAAU,CAAC,KAAK,cAAc;GACjE,IAAI;GACJ,OAAO;GACR,EAAE,CACL;EAEA,MAAM,mBAAmB,IACvB,UAAU,MAAM,GAClB;;;;;;;;EASA,MAAM,aAAa,eAAwB;AACzC,OAAI,CAAC,kBAAkB,SAAS,CAAC,iBAAiB,MAChD,QAAO;AAKT,OADiB,QAAA,eAAe,UAAU,UAAU,iBAAiB,MAAM,KAC7D,QAAQ,QAAQ,QAC5B,QAAO;AAGT,UAAO;IACR;;;;;EAMD,MAAM,0BAAgC;GACpC,MAAM,eAAe,iBAAiB;AAEtC,OAAI,WAAW,SAAS,CAAC,aACvB;;GAIF,MAAM,SAAS,qBAAqB,QAAA,YAAY,kBAAkB,MAAK;AAEvE,WAAA,SAAS,KAAK,8BAA8B;IAC1C,cAAc,aAAa;IAC3B,MAAM,OAAO;IACb,QAAQ,OAAO;IACf,WAAW,OAAO;IAClB,YAAY,kBAAkB;IAC9B,WAAW,YAAY;AACrB,SAAI,SAAS;AAEX,cAAA,eAAe,aAAa,aAAa,GAAE;MAE3C,MAAM,OAAO,OAAO,KAAK,WAAW,IAAG,GACnC,OAAO,OACP,IAAI,OAAO;AAGf,aAAO,KAAK;OACV,MAAM;OACN,QAAQ;QACN,cAAc,aAAa;QAC3B,aAAa,mBAAmB,KAAK;QACrC,QAAQ,OAAO;QACf,aAAa,kBAAkB;QAChC;OACF,CAAA;;;IAGN,CAAA;AAED,QAAK,QAAO;;;EAId,MAAM,cAAc,UAA+B;AACjD,QAAK,QAAQ,MAAK;;;uBAIlB,YAgDoB,2BAAA;IA/CjB,UAAU,WAAA;IACV,UAAQ;;IAqBE,SAAO,cAqBV,CApBN,mBAoBM,OApBN,YAoBM,CAnBJ,YAkBgB,MAAA,cAAA,EAAA;iBAjBL,iBAAA;mFAAgB,QAAA;KACxB,SAAS,UAAA;;4BAeK,CAdf,YAce,MAAA,aAAA,EAAA;MAbb,OAAM;MACN,SAAQ;;6BAOD,CANP,mBAMO,QAAA,EALL,OAAK,eAAA,CAAC,qBACE,iBAAA,QAAgB,aAAA,WAAA,CAAA,EAAA,EAAA,gBAEtB,iBAAA,QAAmB,iBAAA,MAAiB,QAAK,oBAAA,EAAA,EAAA,EAG7C,YAGc,MAAA,WAAA,EAAA;OAFZ,OAAM;OACN,MAAK;OACL,MAAK;;;;;;IAMJ,QAAM,cAAe,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAd,kBAAc,GAAA,CAAA,EAAA,CAAA;2BAxCP,CAHzB,YAGyB,4BAAA;iBAFd,WAAA;6EAAU,QAAA;KACnB,aAAY;KACX,UAAQ;iCAGX,mBAUM,OAVN,YAUM,CATJ,mBAQM,OARN,YAQM,CANJ,YAEqB,oBAAA;KADnB,OAAM;KACL,QAAQ,MAAA,OAAM;6BACjB,mBAEO,QAFP,YAEO,gBADF,MAAA,UAAS,CAAC,UAAO,IAAO,OAAG,GAAA,GAAA,gBAAY,MAAA,KAAI,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"CommandPaletteImportCurl.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImportCurl.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Import cURL Component\n *\n * Provides a form for importing API requests from cURL commands.\n * Parses the cURL command to extract the HTTP method, URL, path, headers,\n * and body, then creates a new operation in the selected document.\n *\n * Validates that no conflicting operation exists at the same path/method.\n *\n * @example\n * <CommandPaletteImportCurl\n * :workspaceStore=\"workspaceStore\"\n * :eventBus=\"eventBus\"\n * :curl=\"curlCommand\"\n * @close=\"handleClose\"\n * @back=\"handleBack\"\n * />\n */\nexport default {\n name: 'CommandPaletteImportCurl',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarIcon,\n ScalarListbox,\n type ScalarComboboxOption,\n} from '@scalar/components'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, type ComputedRef } from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport CommandActionForm from '@/v2/features/command-palette/components/CommandActionForm.vue'\nimport CommandActionInput from '@/v2/features/command-palette/components/CommandActionInput.vue'\nimport { getOperationFromCurl } from '@/v2/features/command-palette/helpers/get-operation-from-curl'\n\nconst { workspaceStore, inputValue, eventBus } = defineProps<{\n /** The workspace store for accessing documents and operations */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting operation creation events */\n eventBus: WorkspaceEventBus\n /** The cURL command string to parse and import */\n inputValue: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the import is complete */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst exampleKey = ref('')\n\n/** Trimmed version of the example key for validation and submission */\nconst exampleKeyTrimmed = computed<string>(() => exampleKey.value.trim())\n\n/** Parse the cURL command to extract path, method, and operation details */\nconst { path, method, operation } = getOperationFromCurl(inputValue)\n\n/** List of all available documents (collections) in the workspace */\nconst documents = computed(() =>\n Object.keys(workspaceStore.workspace.documents).map((document) => ({\n id: document,\n label: document,\n })),\n)\n\nconst selectedDocument = ref<ScalarComboboxOption | undefined>(\n documents.value[0],\n)\n\n/**\n * Validation message surfaced under the input.\n *\n * Resolves to `null` when the form is valid; otherwise to a human-readable\n * reason the user can act on. Empty input is the default state so we keep\n * the field free of error styling `isDisabled` still blocks submission\n * there, matching the {@link CommandPaletteOpenApiDocument} pattern.\n */\nconst errorMessage: ComputedRef<string | null> = computed(() => {\n if (!exampleKeyTrimmed.value || !selectedDocument.value) {\n return null\n }\n\n const document = workspaceStore.workspace.documents[selectedDocument.value.id]\n\n if (document?.paths?.[path]?.[method]) {\n return `A ${method.toUpperCase()} operation at \"${path}\" already exists in \"${selectedDocument.value.label}\". Importing this cURL would conflict with it.`\n }\n\n return null\n})\n\n/**\n * Submit is blocked while required fields are missing or a duplicate exists.\n * The inline `errorMessage` makes the duplicate case explicit so the user\n * understands why import is unavailable rather than seeing a silent disable.\n */\nconst isDisabled = computed<boolean>(\n () =>\n !exampleKeyTrimmed.value ||\n !selectedDocument.value ||\n errorMessage.value !== null,\n)\n\n/**\n * Handle the import submission.\n * Creates a new operation in the selected document from the parsed cURL command.\n */\nconst handleImportClick = (): void => {\n const documentName = selectedDocument.value\n\n if (isDisabled.value || !documentName) {\n return\n }\n\n /** Re-parse with the example key to include it in the operation */\n const result = getOperationFromCurl(inputValue, exampleKeyTrimmed.value)\n\n eventBus.emit('operation:create:operation', {\n documentName: documentName.id,\n path: result.path,\n method: result.method,\n operation: result.operation,\n exampleKey: exampleKeyTrimmed.value,\n callback: (success) => {\n if (!success) {\n return\n }\n\n // build the sidebar\n workspaceStore.buildSidebar(documentName.id)\n\n const normalizedPath = result.path.startsWith('/')\n ? result.path\n : `/${result.path}`\n\n // Navigate to the new example via the event bus rather than the router\n eventBus.emit('ui:navigate', {\n page: 'example',\n documentSlug: documentName.id,\n path: normalizedPath,\n method: result.method,\n exampleName: exampleKeyTrimmed.value,\n })\n },\n })\n\n emit('close')\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n @submit=\"handleImportClick\">\n <!-- Example key input -->\n <CommandActionInput\n v-model=\"exampleKey\"\n placeholder=\"Curl example key (e.g., example-1)\"\n @delete=\"handleBack\" />\n\n <p\n v-if=\"errorMessage\"\n class=\"text-red px-2 pb-1 text-xs\"\n data-testid=\"command-palette-import-curl-error\"\n role=\"alert\">\n {{ errorMessage }}\n </p>\n\n <!-- Preview of the parsed cURL request (method + URL + path) -->\n <div class=\"flex flex-1 flex-col gap-2\">\n <div\n class=\"flex h-9 flex-row items-center gap-2 rounded border p-[3px] text-sm\">\n <HttpMethod\n class=\"border-r-1 px-1\"\n :method=\"method\" />\n <span class=\"scroll-timeline-x whitespace-nowrap\">\n {{ operation.servers?.[0]?.url || '' }}{{ path }}\n </span>\n </div>\n </div>\n\n <!-- Document selector -->\n <template #options>\n <div class=\"flex items-center gap-2\">\n <ScalarListbox\n v-model=\"selectedDocument\"\n :options=\"documents\">\n <ScalarButton\n class=\"hover:bg-b-2 max-h-8 w-full justify-between gap-1 p-2 text-xs\"\n variant=\"outlined\">\n <span\n class=\"whitespace-nowrap\"\n :class=\"selectedDocument ? 'text-c-1' : 'text-c-3'\">\n {{\n selectedDocument ? selectedDocument.label : 'Select Collection'\n }}\n </span>\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </div>\n </template>\n\n <template #submit>Import Request</template>\n </CommandActionForm>\n</template>\n<style scoped>\n/**\n * Custom horizontal scroll for the URL preview.\n * Hides scrollbar for a cleaner appearance while maintaining scroll functionality.\n */\n.scroll-timeline-x {\n overflow: auto;\n scroll-timeline: --scroll-timeline x;\n /* Firefox support */\n scroll-timeline: --scroll-timeline horizontal;\n /* Hide scrollbar in IE and Edge */\n -ms-overflow-style: none;\n /* Hide scrollbar in Firefox */\n scrollbar-width: none;\n}\n\n/* Hide scrollbar in Chrome, Safari, and Opera */\n.scroll-timeline-x::-webkit-scrollbar {\n display: none;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;CAoBE,MAAM;;;;;;;;EA6BR,MAAM,OAAO;EAOb,MAAM,aAAa,IAAI,GAAE;;EAGzB,MAAM,oBAAoB,eAAuB,WAAW,MAAM,MAAM,CAAA;;EAGxE,MAAM,EAAE,MAAM,QAAQ,cAAc,qBAAqB,QAAA,WAAU;;EAGnE,MAAM,YAAY,eAChB,OAAO,KAAK,QAAA,eAAe,UAAU,UAAU,CAAC,KAAK,cAAc;GACjE,IAAI;GACJ,OAAO;GACR,EAAE,CACL;EAEA,MAAM,mBAAmB,IACvB,UAAU,MAAM,GAClB;;;;;;;;;EAUA,MAAM,eAA2C,eAAe;AAC9D,OAAI,CAAC,kBAAkB,SAAS,CAAC,iBAAiB,MAChD,QAAO;AAKT,OAFiB,QAAA,eAAe,UAAU,UAAU,iBAAiB,MAAM,KAE7D,QAAQ,QAAQ,QAC5B,QAAO,KAAK,OAAO,aAAa,CAAC,iBAAiB,KAAK,uBAAuB,iBAAiB,MAAM,MAAM;AAG7G,UAAO;IACR;;;;;;EAOD,MAAM,aAAa,eAEf,CAAC,kBAAkB,SACnB,CAAC,iBAAiB,SAClB,aAAa,UAAU,KAC3B;;;;;EAMA,MAAM,0BAAgC;GACpC,MAAM,eAAe,iBAAiB;AAEtC,OAAI,WAAW,SAAS,CAAC,aACvB;;GAIF,MAAM,SAAS,qBAAqB,QAAA,YAAY,kBAAkB,MAAK;AAEvE,WAAA,SAAS,KAAK,8BAA8B;IAC1C,cAAc,aAAa;IAC3B,MAAM,OAAO;IACb,QAAQ,OAAO;IACf,WAAW,OAAO;IAClB,YAAY,kBAAkB;IAC9B,WAAW,YAAY;AACrB,SAAI,CAAC,QACH;AAIF,aAAA,eAAe,aAAa,aAAa,GAAE;KAE3C,MAAM,iBAAiB,OAAO,KAAK,WAAW,IAAG,GAC7C,OAAO,OACP,IAAI,OAAO;AAGf,aAAA,SAAS,KAAK,eAAe;MAC3B,MAAM;MACN,cAAc,aAAa;MAC3B,MAAM;MACN,QAAQ,OAAO;MACf,aAAa,kBAAkB;MAChC,CAAA;;IAEJ,CAAA;AAED,QAAK,QAAO;;;EAId,MAAM,cAAc,UAA+B;AACjD,QAAK,QAAQ,MAAK;;;uBAIlB,YAwDoB,2BAAA;IAvDjB,UAAU,WAAA;IACV,UAAQ;;IA6BE,SAAO,cAqBV,CApBN,mBAoBM,OApBN,YAoBM,CAnBJ,YAkBgB,MAAA,cAAA,EAAA;iBAjBL,iBAAA;mFAAgB,QAAA;KACxB,SAAS,UAAA;;4BAeK,CAdf,YAce,MAAA,aAAA,EAAA;MAbb,OAAM;MACN,SAAQ;;6BAOD,CANP,mBAMO,QAAA,EALL,OAAK,eAAA,CAAC,qBACE,iBAAA,QAAgB,aAAA,WAAA,CAAA,EAAA,EAAA,gBAEtB,iBAAA,QAAmB,iBAAA,MAAiB,QAAK,oBAAA,EAAA,EAAA,EAG7C,YAGc,MAAA,WAAA,EAAA;OAFZ,OAAM;OACN,MAAK;OACL,MAAK;;;;;;IAMJ,QAAM,cAAe,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAd,kBAAc,GAAA,CAAA,EAAA,CAAA;2BAhDP;KAHzB,YAGyB,4BAAA;kBAFd,WAAA;8EAAU,QAAA;MACnB,aAAY;MACX,UAAQ;;KAGH,aAAA,SAAA,WAAA,EADR,mBAMI,KANJ,YAMI,gBADC,aAAA,MAAY,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;KAIjB,mBAUM,OAVN,YAUM,CATJ,mBAQM,OARN,YAQM,CANJ,YAEqB,oBAAA;MADnB,OAAM;MACL,QAAQ,MAAA,OAAM;8BACjB,mBAEO,QAFP,YAEO,gBADF,MAAA,UAAS,CAAC,UAAO,IAAO,OAAG,GAAA,GAAA,gBAAY,MAAA,KAAI,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteOpenApiDocument.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue"],"names":[],"mappings":"AA4JA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAUvE;;;;;;;;;;;;;;GAcG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IAEhB,2DAA2D;oBAC3C,cAAc;IAC9B,sDAAsD;cAC5C,iBAAiB;;;;;IAH3B,2DAA2D;oBAC3C,cAAc;IAC9B,sDAAsD;cAC5C,iBAAiB;;;;kFAiOzB,CAAC"}
1
+ {"version":3,"file":"CommandPaletteOpenApiDocument.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue"],"names":[],"mappings":"AA2JA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AASvE;;;;;;;;;;;;;;GAcG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IAEhB,2DAA2D;oBAC3C,cAAc;IAC9B,sDAAsD;cAC5C,iBAAiB;;;;;IAH3B,2DAA2D;oBAC3C,cAAc;IAC9B,sDAAsD;cAC5C,iBAAiB;;;;kFAiOzB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteOpenApiDocument.vue.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette OpenAPI Document Component\n *\n * Provides a form for creating a new empty document in the workspace.\n * Users can name the document and select an icon before creation.\n * Validates that the name is not empty and not already in use.\n *\n * @example\n * <CommandPaletteOpenApiDocument\n * :workspaceStore=\"workspaceStore\"\n * :eventBus=\"eventBus\"\n * @close=\"handleClose\"\n * @back=\"handleBack\"\n * />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { LibraryIcon } from '@scalar/icons/library'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, type ComputedRef } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport IconSelector from '@/components/IconSelector.vue'\n\nimport CommandActionForm from './CommandActionForm.vue'\nimport CommandActionInput from './CommandActionInput.vue'\n\nconst { workspaceStore, eventBus } = defineProps<{\n /** The workspace store for accessing existing documents */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting document creation events */\n eventBus: WorkspaceEventBus\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the document is created successfully */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst router = useRouter()\n\nconst documentName = ref('')\nconst documentNameTrimmed = computed(() => documentName.value.trim())\n\n/** Default icon for new documents (folder icon) */\nconst documentIcon = ref('interface-content-folder')\n\n/**\n * Validation message surfaced under the input.\n *\n * Resolves to `null` when the form is valid; otherwise to a human-readable\n * reason the user can act on. Empty input is the default state so we keep\n * the field free of error styling - `isDisabled` still blocks submission\n * there, matching the `CreateVersionModal` pattern.\n */\nconst errorMessage: ComputedRef<string | null> = computed(() => {\n if (!documentNameTrimmed.value) {\n return null\n }\n\n if (\n workspaceStore.workspace.documents[documentNameTrimmed.value] !== undefined\n ) {\n return `A document named \"${documentNameTrimmed.value}\" already exists. Try a different name.`\n }\n\n return null\n})\n\n/**\n * Submit is blocked while the input is empty or fails validation. We keep the\n * button disabled (rather than letting the user fire a no-op submit) because\n * the inline `errorMessage` already explains the fix out loud.\n */\nconst isDisabled = computed<boolean>(\n () => !documentNameTrimmed.value || errorMessage.value !== null,\n)\n\n/** Handle form submission to create a new document */\nconst handleSubmit = (): void => {\n if (isDisabled.value) {\n return\n }\n\n eventBus.emit('document:create:empty-document', {\n name: documentNameTrimmed.value,\n icon: documentIcon.value,\n callback: (success) => {\n if (success) {\n router.push({\n name: 'document.overview',\n params: {\n documentSlug: documentNameTrimmed.value,\n },\n })\n }\n },\n })\n\n emit('close')\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n @submit=\"handleSubmit\">\n <CommandActionInput\n v-model=\"documentName\"\n label=\"Document Name\"\n placeholder=\"Document Name\"\n @delete=\"handleBack\" />\n\n <p\n v-if=\"errorMessage\"\n class=\"text-red px-2 pb-1 text-xs\"\n data-testid=\"command-palette-document-error\"\n role=\"alert\">\n {{ errorMessage }}\n </p>\n\n <!-- Icon selector for choosing document icon -->\n <template #options>\n <IconSelector\n v-model=\"documentIcon\"\n placement=\"bottom-start\">\n <ScalarButton\n class=\"aspect-square h-auto px-0\"\n variant=\"outlined\">\n <LibraryIcon\n class=\"text-c-2 size-4 stroke-[1.75]\"\n :src=\"documentIcon\" />\n </ScalarButton>\n </IconSelector>\n </template>\n\n <template #submit>Create Document</template>\n </CommandActionForm>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"CommandPaletteOpenApiDocument.vue.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette OpenAPI Document Component\n *\n * Provides a form for creating a new empty document in the workspace.\n * Users can name the document and select an icon before creation.\n * Validates that the name is not empty and not already in use.\n *\n * @example\n * <CommandPaletteOpenApiDocument\n * :workspaceStore=\"workspaceStore\"\n * :eventBus=\"eventBus\"\n * @close=\"handleClose\"\n * @back=\"handleBack\"\n * />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { LibraryIcon } from '@scalar/icons/library'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, type ComputedRef } from 'vue'\n\nimport IconSelector from '@/components/IconSelector.vue'\n\nimport CommandActionForm from './CommandActionForm.vue'\nimport CommandActionInput from './CommandActionInput.vue'\n\nconst { workspaceStore, eventBus } = defineProps<{\n /** The workspace store for accessing existing documents */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting document creation events */\n eventBus: WorkspaceEventBus\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the document is created successfully */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst documentName = ref('')\nconst documentNameTrimmed = computed(() => documentName.value.trim())\n\n/** Default icon for new documents (folder icon) */\nconst documentIcon = ref('interface-content-folder')\n\n/**\n * Validation message surfaced under the input.\n *\n * Resolves to `null` when the form is valid; otherwise to a human-readable\n * reason the user can act on. Empty input is the default state so we keep\n * the field free of error styling - `isDisabled` still blocks submission\n * there, matching the `CreateVersionModal` pattern.\n */\nconst errorMessage: ComputedRef<string | null> = computed(() => {\n if (!documentNameTrimmed.value) {\n return null\n }\n\n if (\n workspaceStore.workspace.documents[documentNameTrimmed.value] !== undefined\n ) {\n return `A document named \"${documentNameTrimmed.value}\" already exists. Try a different name.`\n }\n\n return null\n})\n\n/**\n * Submit is blocked while the input is empty or fails validation. We keep the\n * button disabled (rather than letting the user fire a no-op submit) because\n * the inline `errorMessage` already explains the fix out loud.\n */\nconst isDisabled = computed<boolean>(\n () => !documentNameTrimmed.value || errorMessage.value !== null,\n)\n\n/** Handle form submission to create a new document */\nconst handleSubmit = (): void => {\n if (isDisabled.value) {\n return\n }\n\n eventBus.emit('document:create:empty-document', {\n name: documentNameTrimmed.value,\n icon: documentIcon.value,\n callback: (success) => {\n if (!success) {\n return\n }\n\n // Navigate via the event bus rather than the router\n eventBus.emit('ui:navigate', {\n page: 'document',\n path: 'overview',\n documentSlug: documentNameTrimmed.value,\n })\n },\n })\n\n emit('close')\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n @submit=\"handleSubmit\">\n <CommandActionInput\n v-model=\"documentName\"\n label=\"Document Name\"\n placeholder=\"Document Name\"\n @delete=\"handleBack\" />\n\n <p\n v-if=\"errorMessage\"\n class=\"text-red px-2 pb-1 text-xs\"\n data-testid=\"command-palette-document-error\"\n role=\"alert\">\n {{ errorMessage }}\n </p>\n\n <!-- Icon selector for choosing document icon -->\n <template #options>\n <IconSelector\n v-model=\"documentIcon\"\n placement=\"bottom-start\">\n <ScalarButton\n class=\"aspect-square h-auto px-0\"\n variant=\"outlined\">\n <LibraryIcon\n class=\"text-c-2 size-4 stroke-[1.75]\"\n :src=\"documentIcon\" />\n </ScalarButton>\n </IconSelector>\n </template>\n\n <template #submit>Create Document</template>\n </CommandActionForm>\n</template>\n"],"mappings":""}
@@ -3,7 +3,6 @@ import CommandActionInput_default from "./CommandActionInput.vue.js";
3
3
  import IconSelector_default from "../../../../components/IconSelector.vue.js";
4
4
  import { computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, createVNode, defineComponent, openBlock, ref, toDisplayString, unref, withCtx } from "vue";
5
5
  import { ScalarButton } from "@scalar/components";
6
- import { useRouter } from "vue-router";
7
6
  import { LibraryIcon } from "@scalar/icons/library";
8
7
  //#region src/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue?vue&type=script&setup=true&lang.ts
9
8
  var _hoisted_1 = {
@@ -21,7 +20,6 @@ var CommandPaletteOpenApiDocument_vue_vue_type_script_setup_true_lang_default =
21
20
  emits: ["close", "back"],
22
21
  setup(__props, { emit: __emit }) {
23
22
  const emit = __emit;
24
- const router = useRouter();
25
23
  const documentName = ref("");
26
24
  const documentNameTrimmed = computed(() => documentName.value.trim());
27
25
  /** Default icon for new documents (folder icon) */
@@ -52,9 +50,11 @@ var CommandPaletteOpenApiDocument_vue_vue_type_script_setup_true_lang_default =
52
50
  name: documentNameTrimmed.value,
53
51
  icon: documentIcon.value,
54
52
  callback: (success) => {
55
- if (success) router.push({
56
- name: "document.overview",
57
- params: { documentSlug: documentNameTrimmed.value }
53
+ if (!success) return;
54
+ __props.eventBus.emit("ui:navigate", {
55
+ page: "document",
56
+ path: "overview",
57
+ documentSlug: documentNameTrimmed.value
58
58
  });
59
59
  }
60
60
  });
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteOpenApiDocument.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette OpenAPI Document Component\n *\n * Provides a form for creating a new empty document in the workspace.\n * Users can name the document and select an icon before creation.\n * Validates that the name is not empty and not already in use.\n *\n * @example\n * <CommandPaletteOpenApiDocument\n * :workspaceStore=\"workspaceStore\"\n * :eventBus=\"eventBus\"\n * @close=\"handleClose\"\n * @back=\"handleBack\"\n * />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { LibraryIcon } from '@scalar/icons/library'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, type ComputedRef } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport IconSelector from '@/components/IconSelector.vue'\n\nimport CommandActionForm from './CommandActionForm.vue'\nimport CommandActionInput from './CommandActionInput.vue'\n\nconst { workspaceStore, eventBus } = defineProps<{\n /** The workspace store for accessing existing documents */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting document creation events */\n eventBus: WorkspaceEventBus\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the document is created successfully */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst router = useRouter()\n\nconst documentName = ref('')\nconst documentNameTrimmed = computed(() => documentName.value.trim())\n\n/** Default icon for new documents (folder icon) */\nconst documentIcon = ref('interface-content-folder')\n\n/**\n * Validation message surfaced under the input.\n *\n * Resolves to `null` when the form is valid; otherwise to a human-readable\n * reason the user can act on. Empty input is the default state so we keep\n * the field free of error styling - `isDisabled` still blocks submission\n * there, matching the `CreateVersionModal` pattern.\n */\nconst errorMessage: ComputedRef<string | null> = computed(() => {\n if (!documentNameTrimmed.value) {\n return null\n }\n\n if (\n workspaceStore.workspace.documents[documentNameTrimmed.value] !== undefined\n ) {\n return `A document named \"${documentNameTrimmed.value}\" already exists. Try a different name.`\n }\n\n return null\n})\n\n/**\n * Submit is blocked while the input is empty or fails validation. We keep the\n * button disabled (rather than letting the user fire a no-op submit) because\n * the inline `errorMessage` already explains the fix out loud.\n */\nconst isDisabled = computed<boolean>(\n () => !documentNameTrimmed.value || errorMessage.value !== null,\n)\n\n/** Handle form submission to create a new document */\nconst handleSubmit = (): void => {\n if (isDisabled.value) {\n return\n }\n\n eventBus.emit('document:create:empty-document', {\n name: documentNameTrimmed.value,\n icon: documentIcon.value,\n callback: (success) => {\n if (success) {\n router.push({\n name: 'document.overview',\n params: {\n documentSlug: documentNameTrimmed.value,\n },\n })\n }\n },\n })\n\n emit('close')\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n @submit=\"handleSubmit\">\n <CommandActionInput\n v-model=\"documentName\"\n label=\"Document Name\"\n placeholder=\"Document Name\"\n @delete=\"handleBack\" />\n\n <p\n v-if=\"errorMessage\"\n class=\"text-red px-2 pb-1 text-xs\"\n data-testid=\"command-palette-document-error\"\n role=\"alert\">\n {{ errorMessage }}\n </p>\n\n <!-- Icon selector for choosing document icon -->\n <template #options>\n <IconSelector\n v-model=\"documentIcon\"\n placement=\"bottom-start\">\n <ScalarButton\n class=\"aspect-square h-auto px-0\"\n variant=\"outlined\">\n <LibraryIcon\n class=\"text-c-2 size-4 stroke-[1.75]\"\n :src=\"documentIcon\" />\n </ScalarButton>\n </IconSelector>\n </template>\n\n <template #submit>Create Document</template>\n </CommandActionForm>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAuCA,MAAM,OAAO;EAOb,MAAM,SAAS,WAAU;EAEzB,MAAM,eAAe,IAAI,GAAE;EAC3B,MAAM,sBAAsB,eAAe,aAAa,MAAM,MAAM,CAAA;;EAGpE,MAAM,eAAe,IAAI,2BAA0B;;;;;;;;;EAUnD,MAAM,eAA2C,eAAe;AAC9D,OAAI,CAAC,oBAAoB,MACvB,QAAO;AAGT,OACE,QAAA,eAAe,UAAU,UAAU,oBAAoB,WAAW,KAAA,EAElE,QAAO,qBAAqB,oBAAoB,MAAM;AAGxD,UAAO;IACR;;;;;;EAOD,MAAM,aAAa,eACX,CAAC,oBAAoB,SAAS,aAAa,UAAU,KAC7D;;EAGA,MAAM,qBAA2B;AAC/B,OAAI,WAAW,MACb;AAGF,WAAA,SAAS,KAAK,kCAAkC;IAC9C,MAAM,oBAAoB;IAC1B,MAAM,aAAa;IACnB,WAAW,YAAY;AACrB,SAAI,QACF,QAAO,KAAK;MACV,MAAM;MACN,QAAQ,EACN,cAAc,oBAAoB,OACnC;MACF,CAAA;;IAGN,CAAA;AAED,QAAK,QAAO;;;EAId,MAAM,cAAc,UAA+B;AACjD,QAAK,QAAQ,MAAK;;;uBAKlB,YAiCoB,2BAAA;IAhCjB,UAAU,WAAA;IACV,UAAQ;;IAgBE,SAAO,cAWD,CAVf,YAUe,sBAAA;iBATJ,aAAA;+EAAY,QAAA;KACrB,WAAU;;4BAOK,CANf,YAMe,MAAA,aAAA,EAAA;MALb,OAAM;MACN,SAAQ;;6BAGgB,CAFxB,YAEwB,MAAA,YAAA,EAAA;OADtB,OAAM;OACL,KAAK,aAAA;;;;;;IAKH,QAAM,cAAgB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAf,mBAAe,GAAA,CAAA,EAAA,CAAA;2BAzBR,CAJzB,YAIyB,4BAAA;iBAHd,aAAA;+EAAY,QAAA;KACrB,OAAM;KACN,aAAY;KACX,UAAQ;iCAGH,aAAA,SAAA,WAAA,EADR,mBAMI,KANJ,YAMI,gBADC,aAAA,MAAY,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"CommandPaletteOpenApiDocument.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette OpenAPI Document Component\n *\n * Provides a form for creating a new empty document in the workspace.\n * Users can name the document and select an icon before creation.\n * Validates that the name is not empty and not already in use.\n *\n * @example\n * <CommandPaletteOpenApiDocument\n * :workspaceStore=\"workspaceStore\"\n * :eventBus=\"eventBus\"\n * @close=\"handleClose\"\n * @back=\"handleBack\"\n * />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { LibraryIcon } from '@scalar/icons/library'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, type ComputedRef } from 'vue'\n\nimport IconSelector from '@/components/IconSelector.vue'\n\nimport CommandActionForm from './CommandActionForm.vue'\nimport CommandActionInput from './CommandActionInput.vue'\n\nconst { workspaceStore, eventBus } = defineProps<{\n /** The workspace store for accessing existing documents */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting document creation events */\n eventBus: WorkspaceEventBus\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the document is created successfully */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst documentName = ref('')\nconst documentNameTrimmed = computed(() => documentName.value.trim())\n\n/** Default icon for new documents (folder icon) */\nconst documentIcon = ref('interface-content-folder')\n\n/**\n * Validation message surfaced under the input.\n *\n * Resolves to `null` when the form is valid; otherwise to a human-readable\n * reason the user can act on. Empty input is the default state so we keep\n * the field free of error styling - `isDisabled` still blocks submission\n * there, matching the `CreateVersionModal` pattern.\n */\nconst errorMessage: ComputedRef<string | null> = computed(() => {\n if (!documentNameTrimmed.value) {\n return null\n }\n\n if (\n workspaceStore.workspace.documents[documentNameTrimmed.value] !== undefined\n ) {\n return `A document named \"${documentNameTrimmed.value}\" already exists. Try a different name.`\n }\n\n return null\n})\n\n/**\n * Submit is blocked while the input is empty or fails validation. We keep the\n * button disabled (rather than letting the user fire a no-op submit) because\n * the inline `errorMessage` already explains the fix out loud.\n */\nconst isDisabled = computed<boolean>(\n () => !documentNameTrimmed.value || errorMessage.value !== null,\n)\n\n/** Handle form submission to create a new document */\nconst handleSubmit = (): void => {\n if (isDisabled.value) {\n return\n }\n\n eventBus.emit('document:create:empty-document', {\n name: documentNameTrimmed.value,\n icon: documentIcon.value,\n callback: (success) => {\n if (!success) {\n return\n }\n\n // Navigate via the event bus rather than the router\n eventBus.emit('ui:navigate', {\n page: 'document',\n path: 'overview',\n documentSlug: documentNameTrimmed.value,\n })\n },\n })\n\n emit('close')\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n @submit=\"handleSubmit\">\n <CommandActionInput\n v-model=\"documentName\"\n label=\"Document Name\"\n placeholder=\"Document Name\"\n @delete=\"handleBack\" />\n\n <p\n v-if=\"errorMessage\"\n class=\"text-red px-2 pb-1 text-xs\"\n data-testid=\"command-palette-document-error\"\n role=\"alert\">\n {{ errorMessage }}\n </p>\n\n <!-- Icon selector for choosing document icon -->\n <template #options>\n <IconSelector\n v-model=\"documentIcon\"\n placement=\"bottom-start\">\n <ScalarButton\n class=\"aspect-square h-auto px-0\"\n variant=\"outlined\">\n <LibraryIcon\n class=\"text-c-2 size-4 stroke-[1.75]\"\n :src=\"documentIcon\" />\n </ScalarButton>\n </IconSelector>\n </template>\n\n <template #submit>Create Document</template>\n </CommandActionForm>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAsCA,MAAM,OAAO;EAOb,MAAM,eAAe,IAAI,GAAE;EAC3B,MAAM,sBAAsB,eAAe,aAAa,MAAM,MAAM,CAAA;;EAGpE,MAAM,eAAe,IAAI,2BAA0B;;;;;;;;;EAUnD,MAAM,eAA2C,eAAe;AAC9D,OAAI,CAAC,oBAAoB,MACvB,QAAO;AAGT,OACE,QAAA,eAAe,UAAU,UAAU,oBAAoB,WAAW,KAAA,EAElE,QAAO,qBAAqB,oBAAoB,MAAM;AAGxD,UAAO;IACR;;;;;;EAOD,MAAM,aAAa,eACX,CAAC,oBAAoB,SAAS,aAAa,UAAU,KAC7D;;EAGA,MAAM,qBAA2B;AAC/B,OAAI,WAAW,MACb;AAGF,WAAA,SAAS,KAAK,kCAAkC;IAC9C,MAAM,oBAAoB;IAC1B,MAAM,aAAa;IACnB,WAAW,YAAY;AACrB,SAAI,CAAC,QACH;AAIF,aAAA,SAAS,KAAK,eAAe;MAC3B,MAAM;MACN,MAAM;MACN,cAAc,oBAAoB;MACnC,CAAA;;IAEJ,CAAA;AAED,QAAK,QAAO;;;EAId,MAAM,cAAc,UAA+B;AACjD,QAAK,QAAQ,MAAK;;;uBAKlB,YAiCoB,2BAAA;IAhCjB,UAAU,WAAA;IACV,UAAQ;;IAgBE,SAAO,cAWD,CAVf,YAUe,sBAAA;iBATJ,aAAA;+EAAY,QAAA;KACrB,WAAU;;4BAOK,CANf,YAMe,MAAA,aAAA,EAAA;MALb,OAAM;MACN,SAAQ;;6BAGgB,CAFxB,YAEwB,MAAA,YAAA,EAAA;OADtB,OAAM;OACL,KAAK,aAAA;;;;;;IAKH,QAAM,cAAgB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAf,mBAAe,GAAA,CAAA,EAAA,CAAA;2BAzBR,CAJzB,YAIyB,4BAAA;iBAHd,aAAA;+EAAY,QAAA;KACrB,OAAM;KACN,aAAY;KACX,UAAQ;iCAGH,aAAA,SAAA,WAAA,EADR,mBAMI,KANJ,YAMI,gBADC,aAAA,MAAY,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteRequest.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteRequest.vue"],"names":[],"mappings":"AA+WA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAUvE;;;;;;;;;;;;;;;;;GAiBG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY;IAEhB,iEAAiE;oBACjD,cAAc;IAC9B,uDAAuD;cAC7C,iBAAiB;IAC3B,uDAAuD;mBACxC,MAAM;IACrB,0DAA0D;YAClD,MAAM;;;;;IAPd,iEAAiE;oBACjD,cAAc;IAC9B,uDAAuD;cAC7C,iBAAiB;IAC3B,uDAAuD;mBACxC,MAAM;IACrB,0DAA0D;YAClD,MAAM;;;;kFAslBZ,CAAC"}
1
+ {"version":3,"file":"CommandPaletteRequest.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteRequest.vue"],"names":[],"mappings":"AAmXA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AASvE;;;;;;;;;;;;;;;;;GAiBG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY;IAEhB,iEAAiE;oBACjD,cAAc;IAC9B,uDAAuD;cAC7C,iBAAiB;IAC3B,uDAAuD;mBACxC,MAAM;IACrB,0DAA0D;YAClD,MAAM;;;;;IAPd,iEAAiE;oBACjD,cAAc;IAC9B,uDAAuD;cAC7C,iBAAiB;IAC3B,uDAAuD;mBACxC,MAAM;IACrB,0DAA0D;YAClD,MAAM;;;;kFAgmBZ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteRequest.vue.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteRequest.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Request Component\n *\n * Provides a form for creating a new API request (operation) in a document.\n * Users can specify the request path, HTTP method, document (collection),\n * and optionally assign it to a tag.\n *\n * Validates that no operation with the same path and method already exists\n * in the selected document to prevent duplicates.\n *\n * @example\n * <CommandPaletteRequest\n * :workspaceStore=\"workspaceStore\"\n * :eventBus=\"eventBus\"\n * @close=\"handleClose\"\n * @back=\"handleBack\"\n * />\n */\nexport default {\n name: 'CommandPaletteRequest',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownItem,\n ScalarIcon,\n ScalarListbox,\n} from '@scalar/components'\nimport {\n HTTP_METHODS,\n type HttpMethod,\n} from '@scalar/helpers/http/http-methods'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport HttpMethodBadge from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\n\nimport CommandActionForm from './CommandActionForm.vue'\nimport CommandActionInput from './CommandActionInput.vue'\n\nconst { workspaceStore, eventBus, documentName, tagId } = defineProps<{\n /** The workspace store for accessing documents and operations */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting operation creation events */\n eventBus: WorkspaceEventBus\n /** Preselected document id to create the request in */\n documentName?: string\n /** Preselected tag id to add the request to (optional) */\n tagId?: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the request is created successfully */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\n/** HTTP method option type for selectors */\ntype MethodOption = {\n id: string\n label: string\n method: HttpMethod\n}\n\n/** Tag option type for selectors */\ntype TagOption = {\n id: string\n label: string\n}\n\nconst router = useRouter()\n\nconst requestPath = ref('/')\nconst requestPathTrimmed = computed(() => requestPath.value.trim())\n\n/** All available documents (collections) in the workspace */\nconst availableDocuments = computed(() =>\n Object.entries(workspaceStore.workspace.documents).map(\n ([name, document]) => ({\n id: name,\n label: document.info.title || name,\n }),\n ),\n)\n\n/** Available HTTP methods for the dropdown (GET, POST, PUT, etc.) */\nconst availableMethods: MethodOption[] = HTTP_METHODS.map((method) => ({\n id: method,\n label: method.toUpperCase(),\n method,\n}))\n\nconst selectedDocument = ref<{ id: string; label: string } | undefined>(\n documentName\n ? availableDocuments.value.find((document) => document.id === documentName)\n : (availableDocuments.value[0] ?? undefined),\n)\n\nconst selectedMethod = ref<MethodOption | undefined>(\n availableMethods.find((method) => method.method === 'get'),\n)\n\n/**\n * All available tags for the selected document.\n * Includes a \"No Tag\" option for operations without a tag assignment.\n */\nconst availableTags = computed<TagOption[]>(() => {\n if (!selectedDocument.value) {\n return []\n }\n\n const document = workspaceStore.workspace.documents[selectedDocument.value.id]\n if (!document) {\n return []\n }\n\n return [\n { id: '', label: 'No Tag' },\n ...(document.tags?.map((tag) => ({\n id: tag.name,\n label: tag.name,\n })) ?? []),\n ]\n})\n\nconst selectedTag = ref<TagOption | undefined>(\n tagId ? availableTags.value.find((tag) => tag.id === tagId) : undefined,\n)\n\n// Reset the selected tag to the \"No Tag\" option when the document changes\nwatch(selectedDocument, () => {\n selectedTag.value = availableTags.value.find((tag) => tag.id === '')\n})\n\n/**\n * Check if an operation with the same path and method already exists.\n * Used to prevent creating duplicate operations.\n */\nconst operationExists = computed<boolean>(() => {\n if (\n !selectedDocument.value ||\n !selectedMethod.value ||\n !requestPathTrimmed.value\n ) {\n return false\n }\n\n const document = workspaceStore.workspace.documents[selectedDocument.value.id]\n\n /** Ensure path starts with '/' for consistent lookup */\n const normalizedPath = requestPathTrimmed.value.startsWith('/')\n ? requestPathTrimmed.value\n : `/${requestPathTrimmed.value}`\n\n return !!document?.paths?.[normalizedPath]?.[selectedMethod.value.method]\n})\n\n/**\n * Check if the form should be disabled.\n * Disabled when any required field is missing or operation already exists.\n */\nconst isDisabled = computed<boolean>(() => {\n if (\n !requestPathTrimmed.value ||\n !selectedDocument.value ||\n !selectedMethod.value\n ) {\n return true\n }\n\n /** Prevent creating duplicate operations */\n if (operationExists.value) {\n return true\n }\n\n return false\n})\n\n/** Handle HTTP method selection from dropdown */\nconst handleSelectMethod = (method: MethodOption | undefined): void => {\n if (method) {\n selectedMethod.value = method\n }\n}\n\n/** Handle tag selection from dropdown */\nconst handleSelectTag = (tag: TagOption | undefined): void => {\n if (tag) {\n selectedTag.value = tag\n }\n}\n\n/**\n * Create the request and close the command palette.\n * Emits an event to create a new operation with the specified details.\n */\nconst handleSubmit = (): void => {\n if (isDisabled.value || !selectedDocument.value || !selectedMethod.value) {\n return\n }\n\n const document = workspaceStore.workspace.documents[selectedDocument.value.id]\n\n if (!document) {\n return\n }\n\n eventBus.emit('operation:create:operation', {\n documentName: selectedDocument.value.id,\n path: requestPathTrimmed.value,\n method: selectedMethod.value.method,\n operation: {\n tags: selectedTag.value?.id ? [selectedTag.value.id] : undefined,\n },\n callback: (success) => {\n if (success) {\n /** Build the sidebar */\n workspaceStore.buildSidebar(selectedDocument.value?.id ?? '')\n\n const path = requestPathTrimmed.value.startsWith('/')\n ? requestPathTrimmed.value\n : `/${requestPathTrimmed.value}`\n\n /** Navigate to the example */\n router.push({\n name: 'example',\n params: {\n documentSlug: selectedDocument.value?.id,\n pathEncoded: encodeURIComponent(path),\n method: selectedMethod.value?.method,\n exampleName: 'default',\n },\n })\n }\n },\n })\n\n emit('close')\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n @submit=\"handleSubmit\">\n <!-- Request path input -->\n <CommandActionInput\n v-model=\"requestPath\"\n label=\"Request Path\"\n placeholder=\"/users\"\n @delete=\"handleBack\" />\n\n <!-- Selectors for document, method, and tag -->\n <template #options>\n <div class=\"flex flex-1 gap-1\">\n <!-- Document (collection) selector -->\n <ScalarListbox\n v-model=\"selectedDocument\"\n :options=\"availableDocuments\">\n <ScalarButton\n class=\"hover:bg-b-2 max-h-8 w-[150px] min-w-[150px] justify-between gap-1 p-2 text-xs\"\n variant=\"outlined\">\n <span :class=\"selectedDocument ? 'text-c-1 truncate' : 'text-c-3'\">\n {{\n selectedDocument ? selectedDocument.label : 'Select Document'\n }}\n </span>\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n\n <!-- HTTP method selector (GET, POST, PUT, etc.) -->\n <ScalarDropdown\n placement=\"bottom\"\n resize>\n <ScalarButton\n class=\"hover:bg-b-2 max-h-8 w-[100px] min-w-[100px] justify-between gap-1 p-2 text-xs\"\n variant=\"outlined\">\n <div class=\"flex items-center gap-2\">\n <HttpMethodBadge\n v-if=\"selectedMethod\"\n :method=\"selectedMethod.method\" />\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </div>\n </ScalarButton>\n\n <!-- Dropdown list of all HTTP methods -->\n <template #items>\n <div class=\"custom-scroll max-h-40\">\n <ScalarDropdownItem\n v-for=\"method in availableMethods\"\n :key=\"method.id\"\n class=\"flex h-7 w-full items-center justify-center px-1\"\n @click=\"handleSelectMethod(method)\">\n <HttpMethodBadge :method=\"method.method\" />\n </ScalarDropdownItem>\n </div>\n </template>\n </ScalarDropdown>\n\n <!-- Tag selector (optional) for organizing operations -->\n <ScalarDropdown\n placement=\"bottom\"\n resize>\n <ScalarButton\n class=\"hover:bg-b-2 max-h-8 w-full justify-between gap-1 p-2 text-xs\"\n :disabled=\"!availableTags.length\"\n variant=\"outlined\">\n <span :class=\"selectedTag ? 'text-c-1 truncate' : 'text-c-3'\">\n {{ selectedTag ? selectedTag.label : 'Select Tag (Optional)' }}\n </span>\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n\n <!-- Dropdown list of available tags -->\n <template #items>\n <div class=\"custom-scroll max-h-40\">\n <ScalarDropdownItem\n v-for=\"tag in availableTags\"\n :key=\"tag.id\"\n class=\"flex h-7 w-full items-center px-1\"\n @click=\"handleSelectTag(tag)\">\n <span class=\"truncate\">{{ tag.label }}</span>\n </ScalarDropdownItem>\n </div>\n </template>\n </ScalarDropdown>\n </div>\n </template>\n\n <template #submit>Create Request</template>\n </CommandActionForm>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"CommandPaletteRequest.vue.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteRequest.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Request Component\n *\n * Provides a form for creating a new API request (operation) in a document.\n * Users can specify the request path, HTTP method, document (collection),\n * and optionally assign it to a tag.\n *\n * Validates that no operation with the same path and method already exists\n * in the selected document to prevent duplicates.\n *\n * @example\n * <CommandPaletteRequest\n * :workspaceStore=\"workspaceStore\"\n * :eventBus=\"eventBus\"\n * @close=\"handleClose\"\n * @back=\"handleBack\"\n * />\n */\nexport default {\n name: 'CommandPaletteRequest',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownItem,\n ScalarIcon,\n ScalarListbox,\n} from '@scalar/components'\nimport {\n HTTP_METHODS,\n type HttpMethod,\n} from '@scalar/helpers/http/http-methods'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch, type ComputedRef } from 'vue'\n\nimport HttpMethodBadge from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\n\nimport CommandActionForm from './CommandActionForm.vue'\nimport CommandActionInput from './CommandActionInput.vue'\n\nconst { workspaceStore, eventBus, documentName, tagId } = defineProps<{\n /** The workspace store for accessing documents and operations */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting operation creation events */\n eventBus: WorkspaceEventBus\n /** Preselected document id to create the request in */\n documentName?: string\n /** Preselected tag id to add the request to (optional) */\n tagId?: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the request is created successfully */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\n/** HTTP method option type for selectors */\ntype MethodOption = {\n id: string\n label: string\n method: HttpMethod\n}\n\n/** Tag option type for selectors */\ntype TagOption = {\n id: string\n label: string\n}\n\nconst requestPath = ref('/')\nconst requestPathTrimmed = computed(() => requestPath.value.trim())\n\n/** Ensure path starts with '/' for consistent lookup */\nconst normalizedRequestPath = computed<string>(() =>\n requestPathTrimmed.value.startsWith('/')\n ? requestPathTrimmed.value\n : `/${requestPathTrimmed.value}`,\n)\n\n/** All available documents (collections) in the workspace */\nconst availableDocuments = computed(() =>\n Object.entries(workspaceStore.workspace.documents).map(\n ([name, document]) => ({\n id: name,\n label: document.info.title || name,\n }),\n ),\n)\n\n/** Available HTTP methods for the dropdown (GET, POST, PUT, etc.) */\nconst availableMethods: MethodOption[] = HTTP_METHODS.map((method) => ({\n id: method,\n label: method.toUpperCase(),\n method,\n}))\n\nconst selectedDocument = ref<{ id: string; label: string } | undefined>(\n documentName\n ? availableDocuments.value.find((document) => document.id === documentName)\n : (availableDocuments.value[0] ?? undefined),\n)\n\nconst selectedMethod = ref<MethodOption | undefined>(\n availableMethods.find((method) => method.method === 'get'),\n)\n\n/**\n * All available tags for the selected document.\n * Includes a \"No Tag\" option for operations without a tag assignment.\n */\nconst availableTags = computed<TagOption[]>(() => {\n if (!selectedDocument.value) {\n return []\n }\n\n const document = workspaceStore.workspace.documents[selectedDocument.value.id]\n if (!document) {\n return []\n }\n\n return [\n { id: '', label: 'No Tag' },\n ...(document.tags?.map((tag) => ({\n id: tag.name,\n label: tag.name,\n })) ?? []),\n ]\n})\n\nconst selectedTag = ref<TagOption | undefined>(\n tagId ? availableTags.value.find((tag) => tag.id === tagId) : undefined,\n)\n\n// Reset the selected tag to the \"No Tag\" option when the document changes\nwatch(selectedDocument, () => {\n selectedTag.value = availableTags.value.find((tag) => tag.id === '')\n})\n\n/**\n * Validation message surfaced under the input.\n *\n * Resolves to `null` when the form is valid; otherwise to a human-readable\n * reason the user can act on. Empty input is the default state so we keep\n * the field free of error styling — `isDisabled` still blocks submission\n * there, matching the {@link CommandPaletteOpenApiDocument} pattern.\n */\nconst errorMessage: ComputedRef<string | null> = computed(() => {\n if (\n !requestPathTrimmed.value ||\n !selectedDocument.value ||\n !selectedMethod.value\n ) {\n return null\n }\n\n const document = workspaceStore.workspace.documents[selectedDocument.value.id]\n const method = selectedMethod.value.method\n\n if (document?.paths?.[normalizedRequestPath.value]?.[method]) {\n return `A ${method.toUpperCase()} operation at \"${normalizedRequestPath.value}\" already exists in \"${selectedDocument.value.label}\". Try a different path or method.`\n }\n\n return null\n})\n\n/**\n * Submit is blocked while required fields are missing or a duplicate exists.\n * The inline `errorMessage` explains the duplicate case so the user knows how\n * to recover instead of facing a silently disabled button.\n */\nconst isDisabled = computed<boolean>(\n () =>\n !requestPathTrimmed.value ||\n !selectedDocument.value ||\n !selectedMethod.value ||\n errorMessage.value !== null,\n)\n\n/** Handle HTTP method selection from dropdown */\nconst handleSelectMethod = (method: MethodOption | undefined): void => {\n if (method) {\n selectedMethod.value = method\n }\n}\n\n/** Handle tag selection from dropdown */\nconst handleSelectTag = (tag: TagOption | undefined): void => {\n if (tag) {\n selectedTag.value = tag\n }\n}\n\n/**\n * Create the request and close the command palette.\n * Emits an event to create a new operation with the specified details.\n */\nconst handleSubmit = (): void => {\n if (isDisabled.value || !selectedDocument.value || !selectedMethod.value) {\n return\n }\n\n const document = workspaceStore.workspace.documents[selectedDocument.value.id]\n\n if (!document) {\n return\n }\n\n eventBus.emit('operation:create:operation', {\n documentName: selectedDocument.value.id,\n path: requestPathTrimmed.value,\n method: selectedMethod.value.method,\n operation: {\n tags: selectedTag.value?.id ? [selectedTag.value.id] : undefined,\n },\n callback: (success) => {\n if (!success) {\n return\n }\n\n /** Build the sidebar */\n workspaceStore.buildSidebar(selectedDocument.value?.id ?? '')\n\n /** Navigate to the example via the event bus rather than the router */\n eventBus.emit('ui:navigate', {\n page: 'example',\n documentSlug: selectedDocument.value?.id,\n path: normalizedRequestPath.value,\n method: selectedMethod.value?.method ?? 'get',\n exampleName: 'default',\n })\n },\n })\n\n emit('close')\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n @submit=\"handleSubmit\">\n <!-- Request path input -->\n <CommandActionInput\n v-model=\"requestPath\"\n label=\"Request Path\"\n placeholder=\"/users\"\n @delete=\"handleBack\" />\n\n <p\n v-if=\"errorMessage\"\n class=\"text-red px-2 pb-1 text-xs\"\n data-testid=\"command-palette-request-error\"\n role=\"alert\">\n {{ errorMessage }}\n </p>\n\n <!-- Selectors for document, method, and tag -->\n <template #options>\n <div class=\"flex flex-1 gap-1\">\n <!-- Document (collection) selector -->\n <ScalarListbox\n v-model=\"selectedDocument\"\n :options=\"availableDocuments\">\n <ScalarButton\n class=\"hover:bg-b-2 max-h-8 w-[150px] min-w-[150px] justify-between gap-1 p-2 text-xs\"\n variant=\"outlined\">\n <span :class=\"selectedDocument ? 'text-c-1 truncate' : 'text-c-3'\">\n {{\n selectedDocument ? selectedDocument.label : 'Select Document'\n }}\n </span>\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n\n <!-- HTTP method selector (GET, POST, PUT, etc.) -->\n <ScalarDropdown\n placement=\"bottom\"\n resize>\n <ScalarButton\n class=\"hover:bg-b-2 max-h-8 w-[100px] min-w-[100px] justify-between gap-1 p-2 text-xs\"\n variant=\"outlined\">\n <div class=\"flex items-center gap-2\">\n <HttpMethodBadge\n v-if=\"selectedMethod\"\n :method=\"selectedMethod.method\" />\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </div>\n </ScalarButton>\n\n <!-- Dropdown list of all HTTP methods -->\n <template #items>\n <div class=\"custom-scroll max-h-40\">\n <ScalarDropdownItem\n v-for=\"method in availableMethods\"\n :key=\"method.id\"\n class=\"flex h-7 w-full items-center justify-center px-1\"\n @click=\"handleSelectMethod(method)\">\n <HttpMethodBadge :method=\"method.method\" />\n </ScalarDropdownItem>\n </div>\n </template>\n </ScalarDropdown>\n\n <!-- Tag selector (optional) for organizing operations -->\n <ScalarDropdown\n placement=\"bottom\"\n resize>\n <ScalarButton\n class=\"hover:bg-b-2 max-h-8 w-full justify-between gap-1 p-2 text-xs\"\n :disabled=\"!availableTags.length\"\n variant=\"outlined\">\n <span :class=\"selectedTag ? 'text-c-1 truncate' : 'text-c-3'\">\n {{ selectedTag ? selectedTag.label : 'Select Tag (Optional)' }}\n </span>\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n\n <!-- Dropdown list of available tags -->\n <template #items>\n <div class=\"custom-scroll max-h-40\">\n <ScalarDropdownItem\n v-for=\"tag in availableTags\"\n :key=\"tag.id\"\n class=\"flex h-7 w-full items-center px-1\"\n @click=\"handleSelectTag(tag)\">\n <span class=\"truncate\">{{ tag.label }}</span>\n </ScalarDropdownItem>\n </div>\n </template>\n </ScalarDropdown>\n </div>\n </template>\n\n <template #submit>Create Request</template>\n </CommandActionForm>\n</template>\n"],"mappings":""}
@@ -3,14 +3,19 @@ import CommandActionForm_default from "./CommandActionForm.vue.js";
3
3
  import CommandActionInput_default from "./CommandActionInput.vue.js";
4
4
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, renderList, toDisplayString, unref, watch, withCtx } from "vue";
5
5
  import { ScalarButton, ScalarDropdown, ScalarDropdownItem, ScalarIcon, ScalarListbox } from "@scalar/components";
6
- import { useRouter } from "vue-router";
7
6
  import { HTTP_METHODS } from "@scalar/helpers/http/http-methods";
8
7
  //#region src/v2/features/command-palette/components/CommandPaletteRequest.vue?vue&type=script&setup=true&lang.ts
9
- var _hoisted_1 = { class: "flex flex-1 gap-1" };
10
- var _hoisted_2 = { class: "flex items-center gap-2" };
11
- var _hoisted_3 = { class: "custom-scroll max-h-40" };
8
+ var _hoisted_1 = {
9
+ key: 0,
10
+ class: "text-red px-2 pb-1 text-xs",
11
+ "data-testid": "command-palette-request-error",
12
+ role: "alert"
13
+ };
14
+ var _hoisted_2 = { class: "flex flex-1 gap-1" };
15
+ var _hoisted_3 = { class: "flex items-center gap-2" };
12
16
  var _hoisted_4 = { class: "custom-scroll max-h-40" };
13
- var _hoisted_5 = { class: "truncate" };
17
+ var _hoisted_5 = { class: "custom-scroll max-h-40" };
18
+ var _hoisted_6 = { class: "truncate" };
14
19
  var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
15
20
  name: "CommandPaletteRequest",
16
21
  props: {
@@ -23,9 +28,10 @@ var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PU
23
28
  setup(__props, { emit: __emit }) {
24
29
  const emit = __emit;
25
30
  /** HTTP method option type for selectors */
26
- const router = useRouter();
27
31
  const requestPath = ref("/");
28
32
  const requestPathTrimmed = computed(() => requestPath.value.trim());
33
+ /** Ensure path starts with '/' for consistent lookup */
34
+ const normalizedRequestPath = computed(() => requestPathTrimmed.value.startsWith("/") ? requestPathTrimmed.value : `/${requestPathTrimmed.value}`);
29
35
  /** All available documents (collections) in the workspace */
30
36
  const availableDocuments = computed(() => Object.entries(__props.workspaceStore.workspace.documents).map(([name, document]) => ({
31
37
  id: name,
@@ -60,26 +66,26 @@ var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PU
60
66
  selectedTag.value = availableTags.value.find((tag) => tag.id === "");
61
67
  });
62
68
  /**
63
- * Check if an operation with the same path and method already exists.
64
- * Used to prevent creating duplicate operations.
69
+ * Validation message surfaced under the input.
70
+ *
71
+ * Resolves to `null` when the form is valid; otherwise to a human-readable
72
+ * reason the user can act on. Empty input is the default state so we keep
73
+ * the field free of error styling — `isDisabled` still blocks submission
74
+ * there, matching the {@link CommandPaletteOpenApiDocument} pattern.
65
75
  */
66
- const operationExists = computed(() => {
67
- if (!selectedDocument.value || !selectedMethod.value || !requestPathTrimmed.value) return false;
76
+ const errorMessage = computed(() => {
77
+ if (!requestPathTrimmed.value || !selectedDocument.value || !selectedMethod.value) return null;
68
78
  const document = __props.workspaceStore.workspace.documents[selectedDocument.value.id];
69
- /** Ensure path starts with '/' for consistent lookup */
70
- const normalizedPath = requestPathTrimmed.value.startsWith("/") ? requestPathTrimmed.value : `/${requestPathTrimmed.value}`;
71
- return !!document?.paths?.[normalizedPath]?.[selectedMethod.value.method];
79
+ const method = selectedMethod.value.method;
80
+ if (document?.paths?.[normalizedRequestPath.value]?.[method]) return `A ${method.toUpperCase()} operation at "${normalizedRequestPath.value}" already exists in "${selectedDocument.value.label}". Try a different path or method.`;
81
+ return null;
72
82
  });
73
83
  /**
74
- * Check if the form should be disabled.
75
- * Disabled when any required field is missing or operation already exists.
84
+ * Submit is blocked while required fields are missing or a duplicate exists.
85
+ * The inline `errorMessage` explains the duplicate case so the user knows how
86
+ * to recover instead of facing a silently disabled button.
76
87
  */
77
- const isDisabled = computed(() => {
78
- if (!requestPathTrimmed.value || !selectedDocument.value || !selectedMethod.value) return true;
79
- /** Prevent creating duplicate operations */
80
- if (operationExists.value) return true;
81
- return false;
82
- });
88
+ const isDisabled = computed(() => !requestPathTrimmed.value || !selectedDocument.value || !selectedMethod.value || errorMessage.value !== null);
83
89
  /** Handle HTTP method selection from dropdown */
84
90
  const handleSelectMethod = (method) => {
85
91
  if (method) selectedMethod.value = method;
@@ -101,21 +107,17 @@ var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PU
101
107
  method: selectedMethod.value.method,
102
108
  operation: { tags: selectedTag.value?.id ? [selectedTag.value.id] : void 0 },
103
109
  callback: (success) => {
104
- if (success) {
105
- /** Build the sidebar */
106
- __props.workspaceStore.buildSidebar(selectedDocument.value?.id ?? "");
107
- const path = requestPathTrimmed.value.startsWith("/") ? requestPathTrimmed.value : `/${requestPathTrimmed.value}`;
108
- /** Navigate to the example */
109
- router.push({
110
- name: "example",
111
- params: {
112
- documentSlug: selectedDocument.value?.id,
113
- pathEncoded: encodeURIComponent(path),
114
- method: selectedMethod.value?.method,
115
- exampleName: "default"
116
- }
117
- });
118
- }
110
+ if (!success) return;
111
+ /** Build the sidebar */
112
+ __props.workspaceStore.buildSidebar(selectedDocument.value?.id ?? "");
113
+ /** Navigate to the example via the event bus rather than the router */
114
+ __props.eventBus.emit("ui:navigate", {
115
+ page: "example",
116
+ documentSlug: selectedDocument.value?.id,
117
+ path: normalizedRequestPath.value,
118
+ method: selectedMethod.value?.method ?? "get",
119
+ exampleName: "default"
120
+ });
119
121
  }
120
122
  });
121
123
  emit("close");
@@ -129,7 +131,7 @@ var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PU
129
131
  disabled: isDisabled.value,
130
132
  onSubmit: handleSubmit
131
133
  }, {
132
- options: withCtx(() => [createElementVNode("div", _hoisted_1, [
134
+ options: withCtx(() => [createElementVNode("div", _hoisted_2, [
133
135
  createVNode(unref(ScalarListbox), {
134
136
  modelValue: selectedDocument.value,
135
137
  "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => selectedDocument.value = $event),
@@ -152,7 +154,7 @@ var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PU
152
154
  placement: "bottom",
153
155
  resize: ""
154
156
  }, {
155
- items: withCtx(() => [createElementVNode("div", _hoisted_3, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(availableMethods), (method) => {
157
+ items: withCtx(() => [createElementVNode("div", _hoisted_4, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(availableMethods), (method) => {
156
158
  return openBlock(), createBlock(unref(ScalarDropdownItem), {
157
159
  key: method.id,
158
160
  class: "flex h-7 w-full items-center justify-center px-1",
@@ -166,7 +168,7 @@ var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PU
166
168
  class: "hover:bg-b-2 max-h-8 w-[100px] min-w-[100px] justify-between gap-1 p-2 text-xs",
167
169
  variant: "outlined"
168
170
  }, {
169
- default: withCtx(() => [createElementVNode("div", _hoisted_2, [selectedMethod.value ? (openBlock(), createBlock(HttpMethod_default, {
171
+ default: withCtx(() => [createElementVNode("div", _hoisted_3, [selectedMethod.value ? (openBlock(), createBlock(HttpMethod_default, {
170
172
  key: 0,
171
173
  method: selectedMethod.value.method
172
174
  }, null, 8, ["method"])) : createCommentVNode("", true), createVNode(unref(ScalarIcon), {
@@ -182,13 +184,13 @@ var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PU
182
184
  placement: "bottom",
183
185
  resize: ""
184
186
  }, {
185
- items: withCtx(() => [createElementVNode("div", _hoisted_4, [(openBlock(true), createElementBlock(Fragment, null, renderList(availableTags.value, (tag) => {
187
+ items: withCtx(() => [createElementVNode("div", _hoisted_5, [(openBlock(true), createElementBlock(Fragment, null, renderList(availableTags.value, (tag) => {
186
188
  return openBlock(), createBlock(unref(ScalarDropdownItem), {
187
189
  key: tag.id,
188
190
  class: "flex h-7 w-full items-center px-1",
189
191
  onClick: ($event) => handleSelectTag(tag)
190
192
  }, {
191
- default: withCtx(() => [createElementVNode("span", _hoisted_5, toDisplayString(tag.label), 1)]),
193
+ default: withCtx(() => [createElementVNode("span", _hoisted_6, toDisplayString(tag.label), 1)]),
192
194
  _: 2
193
195
  }, 1032, ["onClick"]);
194
196
  }), 128))])]),
@@ -214,7 +216,7 @@ var CommandPaletteRequest_vue_vue_type_script_setup_true_lang_default = /* @__PU
214
216
  label: "Request Path",
215
217
  placeholder: "/users",
216
218
  onDelete: handleBack
217
- }, null, 8, ["modelValue"])]),
219
+ }, null, 8, ["modelValue"]), errorMessage.value ? (openBlock(), createElementBlock("p", _hoisted_1, toDisplayString(errorMessage.value), 1)) : createCommentVNode("", true)]),
218
220
  _: 1
219
221
  }, 8, ["disabled"]);
220
222
  };