@scalar/api-client 3.3.1 → 3.5.0

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 (191) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/monacoeditorwork/yaml.worker.bundle.js +92 -79
  3. package/dist/style.css +87 -57
  4. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts +2 -0
  5. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
  6. package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
  7. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +5 -0
  8. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
  9. package/dist/v2/blocks/operation-block/components/Header.vue.d.ts +4 -0
  10. package/dist/v2/blocks/operation-block/components/Header.vue.d.ts.map +1 -1
  11. package/dist/v2/blocks/operation-block/components/Header.vue.js +1 -1
  12. package/dist/v2/blocks/operation-block/components/Header.vue.js.map +1 -1
  13. package/dist/v2/blocks/operation-block/components/Header.vue.script.js +6 -0
  14. package/dist/v2/blocks/operation-block/components/Header.vue.script.js.map +1 -1
  15. package/dist/v2/blocks/operation-block/helpers/response-cache.d.ts +2 -1
  16. package/dist/v2/blocks/operation-block/helpers/response-cache.d.ts.map +1 -1
  17. package/dist/v2/blocks/operation-block/helpers/response-cache.js +9 -2
  18. package/dist/v2/blocks/operation-block/helpers/response-cache.js.map +1 -1
  19. package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts +2 -2
  20. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts +2 -2
  21. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts +4 -0
  22. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts.map +1 -1
  23. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js +1 -1
  24. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js.map +1 -1
  25. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js +84 -71
  26. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js.map +1 -1
  27. package/dist/v2/blocks/scalar-address-bar-block/helpers/is-placeholder-path.d.ts +13 -0
  28. package/dist/v2/blocks/scalar-address-bar-block/helpers/is-placeholder-path.d.ts.map +1 -0
  29. package/dist/v2/blocks/scalar-address-bar-block/helpers/is-placeholder-path.js +28 -0
  30. package/dist/v2/blocks/scalar-address-bar-block/helpers/is-placeholder-path.js.map +1 -0
  31. package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.d.ts +16 -0
  32. package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.d.ts.map +1 -0
  33. package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.js +28 -0
  34. package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.js.map +1 -0
  35. package/dist/v2/blocks/scalar-address-bar-block/hooks/use-path-masking.d.ts +31 -0
  36. package/dist/v2/blocks/scalar-address-bar-block/hooks/use-path-masking.d.ts.map +1 -0
  37. package/dist/v2/blocks/scalar-address-bar-block/hooks/use-path-masking.js +18 -0
  38. package/dist/v2/blocks/scalar-address-bar-block/hooks/use-path-masking.js.map +1 -0
  39. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-callback.d.ts +69 -0
  40. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-callback.d.ts.map +1 -0
  41. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-callback.js +75 -0
  42. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-callback.js.map +1 -0
  43. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts +17 -0
  44. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts.map +1 -1
  45. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js +43 -44
  46. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js.map +1 -1
  47. package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
  48. package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
  49. package/dist/v2/components/code-input/CodeInput.vue.script.js +1 -1
  50. package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
  51. package/dist/v2/constants.js +1 -1
  52. package/dist/v2/features/app/App.vue.d.ts +25 -1
  53. package/dist/v2/features/app/App.vue.d.ts.map +1 -1
  54. package/dist/v2/features/app/App.vue.js.map +1 -1
  55. package/dist/v2/features/app/App.vue.script.js +54 -39
  56. package/dist/v2/features/app/App.vue.script.js.map +1 -1
  57. package/dist/v2/features/app/app-events.js +4 -4
  58. package/dist/v2/features/app/app-events.js.map +1 -1
  59. package/dist/v2/features/app/app-state.d.ts +20 -14
  60. package/dist/v2/features/app/app-state.d.ts.map +1 -1
  61. package/dist/v2/features/app/app-state.js +89 -55
  62. package/dist/v2/features/app/app-state.js.map +1 -1
  63. package/dist/v2/features/app/components/AppHeader.vue.d.ts +26 -3
  64. package/dist/v2/features/app/components/AppHeader.vue.d.ts.map +1 -1
  65. package/dist/v2/features/app/components/AppHeader.vue.js.map +1 -1
  66. package/dist/v2/features/app/components/AppHeader.vue.script.js +15 -6
  67. package/dist/v2/features/app/components/AppHeader.vue.script.js.map +1 -1
  68. package/dist/v2/features/app/components/AppSidebar.vue.d.ts +2 -2
  69. package/dist/v2/features/app/components/AppSidebar.vue.d.ts.map +1 -1
  70. package/dist/v2/features/app/components/AppSidebar.vue.js +1 -1
  71. package/dist/v2/features/app/components/AppSidebar.vue.js.map +1 -1
  72. package/dist/v2/features/app/components/AppSidebar.vue.script.js +86 -108
  73. package/dist/v2/features/app/components/AppSidebar.vue.script.js.map +1 -1
  74. package/dist/v2/features/app/components/CreateVersionModal.vue.d.ts +28 -0
  75. package/dist/v2/features/app/components/CreateVersionModal.vue.d.ts.map +1 -0
  76. package/dist/v2/features/app/components/CreateVersionModal.vue.js +7 -0
  77. package/dist/v2/features/app/components/CreateVersionModal.vue.js.map +1 -0
  78. package/dist/v2/features/app/components/CreateVersionModal.vue.script.js +84 -0
  79. package/dist/v2/features/app/components/CreateVersionModal.vue.script.js.map +1 -0
  80. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts +26 -0
  81. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts.map +1 -0
  82. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js +9 -0
  83. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js.map +1 -0
  84. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js +376 -0
  85. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js.map +1 -0
  86. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.d.ts +16 -0
  87. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.d.ts.map +1 -0
  88. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.js +7 -0
  89. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.js.map +1 -0
  90. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.script.js +51 -0
  91. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.script.js.map +1 -0
  92. package/dist/v2/features/app/components/SidebarDocument.vue.d.ts +45 -0
  93. package/dist/v2/features/app/components/SidebarDocument.vue.d.ts.map +1 -0
  94. package/dist/v2/features/app/components/SidebarDocument.vue.js +7 -0
  95. package/dist/v2/features/app/components/SidebarDocument.vue.js.map +1 -0
  96. package/dist/v2/features/app/components/SidebarDocument.vue.script.js +137 -0
  97. package/dist/v2/features/app/components/SidebarDocument.vue.script.js.map +1 -0
  98. package/dist/v2/features/app/helpers/check-version-conflict.d.ts +51 -0
  99. package/dist/v2/features/app/helpers/check-version-conflict.d.ts.map +1 -0
  100. package/dist/v2/features/app/helpers/check-version-conflict.js +79 -0
  101. package/dist/v2/features/app/helpers/check-version-conflict.js.map +1 -0
  102. package/dist/v2/features/app/helpers/compute-version-status.d.ts +45 -0
  103. package/dist/v2/features/app/helpers/compute-version-status.d.ts.map +1 -0
  104. package/dist/v2/features/app/helpers/compute-version-status.js +18 -0
  105. package/dist/v2/features/app/helpers/compute-version-status.js.map +1 -0
  106. package/dist/v2/features/app/helpers/create-draft-registry-document.d.ts +39 -0
  107. package/dist/v2/features/app/helpers/create-draft-registry-document.d.ts.map +1 -0
  108. package/dist/v2/features/app/helpers/create-draft-registry-document.js +64 -0
  109. package/dist/v2/features/app/helpers/create-draft-registry-document.js.map +1 -0
  110. package/dist/v2/features/app/helpers/create-temp-operation.d.ts.map +1 -1
  111. package/dist/v2/features/app/helpers/create-temp-operation.js +5 -8
  112. package/dist/v2/features/app/helpers/create-temp-operation.js.map +1 -1
  113. package/dist/v2/features/app/helpers/detect-document-conflicts.d.ts +26 -0
  114. package/dist/v2/features/app/helpers/detect-document-conflicts.d.ts.map +1 -0
  115. package/dist/v2/features/app/helpers/detect-document-conflicts.js +27 -0
  116. package/dist/v2/features/app/helpers/detect-document-conflicts.js.map +1 -0
  117. package/dist/v2/features/app/helpers/filter-workspaces.d.ts +14 -14
  118. package/dist/v2/features/app/helpers/filter-workspaces.d.ts.map +1 -1
  119. package/dist/v2/features/app/helpers/filter-workspaces.js +15 -15
  120. package/dist/v2/features/app/helpers/filter-workspaces.js.map +1 -1
  121. package/dist/v2/features/app/helpers/group-workspaces.d.ts +23 -3
  122. package/dist/v2/features/app/helpers/group-workspaces.d.ts.map +1 -1
  123. package/dist/v2/features/app/helpers/group-workspaces.js +22 -7
  124. package/dist/v2/features/app/helpers/group-workspaces.js.map +1 -1
  125. package/dist/v2/features/app/helpers/load-registry-document.d.ts +16 -1
  126. package/dist/v2/features/app/helpers/load-registry-document.d.ts.map +1 -1
  127. package/dist/v2/features/app/helpers/load-registry-document.js +7 -6
  128. package/dist/v2/features/app/helpers/load-registry-document.js.map +1 -1
  129. package/dist/v2/features/app/helpers/routes.d.ts +5 -1
  130. package/dist/v2/features/app/helpers/routes.d.ts.map +1 -1
  131. package/dist/v2/features/app/helpers/routes.js +1 -1
  132. package/dist/v2/features/app/helpers/routes.js.map +1 -1
  133. package/dist/v2/features/app/helpers/version-status-presentation.d.ts +24 -0
  134. package/dist/v2/features/app/helpers/version-status-presentation.d.ts.map +1 -0
  135. package/dist/v2/features/app/helpers/version-status-presentation.js +43 -0
  136. package/dist/v2/features/app/helpers/version-status-presentation.js.map +1 -0
  137. package/dist/v2/features/app/hooks/use-active-document-version.d.ts +41 -0
  138. package/dist/v2/features/app/hooks/use-active-document-version.d.ts.map +1 -0
  139. package/dist/v2/features/app/hooks/use-active-document-version.js +60 -0
  140. package/dist/v2/features/app/hooks/use-active-document-version.js.map +1 -0
  141. package/dist/v2/features/app/hooks/use-sidebar-documents.d.ts +71 -23
  142. package/dist/v2/features/app/hooks/use-sidebar-documents.d.ts.map +1 -1
  143. package/dist/v2/features/app/hooks/use-sidebar-documents.js +167 -45
  144. package/dist/v2/features/app/hooks/use-sidebar-documents.js.map +1 -1
  145. package/dist/v2/features/app/hooks/use-version-conflict-check.d.ts +35 -0
  146. package/dist/v2/features/app/hooks/use-version-conflict-check.d.ts.map +1 -0
  147. package/dist/v2/features/app/hooks/use-version-conflict-check.js +62 -0
  148. package/dist/v2/features/app/hooks/use-version-conflict-check.js.map +1 -0
  149. package/dist/v2/features/collection/DocumentCollection.vue.d.ts.map +1 -1
  150. package/dist/v2/features/collection/DocumentCollection.vue.js.map +1 -1
  151. package/dist/v2/features/collection/DocumentCollection.vue.script.js +6 -1
  152. package/dist/v2/features/collection/DocumentCollection.vue.script.js.map +1 -1
  153. package/dist/v2/features/collection/OperationCollection.vue.script.js +1 -0
  154. package/dist/v2/features/collection/OperationCollection.vue.script.js.map +1 -1
  155. package/dist/v2/features/collection/WorkspaceCollection.vue.script.js +1 -0
  156. package/dist/v2/features/collection/WorkspaceCollection.vue.script.js.map +1 -1
  157. package/dist/v2/features/collection/components/Authentication.vue.script.js +1 -0
  158. package/dist/v2/features/collection/components/Authentication.vue.script.js.map +1 -1
  159. package/dist/v2/features/collection/components/Cookies.vue.script.js +1 -0
  160. package/dist/v2/features/collection/components/Cookies.vue.script.js.map +1 -1
  161. package/dist/v2/features/collection/components/Editor/Editor.vue.script.js +1 -0
  162. package/dist/v2/features/collection/components/Editor/Editor.vue.script.js.map +1 -1
  163. package/dist/v2/features/collection/components/Environment.vue.script.js +1 -0
  164. package/dist/v2/features/collection/components/Environment.vue.script.js.map +1 -1
  165. package/dist/v2/features/collection/components/GetStarted.vue.d.ts +12 -4
  166. package/dist/v2/features/collection/components/GetStarted.vue.d.ts.map +1 -1
  167. package/dist/v2/features/collection/components/GetStarted.vue.js.map +1 -1
  168. package/dist/v2/features/collection/components/GetStarted.vue.script.js +56 -13
  169. package/dist/v2/features/collection/components/GetStarted.vue.script.js.map +1 -1
  170. package/dist/v2/features/collection/components/Overview.vue.script.js +1 -0
  171. package/dist/v2/features/collection/components/Overview.vue.script.js.map +1 -1
  172. package/dist/v2/features/collection/components/Runner/components/Runner.vue.script.js +1 -0
  173. package/dist/v2/features/collection/components/Runner/components/Runner.vue.script.js.map +1 -1
  174. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js +2 -2
  175. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js.map +1 -1
  176. package/dist/v2/features/collection/components/Scripts.vue.script.js +1 -0
  177. package/dist/v2/features/collection/components/Scripts.vue.script.js.map +1 -1
  178. package/dist/v2/features/collection/components/Servers.vue.script.js +1 -0
  179. package/dist/v2/features/collection/components/Servers.vue.script.js.map +1 -1
  180. package/dist/v2/features/collection/components/Settings.vue.script.js +1 -0
  181. package/dist/v2/features/collection/components/Settings.vue.script.js.map +1 -1
  182. package/dist/v2/features/editor/hooks/use-three-way-merge-editor.js +1 -1
  183. package/dist/v2/features/operation/Operation.vue.d.ts.map +1 -1
  184. package/dist/v2/features/operation/Operation.vue.js.map +1 -1
  185. package/dist/v2/features/operation/Operation.vue.script.js +3 -0
  186. package/dist/v2/features/operation/Operation.vue.script.js.map +1 -1
  187. package/dist/v2/helpers/safe-run.d.ts +25 -1
  188. package/dist/v2/helpers/safe-run.d.ts.map +1 -1
  189. package/dist/v2/helpers/safe-run.js +26 -2
  190. package/dist/v2/helpers/safe-run.js.map +1 -1
  191. package/package.json +16 -15
@@ -1 +1 @@
1
- {"version":3,"file":"CodeInput.vue.script.js","names":["$attrs","$slots"],"sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeInputModelValue =\n | string\n | number\n | boolean\n | Array<string | number | boolean>\n | Record<string, unknown>\n\n/**\n * CodeInput\n *\n * A versatile input component that adapts its rendering based on props:\n * - Disabled mode: Read-only text display\n * - Select mode: Dropdown for enums, booleans, or examples\n * - Editor mode: CodeMirror with environment variable support\n *\n * Type `{{` to trigger autocomplete for environment variables and runtime context functions\n * (for example `{{$guid}}`) when an environment is provided.\n * It takes in any data but always will emit a string value,\n * this string should then be parsed in accordance to the schema or content type.\n *\n * @example\n * ```vue\n * <!-- Basic input with environment variables -->\n * <CodeInput v-model=\"value\" :environment=\"env\" />\n *\n * <!-- Boolean select -->\n * <CodeInput v-model=\"flag\" type=\"boolean\" />\n *\n * <!-- JSON editor with linting -->\n * <CodeInput v-model=\"data\" language=\"json\" :lint=\"true\" />\n * ```\n */\nexport default {\n inheritAttrs: false,\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport {\n colorPicker as colorPickerExtension,\n useCodeMirror,\n useDropdown,\n type CodeMirrorLanguage,\n type Extension,\n} from '@scalar/use-codemirror'\nimport {\n CONTEXT_FUNCTION_NAMES,\n getContextFunctionComment,\n isContextFunctionName,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { nanoid } from 'nanoid'\nimport { computed, ref, toRef, useAttrs, watch, type Ref } from 'vue'\n\nimport DataTableInputSelect from '@/v2/components/data-table/DataTableInputSelect.vue'\nimport EnvironmentVariableDropdown from '@/v2/features/environments/components/EnvironmentVariablesDropdown.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { backspaceCommand, pillPlugin } from './code-variable-widget'\n\ntype Props = {\n modelValue: CodeInputModelValue\n /** Environment for variable substitution. Pass undefined to disable environment variables */\n environment: XScalarEnvironment | undefined\n /** Type of the input value, affects rendering mode for booleans */\n type?: string | string[]\n /** Render as disabled text display */\n disabled?: boolean\n /** Show error styling */\n error?: boolean\n /** Layout context affects styling and behavior */\n layout?: ClientLayout\n /** Predefined enum values, triggers select mode */\n enum?: string[]\n /** Example values, triggers select mode */\n examples?: string[]\n /** Default value to show in select mode */\n default?: Props['modelValue']\n /** Allow null in boolean select options */\n nullable?: boolean\n /** Placeholder text for empty input */\n placeholder?: string\n /** Show required indicator */\n required?: boolean\n /** Enable color picker extension */\n colorPicker?: boolean\n /** Show line numbers in editor */\n lineNumbers?: boolean\n /** Enable linting */\n lint?: boolean\n /** Enable line wrapping */\n lineWrapping?: boolean\n /** CodeMirror language mode */\n language?: CodeMirrorLanguage\n /** Additional CodeMirror extensions */\n extensions?: Extension[]\n /** Disable tab key for indentation */\n disableTabIndent?: boolean\n /** Disable enter key */\n disableEnter?: boolean\n /** Disable automatic bracket closing */\n disableCloseBrackets?: boolean\n /** Emit submit event on blur */\n emitOnBlur?: boolean\n /** Enable environment variable pills */\n withVariables?: boolean\n /** Enable fake data suggestions like $guid, $timestamp, etc. Should only be enabled for parameters and request bodies */\n withFakeData?: boolean\n /** Emit change event even if the value is the same */\n alwaysEmitChange?: boolean\n /** Custom change handler, prevents default emit */\n handleFieldChange?: (value: string) => void\n /** Custom submit handler, prevents default emit */\n handleFieldSubmit?: (value: string) => void\n /** Put a linethrough on the input text */\n linethrough?: boolean\n}\n\nconst {\n modelValue,\n environment,\n type,\n disabled = false,\n error = false,\n layout = 'desktop',\n enum: enumProp,\n examples,\n default: defaultProp,\n nullable = false,\n placeholder,\n required,\n colorPicker = false,\n lineNumbers = false,\n lint = false,\n lineWrapping = false,\n language,\n extensions = [],\n disableTabIndent = false,\n disableEnter = false,\n disableCloseBrackets = false,\n emitOnBlur = true,\n alwaysEmitChange = false,\n withVariables = true,\n withFakeData = false,\n handleFieldChange,\n handleFieldSubmit,\n} = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'submit': [value: string, event: KeyboardEvent | FocusEvent]\n 'navigate': [route: { page: 'document'; path: 'environment' }]\n 'blur': [value: string, event: FocusEvent]\n}>()\n\n// ---------------------------------------------------------------------------\n// Component identity and focus state\n\nconst attrs = useAttrs() as { id?: string }\nconst componentId = attrs.id || `id-${nanoid()}`\nconst isFocused = ref(false)\n\n// ---------------------------------------------------------------------------\n// Rendering mode detection\n\n/**\n * Determines if we should render a select dropdown for boolean types.\n */\nconst isBooleanMode = computed((): boolean => {\n if (enumProp?.length) {\n return false\n }\n return type === 'boolean' || (Array.isArray(type) && type.includes('boolean'))\n})\n\n/**\n * Options for boolean select mode.\n */\nconst booleanOptions = computed((): string[] =>\n nullable ? ['true', 'false', 'null'] : ['true', 'false'],\n)\n\n/**\n * Default type when dealing with type arrays.\n * Finds the first non-null type.\n */\nconst defaultType = computed((): string | undefined => {\n if (Array.isArray(type)) {\n return type.find((t) => t !== 'null') ?? 'string'\n }\n return type\n})\n\n// ---------------------------------------------------------------------------\n// Event handlers\n\n/**\n * Handles value changes during typing.\n */\nconst handleChange = (value: string): void => {\n if (!alwaysEmitChange && value === serializeValue(modelValue)) {\n return\n }\n\n // Use custom handler or emit update\n if (handleFieldChange) {\n handleFieldChange(value)\n } else {\n emit('update:modelValue', value)\n }\n}\n\n/**\n * Handles form submission (enter key or blur with emitOnBlur).\n */\nconst handleSubmit = (\n value: string,\n event: KeyboardEvent | FocusEvent,\n): void => {\n if (handleFieldSubmit) {\n handleFieldSubmit(value)\n } else {\n emit('submit', value, event)\n }\n}\n\n/**\n * Handles input blur event.\n */\nconst handleBlur = (value: string, event: FocusEvent): void => {\n isFocused.value = false\n\n if (emitOnBlur && modelValue) {\n handleSubmit(value, event)\n }\n\n emit('blur', value, event)\n}\n\n/**\n * Handles model value updates from select components.\n */\nconst handleSelectChange = (value: string): void =>\n emit('update:modelValue', value)\n\n// ---------------------------------------------------------------------------\n// CodeMirror setup\n\n/**\n * Build extensions array.\n * Note: Extensions are not reactive after initialization.\n */\nconst buildExtensions = (): Extension[] => {\n const extensionsList: Extension[] = [...extensions]\n\n if (colorPicker) {\n extensionsList.push(colorPickerExtension)\n }\n\n return extensionsList\n}\n\n/**\n * Reactive pill plugin for environment variable visualization.\n */\nconst contextFunctionDropdownItems = computed(() =>\n withFakeData\n ? CONTEXT_FUNCTION_NAMES.map((key) => ({\n key,\n description: getContextFunctionComment(key),\n }))\n : [],\n)\n\nconst pillPluginExtension = computed(() =>\n pillPlugin({\n environment,\n isContextFunctionName,\n isReadOnly: layout === 'modal',\n }),\n)\n\n/**\n * Combined extensions for CodeMirror.\n */\nconst codeMirrorExtensions = computed((): Extension[] => [\n ...buildExtensions(),\n pillPluginExtension.value,\n backspaceCommand,\n])\n\nconst codeMirrorRef: Ref<HTMLDivElement | null> = ref(null)\n\n/** Converts the model value to a string for CodeMirror */\nconst serializeValue = (value: CodeInputModelValue): string => {\n if (typeof value === 'string') {\n return value\n }\n return JSON.stringify(value)\n}\n\nconst { codeMirror, setCodeMirrorContent } = useCodeMirror({\n content: toRef(() => serializeValue(modelValue)),\n onChange: (value) => {\n handleChange(value)\n updateDropdownVisibility()\n },\n onFocus: () => {\n isFocused.value = true\n },\n onBlur: handleBlur,\n codeMirrorRef,\n disableTabIndent: toRef(() => disableTabIndent),\n disableEnter: toRef(() => disableEnter),\n disableCloseBrackets: toRef(() => disableCloseBrackets),\n lineNumbers: toRef(() => lineNumbers),\n language: toRef(() => language),\n lint: toRef(() => lint),\n extensions: codeMirrorExtensions,\n placeholder: toRef(() => placeholder),\n})\n\n/**\n * Handle autofocus attribute.\n */\nwatch(codeMirror, () => {\n if (codeMirror.value && Object.hasOwn(attrs, 'autofocus')) {\n codeMirror.value.focus()\n }\n})\n\n// ---------------------------------------------------------------------------\n// Environment variable dropdown\n\nconst showDropdown = ref(false)\nconst dropdownQuery = ref('')\nconst dropdownPosition = ref({ left: 0, top: 0 })\nconst dropdownRef = ref<InstanceType<\n typeof EnvironmentVariableDropdown\n> | null>(null)\n\nconst { handleDropdownSelect, updateDropdownVisibility } = useDropdown({\n codeMirror,\n query: dropdownQuery,\n showDropdown,\n dropdownPosition,\n})\n\n/**\n * Determines if the environment variable dropdown should be visible.\n * Shows when environment is defined (for env vars) or withFakeData is true (for context functions)\n */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n (Boolean(environment) || withFakeData)\n )\n})\n\n// ---------------------------------------------------------------------------\n// Keyboard event handling\n\n/**\n * Handles keyboard navigation for dropdown and form submission.\n */\nconst handleKeyDown = (key: string, event: KeyboardEvent): void => {\n if (showDropdown.value) {\n if (key === 'down' || key === 'up') {\n event.preventDefault()\n dropdownRef.value?.handleArrowKey(key)\n } else if (key === 'enter') {\n event.preventDefault()\n dropdownRef.value?.handleSelect()\n }\n return\n }\n\n if (key === 'escape' && !disableTabIndent) {\n event.stopPropagation()\n }\n\n if (key === 'enter' && event.target instanceof HTMLDivElement) {\n handleSubmit(event.target.textContent ?? '', event)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n\ndefineExpose({\n /**\n * Focus the codemirror element\n *\n * @param cursorAtEnd boolean place the cursor at the end of the input\n */\n focus: (position?: 'start' | 'end' | number) => {\n if (!codeMirror.value) {\n return\n }\n codeMirror.value.focus()\n\n if (!isDefined(position)) {\n return\n }\n\n const anchor = (() => {\n if (position === 'start') {\n return 0\n }\n if (position === 'end') {\n return codeMirror.value.state.doc.length\n }\n return position\n })()\n\n // Move the cursor to the specified position\n codeMirror.value.dispatch({\n selection: { anchor },\n scrollIntoView: true,\n })\n },\n isFocused,\n handleChange,\n handleSubmit,\n handleBlur,\n booleanOptions,\n codeMirror,\n codeMirrorRef,\n modelValue,\n setCodeMirrorContent,\n cursorPosition: () => codeMirror.value?.state.selection.main.head,\n serializeValue,\n})\n</script>\n\n<template>\n <!-- Disabled mode: read-only text display -->\n <div\n v-if=\"disabled\"\n class=\"text-c-2 flex cursor-default items-center justify-center\"\n :class=\"{\n 'font-code pr-2 pl-1 text-base': layout === 'modal',\n 'px-2': layout !== 'modal',\n 'line-through': linethrough,\n }\"\n data-testid=\"code-input-disabled\">\n <span class=\"whitespace-nowrap\">{{ modelValue }}</span>\n </div>\n\n <!-- Enum mode: select dropdown with predefined values -->\n <DataTableInputSelect\n v-else-if=\"enumProp?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :type=\"defaultType\"\n :value=\"enumProp\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Boolean mode: select dropdown with true/false (and optionally null) -->\n <DataTableInputSelect\n v-else-if=\"isBooleanMode\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"booleanOptions\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Examples mode: select dropdown with example values -->\n <DataTableInputSelect\n v-else-if=\"examples?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"examples\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Editor mode: CodeMirror with environment variable support -->\n <div\n v-else\n :id=\"componentId\"\n v-bind=\"$attrs\"\n ref=\"codeMirrorRef\"\n class=\"group/input group-[.alert]:outline-orange group-[.error]:outline-red font-code peer relative w-full overflow-hidden text-xs leading-[1.44] whitespace-nowrap -outline-offset-1 has-[:focus-visible]:rounded-[4px] has-[:focus-visible]:outline\"\n :class=\"{\n 'line-wrapping has-[:focus-visible]:bg-b-1 has-[:focus-visible]:absolute has-[:focus-visible]:z-1':\n lineWrapping,\n 'flow-code-input--error': error,\n 'line-through': linethrough,\n }\"\n @keydown.down.stop=\"handleKeyDown('down', $event)\"\n @keydown.enter=\"handleKeyDown('enter', $event)\"\n @keydown.escape=\"handleKeyDown('escape', $event)\"\n @keydown.up.stop=\"handleKeyDown('up', $event)\">\n <!-- Tab exit hint (shown when focused) -->\n <div\n v-if=\"!disableTabIndent\"\n class=\"z-context text-c-2 absolute right-1.5 bottom-1 hidden font-sans group-has-[:focus-visible]/input:block\"\n role=\"alert\">\n Press\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Esc</kbd> then\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Tab</kbd> to exit\n </div>\n </div>\n\n <!-- Warning slot (positioned absolutely) -->\n <div\n v-if=\"$slots.warning\"\n class=\"centered-y text-orange absolute right-7 text-xs\">\n <slot name=\"warning\" />\n </div>\n\n <!-- Icon slot (positioned absolutely) -->\n <div\n v-if=\"$slots.icon\"\n class=\"centered-y absolute right-0 flex h-full items-center p-1.5 group-has-[.cm-focused]:z-1\">\n <slot name=\"icon\" />\n </div>\n\n <!-- Required indicator -->\n <div\n v-if=\"required\"\n class=\"required centered-y text-xxs text-c-3 group-[.error]:text-red bg-b-1 pointer-events-none absolute right-0 mr-0.5 pt-px pr-2 opacity-100 shadow-[-8px_0_4px_var(--scalar-background-1)] transition-opacity duration-150 group-[.alert]:bg-transparent group-[.alert]:shadow-none group-[.error]:bg-transparent group-[.error]:shadow-none peer-has-[.cm-focused]:opacity-0\">\n Required\n </div>\n\n <!-- Environment variable autocomplete dropdown -->\n <EnvironmentVariableDropdown\n v-if=\"displayVariablesDropdown\"\n ref=\"dropdownRef\"\n :contextFunctionItems=\"contextFunctionDropdownItems\"\n :dropdownPosition=\"dropdownPosition\"\n :environment=\"environment\"\n :query=\"dropdownQuery\"\n @redirect=\"emit('navigate', { page: 'document', path: 'environment' })\"\n @select=\"handleDropdownSelect\" />\n</template>\n<style scoped>\n/*\n Deep styling for customizing Codemirror\n */\n:deep(.cm-editor) {\n height: 100%;\n outline: none;\n padding: 0;\n background: transparent;\n}\n:deep(.cm-placeholder) {\n color: var(--scalar-color-3);\n}\n:deep(.cm-content) {\n font-family: var(--scalar-font-code);\n font-size: var(--scalar-small);\n max-height: 20px;\n padding: 8px 0;\n}\n/* Tooltip helper */\n:deep(.cm-tooltip) {\n background: transparent !important;\n filter: brightness(var(--scalar-lifted-brightness));\n border-radius: var(--scalar-radius);\n box-shadow: var(--scalar-shadow-2);\n border: none !important;\n outline: none !important;\n overflow: hidden !important;\n}\n:deep(.cm-tooltip-autocomplete ul li) {\n padding: 3px 6px !important;\n}\n:deep(.cm-completionIcon-type:after) {\n color: var(--scalar-color-3) !important;\n}\n:deep(.cm-tooltip-autocomplete ul li[aria-selected]) {\n background: var(--scalar-background-2) !important;\n color: var(--scalar-color-1) !important;\n}\n:deep(.cm-tooltip-autocomplete ul) {\n padding: 6px !important;\n position: relative;\n}\n:deep(.cm-tooltip-autocomplete ul li:hover) {\n border-radius: 3px;\n color: var(--scalar-color-1) !important;\n background: var(--scalar-background-3) !important;\n}\n/* Disable active line highlighting */\n:deep(.cm-activeLine),\n:deep(.cm-activeLineGutter) {\n background-color: transparent;\n}\n/* Color selection matching */\n:deep(.cm-selectionMatch),\n:deep(.cm-matchingBracket) {\n border-radius: var(--scalar-radius);\n background: var(--scalar-background-4) !important;\n}\n/* Color Picker Swatches */\n:deep(.cm-css-color-picker-wrapper) {\n display: inline-flex;\n outline: 1px solid var(--scalar-background-3);\n border-radius: 3px;\n overflow: hidden;\n}\n/* Number gutter */\n:deep(.cm-gutters) {\n background-color: transparent;\n border-right: none;\n color: var(--scalar-color-3);\n font-size: var(--scalar-small);\n line-height: 22px;\n border-radius: 0 0 0 3px;\n}\n:deep(.cm-gutters:before) {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: calc(100% - 2px);\n height: calc(100% - 4px);\n border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);\n background-color: var(--scalar-background-1);\n}\n:deep(.cm-gutterElement) {\n font-family: var(--scalar-font-code) !important;\n padding-left: 0px !important;\n padding-right: 6px !important;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n position: relative;\n}\n:deep(.cm-lineNumbers .cm-gutterElement) {\n min-width: fit-content;\n}\n:deep(.cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement) {\n padding-left: 0 !important;\n}\n:deep(.cm-scroller) {\n overflow: auto;\n}\n.line-wrapping:focus-within :deep(.cm-content) {\n display: inline-table;\n min-height: fit-content;\n padding: 3px 6px;\n white-space: break-spaces;\n word-break: break-all;\n}\n</style>\n<style>\n.cm-pill {\n color: var(--scalar-color-1) !important;\n padding: 0px 9px;\n border-radius: 3px;\n display: inline-block;\n border-radius: 30px;\n font-size: var(--scalar-small);\n}\n.light-mode .cm-pill {\n background: var(--scalar-background-3) !important;\n}\n.dark-mode .cm-pill {\n background: color-mix(in srgb, var(--tw-bg-base), transparent 90%) !important;\n}\n.cm-pill--context-fn {\n border: 1px dashed color-mix(in srgb, var(--scalar-color-3), transparent 35%);\n padding: 0px 8px;\n}\n.light-mode .cm-pill--context-fn {\n background: color-mix(\n in srgb,\n var(--scalar-background-3),\n transparent 40%\n ) !important;\n}\n.dark-mode .cm-pill--context-fn {\n background: color-mix(\n in srgb,\n var(--scalar-background-3),\n transparent 55%\n ) !important;\n}\n.cm-pill:first-of-type {\n margin-left: 0;\n}\n.cm-editor .cm-widgetBuffer {\n display: none;\n}\n.cm-foldPlaceholder:hover {\n color: var(--scalar-color-1);\n}\n.cm-foldGutter .cm-gutterElement {\n font-size: var(--scalar-heading-4);\n padding: 2px !important;\n}\n.cm-foldGutter .cm-gutterElement:first-of-type {\n display: none;\n}\n.cm-foldGutter .cm-gutterElement .cm-foldMarker {\n padding: 2px;\n padding-top: 2px;\n}\n.cm-foldGutter .cm-gutterElement:hover .cm-foldMarker {\n background: var(--scalar-background-2);\n border-radius: var(--scalar-radius);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"CodeInput.vue.script.js","names":["$attrs","$slots"],"sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeInputModelValue =\n | string\n | number\n | boolean\n | Array<string | number | boolean>\n | Record<string, unknown>\n\n/**\n * CodeInput\n *\n * A versatile input component that adapts its rendering based on props:\n * - Disabled mode: Read-only text display\n * - Select mode: Dropdown for enums, booleans, or examples\n * - Editor mode: CodeMirror with environment variable support\n *\n * Type `{{` to trigger autocomplete for environment variables and runtime context functions\n * (for example `{{$guid}}`) when an environment is provided.\n * It takes in any data but always will emit a string value,\n * this string should then be parsed in accordance to the schema or content type.\n *\n * @example\n * ```vue\n * <!-- Basic input with environment variables -->\n * <CodeInput v-model=\"value\" :environment=\"env\" />\n *\n * <!-- Boolean select -->\n * <CodeInput v-model=\"flag\" type=\"boolean\" />\n *\n * <!-- JSON editor with linting -->\n * <CodeInput v-model=\"data\" language=\"json\" :lint=\"true\" />\n * ```\n */\nexport default {\n inheritAttrs: false,\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport {\n colorPicker as colorPickerExtension,\n useCodeMirror,\n useDropdown,\n type CodeMirrorLanguage,\n type Extension,\n} from '@scalar/use-codemirror'\nimport {\n CONTEXT_FUNCTION_NAMES,\n getContextFunctionComment,\n isContextFunctionName,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { nanoid } from 'nanoid'\nimport { computed, ref, toRef, useAttrs, watch, type Ref } from 'vue'\n\nimport DataTableInputSelect from '@/v2/components/data-table/DataTableInputSelect.vue'\nimport EnvironmentVariableDropdown from '@/v2/features/environments/components/EnvironmentVariablesDropdown.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { backspaceCommand, pillPlugin } from './code-variable-widget'\n\ntype Props = {\n modelValue: CodeInputModelValue\n /** Environment for variable substitution. Pass undefined to disable environment variables */\n environment: XScalarEnvironment | undefined\n /** Type of the input value, affects rendering mode for booleans */\n type?: string | string[]\n /** Render as disabled text display */\n disabled?: boolean\n /** Show error styling */\n error?: boolean\n /** Layout context affects styling and behavior */\n layout?: ClientLayout\n /** Predefined enum values, triggers select mode */\n enum?: string[]\n /** Example values, triggers select mode */\n examples?: string[]\n /** Default value to show in select mode */\n default?: Props['modelValue']\n /** Allow null in boolean select options */\n nullable?: boolean\n /** Placeholder text for empty input */\n placeholder?: string\n /** Show required indicator */\n required?: boolean\n /** Enable color picker extension */\n colorPicker?: boolean\n /** Show line numbers in editor */\n lineNumbers?: boolean\n /** Enable linting */\n lint?: boolean\n /** Enable line wrapping */\n lineWrapping?: boolean\n /** CodeMirror language mode */\n language?: CodeMirrorLanguage\n /** Additional CodeMirror extensions */\n extensions?: Extension[]\n /** Disable tab key for indentation */\n disableTabIndent?: boolean\n /** Disable enter key */\n disableEnter?: boolean\n /** Disable automatic bracket closing */\n disableCloseBrackets?: boolean\n /** Emit submit event on blur */\n emitOnBlur?: boolean\n /** Enable environment variable pills */\n withVariables?: boolean\n /** Enable fake data suggestions like $guid, $timestamp, etc. Should only be enabled for parameters and request bodies */\n withFakeData?: boolean\n /** Emit change event even if the value is the same */\n alwaysEmitChange?: boolean\n /** Custom change handler, prevents default emit */\n handleFieldChange?: (value: string) => void\n /** Custom submit handler, prevents default emit */\n handleFieldSubmit?: (value: string) => void\n /** Put a linethrough on the input text */\n linethrough?: boolean\n}\n\nconst {\n modelValue,\n environment,\n type,\n disabled = false,\n error = false,\n layout = 'desktop',\n enum: enumProp,\n examples,\n default: defaultProp,\n nullable = false,\n placeholder,\n required,\n colorPicker = false,\n lineNumbers = false,\n lint = false,\n lineWrapping = false,\n language,\n extensions = [],\n disableTabIndent = false,\n disableEnter = false,\n disableCloseBrackets = false,\n emitOnBlur = true,\n alwaysEmitChange = false,\n withVariables = true,\n withFakeData = false,\n handleFieldChange,\n handleFieldSubmit,\n} = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'submit': [value: string, event: KeyboardEvent | FocusEvent]\n 'navigate': [route: { page: 'document'; path: 'environment' }]\n 'blur': [value: string, event: FocusEvent]\n}>()\n\n// ---------------------------------------------------------------------------\n// Component identity and focus state\n\nconst attrs = useAttrs() as { id?: string }\nconst componentId = attrs.id || `id-${nanoid()}`\nconst isFocused = ref(false)\n\n// ---------------------------------------------------------------------------\n// Rendering mode detection\n\n/**\n * Determines if we should render a select dropdown for boolean types.\n */\nconst isBooleanMode = computed((): boolean => {\n if (enumProp?.length) {\n return false\n }\n return type === 'boolean' || (Array.isArray(type) && type.includes('boolean'))\n})\n\n/**\n * Options for boolean select mode.\n */\nconst booleanOptions = computed((): string[] =>\n nullable ? ['true', 'false', 'null'] : ['true', 'false'],\n)\n\n/**\n * Default type when dealing with type arrays.\n * Finds the first non-null type.\n */\nconst defaultType = computed((): string | undefined => {\n if (Array.isArray(type)) {\n return type.find((t) => t !== 'null') ?? 'string'\n }\n return type\n})\n\n// ---------------------------------------------------------------------------\n// Event handlers\n\n/**\n * Handles value changes during typing.\n */\nconst handleChange = (value: string): void => {\n if (!alwaysEmitChange && value === serializeValue(modelValue)) {\n return\n }\n\n // Use custom handler or emit update\n if (handleFieldChange) {\n handleFieldChange(value)\n } else {\n emit('update:modelValue', value)\n }\n}\n\n/**\n * Handles form submission (enter key or blur with emitOnBlur).\n */\nconst handleSubmit = (\n value: string,\n event: KeyboardEvent | FocusEvent,\n): void => {\n if (handleFieldSubmit) {\n handleFieldSubmit(value)\n } else {\n emit('submit', value, event)\n }\n}\n\n/**\n * Handles input blur event.\n */\nconst handleBlur = (value: string, event: FocusEvent): void => {\n isFocused.value = false\n\n if (emitOnBlur && modelValue) {\n handleSubmit(value, event)\n }\n\n emit('blur', value, event)\n}\n\n/**\n * Handles model value updates from select components.\n */\nconst handleSelectChange = (value: string): void =>\n emit('update:modelValue', value)\n\n// ---------------------------------------------------------------------------\n// CodeMirror setup\n\n/**\n * Build extensions array.\n * Note: Extensions are not reactive after initialization.\n */\nconst buildExtensions = (): Extension[] => {\n const extensionsList: Extension[] = [...extensions]\n\n if (colorPicker) {\n extensionsList.push(colorPickerExtension)\n }\n\n return extensionsList\n}\n\n/**\n * Reactive pill plugin for environment variable visualization.\n */\nconst contextFunctionDropdownItems = computed(() =>\n withFakeData\n ? CONTEXT_FUNCTION_NAMES.map((key) => ({\n key,\n description: getContextFunctionComment(key),\n }))\n : [],\n)\n\nconst pillPluginExtension = computed(() =>\n pillPlugin({\n environment,\n isContextFunctionName,\n isReadOnly: layout === 'modal',\n }),\n)\n\n/**\n * Combined extensions for CodeMirror.\n */\nconst codeMirrorExtensions = computed((): Extension[] => [\n ...buildExtensions(),\n pillPluginExtension.value,\n backspaceCommand,\n])\n\nconst codeMirrorRef: Ref<HTMLDivElement | null> = ref(null)\n\n/** Converts the model value to a string for CodeMirror */\nconst serializeValue = (value: CodeInputModelValue): string => {\n if (typeof value === 'string') {\n return value\n }\n return JSON.stringify(value)\n}\n\nconst { codeMirror, setCodeMirrorContent } = useCodeMirror({\n content: toRef(() => serializeValue(modelValue)),\n onChange: (value) => {\n handleChange(value)\n updateDropdownVisibility()\n },\n onFocus: () => {\n isFocused.value = true\n },\n onBlur: handleBlur,\n codeMirrorRef,\n disableTabIndent: toRef(() => disableTabIndent),\n disableEnter: toRef(() => disableEnter),\n disableCloseBrackets: toRef(() => disableCloseBrackets),\n lineNumbers: toRef(() => lineNumbers),\n language: toRef(() => language),\n lint: toRef(() => lint),\n extensions: codeMirrorExtensions,\n placeholder: toRef(() => placeholder),\n})\n\n/**\n * Handle autofocus attribute.\n */\nwatch(codeMirror, () => {\n if (codeMirror.value && Object.hasOwn(attrs, 'autofocus')) {\n codeMirror.value.focus()\n }\n})\n\n// ---------------------------------------------------------------------------\n// Environment variable dropdown\n\nconst showDropdown = ref(false)\nconst dropdownQuery = ref('')\nconst dropdownPosition = ref({ left: 0, top: 0 })\nconst dropdownRef = ref<InstanceType<\n typeof EnvironmentVariableDropdown\n> | null>(null)\n\nconst { handleDropdownSelect, updateDropdownVisibility } = useDropdown({\n codeMirror,\n query: dropdownQuery,\n showDropdown,\n dropdownPosition,\n})\n\n/**\n * Determines if the environment variable dropdown should be visible.\n * Shows when environment is defined (for env vars) or withFakeData is true (for context functions)\n */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n (Boolean(environment) || withFakeData)\n )\n})\n\n// ---------------------------------------------------------------------------\n// Keyboard event handling\n\n/**\n * Handles keyboard navigation for dropdown and form submission.\n */\nconst handleKeyDown = (key: string, event: KeyboardEvent): void => {\n if (showDropdown.value) {\n if (key === 'down' || key === 'up') {\n event.preventDefault()\n dropdownRef.value?.handleArrowKey(key)\n } else if (key === 'enter') {\n event.preventDefault()\n dropdownRef.value?.handleSelect()\n }\n return\n }\n\n if (key === 'escape' && !disableTabIndent) {\n event.stopPropagation()\n }\n\n if (key === 'enter' && event.target instanceof HTMLDivElement) {\n handleSubmit(codeMirror.value?.state.doc.toString() ?? '', event)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n\ndefineExpose({\n /**\n * Focus the codemirror element\n *\n * @param cursorAtEnd boolean place the cursor at the end of the input\n */\n focus: (position?: 'start' | 'end' | number) => {\n if (!codeMirror.value) {\n return\n }\n codeMirror.value.focus()\n\n if (!isDefined(position)) {\n return\n }\n\n const anchor = (() => {\n if (position === 'start') {\n return 0\n }\n if (position === 'end') {\n return codeMirror.value.state.doc.length\n }\n return position\n })()\n\n // Move the cursor to the specified position\n codeMirror.value.dispatch({\n selection: { anchor },\n scrollIntoView: true,\n })\n },\n isFocused,\n handleChange,\n handleSubmit,\n handleBlur,\n booleanOptions,\n codeMirror,\n codeMirrorRef,\n modelValue,\n setCodeMirrorContent,\n cursorPosition: () => codeMirror.value?.state.selection.main.head,\n serializeValue,\n})\n</script>\n\n<template>\n <!-- Disabled mode: read-only text display -->\n <div\n v-if=\"disabled\"\n class=\"text-c-2 flex cursor-default items-center justify-center\"\n :class=\"{\n 'font-code pr-2 pl-1 text-base': layout === 'modal',\n 'px-2': layout !== 'modal',\n 'line-through': linethrough,\n }\"\n data-testid=\"code-input-disabled\">\n <span class=\"whitespace-nowrap\">{{ modelValue }}</span>\n </div>\n\n <!-- Enum mode: select dropdown with predefined values -->\n <DataTableInputSelect\n v-else-if=\"enumProp?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :type=\"defaultType\"\n :value=\"enumProp\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Boolean mode: select dropdown with true/false (and optionally null) -->\n <DataTableInputSelect\n v-else-if=\"isBooleanMode\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"booleanOptions\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Examples mode: select dropdown with example values -->\n <DataTableInputSelect\n v-else-if=\"examples?.length\"\n :default=\"defaultProp\"\n :modelValue=\"modelValue\"\n :value=\"examples\"\n @update:modelValue=\"handleSelectChange\" />\n\n <!-- Editor mode: CodeMirror with environment variable support -->\n <div\n v-else\n :id=\"componentId\"\n v-bind=\"$attrs\"\n ref=\"codeMirrorRef\"\n class=\"group/input group-[.alert]:outline-orange group-[.error]:outline-red font-code peer relative w-full overflow-hidden text-xs leading-[1.44] whitespace-nowrap -outline-offset-1 has-[:focus-visible]:rounded-[4px] has-[:focus-visible]:outline\"\n :class=\"{\n 'line-wrapping has-[:focus-visible]:bg-b-1 has-[:focus-visible]:absolute has-[:focus-visible]:z-1':\n lineWrapping,\n 'flow-code-input--error': error,\n 'line-through': linethrough,\n }\"\n @keydown.down.stop=\"handleKeyDown('down', $event)\"\n @keydown.enter=\"handleKeyDown('enter', $event)\"\n @keydown.escape=\"handleKeyDown('escape', $event)\"\n @keydown.up.stop=\"handleKeyDown('up', $event)\">\n <!-- Tab exit hint (shown when focused) -->\n <div\n v-if=\"!disableTabIndent\"\n class=\"z-context text-c-2 absolute right-1.5 bottom-1 hidden font-sans group-has-[:focus-visible]/input:block\"\n role=\"alert\">\n Press\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Esc</kbd> then\n <kbd class=\"-mx-0.25 rounded border px-0.5 font-mono\">Tab</kbd> to exit\n </div>\n </div>\n\n <!-- Warning slot (positioned absolutely) -->\n <div\n v-if=\"$slots.warning\"\n class=\"centered-y text-orange absolute right-7 text-xs\">\n <slot name=\"warning\" />\n </div>\n\n <!-- Icon slot (positioned absolutely) -->\n <div\n v-if=\"$slots.icon\"\n class=\"centered-y absolute right-0 flex h-full items-center p-1.5 group-has-[.cm-focused]:z-1\">\n <slot name=\"icon\" />\n </div>\n\n <!-- Required indicator -->\n <div\n v-if=\"required\"\n class=\"required centered-y text-xxs text-c-3 group-[.error]:text-red bg-b-1 pointer-events-none absolute right-0 mr-0.5 pt-px pr-2 opacity-100 shadow-[-8px_0_4px_var(--scalar-background-1)] transition-opacity duration-150 group-[.alert]:bg-transparent group-[.alert]:shadow-none group-[.error]:bg-transparent group-[.error]:shadow-none peer-has-[.cm-focused]:opacity-0\">\n Required\n </div>\n\n <!-- Environment variable autocomplete dropdown -->\n <EnvironmentVariableDropdown\n v-if=\"displayVariablesDropdown\"\n ref=\"dropdownRef\"\n :contextFunctionItems=\"contextFunctionDropdownItems\"\n :dropdownPosition=\"dropdownPosition\"\n :environment=\"environment\"\n :query=\"dropdownQuery\"\n @redirect=\"emit('navigate', { page: 'document', path: 'environment' })\"\n @select=\"handleDropdownSelect\" />\n</template>\n<style scoped>\n/*\n Deep styling for customizing Codemirror\n */\n:deep(.cm-editor) {\n height: 100%;\n outline: none;\n padding: 0;\n background: transparent;\n}\n:deep(.cm-placeholder) {\n color: var(--scalar-color-3);\n}\n:deep(.cm-content) {\n font-family: var(--scalar-font-code);\n font-size: var(--scalar-small);\n max-height: 20px;\n padding: 8px 0;\n}\n/* Tooltip helper */\n:deep(.cm-tooltip) {\n background: transparent !important;\n filter: brightness(var(--scalar-lifted-brightness));\n border-radius: var(--scalar-radius);\n box-shadow: var(--scalar-shadow-2);\n border: none !important;\n outline: none !important;\n overflow: hidden !important;\n}\n:deep(.cm-tooltip-autocomplete ul li) {\n padding: 3px 6px !important;\n}\n:deep(.cm-completionIcon-type:after) {\n color: var(--scalar-color-3) !important;\n}\n:deep(.cm-tooltip-autocomplete ul li[aria-selected]) {\n background: var(--scalar-background-2) !important;\n color: var(--scalar-color-1) !important;\n}\n:deep(.cm-tooltip-autocomplete ul) {\n padding: 6px !important;\n position: relative;\n}\n:deep(.cm-tooltip-autocomplete ul li:hover) {\n border-radius: 3px;\n color: var(--scalar-color-1) !important;\n background: var(--scalar-background-3) !important;\n}\n/* Disable active line highlighting */\n:deep(.cm-activeLine),\n:deep(.cm-activeLineGutter) {\n background-color: transparent;\n}\n/* Color selection matching */\n:deep(.cm-selectionMatch),\n:deep(.cm-matchingBracket) {\n border-radius: var(--scalar-radius);\n background: var(--scalar-background-4) !important;\n}\n/* Color Picker Swatches */\n:deep(.cm-css-color-picker-wrapper) {\n display: inline-flex;\n outline: 1px solid var(--scalar-background-3);\n border-radius: 3px;\n overflow: hidden;\n}\n/* Number gutter */\n:deep(.cm-gutters) {\n background-color: transparent;\n border-right: none;\n color: var(--scalar-color-3);\n font-size: var(--scalar-small);\n line-height: 22px;\n border-radius: 0 0 0 3px;\n}\n:deep(.cm-gutters:before) {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: calc(100% - 2px);\n height: calc(100% - 4px);\n border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);\n background-color: var(--scalar-background-1);\n}\n:deep(.cm-gutterElement) {\n font-family: var(--scalar-font-code) !important;\n padding-left: 0px !important;\n padding-right: 6px !important;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n position: relative;\n}\n:deep(.cm-lineNumbers .cm-gutterElement) {\n min-width: fit-content;\n}\n:deep(.cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement) {\n padding-left: 0 !important;\n}\n:deep(.cm-scroller) {\n overflow: auto;\n}\n.line-wrapping:focus-within :deep(.cm-content) {\n display: inline-table;\n min-height: fit-content;\n padding: 3px 6px;\n white-space: break-spaces;\n word-break: break-all;\n}\n</style>\n<style>\n.cm-pill {\n color: var(--scalar-color-1) !important;\n padding: 0px 9px;\n border-radius: 3px;\n display: inline-block;\n border-radius: 30px;\n font-size: var(--scalar-small);\n}\n.light-mode .cm-pill {\n background: var(--scalar-background-3) !important;\n}\n.dark-mode .cm-pill {\n background: color-mix(in srgb, var(--tw-bg-base), transparent 90%) !important;\n}\n.cm-pill--context-fn {\n border: 1px dashed color-mix(in srgb, var(--scalar-color-3), transparent 35%);\n padding: 0px 8px;\n}\n.light-mode .cm-pill--context-fn {\n background: color-mix(\n in srgb,\n var(--scalar-background-3),\n transparent 40%\n ) !important;\n}\n.dark-mode .cm-pill--context-fn {\n background: color-mix(\n in srgb,\n var(--scalar-background-3),\n transparent 55%\n ) !important;\n}\n.cm-pill:first-of-type {\n margin-left: 0;\n}\n.cm-editor .cm-widgetBuffer {\n display: none;\n}\n.cm-foldPlaceholder:hover {\n color: var(--scalar-color-1);\n}\n.cm-foldGutter .cm-gutterElement {\n font-size: var(--scalar-heading-4);\n padding: 2px !important;\n}\n.cm-foldGutter .cm-gutterElement:first-of-type {\n display: none;\n}\n.cm-foldGutter .cm-gutterElement .cm-foldMarker {\n padding: 2px;\n padding-top: 2px;\n}\n.cm-foldGutter .cm-gutterElement:hover .cm-foldMarker {\n background: var(--scalar-background-2);\n border-radius: var(--scalar-radius);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  //#region src/v2/constants.ts
2
2
  /** The version number taken from the package.json. Consumers can override at build time via define (e.g. OVERRIDE_PACKAGE_VERSION: JSON.stringify('1.2.3')). */
3
- var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "3.3.1";
3
+ var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "3.5.0";
4
4
  //#endregion
5
5
  export { APP_VERSION };
6
6
 
@@ -4,7 +4,7 @@ import type { RegistryDocumentsState } from '../../../v2/features/app/hooks/use-
4
4
  import type { CommandPaletteState } from '../../../v2/features/command-palette/hooks/use-command-palette-state.js';
5
5
  import type { ImportDocumentFromRegistry } from '../../../v2/types/configuration';
6
6
  import type { ClientLayout } from '../../../v2/types/layout';
7
- import { type AppState } from './app-state.js';
7
+ import type { AppState } from './app-state.js';
8
8
  /**
9
9
  * Main entry point for the API client for electron and web.
10
10
  *
@@ -46,6 +46,19 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
46
46
  'create-workspace'?: (payload: {
47
47
  state: ModalState;
48
48
  }) => unknown;
49
+ /**
50
+ * Replaces the Scalar logo inside the header menu button. Typically used by
51
+ * team-aware consumers (e.g. Scalar Cloud) to render a team avatar so the
52
+ * left-most chrome reads as "this team's workspace" rather than the
53
+ * generic Scalar wordmark.
54
+ *
55
+ * Receives `isTeamWorkspace` so consumers can opt into rendering a team
56
+ * image only when the active workspace actually belongs to a team, while
57
+ * keeping the default Scalar logo for local workspaces.
58
+ */
59
+ 'header-logo'?: (payload: {
60
+ isTeamWorkspace: boolean;
61
+ }) => unknown;
49
62
  /**
50
63
  * Slot for customizing the menu items section of the app header.
51
64
  * Defaults to a workspace picker bound to the current app state. Overriding this slot
@@ -53,6 +66,17 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
53
66
  * any workspace switcher (or other menu content) they need.
54
67
  */
55
68
  'header-menu-items'?: () => unknown;
69
+ /**
70
+ * Slot rendered at the trailing edge of the header, immediately before the
71
+ * `header-end` slot. Use this for context-specific action buttons (for
72
+ * example a "Save" button) so they sit next to the document chrome rather
73
+ * than getting mixed in with the user / account controls in `header-end`.
74
+ *
75
+ * When both this slot and `header-end` are provided, a vertical divider is
76
+ * inserted between them so the two groups read as visually distinct
77
+ * clusters.
78
+ */
79
+ 'header-actions'?: () => unknown;
56
80
  /**
57
81
  * Slot for customizing the end section of the app header.
58
82
  * Typically used for user menus, action buttons, or other trailing controls.
@@ -1 +1 @@
1
- {"version":3,"file":"App.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/app/App.vue"],"names":[],"mappings":"AA8SA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAa7D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAA;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+DAA+D,CAAA;AAKxG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C;;;;GAIG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;YAER,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC;cAC5B,YAAY,EAAE;iBACX,MAAM,QAAQ;4BACH,MAAM,mBAAmB;IACjD,+FAA+F;4BACvE,0BAA0B;IAClD;;;OAGG;wBACiB,sBAAsB;;;;YAVlC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC;cAC5B,YAAY,EAAE;iBACX,MAAM,QAAQ;4BACH,MAAM,mBAAmB;IACjD,+FAA+F;4BACvE,0BAA0B;IAClD;;;OAGG;wBACiB,sBAAsB;;IAa1C;;;OAGG;yBACkB,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,UAAU,CAAA;KAAE,KAAK,OAAO;IAChE;;;;;OAKG;0BACmB,MAAM,OAAO;IACnC;;;OAGG;mBACY,MAAM,OAAO;EAqZ1B,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"App.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/app/App.vue"],"names":[],"mappings":"AAmWA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAe7D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAA;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+DAA+D,CAAA;AAKxG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C;;;;GAIG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;YAER,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC;cAC5B,YAAY,EAAE;iBACX,MAAM,QAAQ;4BACH,MAAM,mBAAmB;IACjD,+FAA+F;4BACvE,0BAA0B;IAClD;;;OAGG;wBACiB,sBAAsB;;;;YAVlC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC;cAC5B,YAAY,EAAE;iBACX,MAAM,QAAQ;4BACH,MAAM,mBAAmB;IACjD,+FAA+F;4BACvE,0BAA0B;IAClD;;;OAGG;wBACiB,sBAAsB;;IAa1C;;;OAGG;yBACkB,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,UAAU,CAAA;KAAE,KAAK,OAAO;IAChE;;;;;;;;;OASG;oBACa,CAAC,OAAO,EAAE;QAAE,eAAe,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO;IAClE;;;;;OAKG;0BACmB,MAAM,OAAO;IACnC;;;;;;;;;OASG;uBACgB,MAAM,OAAO;IAChC;;;OAGG;mBACY,MAAM,OAAO;EA0a1B,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"App.vue.js","names":[],"sources":["../../../../src/v2/features/app/App.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Main entry point for the API client for electron and web.\n *\n * This component handles all events and store business logic for the application.\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarMenuWorkspacePicker,\n ScalarTeleportRoot,\n useModal,\n type ModalState,\n} from '@scalar/components'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport { ScalarToasts } from '@scalar/use-toasts'\nimport { extensions } from '@scalar/workspace-store/schemas/extensions'\nimport { computed, onBeforeUnmount, toValue, watch } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport { SidebarToggle } from '@/v2/components/sidebar'\nimport AppHeader from '@/v2/features/app/components/AppHeader.vue'\nimport AppSidebar from '@/v2/features/app/components/AppSidebar.vue'\nimport CreateWorkspaceModal from '@/v2/features/app/components/CreateWorkspaceModal.vue'\nimport SplashScreen from '@/v2/features/app/components/SplashScreen.vue'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { useDocumentWatcher } from '@/v2/features/app/hooks/use-document-watcher'\nimport type { RegistryDocumentsState } from '@/v2/features/app/hooks/use-sidebar-documents'\nimport type { CommandPaletteState } from '@/v2/features/command-palette/hooks/use-command-palette-state'\nimport TheCommandPalette from '@/v2/features/command-palette/TheCommandPalette.vue'\nimport { useMonacoEditorConfiguration } from '@/v2/features/editor'\nimport { useColorMode } from '@/v2/hooks/use-color-mode'\nimport { useGlobalHotKeys } from '@/v2/hooks/use-global-hot-keys'\nimport type { ImportDocumentFromRegistry } from '@/v2/types/configuration'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { type AppState } from './app-state'\nimport DesktopTabs from './components/DesktopTabs.vue'\n\nconst {\n layout,\n plugins = [],\n getAppState,\n getCommandPaletteState,\n fetchRegistryDocument,\n registryDocuments = { status: 'success', documents: [] },\n} = defineProps<{\n layout: Exclude<ClientLayout, 'modal'>\n plugins?: ClientPlugin[]\n getAppState: () => AppState\n getCommandPaletteState: () => CommandPaletteState\n /** Fetches the full document from registry by meta. Passed through to route props for sync. */\n fetchRegistryDocument?: ImportDocumentFromRegistry\n /**\n * The list of all available registry documents, with a loading status so the\n * sidebar can render skeleton placeholders until the real list is ready.\n */\n registryDocuments?: RegistryDocumentsState\n}>()\n\ndefineSlots<{\n /**\n * Slot for customizing the create workspace modal.\n * This slot is used to render custom actions or components within the create workspace modal.\n */\n 'create-workspace'?: (payload: { state: ModalState }) => unknown\n /**\n * Slot for customizing the menu items section of the app header.\n * Defaults to a workspace picker bound to the current app state. Overriding this slot\n * replaces the default picker entirely, so the consumer is responsible for rendering\n * any workspace switcher (or other menu content) they need.\n */\n 'header-menu-items'?: () => unknown\n /**\n * Slot for customizing the end section of the app header.\n * Typically used for user menus, action buttons, or other trailing controls.\n */\n 'header-end'?: () => unknown\n}>()\n\ndefineExpose({\n openCreateWorkspace: () => createWorkspaceModalState.show(),\n})\n\nconst app = getAppState()\nconst paletteState = getCommandPaletteState()\n\n/** Expose workspace store to window for debugging purposes. */\nif (typeof window !== 'undefined') {\n window.dataDumpWorkspace = () => app.store.value\n window.dumpAppState = () => app\n}\n\n/** Call lifecycle hooks on plugins and subscribe to event bus events */\nconst pluginUnsubscribes: (() => void)[] = []\n\nfor (const plugin of plugins) {\n plugin.lifecycle?.onInit?.({ config: { telemetry: app.telemetry.value } })\n\n if (plugin.on) {\n for (const [event, handler] of Object.entries(plugin.on)) {\n pluginUnsubscribes.push(app.eventBus.on(event as any, handler as any))\n }\n }\n}\n\n/** Notify plugins when telemetry config changes */\nwatch(app.telemetry, () => {\n for (const plugin of plugins) {\n plugin.lifecycle?.onConfigChange?.({\n config: { telemetry: app.telemetry.value },\n })\n }\n})\n\nonBeforeUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n})\n\n/** Register global hotkeys for the app, passing the workspace event bus and layout state */\nuseGlobalHotKeys(app.eventBus, layout)\n\nconst DEFAULT_DOCUMENT_WATCH_TIMEOUT = 5000\n\n/** Watch the active document for changes and rebase it with its remote source */\nuseDocumentWatcher({\n documentName: () =>\n app.store.value?.workspace[extensions.workspace.activeDocument],\n store: app.store,\n initialTimeout: DEFAULT_DOCUMENT_WATCH_TIMEOUT,\n})\n\n/** Color mode */\nuseColorMode({ workspaceStore: app.store })\n\nconst currentTheme = computed(() => app.theme.styles.value.themeStyles)\nconst isDarkMode = computed(() => app.isDarkMode.value)\n\n/** Setup monaco editor configuration */\nuseMonacoEditorConfiguration({\n theme: currentTheme,\n darkMode: isDarkMode,\n})\n\nconst navigateToWorkspaceOverview = (namespace?: string, slug?: string) => {\n app.eventBus.emit('ui:navigate', {\n page: 'workspace',\n path: 'environment',\n namespace,\n workspaceSlug: slug,\n })\n}\n\n/** Sets the active workspace by ID: finds the workspace in the list and updates app state & navigation. */\nconst setActiveWorkspace = (id?: string) => {\n if (!id) {\n return\n }\n const workspace = app.workspace.workspaceList.value?.find(\n (workspace) => workspace.id === id,\n )\n if (!workspace) {\n return\n }\n\n navigateToWorkspaceOverview(workspace.namespace, workspace.slug)\n}\n\nconst createWorkspaceModalState = useModal()\n\n/** Props to pass to the RouterView component. */\nconst routerViewProps = computed<RouteProps>(() => {\n return {\n documentSlug: app.activeEntities.documentSlug.value ?? '',\n document: app.store.value?.workspace.activeDocument ?? null,\n environment: app.environment.value,\n eventBus: app.eventBus,\n exampleName: app.activeEntities.exampleName.value,\n fetchRegistryDocument,\n layout,\n method: app.activeEntities.method.value,\n path: app.activeEntities.path.value,\n workspaceStore: app.store.value!,\n activeWorkspace: app.workspace.activeWorkspace.value!,\n plugins,\n isDarkMode: app.isDarkMode.value,\n currentTheme: app.theme.styles.value.themeStyles,\n customThemes: toValue(app.theme.customThemes),\n telemetry: app.telemetry.value,\n onUpdateTelemetry: (value: boolean) => {\n app.telemetry.value = value\n },\n options: app.options,\n }\n})\n</script>\n\n<template>\n <ScalarTeleportRoot>\n <!-- Theme style tag -->\n <div v-html=\"app.theme.themeStyleTag.value\" />\n\n <!-- Toasts -->\n <ScalarToasts />\n\n <!-- Main content -->\n <main\n v-if=\"\n app.store.value !== null &&\n app.workspace.activeWorkspace.value !== null &&\n !app.loading.value\n \">\n <div class=\"relative flex h-dvh w-dvw flex-col\">\n <SidebarToggle\n v-model=\"app.sidebar.isOpen.value\"\n class=\"absolute z-60 md:hidden\"\n :class=\"layout === 'desktop' ? 'top-14 left-4' : 'top-4 left-4'\" />\n <AppHeader\n @navigate:to:settings=\"\n app.eventBus.emit('ui:navigate', {\n page: 'workspace',\n path: 'settings',\n })\n \">\n <template #menuItems>\n <slot name=\"header-menu-items\">\n <ScalarMenuWorkspacePicker\n :modelValue=\"app.workspace.activeWorkspace.value?.id\"\n :workspaceOptions=\"app.workspace.workspaceGroups.value\"\n @createWorkspace=\"createWorkspaceModalState.show()\"\n @update:modelValue=\"(value) => setActiveWorkspace(value)\" />\n </slot>\n </template>\n <template #end>\n <slot name=\"header-end\" />\n </template>\n </AppHeader>\n <div class=\"flex min-h-0 flex-1 flex-row\">\n <!-- App sidebar -->\n <AppSidebar\n :app=\"app\"\n :fetchRegistryDocument=\"fetchRegistryDocument\"\n :registryDocuments=\"registryDocuments\"\n :sidebarWidth=\"app.sidebar.width.value\"\n @update:sidebarWidth=\"app.sidebar.handleSidebarWidthUpdate\" />\n\n <div class=\"flex min-h-0 flex-1 flex-col\">\n <!-- App Tabs -->\n <DesktopTabs\n v-if=\"layout === 'desktop'\"\n :activeTabIndex=\"app.tabs.activeTabIndex.value\"\n :eventBus=\"app.eventBus\"\n :tabs=\"app.tabs.state.value\" />\n\n <!-- Router view min-h-0 is required for scrolling, do not remove it -->\n <div class=\"bg-b-1 relative min-h-0 flex-1\">\n <RouterView v-bind=\"routerViewProps\" />\n </div>\n </div>\n </div>\n </div>\n\n <slot\n name=\"create-workspace\"\n :state=\"createWorkspaceModalState\">\n <!-- Create workspace modal -->\n <CreateWorkspaceModal\n :state=\"createWorkspaceModalState\"\n @create:workspace=\"(payload) => app.workspace.create(payload)\" />\n </slot>\n <!-- Popup command palette to add resources from anywhere -->\n <TheCommandPalette\n :eventBus=\"app.eventBus\"\n :paletteState=\"paletteState\"\n :workspaceStore=\"app.store.value!\" />\n </main>\n <!-- Splash screen -->\n <main v-else>\n <SplashScreen />\n </main>\n </ScalarTeleportRoot>\n</template>\n\n<style>\n#scalar-client {\n position: relative;\n background-color: var(--scalar-background-2);\n}\n.dark-mode #scalar-client {\n background-color: color-mix(in srgb, var(--scalar-background-1) 65%, black);\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"App.vue.js","names":[],"sources":["../../../../src/v2/features/app/App.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Main entry point for the API client for electron and web.\n *\n * This component handles all events and store business logic for the application.\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarTeleportRoot,\n useModal,\n type ModalState,\n} from '@scalar/components'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport { ScalarToasts } from '@scalar/use-toasts'\nimport { extensions } from '@scalar/workspace-store/schemas/extensions'\nimport { computed, onBeforeUnmount, toValue, watch } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport { SidebarToggle } from '@/v2/components/sidebar'\nimport AppHeader from '@/v2/features/app/components/AppHeader.vue'\nimport AppSidebar from '@/v2/features/app/components/AppSidebar.vue'\nimport CreateWorkspaceModal from '@/v2/features/app/components/CreateWorkspaceModal.vue'\nimport DocumentBreadcrumb from '@/v2/features/app/components/DocumentBreadcrumb.vue'\nimport DocumentSyncIndicator from '@/v2/features/app/components/DocumentSyncIndicator.vue'\nimport SplashScreen from '@/v2/features/app/components/SplashScreen.vue'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { useDocumentWatcher } from '@/v2/features/app/hooks/use-document-watcher'\nimport type { RegistryDocumentsState } from '@/v2/features/app/hooks/use-sidebar-documents'\nimport type { CommandPaletteState } from '@/v2/features/command-palette/hooks/use-command-palette-state'\nimport TheCommandPalette from '@/v2/features/command-palette/TheCommandPalette.vue'\nimport { useMonacoEditorConfiguration } from '@/v2/features/editor'\nimport { useColorMode } from '@/v2/hooks/use-color-mode'\nimport { useGlobalHotKeys } from '@/v2/hooks/use-global-hot-keys'\nimport type { ImportDocumentFromRegistry } from '@/v2/types/configuration'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport type { AppState } from './app-state'\nimport DesktopTabs from './components/DesktopTabs.vue'\n\nconst {\n layout,\n plugins = [],\n getAppState,\n getCommandPaletteState,\n fetchRegistryDocument,\n registryDocuments = { status: 'success', documents: [] },\n} = defineProps<{\n layout: Exclude<ClientLayout, 'modal'>\n plugins?: ClientPlugin[]\n getAppState: () => AppState\n getCommandPaletteState: () => CommandPaletteState\n /** Fetches the full document from registry by meta. Passed through to route props for sync. */\n fetchRegistryDocument?: ImportDocumentFromRegistry\n /**\n * The list of all available registry documents, with a loading status so the\n * sidebar can render skeleton placeholders until the real list is ready.\n */\n registryDocuments?: RegistryDocumentsState\n}>()\n\ndefineSlots<{\n /**\n * Slot for customizing the create workspace modal.\n * This slot is used to render custom actions or components within the create workspace modal.\n */\n 'create-workspace'?: (payload: { state: ModalState }) => unknown\n /**\n * Replaces the Scalar logo inside the header menu button. Typically used by\n * team-aware consumers (e.g. Scalar Cloud) to render a team avatar so the\n * left-most chrome reads as \"this team's workspace\" rather than the\n * generic Scalar wordmark.\n *\n * Receives `isTeamWorkspace` so consumers can opt into rendering a team\n * image only when the active workspace actually belongs to a team, while\n * keeping the default Scalar logo for local workspaces.\n */\n 'header-logo'?: (payload: { isTeamWorkspace: boolean }) => unknown\n /**\n * Slot for customizing the menu items section of the app header.\n * Defaults to a workspace picker bound to the current app state. Overriding this slot\n * replaces the default picker entirely, so the consumer is responsible for rendering\n * any workspace switcher (or other menu content) they need.\n */\n 'header-menu-items'?: () => unknown\n /**\n * Slot rendered at the trailing edge of the header, immediately before the\n * `header-end` slot. Use this for context-specific action buttons (for\n * example a \"Save\" button) so they sit next to the document chrome rather\n * than getting mixed in with the user / account controls in `header-end`.\n *\n * When both this slot and `header-end` are provided, a vertical divider is\n * inserted between them so the two groups read as visually distinct\n * clusters.\n */\n 'header-actions'?: () => unknown\n /**\n * Slot for customizing the end section of the app header.\n * Typically used for user menus, action buttons, or other trailing controls.\n */\n 'header-end'?: () => unknown\n}>()\n\ndefineExpose({\n openCreateWorkspace: () => createWorkspaceModalState.show(),\n})\n\nconst app = getAppState()\nconst paletteState = getCommandPaletteState()\n\n/** Expose workspace store to window for debugging purposes. */\nif (typeof window !== 'undefined') {\n window.dataDumpWorkspace = () => app.store.value\n window.dumpAppState = () => app\n}\n\n/** Call lifecycle hooks on plugins and subscribe to event bus events */\nconst pluginUnsubscribes: (() => void)[] = []\n\nfor (const plugin of plugins) {\n plugin.lifecycle?.onInit?.({ config: { telemetry: app.telemetry.value } })\n\n if (plugin.on) {\n for (const [event, handler] of Object.entries(plugin.on)) {\n pluginUnsubscribes.push(app.eventBus.on(event as any, handler as any))\n }\n }\n}\n\n/** Notify plugins when telemetry config changes */\nwatch(app.telemetry, () => {\n for (const plugin of plugins) {\n plugin.lifecycle?.onConfigChange?.({\n config: { telemetry: app.telemetry.value },\n })\n }\n})\n\nonBeforeUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n})\n\n/** Register global hotkeys for the app, passing the workspace event bus and layout state */\nuseGlobalHotKeys(app.eventBus, layout)\n\nconst DEFAULT_DOCUMENT_WATCH_TIMEOUT = 5000\n\n/** Watch the active document for changes and rebase it with its remote source */\nuseDocumentWatcher({\n documentName: () =>\n app.store.value?.workspace[extensions.workspace.activeDocument],\n store: app.store,\n initialTimeout: DEFAULT_DOCUMENT_WATCH_TIMEOUT,\n})\n\n/** Color mode */\nuseColorMode({ workspaceStore: app.store })\n\nconst currentTheme = computed(() => app.theme.styles.value.themeStyles)\nconst isDarkMode = computed(() => app.isDarkMode.value)\n\n/** Setup monaco editor configuration */\nuseMonacoEditorConfiguration({\n theme: currentTheme,\n darkMode: isDarkMode,\n})\n\nconst createWorkspaceModalState = useModal()\n\n/** Props to pass to the RouterView component. */\nconst routerViewProps = computed<RouteProps>(() => {\n return {\n documentSlug: app.activeEntities.documentSlug.value ?? '',\n document: app.store.value?.workspace.activeDocument ?? null,\n environment: app.environment.value,\n eventBus: app.eventBus,\n exampleName: app.activeEntities.exampleName.value,\n fetchRegistryDocument,\n layout,\n method: app.activeEntities.method.value,\n path: app.activeEntities.path.value,\n workspaceStore: app.store.value!,\n activeWorkspace: app.workspace.activeWorkspace.value!,\n isTeamWorkspace: app.workspace.isTeamWorkspace.value,\n plugins,\n isDarkMode: app.isDarkMode.value,\n currentTheme: app.theme.styles.value.themeStyles,\n customThemes: toValue(app.theme.customThemes),\n telemetry: app.telemetry.value,\n onUpdateTelemetry: (value: boolean) => {\n app.telemetry.value = value\n },\n options: app.options,\n }\n})\n</script>\n\n<template>\n <ScalarTeleportRoot>\n <!-- Theme style tag -->\n <div v-html=\"app.theme.themeStyleTag.value\" />\n\n <!-- Toasts -->\n <ScalarToasts />\n\n <!-- Main content -->\n <main\n v-if=\"\n app.store.value !== null &&\n app.workspace.activeWorkspace.value !== null &&\n !app.loading.value\n \">\n <div class=\"relative flex h-dvh w-dvw flex-col\">\n <SidebarToggle\n v-model=\"app.sidebar.isOpen.value\"\n class=\"absolute z-60 md:hidden\"\n :class=\"layout === 'desktop' ? 'top-14 left-4' : 'top-4 left-4'\" />\n <AppHeader\n :menuTitle=\"app.workspace.isTeamWorkspace.value ? 'Team' : 'Local'\"\n @navigate:to:settings=\"\n app.eventBus.emit('ui:navigate', {\n page: 'workspace',\n path: 'settings',\n })\n \">\n <!--\n Only forward the consumer-provided logo (typically a team\n avatar from Scalar Cloud) while the user is actually inside a\n team workspace. Outside of a team context the avatar would be\n misleading, so we omit the `#logo` template entirely and let\n `ScalarMenuButton` fall back to its default Scalar wordmark.\n -->\n <template\n v-if=\"$slots['header-logo'] && app.workspace.isTeamWorkspace.value\"\n #logo>\n <slot\n :isTeamWorkspace=\"app.workspace.isTeamWorkspace.value\"\n name=\"header-logo\" />\n </template>\n <template #menuItems>\n <!--\n The workspace picker used to live here as a submenu. It is now\n surfaced inline in the breadcrumb so the user reaches it in a\n single click. Consumers that want extra menu rows can still\n inject them through the `header-menu-items` slot.\n -->\n <slot name=\"header-menu-items\" />\n </template>\n <template #breadcrumb>\n <DocumentBreadcrumb\n :app=\"app\"\n :fetchRegistryDocument=\"fetchRegistryDocument\"\n :registryDocuments=\"registryDocuments\"\n @createWorkspace=\"createWorkspaceModalState.show()\" />\n </template>\n <template #end>\n <div class=\"flex items-center gap-2\">\n <!--\n Sync status mirrors the icon in the version picker so the\n user can see at a glance whether the active registry-backed\n document is synced / pending push / pending pull / in\n conflict, even when the picker dropdown is closed. We only\n mount it while a document is actually active on the route -\n on workspace-level pages (settings, get-started, etc.)\n there is nothing to sync, and an indicator there would just\n be noise.\n -->\n <DocumentSyncIndicator\n v-if=\"app.activeEntities.documentSlug.value\"\n :app=\"app\"\n :registryDocuments=\"registryDocuments\" />\n <slot\n v-if=\"$slots['header-actions']\"\n name=\"header-actions\" />\n <!--\n Vertical divider between the two trailing slot clusters.\n Only rendered when both `header-actions` and `header-end`\n are provided, so consumers using just one of the slots do\n not get an orphaned separator.\n -->\n <span\n v-if=\"$slots['header-actions'] && $slots['header-end']\"\n aria-hidden=\"true\"\n class=\"bg-border h-4 w-px shrink-0\" />\n <slot\n v-if=\"$slots['header-end']\"\n name=\"header-end\" />\n </div>\n </template>\n </AppHeader>\n <div class=\"flex min-h-0 flex-1 flex-row\">\n <!-- App sidebar -->\n <AppSidebar\n :app=\"app\"\n :fetchRegistryDocument=\"fetchRegistryDocument\"\n :registryDocuments=\"registryDocuments\"\n :sidebarWidth=\"app.sidebar.width.value\"\n @update:sidebarWidth=\"app.sidebar.handleSidebarWidthUpdate\" />\n\n <div class=\"flex min-h-0 flex-1 flex-col\">\n <!-- App Tabs -->\n <DesktopTabs\n v-if=\"layout === 'desktop'\"\n :activeTabIndex=\"app.tabs.activeTabIndex.value\"\n :eventBus=\"app.eventBus\"\n :tabs=\"app.tabs.state.value\" />\n\n <!-- Router view min-h-0 is required for scrolling, do not remove it -->\n <div class=\"bg-b-1 relative min-h-0 flex-1\">\n <RouterView v-bind=\"routerViewProps\" />\n </div>\n </div>\n </div>\n </div>\n\n <slot\n name=\"create-workspace\"\n :state=\"createWorkspaceModalState\">\n <!-- Create workspace modal -->\n <CreateWorkspaceModal\n :state=\"createWorkspaceModalState\"\n @create:workspace=\"(payload) => app.workspace.create(payload)\" />\n </slot>\n <!-- Popup command palette to add resources from anywhere -->\n <TheCommandPalette\n :eventBus=\"app.eventBus\"\n :paletteState=\"paletteState\"\n :workspaceStore=\"app.store.value!\" />\n </main>\n <!-- Splash screen -->\n <main v-else>\n <SplashScreen />\n </main>\n </ScalarTeleportRoot>\n</template>\n\n<style>\n#scalar-client {\n position: relative;\n background-color: var(--scalar-background-2);\n}\n.dark-mode #scalar-client {\n background-color: color-mix(in srgb, var(--scalar-background-1) 65%, black);\n}\n</style>\n"],"mappings":""}
@@ -3,14 +3,16 @@ import SidebarToggle_default from "../../components/sidebar/SidebarToggle.vue.js
3
3
  import CreateWorkspaceModal_default from "./components/CreateWorkspaceModal.vue.js";
4
4
  import AppHeader_default from "./components/AppHeader.vue.js";
5
5
  import AppSidebar_default from "./components/AppSidebar.vue.js";
6
+ import DocumentBreadcrumb_default from "./components/DocumentBreadcrumb.vue.js";
7
+ import DocumentSyncIndicator_default from "./components/DocumentSyncIndicator.vue.js";
6
8
  import SplashScreen_default from "./components/SplashScreen.vue.js";
7
9
  import { useDocumentWatcher } from "./hooks/use-document-watcher.js";
8
10
  import { useMonacoEditorConfiguration } from "../editor/config.js";
9
11
  import { useColorMode } from "../../hooks/use-color-mode.js";
10
12
  import { useGlobalHotKeys } from "../../hooks/use-global-hot-keys.js";
11
13
  import DesktopTabs_default from "./components/DesktopTabs.vue.js";
12
- import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, guardReactiveProps, normalizeClass, normalizeProps, onBeforeUnmount, openBlock, renderSlot, toValue, unref, watch, withCtx } from "vue";
13
- import { ScalarMenuWorkspacePicker, ScalarTeleportRoot, useModal } from "@scalar/components";
14
+ import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createVNode, defineComponent, guardReactiveProps, normalizeClass, normalizeProps, onBeforeUnmount, openBlock, renderSlot, toValue, unref, watch, withCtx } from "vue";
15
+ import { ScalarTeleportRoot, useModal } from "@scalar/components";
14
16
  import { ScalarToasts } from "@scalar/use-toasts";
15
17
  import { RouterView } from "vue-router";
16
18
  import { extensions } from "@scalar/workspace-store/schemas/extensions";
@@ -18,10 +20,16 @@ import { extensions } from "@scalar/workspace-store/schemas/extensions";
18
20
  var _hoisted_1 = ["innerHTML"];
19
21
  var _hoisted_2 = { key: 0 };
20
22
  var _hoisted_3 = { class: "relative flex h-dvh w-dvw flex-col" };
21
- var _hoisted_4 = { class: "flex min-h-0 flex-1 flex-row" };
22
- var _hoisted_5 = { class: "flex min-h-0 flex-1 flex-col" };
23
- var _hoisted_6 = { class: "bg-b-1 relative min-h-0 flex-1" };
24
- var _hoisted_7 = { key: 1 };
23
+ var _hoisted_4 = { class: "flex items-center gap-2" };
24
+ var _hoisted_5 = {
25
+ key: 2,
26
+ "aria-hidden": "true",
27
+ class: "bg-border h-4 w-px shrink-0"
28
+ };
29
+ var _hoisted_6 = { class: "flex min-h-0 flex-1 flex-row" };
30
+ var _hoisted_7 = { class: "flex min-h-0 flex-1 flex-col" };
31
+ var _hoisted_8 = { class: "bg-b-1 relative min-h-0 flex-1" };
32
+ var _hoisted_9 = { key: 1 };
25
33
  var App_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
26
34
  __name: "App",
27
35
  props: {
@@ -73,21 +81,6 @@ var App_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComp
73
81
  theme: computed(() => app.theme.styles.value.themeStyles),
74
82
  darkMode: computed(() => app.isDarkMode.value)
75
83
  });
76
- const navigateToWorkspaceOverview = (namespace, slug) => {
77
- app.eventBus.emit("ui:navigate", {
78
- page: "workspace",
79
- path: "environment",
80
- namespace,
81
- workspaceSlug: slug
82
- });
83
- };
84
- /** Sets the active workspace by ID: finds the workspace in the list and updates app state & navigation. */
85
- const setActiveWorkspace = (id) => {
86
- if (!id) return;
87
- const workspace = app.workspace.workspaceList.value?.find((workspace) => workspace.id === id);
88
- if (!workspace) return;
89
- navigateToWorkspaceOverview(workspace.namespace, workspace.slug);
90
- };
91
84
  const createWorkspaceModalState = useModal();
92
85
  /** Props to pass to the RouterView component. */
93
86
  const routerViewProps = computed(() => {
@@ -103,6 +96,7 @@ var App_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComp
103
96
  path: app.activeEntities.path.value,
104
97
  workspaceStore: app.store.value,
105
98
  activeWorkspace: app.workspace.activeWorkspace.value,
99
+ isTeamWorkspace: app.workspace.isTeamWorkspace.value,
106
100
  plugins: __props.plugins,
107
101
  isDarkMode: app.isDarkMode.value,
108
102
  currentTheme: app.theme.styles.value.themeStyles,
@@ -126,20 +120,41 @@ var App_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComp
126
120
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => unref(app).sidebar.isOpen.value = $event),
127
121
  class: normalizeClass(["absolute z-60 md:hidden", __props.layout === "desktop" ? "top-14 left-4" : "top-4 left-4"])
128
122
  }, null, 8, ["modelValue", "class"]),
129
- createVNode(AppHeader_default, { "onNavigate:to:settings": _cache[3] || (_cache[3] = ($event) => unref(app).eventBus.emit("ui:navigate", {
130
- page: "workspace",
131
- path: "settings"
132
- })) }, {
133
- menuItems: withCtx(() => [renderSlot(_ctx.$slots, "header-menu-items", {}, () => [createVNode(unref(ScalarMenuWorkspacePicker), {
134
- modelValue: unref(app).workspace.activeWorkspace.value?.id,
135
- workspaceOptions: unref(app).workspace.workspaceGroups.value,
136
- onCreateWorkspace: _cache[1] || (_cache[1] = ($event) => unref(createWorkspaceModalState).show()),
137
- "onUpdate:modelValue": _cache[2] || (_cache[2] = (value) => setActiveWorkspace(value))
138
- }, null, 8, ["modelValue", "workspaceOptions"])])]),
139
- end: withCtx(() => [renderSlot(_ctx.$slots, "header-end")]),
140
- _: 3
141
- }),
142
- createElementVNode("div", _hoisted_4, [createVNode(AppSidebar_default, {
123
+ createVNode(AppHeader_default, {
124
+ menuTitle: unref(app).workspace.isTeamWorkspace.value ? "Team" : "Local",
125
+ "onNavigate:to:settings": _cache[2] || (_cache[2] = ($event) => unref(app).eventBus.emit("ui:navigate", {
126
+ page: "workspace",
127
+ path: "settings"
128
+ }))
129
+ }, createSlots({
130
+ menuItems: withCtx(() => [renderSlot(_ctx.$slots, "header-menu-items")]),
131
+ breadcrumb: withCtx(() => [createVNode(DocumentBreadcrumb_default, {
132
+ app: unref(app),
133
+ fetchRegistryDocument: __props.fetchRegistryDocument,
134
+ registryDocuments: __props.registryDocuments,
135
+ onCreateWorkspace: _cache[1] || (_cache[1] = ($event) => unref(createWorkspaceModalState).show())
136
+ }, null, 8, [
137
+ "app",
138
+ "fetchRegistryDocument",
139
+ "registryDocuments"
140
+ ])]),
141
+ end: withCtx(() => [createElementVNode("div", _hoisted_4, [
142
+ unref(app).activeEntities.documentSlug.value ? (openBlock(), createBlock(DocumentSyncIndicator_default, {
143
+ key: 0,
144
+ app: unref(app),
145
+ registryDocuments: __props.registryDocuments
146
+ }, null, 8, ["app", "registryDocuments"])) : createCommentVNode("", true),
147
+ _ctx.$slots["header-actions"] ? renderSlot(_ctx.$slots, "header-actions", { key: 1 }) : createCommentVNode("", true),
148
+ _ctx.$slots["header-actions"] && _ctx.$slots["header-end"] ? (openBlock(), createElementBlock("span", _hoisted_5)) : createCommentVNode("", true),
149
+ _ctx.$slots["header-end"] ? renderSlot(_ctx.$slots, "header-end", { key: 3 }) : createCommentVNode("", true)
150
+ ])]),
151
+ _: 2
152
+ }, [_ctx.$slots["header-logo"] && unref(app).workspace.isTeamWorkspace.value ? {
153
+ name: "logo",
154
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "header-logo", { isTeamWorkspace: unref(app).workspace.isTeamWorkspace.value })]),
155
+ key: "0"
156
+ } : void 0]), 1032, ["menuTitle"]),
157
+ createElementVNode("div", _hoisted_6, [createVNode(AppSidebar_default, {
143
158
  app: unref(app),
144
159
  fetchRegistryDocument: __props.fetchRegistryDocument,
145
160
  registryDocuments: __props.registryDocuments,
@@ -151,7 +166,7 @@ var App_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComp
151
166
  "registryDocuments",
152
167
  "sidebarWidth",
153
168
  "onUpdate:sidebarWidth"
154
- ]), createElementVNode("div", _hoisted_5, [__props.layout === "desktop" ? (openBlock(), createBlock(DesktopTabs_default, {
169
+ ]), createElementVNode("div", _hoisted_7, [__props.layout === "desktop" ? (openBlock(), createBlock(DesktopTabs_default, {
155
170
  key: 0,
156
171
  activeTabIndex: unref(app).tabs.activeTabIndex.value,
157
172
  eventBus: unref(app).eventBus,
@@ -160,11 +175,11 @@ var App_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComp
160
175
  "activeTabIndex",
161
176
  "eventBus",
162
177
  "tabs"
163
- ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_6, [createVNode(unref(RouterView), normalizeProps(guardReactiveProps(routerViewProps.value)), null, 16)])])])
178
+ ])) : createCommentVNode("", true), createElementVNode("div", _hoisted_8, [createVNode(unref(RouterView), normalizeProps(guardReactiveProps(routerViewProps.value)), null, 16)])])])
164
179
  ]),
165
180
  renderSlot(_ctx.$slots, "create-workspace", { state: unref(createWorkspaceModalState) }, () => [createVNode(CreateWorkspaceModal_default, {
166
181
  state: unref(createWorkspaceModalState),
167
- "onCreate:workspace": _cache[4] || (_cache[4] = (payload) => unref(app).workspace.create(payload))
182
+ "onCreate:workspace": _cache[3] || (_cache[3] = (payload) => unref(app).workspace.create(payload))
168
183
  }, null, 8, ["state"])]),
169
184
  createVNode(TheCommandPalette_default, {
170
185
  eventBus: unref(app).eventBus,
@@ -175,7 +190,7 @@ var App_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComp
175
190
  "paletteState",
176
191
  "workspaceStore"
177
192
  ])
178
- ])) : (openBlock(), createElementBlock("main", _hoisted_7, [createVNode(SplashScreen_default)]))
193
+ ])) : (openBlock(), createElementBlock("main", _hoisted_9, [createVNode(SplashScreen_default)]))
179
194
  ]),
180
195
  _: 3
181
196
  });
@@ -1 +1 @@
1
- {"version":3,"file":"App.vue.script.js","names":[],"sources":["../../../../src/v2/features/app/App.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Main entry point for the API client for electron and web.\n *\n * This component handles all events and store business logic for the application.\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarMenuWorkspacePicker,\n ScalarTeleportRoot,\n useModal,\n type ModalState,\n} from '@scalar/components'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport { ScalarToasts } from '@scalar/use-toasts'\nimport { extensions } from '@scalar/workspace-store/schemas/extensions'\nimport { computed, onBeforeUnmount, toValue, watch } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport { SidebarToggle } from '@/v2/components/sidebar'\nimport AppHeader from '@/v2/features/app/components/AppHeader.vue'\nimport AppSidebar from '@/v2/features/app/components/AppSidebar.vue'\nimport CreateWorkspaceModal from '@/v2/features/app/components/CreateWorkspaceModal.vue'\nimport SplashScreen from '@/v2/features/app/components/SplashScreen.vue'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { useDocumentWatcher } from '@/v2/features/app/hooks/use-document-watcher'\nimport type { RegistryDocumentsState } from '@/v2/features/app/hooks/use-sidebar-documents'\nimport type { CommandPaletteState } from '@/v2/features/command-palette/hooks/use-command-palette-state'\nimport TheCommandPalette from '@/v2/features/command-palette/TheCommandPalette.vue'\nimport { useMonacoEditorConfiguration } from '@/v2/features/editor'\nimport { useColorMode } from '@/v2/hooks/use-color-mode'\nimport { useGlobalHotKeys } from '@/v2/hooks/use-global-hot-keys'\nimport type { ImportDocumentFromRegistry } from '@/v2/types/configuration'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { type AppState } from './app-state'\nimport DesktopTabs from './components/DesktopTabs.vue'\n\nconst {\n layout,\n plugins = [],\n getAppState,\n getCommandPaletteState,\n fetchRegistryDocument,\n registryDocuments = { status: 'success', documents: [] },\n} = defineProps<{\n layout: Exclude<ClientLayout, 'modal'>\n plugins?: ClientPlugin[]\n getAppState: () => AppState\n getCommandPaletteState: () => CommandPaletteState\n /** Fetches the full document from registry by meta. Passed through to route props for sync. */\n fetchRegistryDocument?: ImportDocumentFromRegistry\n /**\n * The list of all available registry documents, with a loading status so the\n * sidebar can render skeleton placeholders until the real list is ready.\n */\n registryDocuments?: RegistryDocumentsState\n}>()\n\ndefineSlots<{\n /**\n * Slot for customizing the create workspace modal.\n * This slot is used to render custom actions or components within the create workspace modal.\n */\n 'create-workspace'?: (payload: { state: ModalState }) => unknown\n /**\n * Slot for customizing the menu items section of the app header.\n * Defaults to a workspace picker bound to the current app state. Overriding this slot\n * replaces the default picker entirely, so the consumer is responsible for rendering\n * any workspace switcher (or other menu content) they need.\n */\n 'header-menu-items'?: () => unknown\n /**\n * Slot for customizing the end section of the app header.\n * Typically used for user menus, action buttons, or other trailing controls.\n */\n 'header-end'?: () => unknown\n}>()\n\ndefineExpose({\n openCreateWorkspace: () => createWorkspaceModalState.show(),\n})\n\nconst app = getAppState()\nconst paletteState = getCommandPaletteState()\n\n/** Expose workspace store to window for debugging purposes. */\nif (typeof window !== 'undefined') {\n window.dataDumpWorkspace = () => app.store.value\n window.dumpAppState = () => app\n}\n\n/** Call lifecycle hooks on plugins and subscribe to event bus events */\nconst pluginUnsubscribes: (() => void)[] = []\n\nfor (const plugin of plugins) {\n plugin.lifecycle?.onInit?.({ config: { telemetry: app.telemetry.value } })\n\n if (plugin.on) {\n for (const [event, handler] of Object.entries(plugin.on)) {\n pluginUnsubscribes.push(app.eventBus.on(event as any, handler as any))\n }\n }\n}\n\n/** Notify plugins when telemetry config changes */\nwatch(app.telemetry, () => {\n for (const plugin of plugins) {\n plugin.lifecycle?.onConfigChange?.({\n config: { telemetry: app.telemetry.value },\n })\n }\n})\n\nonBeforeUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n})\n\n/** Register global hotkeys for the app, passing the workspace event bus and layout state */\nuseGlobalHotKeys(app.eventBus, layout)\n\nconst DEFAULT_DOCUMENT_WATCH_TIMEOUT = 5000\n\n/** Watch the active document for changes and rebase it with its remote source */\nuseDocumentWatcher({\n documentName: () =>\n app.store.value?.workspace[extensions.workspace.activeDocument],\n store: app.store,\n initialTimeout: DEFAULT_DOCUMENT_WATCH_TIMEOUT,\n})\n\n/** Color mode */\nuseColorMode({ workspaceStore: app.store })\n\nconst currentTheme = computed(() => app.theme.styles.value.themeStyles)\nconst isDarkMode = computed(() => app.isDarkMode.value)\n\n/** Setup monaco editor configuration */\nuseMonacoEditorConfiguration({\n theme: currentTheme,\n darkMode: isDarkMode,\n})\n\nconst navigateToWorkspaceOverview = (namespace?: string, slug?: string) => {\n app.eventBus.emit('ui:navigate', {\n page: 'workspace',\n path: 'environment',\n namespace,\n workspaceSlug: slug,\n })\n}\n\n/** Sets the active workspace by ID: finds the workspace in the list and updates app state & navigation. */\nconst setActiveWorkspace = (id?: string) => {\n if (!id) {\n return\n }\n const workspace = app.workspace.workspaceList.value?.find(\n (workspace) => workspace.id === id,\n )\n if (!workspace) {\n return\n }\n\n navigateToWorkspaceOverview(workspace.namespace, workspace.slug)\n}\n\nconst createWorkspaceModalState = useModal()\n\n/** Props to pass to the RouterView component. */\nconst routerViewProps = computed<RouteProps>(() => {\n return {\n documentSlug: app.activeEntities.documentSlug.value ?? '',\n document: app.store.value?.workspace.activeDocument ?? null,\n environment: app.environment.value,\n eventBus: app.eventBus,\n exampleName: app.activeEntities.exampleName.value,\n fetchRegistryDocument,\n layout,\n method: app.activeEntities.method.value,\n path: app.activeEntities.path.value,\n workspaceStore: app.store.value!,\n activeWorkspace: app.workspace.activeWorkspace.value!,\n plugins,\n isDarkMode: app.isDarkMode.value,\n currentTheme: app.theme.styles.value.themeStyles,\n customThemes: toValue(app.theme.customThemes),\n telemetry: app.telemetry.value,\n onUpdateTelemetry: (value: boolean) => {\n app.telemetry.value = value\n },\n options: app.options,\n }\n})\n</script>\n\n<template>\n <ScalarTeleportRoot>\n <!-- Theme style tag -->\n <div v-html=\"app.theme.themeStyleTag.value\" />\n\n <!-- Toasts -->\n <ScalarToasts />\n\n <!-- Main content -->\n <main\n v-if=\"\n app.store.value !== null &&\n app.workspace.activeWorkspace.value !== null &&\n !app.loading.value\n \">\n <div class=\"relative flex h-dvh w-dvw flex-col\">\n <SidebarToggle\n v-model=\"app.sidebar.isOpen.value\"\n class=\"absolute z-60 md:hidden\"\n :class=\"layout === 'desktop' ? 'top-14 left-4' : 'top-4 left-4'\" />\n <AppHeader\n @navigate:to:settings=\"\n app.eventBus.emit('ui:navigate', {\n page: 'workspace',\n path: 'settings',\n })\n \">\n <template #menuItems>\n <slot name=\"header-menu-items\">\n <ScalarMenuWorkspacePicker\n :modelValue=\"app.workspace.activeWorkspace.value?.id\"\n :workspaceOptions=\"app.workspace.workspaceGroups.value\"\n @createWorkspace=\"createWorkspaceModalState.show()\"\n @update:modelValue=\"(value) => setActiveWorkspace(value)\" />\n </slot>\n </template>\n <template #end>\n <slot name=\"header-end\" />\n </template>\n </AppHeader>\n <div class=\"flex min-h-0 flex-1 flex-row\">\n <!-- App sidebar -->\n <AppSidebar\n :app=\"app\"\n :fetchRegistryDocument=\"fetchRegistryDocument\"\n :registryDocuments=\"registryDocuments\"\n :sidebarWidth=\"app.sidebar.width.value\"\n @update:sidebarWidth=\"app.sidebar.handleSidebarWidthUpdate\" />\n\n <div class=\"flex min-h-0 flex-1 flex-col\">\n <!-- App Tabs -->\n <DesktopTabs\n v-if=\"layout === 'desktop'\"\n :activeTabIndex=\"app.tabs.activeTabIndex.value\"\n :eventBus=\"app.eventBus\"\n :tabs=\"app.tabs.state.value\" />\n\n <!-- Router view min-h-0 is required for scrolling, do not remove it -->\n <div class=\"bg-b-1 relative min-h-0 flex-1\">\n <RouterView v-bind=\"routerViewProps\" />\n </div>\n </div>\n </div>\n </div>\n\n <slot\n name=\"create-workspace\"\n :state=\"createWorkspaceModalState\">\n <!-- Create workspace modal -->\n <CreateWorkspaceModal\n :state=\"createWorkspaceModalState\"\n @create:workspace=\"(payload) => app.workspace.create(payload)\" />\n </slot>\n <!-- Popup command palette to add resources from anywhere -->\n <TheCommandPalette\n :eventBus=\"app.eventBus\"\n :paletteState=\"paletteState\"\n :workspaceStore=\"app.store.value!\" />\n </main>\n <!-- Splash screen -->\n <main v-else>\n <SplashScreen />\n </main>\n </ScalarTeleportRoot>\n</template>\n\n<style>\n#scalar-client {\n position: relative;\n background-color: var(--scalar-background-2);\n}\n.dark-mode #scalar-client {\n background-color: color-mix(in srgb, var(--scalar-background-1) 65%, black);\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"App.vue.script.js","names":["$slots"],"sources":["../../../../src/v2/features/app/App.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Main entry point for the API client for electron and web.\n *\n * This component handles all events and store business logic for the application.\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarTeleportRoot,\n useModal,\n type ModalState,\n} from '@scalar/components'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport { ScalarToasts } from '@scalar/use-toasts'\nimport { extensions } from '@scalar/workspace-store/schemas/extensions'\nimport { computed, onBeforeUnmount, toValue, watch } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport { SidebarToggle } from '@/v2/components/sidebar'\nimport AppHeader from '@/v2/features/app/components/AppHeader.vue'\nimport AppSidebar from '@/v2/features/app/components/AppSidebar.vue'\nimport CreateWorkspaceModal from '@/v2/features/app/components/CreateWorkspaceModal.vue'\nimport DocumentBreadcrumb from '@/v2/features/app/components/DocumentBreadcrumb.vue'\nimport DocumentSyncIndicator from '@/v2/features/app/components/DocumentSyncIndicator.vue'\nimport SplashScreen from '@/v2/features/app/components/SplashScreen.vue'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { useDocumentWatcher } from '@/v2/features/app/hooks/use-document-watcher'\nimport type { RegistryDocumentsState } from '@/v2/features/app/hooks/use-sidebar-documents'\nimport type { CommandPaletteState } from '@/v2/features/command-palette/hooks/use-command-palette-state'\nimport TheCommandPalette from '@/v2/features/command-palette/TheCommandPalette.vue'\nimport { useMonacoEditorConfiguration } from '@/v2/features/editor'\nimport { useColorMode } from '@/v2/hooks/use-color-mode'\nimport { useGlobalHotKeys } from '@/v2/hooks/use-global-hot-keys'\nimport type { ImportDocumentFromRegistry } from '@/v2/types/configuration'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport type { AppState } from './app-state'\nimport DesktopTabs from './components/DesktopTabs.vue'\n\nconst {\n layout,\n plugins = [],\n getAppState,\n getCommandPaletteState,\n fetchRegistryDocument,\n registryDocuments = { status: 'success', documents: [] },\n} = defineProps<{\n layout: Exclude<ClientLayout, 'modal'>\n plugins?: ClientPlugin[]\n getAppState: () => AppState\n getCommandPaletteState: () => CommandPaletteState\n /** Fetches the full document from registry by meta. Passed through to route props for sync. */\n fetchRegistryDocument?: ImportDocumentFromRegistry\n /**\n * The list of all available registry documents, with a loading status so the\n * sidebar can render skeleton placeholders until the real list is ready.\n */\n registryDocuments?: RegistryDocumentsState\n}>()\n\ndefineSlots<{\n /**\n * Slot for customizing the create workspace modal.\n * This slot is used to render custom actions or components within the create workspace modal.\n */\n 'create-workspace'?: (payload: { state: ModalState }) => unknown\n /**\n * Replaces the Scalar logo inside the header menu button. Typically used by\n * team-aware consumers (e.g. Scalar Cloud) to render a team avatar so the\n * left-most chrome reads as \"this team's workspace\" rather than the\n * generic Scalar wordmark.\n *\n * Receives `isTeamWorkspace` so consumers can opt into rendering a team\n * image only when the active workspace actually belongs to a team, while\n * keeping the default Scalar logo for local workspaces.\n */\n 'header-logo'?: (payload: { isTeamWorkspace: boolean }) => unknown\n /**\n * Slot for customizing the menu items section of the app header.\n * Defaults to a workspace picker bound to the current app state. Overriding this slot\n * replaces the default picker entirely, so the consumer is responsible for rendering\n * any workspace switcher (or other menu content) they need.\n */\n 'header-menu-items'?: () => unknown\n /**\n * Slot rendered at the trailing edge of the header, immediately before the\n * `header-end` slot. Use this for context-specific action buttons (for\n * example a \"Save\" button) so they sit next to the document chrome rather\n * than getting mixed in with the user / account controls in `header-end`.\n *\n * When both this slot and `header-end` are provided, a vertical divider is\n * inserted between them so the two groups read as visually distinct\n * clusters.\n */\n 'header-actions'?: () => unknown\n /**\n * Slot for customizing the end section of the app header.\n * Typically used for user menus, action buttons, or other trailing controls.\n */\n 'header-end'?: () => unknown\n}>()\n\ndefineExpose({\n openCreateWorkspace: () => createWorkspaceModalState.show(),\n})\n\nconst app = getAppState()\nconst paletteState = getCommandPaletteState()\n\n/** Expose workspace store to window for debugging purposes. */\nif (typeof window !== 'undefined') {\n window.dataDumpWorkspace = () => app.store.value\n window.dumpAppState = () => app\n}\n\n/** Call lifecycle hooks on plugins and subscribe to event bus events */\nconst pluginUnsubscribes: (() => void)[] = []\n\nfor (const plugin of plugins) {\n plugin.lifecycle?.onInit?.({ config: { telemetry: app.telemetry.value } })\n\n if (plugin.on) {\n for (const [event, handler] of Object.entries(plugin.on)) {\n pluginUnsubscribes.push(app.eventBus.on(event as any, handler as any))\n }\n }\n}\n\n/** Notify plugins when telemetry config changes */\nwatch(app.telemetry, () => {\n for (const plugin of plugins) {\n plugin.lifecycle?.onConfigChange?.({\n config: { telemetry: app.telemetry.value },\n })\n }\n})\n\nonBeforeUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n})\n\n/** Register global hotkeys for the app, passing the workspace event bus and layout state */\nuseGlobalHotKeys(app.eventBus, layout)\n\nconst DEFAULT_DOCUMENT_WATCH_TIMEOUT = 5000\n\n/** Watch the active document for changes and rebase it with its remote source */\nuseDocumentWatcher({\n documentName: () =>\n app.store.value?.workspace[extensions.workspace.activeDocument],\n store: app.store,\n initialTimeout: DEFAULT_DOCUMENT_WATCH_TIMEOUT,\n})\n\n/** Color mode */\nuseColorMode({ workspaceStore: app.store })\n\nconst currentTheme = computed(() => app.theme.styles.value.themeStyles)\nconst isDarkMode = computed(() => app.isDarkMode.value)\n\n/** Setup monaco editor configuration */\nuseMonacoEditorConfiguration({\n theme: currentTheme,\n darkMode: isDarkMode,\n})\n\nconst createWorkspaceModalState = useModal()\n\n/** Props to pass to the RouterView component. */\nconst routerViewProps = computed<RouteProps>(() => {\n return {\n documentSlug: app.activeEntities.documentSlug.value ?? '',\n document: app.store.value?.workspace.activeDocument ?? null,\n environment: app.environment.value,\n eventBus: app.eventBus,\n exampleName: app.activeEntities.exampleName.value,\n fetchRegistryDocument,\n layout,\n method: app.activeEntities.method.value,\n path: app.activeEntities.path.value,\n workspaceStore: app.store.value!,\n activeWorkspace: app.workspace.activeWorkspace.value!,\n isTeamWorkspace: app.workspace.isTeamWorkspace.value,\n plugins,\n isDarkMode: app.isDarkMode.value,\n currentTheme: app.theme.styles.value.themeStyles,\n customThemes: toValue(app.theme.customThemes),\n telemetry: app.telemetry.value,\n onUpdateTelemetry: (value: boolean) => {\n app.telemetry.value = value\n },\n options: app.options,\n }\n})\n</script>\n\n<template>\n <ScalarTeleportRoot>\n <!-- Theme style tag -->\n <div v-html=\"app.theme.themeStyleTag.value\" />\n\n <!-- Toasts -->\n <ScalarToasts />\n\n <!-- Main content -->\n <main\n v-if=\"\n app.store.value !== null &&\n app.workspace.activeWorkspace.value !== null &&\n !app.loading.value\n \">\n <div class=\"relative flex h-dvh w-dvw flex-col\">\n <SidebarToggle\n v-model=\"app.sidebar.isOpen.value\"\n class=\"absolute z-60 md:hidden\"\n :class=\"layout === 'desktop' ? 'top-14 left-4' : 'top-4 left-4'\" />\n <AppHeader\n :menuTitle=\"app.workspace.isTeamWorkspace.value ? 'Team' : 'Local'\"\n @navigate:to:settings=\"\n app.eventBus.emit('ui:navigate', {\n page: 'workspace',\n path: 'settings',\n })\n \">\n <!--\n Only forward the consumer-provided logo (typically a team\n avatar from Scalar Cloud) while the user is actually inside a\n team workspace. Outside of a team context the avatar would be\n misleading, so we omit the `#logo` template entirely and let\n `ScalarMenuButton` fall back to its default Scalar wordmark.\n -->\n <template\n v-if=\"$slots['header-logo'] && app.workspace.isTeamWorkspace.value\"\n #logo>\n <slot\n :isTeamWorkspace=\"app.workspace.isTeamWorkspace.value\"\n name=\"header-logo\" />\n </template>\n <template #menuItems>\n <!--\n The workspace picker used to live here as a submenu. It is now\n surfaced inline in the breadcrumb so the user reaches it in a\n single click. Consumers that want extra menu rows can still\n inject them through the `header-menu-items` slot.\n -->\n <slot name=\"header-menu-items\" />\n </template>\n <template #breadcrumb>\n <DocumentBreadcrumb\n :app=\"app\"\n :fetchRegistryDocument=\"fetchRegistryDocument\"\n :registryDocuments=\"registryDocuments\"\n @createWorkspace=\"createWorkspaceModalState.show()\" />\n </template>\n <template #end>\n <div class=\"flex items-center gap-2\">\n <!--\n Sync status mirrors the icon in the version picker so the\n user can see at a glance whether the active registry-backed\n document is synced / pending push / pending pull / in\n conflict, even when the picker dropdown is closed. We only\n mount it while a document is actually active on the route -\n on workspace-level pages (settings, get-started, etc.)\n there is nothing to sync, and an indicator there would just\n be noise.\n -->\n <DocumentSyncIndicator\n v-if=\"app.activeEntities.documentSlug.value\"\n :app=\"app\"\n :registryDocuments=\"registryDocuments\" />\n <slot\n v-if=\"$slots['header-actions']\"\n name=\"header-actions\" />\n <!--\n Vertical divider between the two trailing slot clusters.\n Only rendered when both `header-actions` and `header-end`\n are provided, so consumers using just one of the slots do\n not get an orphaned separator.\n -->\n <span\n v-if=\"$slots['header-actions'] && $slots['header-end']\"\n aria-hidden=\"true\"\n class=\"bg-border h-4 w-px shrink-0\" />\n <slot\n v-if=\"$slots['header-end']\"\n name=\"header-end\" />\n </div>\n </template>\n </AppHeader>\n <div class=\"flex min-h-0 flex-1 flex-row\">\n <!-- App sidebar -->\n <AppSidebar\n :app=\"app\"\n :fetchRegistryDocument=\"fetchRegistryDocument\"\n :registryDocuments=\"registryDocuments\"\n :sidebarWidth=\"app.sidebar.width.value\"\n @update:sidebarWidth=\"app.sidebar.handleSidebarWidthUpdate\" />\n\n <div class=\"flex min-h-0 flex-1 flex-col\">\n <!-- App Tabs -->\n <DesktopTabs\n v-if=\"layout === 'desktop'\"\n :activeTabIndex=\"app.tabs.activeTabIndex.value\"\n :eventBus=\"app.eventBus\"\n :tabs=\"app.tabs.state.value\" />\n\n <!-- Router view min-h-0 is required for scrolling, do not remove it -->\n <div class=\"bg-b-1 relative min-h-0 flex-1\">\n <RouterView v-bind=\"routerViewProps\" />\n </div>\n </div>\n </div>\n </div>\n\n <slot\n name=\"create-workspace\"\n :state=\"createWorkspaceModalState\">\n <!-- Create workspace modal -->\n <CreateWorkspaceModal\n :state=\"createWorkspaceModalState\"\n @create:workspace=\"(payload) => app.workspace.create(payload)\" />\n </slot>\n <!-- Popup command palette to add resources from anywhere -->\n <TheCommandPalette\n :eventBus=\"app.eventBus\"\n :paletteState=\"paletteState\"\n :workspaceStore=\"app.store.value!\" />\n </main>\n <!-- Splash screen -->\n <main v-else>\n <SplashScreen />\n </main>\n </ScalarTeleportRoot>\n</template>\n\n<style>\n#scalar-client {\n position: relative;\n background-color: var(--scalar-background-2);\n}\n.dark-mode #scalar-client {\n background-color: color-mix(in srgb, var(--scalar-background-1) 65%, black);\n}\n</style>\n"],"mappings":"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"}
@@ -164,7 +164,7 @@ function initializeAppEventHandlers({ eventBus, store, router, rebuildSidebar, n
164
164
  const params = {
165
165
  documentSlug: payload.documentSlug,
166
166
  workspaceSlug: payload.workspaceSlug,
167
- namespace: payload.namespace
167
+ teamSlug: payload.teamSlug
168
168
  };
169
169
  if (payload.path === "overview") return execCallback(await fn({
170
170
  name: "document.overview",
@@ -194,7 +194,7 @@ function initializeAppEventHandlers({ eventBus, store, router, rebuildSidebar, n
194
194
  if (payload.page === "workspace") {
195
195
  const params = {
196
196
  workspaceSlug: payload.workspaceSlug,
197
- namespace: payload.namespace
197
+ teamSlug: payload.teamSlug
198
198
  };
199
199
  if (payload.path === "get-started") return execCallback(await fn({
200
200
  name: "workspace.get-started",
@@ -216,7 +216,7 @@ function initializeAppEventHandlers({ eventBus, store, router, rebuildSidebar, n
216
216
  if (payload.page === "example") return execCallback(await fn({
217
217
  name: "example",
218
218
  params: {
219
- namespace: payload.namespace,
219
+ teamSlug: payload.teamSlug,
220
220
  workspaceSlug: payload.workspaceSlug,
221
221
  documentSlug: payload.documentSlug,
222
222
  pathEncoded: encodeURIComponent(payload.path),
@@ -226,7 +226,7 @@ function initializeAppEventHandlers({ eventBus, store, router, rebuildSidebar, n
226
226
  }));
227
227
  if (payload.page === "operation") {
228
228
  const params = {
229
- namespace: payload.namespace,
229
+ teamSlug: payload.teamSlug,
230
230
  workspaceSlug: payload.workspaceSlug,
231
231
  documentSlug: payload.documentSlug,
232
232
  pathEncoded: encodeURIComponent(payload.operationPath),