@scalar/api-client
Advanced tools
| import type { CustomFetch } from '../../v2/blocks/operation-block/helpers/send-request.js'; | ||
| import type { ApiReferenceConfigurationRaw } from '@scalar/types/api-reference'; | ||
| import type { Ref } from 'vue'; | ||
| /** | ||
| * Configuration options for the API Client (app and modal). | ||
| */ | ||
| export type ApiClientOptions = Partial<Pick<ApiReferenceConfigurationRaw, 'authentication' | 'baseServerURL' | 'hideClientButton' | 'hiddenClients' | 'oauth2RedirectUri' | 'proxyUrl' | 'servers'>> & { | ||
| /** | ||
| * Custom fetch implementation used for all outgoing API requests. | ||
| * When provided, replaces the global fetch in the request execution engine (sendRequest). | ||
| */ | ||
| customFetch?: CustomFetch; | ||
| }; | ||
| export type ApiClientOptionsRef = Ref<ApiClientOptions>; | ||
| //# sourceMappingURL=options.d.ts.map |
| {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../src/v2/types/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AACnF,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAC/E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAE9B;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,CACpC,IAAI,CACF,4BAA4B,EAC1B,gBAAgB,GAChB,eAAe,GACf,kBAAkB,GAClB,eAAe,GACf,mBAAmB,GACnB,UAAU,GACV,SAAS,CACZ,CACF,GAAG;IACF;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,GAAG,CAAC,gBAAgB,CAAC,CAAA"} |
@@ -7,5 +7,5 @@ type __VLS_Props = { | ||
| declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { | ||
| change: (value: "delete" | "head" | "get" | "options" | "put" | "post" | "patch" | "trace") => any; | ||
| change: (value: "head" | "delete" | "get" | "options" | "patch" | "post" | "put" | "trace") => any; | ||
| }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{ | ||
| onChange?: ((value: "delete" | "head" | "get" | "options" | "put" | "post" | "patch" | "trace") => any) | undefined; | ||
| onChange?: ((value: "head" | "delete" | "get" | "options" | "patch" | "post" | "put" | "trace") => any) | undefined; | ||
| }>, { | ||
@@ -12,0 +12,0 @@ isSquare: boolean; |
@@ -10,7 +10,7 @@ type __VLS_Props = { | ||
| declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { | ||
| cancel: () => any; | ||
| submit: () => any; | ||
| cancel: () => any; | ||
| }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{ | ||
| onCancel?: (() => any) | undefined; | ||
| onSubmit?: (() => any) | undefined; | ||
| onCancel?: (() => any) | undefined; | ||
| }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; | ||
@@ -17,0 +17,0 @@ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>; |
@@ -30,2 +30,4 @@ import { type ErrorResponse } from '@scalar/helpers/errors/normalize-error'; | ||
| }); | ||
| /** Custom fetch function signature compatible with the global fetch API */ | ||
| export type CustomFetch = typeof fetch; | ||
| /** | ||
@@ -44,3 +46,3 @@ * Execute the built fetch request and return a structured response. | ||
| */ | ||
| export declare const sendRequest: ({ isUsingProxy, requestPayload, plugins, }: { | ||
| export declare const sendRequest: ({ isUsingProxy, requestPayload, plugins, customFetch, }: { | ||
| isUsingProxy: boolean; | ||
@@ -50,2 +52,4 @@ requestPayload: RequestPayload; | ||
| plugins?: ClientPlugin[]; | ||
| /** Optional custom fetch implementation, overrides the global fetch */ | ||
| customFetch?: CustomFetch; | ||
| }) => Promise<ErrorResponse<{ | ||
@@ -52,0 +56,0 @@ response: ResponseInstance; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"send-request.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/operation-block/helpers/send-request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,aAAa,EAAkB,MAAM,wCAAwC,CAAA;AAGnG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAGnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAA;AAe7E,0DAA0D;AAC1D,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG;IACzD,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,wCAAwC;IACxC,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,0BAA0B;IAC1B,MAAM,EAAE,UAAU,CAAA;IAClB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,CACE;IACE,wBAAwB;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAA;CACb,GACD;IACE,qDAAqD;IACrD,MAAM,EAAE,2BAA2B,CAAC,UAAU,CAAC,CAAA;CAChD,CACJ,CAAA;AAKH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GAAU,4CAI/B;IACD,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,cAAc,CAAA;IAC9B,iEAAiE;IACjE,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;CACzB,KAAG,OAAO,CACT,aAAa,CAAC;IACZ,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,cAAc,EAAE,cAAc,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,QAAQ,CAAA;CAC3B,CAAC,CA2DH,CAAA"} | ||
| {"version":3,"file":"send-request.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/operation-block/helpers/send-request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,aAAa,EAAkB,MAAM,wCAAwC,CAAA;AAGnG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAGnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAA;AAe7E,0DAA0D;AAC1D,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG;IACzD,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,wCAAwC;IACxC,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,0BAA0B;IAC1B,MAAM,EAAE,UAAU,CAAA;IAClB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,CACE;IACE,wBAAwB;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAA;CACb,GACD;IACE,qDAAqD;IACrD,MAAM,EAAE,2BAA2B,CAAC,UAAU,CAAC,CAAA;CAChD,CACJ,CAAA;AAKH,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,OAAO,KAAK,CAAA;AAEtC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GAAU,yDAK/B;IACD,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,cAAc,CAAA;IAC9B,iEAAiE;IACjE,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB,uEAAuE;IACvE,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B,KAAG,OAAO,CACT,aAAa,CAAC;IACZ,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,cAAc,EAAE,cAAc,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,QAAQ,CAAA;CAC3B,CAAC,CA0DH,CAAA"} |
@@ -33,6 +33,6 @@ import { getCookieHeaderKeys } from "./get-cookie-header-keys.js"; | ||
| */ | ||
| var sendRequest = async ({ isUsingProxy, requestPayload, plugins = [] }) => { | ||
| var sendRequest = async ({ isUsingProxy, requestPayload, plugins = [], customFetch = fetch }) => { | ||
| try { | ||
| const startTime = performance.now(); | ||
| const response = isElectron() && window.proxiedFetch ? await window.proxiedFetch?.(...requestPayload) : await fetch(buildSafeBodyRequest(...requestPayload)); | ||
| const response = isElectron() ? await customFetch(...requestPayload) : await customFetch(buildSafeBodyRequest(...requestPayload)); | ||
| const endTime = performance.now(); | ||
@@ -39,0 +39,0 @@ const timestamp = Date.now(); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"send-request.js","names":[],"sources":["../../../../../src/v2/blocks/operation-block/helpers/send-request.ts"],"sourcesContent":["import { ERRORS, type ErrorResponse, normalizeError } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { httpStatusCodes } from '@scalar/helpers/http/http-status-codes'\nimport { normalizeHeaders } from '@scalar/helpers/http/normalize-headers'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { RequestPayload } from '@scalar/workspace-store/request-example'\nimport * as cookie from 'cookie'\nimport { parseSetCookie } from 'set-cookie-parser'\n\nimport { getCookieHeaderKeys } from '@/v2/blocks/operation-block/helpers/get-cookie-header-keys'\nimport { resolveResponseBodyHandler } from '@/v2/blocks/response-block/helpers/resolve-response-body-handler'\nimport {\n resolveResponseContentType,\n resolveResponseMimeType,\n} from '@/v2/blocks/response-block/helpers/resolve-response-content-type'\n\nimport { decodeBuffer } from './decode-buffer'\n\nconst CUSTOM_COOKIE_HEADER = 'x-scalar-set-cookie'\n\n/** A single set of populated values for a sent request */\nexport type ResponseInstance = Omit<Response, 'headers'> & {\n /** Store headers as an object to match what we had with axios */\n headers: Record<string, string>\n /** Keys of headers which set cookies */\n cookieHeaderKeys: string[]\n /** Time in ms the request took */\n duration: number\n /** The response status */\n status: number\n /** The response status text */\n statusText: string\n /** The response method */\n method: HttpMethod\n /** The request path */\n path: string\n} & (\n | {\n /** The response data */\n data: string | Blob\n /** The response size in bytes */\n size: number\n }\n | {\n /** A stream reader for a streamable response body */\n reader: ReadableStreamDefaultReader<Uint8Array>\n }\n )\n\n/** HTTP status codes that should not include a response body */\nconst NO_BODY_STATUS_CODES = [204, 205, 304]\n\n/**\n * Execute the built fetch request and return a structured response.\n *\n * This function handles the complete request lifecycle including plugin hooks,\n * response processing, streaming detection, and error handling. It supports both\n * standard responses and server-sent event streams.\n *\n * @param request - The request built by the buildRequest helper\n * @param operation - The OpenAPI operation being executed\n * @param plugins - Array of client plugins to execute hooks\n * @param isUsingProxy - Whether the request is being proxied for header handling\n * @returns A tuple with either an error or the response data\n */\nexport const sendRequest = async ({\n isUsingProxy,\n requestPayload,\n plugins = [],\n}: {\n isUsingProxy: boolean\n requestPayload: RequestPayload\n /** Registered client plugins for custom content type handling */\n plugins?: ClientPlugin[]\n}): Promise<\n ErrorResponse<{\n response: ResponseInstance\n requestPayload: RequestPayload\n timestamp: number\n originalResponse: Response\n }>\n> => {\n try {\n // Execute the request and measure duration\n const startTime = performance.now()\n\n // We may use a custom fetch function on electron\n const response =\n isElectron() && window.proxiedFetch\n ? await window.proxiedFetch?.(...requestPayload)\n : await fetch(buildSafeBodyRequest(...requestPayload))\n\n const endTime = performance.now()\n const timestamp = Date.now()\n const duration = endTime - startTime\n\n // Extract response metadata early for reuse\n const contentType = response.headers.get('content-type')\n const responseHeaders = normalizeHeaders(response.headers, isUsingProxy)\n const responseUrl = new URL(response.url)\n const fullPath = responseUrl.pathname + responseUrl.search\n const statusText = response.statusText || httpStatusCodes[response.status]?.name || ''\n const method = (requestPayload[1].method ?? 'GET') as HttpMethod\n const shouldSkipBody = NO_BODY_STATUS_CODES.includes(response.status)\n\n /**\n * Handle server-sent event streams separately.\n * These responses need a reader instead of buffered data.\n * We check this early to avoid unnecessary body reading.\n */\n if (contentType?.startsWith('text/event-stream') && response.body) {\n return buildStreamingResponse({\n response,\n requestPayload,\n timestamp,\n duration,\n responseHeaders,\n statusText,\n method,\n fullPath,\n })\n }\n\n return buildStandardResponse({\n response,\n requestPayload,\n timestamp,\n duration,\n responseHeaders,\n statusText,\n method,\n fullPath,\n contentType,\n shouldSkipBody,\n plugins,\n })\n } catch (error) {\n return [normalizeError(error, ERRORS.REQUEST_FAILED), null]\n }\n}\n\n/**\n * Extracts and serializes custom cookies from the response using the custom cookie header.\n *\n * This function parses the custom cookie header (if present), serializes each cookie using the\n * 'cookie' library, and then deletes the custom cookie header from the response.\n * Returns an array of serialized cookie strings, or null if no cookies were found.\n *\n * The @ts-expect-error is present due to a type mismatch between the 'cookie' parsing and serialization libraries.\n */\nconst getCustomCookie = (response: Response): string[] | null => {\n const result = parseSetCookie(response.headers.get(CUSTOM_COOKIE_HEADER) ?? '').map((c) =>\n cookie.serialize(c.name, c.value, {\n ...c,\n sameSite: c.sameSite as boolean | 'lax' | 'strict' | 'none' | undefined,\n encode: (str: string) => str,\n }),\n )\n\n if (result.length) {\n return result\n }\n\n return null\n}\n\n/**\n * Build a streaming response for server-sent events.\n * Streaming responses use a reader instead of buffering the entire body.\n */\nconst buildStreamingResponse = ({\n response,\n requestPayload,\n timestamp,\n duration,\n responseHeaders,\n statusText,\n method,\n fullPath,\n}: {\n response: Response\n requestPayload: RequestPayload\n timestamp: number\n duration: number\n responseHeaders: Record<string, string>\n statusText: string\n method: HttpMethod\n fullPath: string\n}): ErrorResponse<{\n response: ResponseInstance\n requestPayload: RequestPayload\n timestamp: number\n originalResponse: Response\n}> => {\n const normalizedResponse = new Response(null, {\n status: response.status,\n statusText,\n headers: response.headers,\n })\n\n const customCookie = getCustomCookie(normalizedResponse)\n const cookieHeaderKeys = customCookie ?? getCookieHeaderKeys(normalizedResponse.headers)\n\n return [\n null,\n {\n timestamp,\n requestPayload,\n response: {\n ...normalizedResponse,\n headers: responseHeaders,\n cookieHeaderKeys,\n reader: response.body!.getReader(),\n duration,\n method,\n path: fullPath,\n },\n originalResponse: normalizedResponse.clone(),\n },\n ]\n}\n\n/**\n * Build a standard response with buffered body data.\n * This handles all non-streaming responses including JSON, text, and binary data.\n */\nconst buildStandardResponse = async ({\n response,\n requestPayload,\n timestamp,\n duration,\n responseHeaders,\n statusText,\n method,\n fullPath,\n contentType,\n shouldSkipBody,\n plugins,\n}: {\n response: Response\n requestPayload: RequestPayload\n timestamp: number\n duration: number\n responseHeaders: Record<string, string>\n statusText: string\n method: HttpMethod\n fullPath: string\n contentType: string | null\n shouldSkipBody: boolean\n plugins: ClientPlugin[]\n}): Promise<\n ErrorResponse<{\n response: ResponseInstance\n requestPayload: RequestPayload\n timestamp: number\n originalResponse: Response\n }>\n> => {\n /**\n * Clone the response to preserve the original for body reading.\n * Read the body once and reuse the buffer for both decoding and creating a new Response.\n */\n const clonedResponse = response.clone()\n const arrayBuffer = await clonedResponse.arrayBuffer()\n const responseType = resolveResponseContentType(contentType)\n const mimeEssence = resolveResponseMimeType(contentType).essence\n const pluginHandler = resolveResponseBodyHandler(mimeEssence, plugins)\n const responseData = await decodeBuffer(arrayBuffer, responseType, pluginHandler)\n\n /**\n * Create a new Response using the arrayBuffer we already read.\n * ArrayBuffers can be reused to create new Response objects without additional memory.\n */\n const normalizedResponse = new Response(shouldSkipBody ? null : arrayBuffer, {\n status: response.status,\n statusText,\n headers: response.headers,\n })\n\n const customCookie = getCustomCookie(normalizedResponse)\n const cookieHeaderKeys = customCookie ?? getCookieHeaderKeys(normalizedResponse.headers)\n\n return [\n null,\n {\n timestamp,\n requestPayload,\n response: {\n ...normalizedResponse,\n headers: responseHeaders,\n cookieHeaderKeys,\n data: responseData,\n size: arrayBuffer.byteLength,\n duration,\n method,\n status: response.status,\n path: fullPath,\n },\n originalResponse: response.clone(),\n },\n ]\n}\n"],"mappings":";;;;;;;;;;;;AAoBA,IAAM,uBAAuB;;AAgC7B,IAAM,uBAAuB;CAAC;CAAK;CAAK;CAAI;;;;;;;;;;;;;;AAe5C,IAAa,cAAc,OAAO,EAChC,cACA,gBACA,UAAU,EAAE,OAaT;AACH,KAAI;EAEF,MAAM,YAAY,YAAY,KAAK;EAGnC,MAAM,WACJ,YAAY,IAAI,OAAO,eACnB,MAAM,OAAO,eAAe,GAAG,eAAe,GAC9C,MAAM,MAAM,qBAAqB,GAAG,eAAe,CAAC;EAE1D,MAAM,UAAU,YAAY,KAAK;EACjC,MAAM,YAAY,KAAK,KAAK;EAC5B,MAAM,WAAW,UAAU;EAG3B,MAAM,cAAc,SAAS,QAAQ,IAAI,eAAe;EACxD,MAAM,kBAAkB,iBAAiB,SAAS,SAAS,aAAa;EACxE,MAAM,cAAc,IAAI,IAAI,SAAS,IAAI;EACzC,MAAM,WAAW,YAAY,WAAW,YAAY;EACpD,MAAM,aAAa,SAAS,cAAc,gBAAgB,SAAS,SAAS,QAAQ;EACpF,MAAM,SAAU,eAAe,GAAG,UAAU;EAC5C,MAAM,iBAAiB,qBAAqB,SAAS,SAAS,OAAO;;;;;;AAOrE,MAAI,aAAa,WAAW,oBAAoB,IAAI,SAAS,KAC3D,QAAO,uBAAuB;GAC5B;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD,CAAC;AAGJ,SAAO,sBAAsB;GAC3B;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD,CAAC;UACK,OAAO;AACd,SAAO,CAAC,eAAe,OAAO,OAAO,eAAe,EAAE,KAAK;;;;;;;;;;;;AAa/D,IAAM,mBAAmB,aAAwC;CAC/D,MAAM,SAAS,eAAe,SAAS,QAAQ,IAAI,qBAAqB,IAAI,GAAG,CAAC,KAAK,MACnF,OAAO,UAAU,EAAE,MAAM,EAAE,OAAO;EAChC,GAAG;EACH,UAAU,EAAE;EACZ,SAAS,QAAgB;EAC1B,CAAC,CACH;AAED,KAAI,OAAO,OACT,QAAO;AAGT,QAAO;;;;;;AAOT,IAAM,0BAA0B,EAC9B,UACA,gBACA,WACA,UACA,iBACA,YACA,QACA,eAeI;CACJ,MAAM,qBAAqB,IAAI,SAAS,MAAM;EAC5C,QAAQ,SAAS;EACjB;EACA,SAAS,SAAS;EACnB,CAAC;CAGF,MAAM,mBADe,gBAAgB,mBAAmB,IACf,oBAAoB,mBAAmB,QAAQ;AAExF,QAAO,CACL,MACA;EACE;EACA;EACA,UAAU;GACR,GAAG;GACH,SAAS;GACT;GACA,QAAQ,SAAS,KAAM,WAAW;GAClC;GACA;GACA,MAAM;GACP;EACD,kBAAkB,mBAAmB,OAAO;EAC7C,CACF;;;;;;AAOH,IAAM,wBAAwB,OAAO,EACnC,UACA,gBACA,WACA,UACA,iBACA,YACA,QACA,UACA,aACA,gBACA,cAoBG;CAMH,MAAM,cAAc,MADG,SAAS,OAAO,CACE,aAAa;CACtD,MAAM,eAAe,2BAA2B,YAAY;CAC5D,MAAM,cAAc,wBAAwB,YAAY,CAAC;CAEzD,MAAM,eAAe,MAAM,aAAa,aAAa,cAD/B,2BAA2B,aAAa,QAAQ,CACW;;;;;CAMjF,MAAM,qBAAqB,IAAI,SAAS,iBAAiB,OAAO,aAAa;EAC3E,QAAQ,SAAS;EACjB;EACA,SAAS,SAAS;EACnB,CAAC;CAGF,MAAM,mBADe,gBAAgB,mBAAmB,IACf,oBAAoB,mBAAmB,QAAQ;AAExF,QAAO,CACL,MACA;EACE;EACA;EACA,UAAU;GACR,GAAG;GACH,SAAS;GACT;GACA,MAAM;GACN,MAAM,YAAY;GAClB;GACA;GACA,QAAQ,SAAS;GACjB,MAAM;GACP;EACD,kBAAkB,SAAS,OAAO;EACnC,CACF"} | ||
| {"version":3,"file":"send-request.js","names":[],"sources":["../../../../../src/v2/blocks/operation-block/helpers/send-request.ts"],"sourcesContent":["import { ERRORS, type ErrorResponse, normalizeError } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { httpStatusCodes } from '@scalar/helpers/http/http-status-codes'\nimport { normalizeHeaders } from '@scalar/helpers/http/normalize-headers'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { RequestPayload } from '@scalar/workspace-store/request-example'\nimport * as cookie from 'cookie'\nimport { parseSetCookie } from 'set-cookie-parser'\n\nimport { getCookieHeaderKeys } from '@/v2/blocks/operation-block/helpers/get-cookie-header-keys'\nimport { resolveResponseBodyHandler } from '@/v2/blocks/response-block/helpers/resolve-response-body-handler'\nimport {\n resolveResponseContentType,\n resolveResponseMimeType,\n} from '@/v2/blocks/response-block/helpers/resolve-response-content-type'\n\nimport { decodeBuffer } from './decode-buffer'\n\nconst CUSTOM_COOKIE_HEADER = 'x-scalar-set-cookie'\n\n/** A single set of populated values for a sent request */\nexport type ResponseInstance = Omit<Response, 'headers'> & {\n /** Store headers as an object to match what we had with axios */\n headers: Record<string, string>\n /** Keys of headers which set cookies */\n cookieHeaderKeys: string[]\n /** Time in ms the request took */\n duration: number\n /** The response status */\n status: number\n /** The response status text */\n statusText: string\n /** The response method */\n method: HttpMethod\n /** The request path */\n path: string\n} & (\n | {\n /** The response data */\n data: string | Blob\n /** The response size in bytes */\n size: number\n }\n | {\n /** A stream reader for a streamable response body */\n reader: ReadableStreamDefaultReader<Uint8Array>\n }\n )\n\n/** HTTP status codes that should not include a response body */\nconst NO_BODY_STATUS_CODES = [204, 205, 304]\n\n/** Custom fetch function signature compatible with the global fetch API */\nexport type CustomFetch = typeof fetch\n\n/**\n * Execute the built fetch request and return a structured response.\n *\n * This function handles the complete request lifecycle including plugin hooks,\n * response processing, streaming detection, and error handling. It supports both\n * standard responses and server-sent event streams.\n *\n * @param request - The request built by the buildRequest helper\n * @param operation - The OpenAPI operation being executed\n * @param plugins - Array of client plugins to execute hooks\n * @param isUsingProxy - Whether the request is being proxied for header handling\n * @returns A tuple with either an error or the response data\n */\nexport const sendRequest = async ({\n isUsingProxy,\n requestPayload,\n plugins = [],\n customFetch = fetch,\n}: {\n isUsingProxy: boolean\n requestPayload: RequestPayload\n /** Registered client plugins for custom content type handling */\n plugins?: ClientPlugin[]\n /** Optional custom fetch implementation, overrides the global fetch */\n customFetch?: CustomFetch\n}): Promise<\n ErrorResponse<{\n response: ResponseInstance\n requestPayload: RequestPayload\n timestamp: number\n originalResponse: Response\n }>\n> => {\n try {\n // Execute the request and measure duration\n const startTime = performance.now()\n\n // In electron we allow GET requests to have a body\n const response = isElectron()\n ? await customFetch(...requestPayload)\n : await customFetch(buildSafeBodyRequest(...requestPayload))\n\n const endTime = performance.now()\n const timestamp = Date.now()\n const duration = endTime - startTime\n\n // Extract response metadata early for reuse\n const contentType = response.headers.get('content-type')\n const responseHeaders = normalizeHeaders(response.headers, isUsingProxy)\n const responseUrl = new URL(response.url)\n const fullPath = responseUrl.pathname + responseUrl.search\n const statusText = response.statusText || httpStatusCodes[response.status]?.name || ''\n const method = (requestPayload[1].method ?? 'GET') as HttpMethod\n const shouldSkipBody = NO_BODY_STATUS_CODES.includes(response.status)\n\n /**\n * Handle server-sent event streams separately.\n * These responses need a reader instead of buffered data.\n * We check this early to avoid unnecessary body reading.\n */\n if (contentType?.startsWith('text/event-stream') && response.body) {\n return buildStreamingResponse({\n response,\n requestPayload,\n timestamp,\n duration,\n responseHeaders,\n statusText,\n method,\n fullPath,\n })\n }\n\n return buildStandardResponse({\n response,\n requestPayload,\n timestamp,\n duration,\n responseHeaders,\n statusText,\n method,\n fullPath,\n contentType,\n shouldSkipBody,\n plugins,\n })\n } catch (error) {\n return [normalizeError(error, ERRORS.REQUEST_FAILED), null]\n }\n}\n\n/**\n * Extracts and serializes custom cookies from the response using the custom cookie header.\n *\n * This function parses the custom cookie header (if present), serializes each cookie using the\n * 'cookie' library, and then deletes the custom cookie header from the response.\n * Returns an array of serialized cookie strings, or null if no cookies were found.\n *\n * The @ts-expect-error is present due to a type mismatch between the 'cookie' parsing and serialization libraries.\n */\nconst getCustomCookie = (response: Response): string[] | null => {\n const result = parseSetCookie(response.headers.get(CUSTOM_COOKIE_HEADER) ?? '').map((c) =>\n cookie.serialize(c.name, c.value, {\n ...c,\n sameSite: c.sameSite as boolean | 'lax' | 'strict' | 'none' | undefined,\n encode: (str: string) => str,\n }),\n )\n\n if (result.length) {\n return result\n }\n\n return null\n}\n\n/**\n * Build a streaming response for server-sent events.\n * Streaming responses use a reader instead of buffering the entire body.\n */\nconst buildStreamingResponse = ({\n response,\n requestPayload,\n timestamp,\n duration,\n responseHeaders,\n statusText,\n method,\n fullPath,\n}: {\n response: Response\n requestPayload: RequestPayload\n timestamp: number\n duration: number\n responseHeaders: Record<string, string>\n statusText: string\n method: HttpMethod\n fullPath: string\n}): ErrorResponse<{\n response: ResponseInstance\n requestPayload: RequestPayload\n timestamp: number\n originalResponse: Response\n}> => {\n const normalizedResponse = new Response(null, {\n status: response.status,\n statusText,\n headers: response.headers,\n })\n\n const customCookie = getCustomCookie(normalizedResponse)\n const cookieHeaderKeys = customCookie ?? getCookieHeaderKeys(normalizedResponse.headers)\n\n return [\n null,\n {\n timestamp,\n requestPayload,\n response: {\n ...normalizedResponse,\n headers: responseHeaders,\n cookieHeaderKeys,\n reader: response.body!.getReader(),\n duration,\n method,\n path: fullPath,\n },\n originalResponse: normalizedResponse.clone(),\n },\n ]\n}\n\n/**\n * Build a standard response with buffered body data.\n * This handles all non-streaming responses including JSON, text, and binary data.\n */\nconst buildStandardResponse = async ({\n response,\n requestPayload,\n timestamp,\n duration,\n responseHeaders,\n statusText,\n method,\n fullPath,\n contentType,\n shouldSkipBody,\n plugins,\n}: {\n response: Response\n requestPayload: RequestPayload\n timestamp: number\n duration: number\n responseHeaders: Record<string, string>\n statusText: string\n method: HttpMethod\n fullPath: string\n contentType: string | null\n shouldSkipBody: boolean\n plugins: ClientPlugin[]\n}): Promise<\n ErrorResponse<{\n response: ResponseInstance\n requestPayload: RequestPayload\n timestamp: number\n originalResponse: Response\n }>\n> => {\n /**\n * Clone the response to preserve the original for body reading.\n * Read the body once and reuse the buffer for both decoding and creating a new Response.\n */\n const clonedResponse = response.clone()\n const arrayBuffer = await clonedResponse.arrayBuffer()\n const responseType = resolveResponseContentType(contentType)\n const mimeEssence = resolveResponseMimeType(contentType).essence\n const pluginHandler = resolveResponseBodyHandler(mimeEssence, plugins)\n const responseData = await decodeBuffer(arrayBuffer, responseType, pluginHandler)\n\n /**\n * Create a new Response using the arrayBuffer we already read.\n * ArrayBuffers can be reused to create new Response objects without additional memory.\n */\n const normalizedResponse = new Response(shouldSkipBody ? null : arrayBuffer, {\n status: response.status,\n statusText,\n headers: response.headers,\n })\n\n const customCookie = getCustomCookie(normalizedResponse)\n const cookieHeaderKeys = customCookie ?? getCookieHeaderKeys(normalizedResponse.headers)\n\n return [\n null,\n {\n timestamp,\n requestPayload,\n response: {\n ...normalizedResponse,\n headers: responseHeaders,\n cookieHeaderKeys,\n data: responseData,\n size: arrayBuffer.byteLength,\n duration,\n method,\n status: response.status,\n path: fullPath,\n },\n originalResponse: response.clone(),\n },\n ]\n}\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OperationBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"OperationBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"names":[],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OperationBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: HttpMethodType\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { executeHook, type ClientPlugin } from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.1/strict/operation'\nimport { computed, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { generateClientOptions } from '@/v2/blocks/operation-code-sample'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n method,\n operation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast('Path parameters must have values.', 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path,\n proxyUrl,\n server,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'beforeRequest',\n plugins,\n )\n\n const envVariables = {\n ...getEnvironmentVariables(environment),\n ...variablesStore.getVariables(),\n }\n\n // Build the fetch Request after hooks may have mutated the factory\n const requestResult = (() => {\n try {\n return {\n ok: true,\n result: buildRequest(requestBuilder, {\n envVariables,\n }),\n } as const\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return {\n ok: false,\n error: message,\n } as const\n }\n })()\n\n if (requestResult.ok === false) {\n toast(requestResult.error, 'error')\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = requestResult.result.controller\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: requestResult.result.isUsingProxy,\n requestPayload: requestResult.result.requestPayload,\n plugins,\n })\n\n if (sendResult) {\n // Execute the responseReceived hook\n await executeHook(\n {\n response: sendResult.originalResponse.clone(),\n requestBuilder,\n request: buildSafeBodyRequest(...sendResult.requestPayload),\n document,\n operation,\n variablesStore,\n },\n 'responseReceived',\n plugins,\n )\n }\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as HttpMethodType,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\n/**\n * When the path, method, or example key changes: save current response to\n * cache (so it can be restored when navigating back), then restore from cache\n * for the new operation or clear if no cached response. Response is only\n * cleared on page refresh or when making a new request for that operation.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n const newKey = getOperationExampleKey(newMethod, newPath, newExampleKey)\n const cached = responseCache.get(newKey)\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n response.value = null\n requestPayload.value = null\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentUrl\n :environment\n :environments\n :eventBus\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :layout\n :method\n :path\n :server\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @select:history:item=\"handleSelectHistoryItem\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <RequestBlock\n :authMeta\n :clientOptions\n :defaultHeaders\n :documentCookies\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :operation\n :options=\"toValue(options)\"\n :path\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :layout\n :plugins\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"OperationBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: HttpMethodType\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { executeHook, type ClientPlugin } from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.1/strict/operation'\nimport { computed, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { generateClientOptions } from '@/v2/blocks/operation-code-sample'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n method,\n operation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast('Path parameters must have values.', 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path,\n proxyUrl,\n server,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'beforeRequest',\n plugins,\n )\n\n const envVariables = {\n ...getEnvironmentVariables(environment),\n ...variablesStore.getVariables(),\n }\n\n // Build the fetch Request after hooks may have mutated the factory\n const requestResult = (() => {\n try {\n return {\n ok: true,\n result: buildRequest(requestBuilder, {\n envVariables,\n }),\n } as const\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return {\n ok: false,\n error: message,\n } as const\n }\n })()\n\n if (requestResult.ok === false) {\n toast(requestResult.error, 'error')\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = requestResult.result.controller\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: requestResult.result.isUsingProxy,\n requestPayload: requestResult.result.requestPayload,\n plugins,\n customFetch: toValue(options)?.customFetch,\n })\n\n if (sendResult) {\n // Execute the responseReceived hook\n await executeHook(\n {\n response: sendResult.originalResponse.clone(),\n requestBuilder,\n request: buildSafeBodyRequest(...sendResult.requestPayload),\n document,\n operation,\n variablesStore,\n },\n 'responseReceived',\n plugins,\n )\n }\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as HttpMethodType,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\n/**\n * When the path, method, or example key changes: save current response to\n * cache (so it can be restored when navigating back), then restore from cache\n * for the new operation or clear if no cached response. Response is only\n * cleared on page refresh or when making a new request for that operation.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n const newKey = getOperationExampleKey(newMethod, newPath, newExampleKey)\n const cached = responseCache.get(newKey)\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n response.value = null\n requestPayload.value = null\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentUrl\n :environment\n :environments\n :eventBus\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :layout\n :method\n :path\n :server\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @select:history:item=\"handleSelectHistoryItem\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <RequestBlock\n :authMeta\n :clientOptions\n :defaultHeaders\n :documentCookies\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :operation\n :options=\"toValue(options)\"\n :path\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :layout\n :plugins\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":""} |
@@ -129,3 +129,4 @@ import ViewLayout_default from "../../../components/ViewLayout/ViewLayout.vue.js"; | ||
| requestPayload: requestResult.result.requestPayload, | ||
| plugins: __props.plugins | ||
| plugins: __props.plugins, | ||
| customFetch: toValue(__props.options)?.customFetch | ||
| }); | ||
@@ -132,0 +133,0 @@ if (sendResult) await executeHook({ |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OperationBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: HttpMethodType\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { executeHook, type ClientPlugin } from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.1/strict/operation'\nimport { computed, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { generateClientOptions } from '@/v2/blocks/operation-code-sample'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n method,\n operation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast('Path parameters must have values.', 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path,\n proxyUrl,\n server,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'beforeRequest',\n plugins,\n )\n\n const envVariables = {\n ...getEnvironmentVariables(environment),\n ...variablesStore.getVariables(),\n }\n\n // Build the fetch Request after hooks may have mutated the factory\n const requestResult = (() => {\n try {\n return {\n ok: true,\n result: buildRequest(requestBuilder, {\n envVariables,\n }),\n } as const\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return {\n ok: false,\n error: message,\n } as const\n }\n })()\n\n if (requestResult.ok === false) {\n toast(requestResult.error, 'error')\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = requestResult.result.controller\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: requestResult.result.isUsingProxy,\n requestPayload: requestResult.result.requestPayload,\n plugins,\n })\n\n if (sendResult) {\n // Execute the responseReceived hook\n await executeHook(\n {\n response: sendResult.originalResponse.clone(),\n requestBuilder,\n request: buildSafeBodyRequest(...sendResult.requestPayload),\n document,\n operation,\n variablesStore,\n },\n 'responseReceived',\n plugins,\n )\n }\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as HttpMethodType,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\n/**\n * When the path, method, or example key changes: save current response to\n * cache (so it can be restored when navigating back), then restore from cache\n * for the new operation or clear if no cached response. Response is only\n * cleared on page refresh or when making a new request for that operation.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n const newKey = getOperationExampleKey(newMethod, newPath, newExampleKey)\n const cached = responseCache.get(newKey)\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n response.value = null\n requestPayload.value = null\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentUrl\n :environment\n :environments\n :eventBus\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :layout\n :method\n :path\n :server\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @select:history:item=\"handleSelectHistoryItem\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <RequestBlock\n :authMeta\n :clientOptions\n :defaultHeaders\n :documentCookies\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :operation\n :options=\"toValue(options)\"\n :path\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :layout\n :plugins\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":"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"} | ||
| {"version":3,"file":"OperationBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: HttpMethodType\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { executeHook, type ClientPlugin } from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.1/strict/operation'\nimport { computed, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { generateClientOptions } from '@/v2/blocks/operation-code-sample'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n method,\n operation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast('Path parameters must have values.', 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path,\n proxyUrl,\n server,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'beforeRequest',\n plugins,\n )\n\n const envVariables = {\n ...getEnvironmentVariables(environment),\n ...variablesStore.getVariables(),\n }\n\n // Build the fetch Request after hooks may have mutated the factory\n const requestResult = (() => {\n try {\n return {\n ok: true,\n result: buildRequest(requestBuilder, {\n envVariables,\n }),\n } as const\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return {\n ok: false,\n error: message,\n } as const\n }\n })()\n\n if (requestResult.ok === false) {\n toast(requestResult.error, 'error')\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = requestResult.result.controller\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: requestResult.result.isUsingProxy,\n requestPayload: requestResult.result.requestPayload,\n plugins,\n customFetch: toValue(options)?.customFetch,\n })\n\n if (sendResult) {\n // Execute the responseReceived hook\n await executeHook(\n {\n response: sendResult.originalResponse.clone(),\n requestBuilder,\n request: buildSafeBodyRequest(...sendResult.requestPayload),\n document,\n operation,\n variablesStore,\n },\n 'responseReceived',\n plugins,\n )\n }\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as HttpMethodType,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\n/**\n * When the path, method, or example key changes: save current response to\n * cache (so it can be restored when navigating back), then restore from cache\n * for the new operation or clear if no cached response. Response is only\n * cleared on page refresh or when making a new request for that operation.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n const newKey = getOperationExampleKey(newMethod, newPath, newExampleKey)\n const cached = responseCache.get(newKey)\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n response.value = null\n requestPayload.value = null\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentUrl\n :environment\n :environments\n :eventBus\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :layout\n :method\n :path\n :server\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @select:history:item=\"handleSelectHistoryItem\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <RequestBlock\n :authMeta\n :clientOptions\n :defaultHeaders\n :documentCookies\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :operation\n :options=\"toValue(options)\"\n :path\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :layout\n :plugins\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OperationCodeSample.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"names":[],"mappings":"AAqeA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAA;AAErF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEvE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACzF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AACxG,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAiBrE,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,yCAAyC,CAAA;AAMhD,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAA;IACpC;;OAEG;IACH,aAAa,EAAE,iBAAiB,EAAE,CAAA;IAClC;;;;OAIG;IACH,cAAc,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACzC;;OAEG;IACH,cAAc,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IACpC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAA;IAC3B;;OAEG;IACH,eAAe,EAAE,0BAA0B,EAAE,CAAA;IAC7C;;OAEG;IACH,MAAM,EAAE,cAAc,CAAA;IACtB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,SAAS,EAAE,eAAe,CAAA;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,MAAM,CAAA;IAC5B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;OAEG;IACH,aAAa,CAAC,EAAE,aAAa,EAAE,CAAA;IAC/B;;;OAGG;IACH,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzD,CAAA;AAED;;;;;;;;GAQG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IAgLlB,8DAA8D;sBAC1C,MAAM;;;;IAD1B,8DAA8D;sBAC1C,MAAM;;;;YA5JhB,MAAM,OAAO;YACb,CAAC,EAAE,WAAW,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO;EAghB3D,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"} | ||
| {"version":3,"file":"OperationCodeSample.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"names":[],"mappings":"AAifA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAA;AAErF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEvE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACzF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AACxG,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAiBrE,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,yCAAyC,CAAA;AAMhD,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAA;IACpC;;OAEG;IACH,aAAa,EAAE,iBAAiB,EAAE,CAAA;IAClC;;;;OAIG;IACH,cAAc,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACzC;;OAEG;IACH,cAAc,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IACpC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAA;IAC3B;;OAEG;IACH,eAAe,EAAE,0BAA0B,EAAE,CAAA;IAC7C;;OAEG;IACH,MAAM,EAAE,cAAc,CAAA;IACtB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,SAAS,EAAE,eAAe,CAAA;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,MAAM,CAAA;IAC5B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;OAEG;IACH,aAAa,CAAC,EAAE,aAAa,EAAE,CAAA;IAC/B;;;OAGG;IACH,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzD,CAAA;AAED;;;;;;;;GAQG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IA4LlB,8DAA8D;sBAC1C,MAAM;;;;IAD1B,8DAA8D;sBAC1C,MAAM;;;;YAxKhB,MAAM,OAAO;YACb,CAAC,EAAE,WAAW,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO;EA4hB3D,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"} |
@@ -5,3 +5,3 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_export-helper.js"; | ||
| //#region src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue | ||
| var OperationCodeSample_default = /* @__PURE__ */ _plugin_vue_export_helper_default(OperationCodeSample_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-0e4ddc16"]]); | ||
| var OperationCodeSample_default = /* @__PURE__ */ _plugin_vue_export_helper_default(OperationCodeSample_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-59da314d"]]); | ||
| //#endregion | ||
@@ -8,0 +8,0 @@ export { OperationCodeSample_default as default }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OperationCodeSample.vue.js","names":[],"sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type OperationCodeSampleProps = {\n /**\n * Integration type: determines if the code sample is displayed in a client environment\n * or in an API reference environment.\n */\n integration?: 'client' | 'reference'\n /**\n * List of all http clients formatted into option groups for the client selector\n */\n clientOptions: ClientOptionGroup[]\n /**\n * Pre-selected client, this will determine which client is initially selected in the dropdown\n *\n * @defaults to shell/curl or a custom sample if one is available\n */\n selectedClient?: AvailableClients[number]\n /**\n * Which server from the spec to use for the code example\n */\n selectedServer?: ServerObject | null\n /**\n * The selected content type from the requestBody.content, this will determine which examples are available\n * as well as the content type of the code example\n *\n * @defaults to the first content type if not provided\n */\n selectedContentType?: string\n /**\n * Example name to use for resolving example values for parameters AND requestBody\n *\n * @example \"limited\"\n * ```ts\n * parameters: {\n * name: 'foobar',\n * in: 'query',\n * examples: {\n * limited: {\n * dataValue: 10,\n * }\n * }\n * },\n * body: {\n * content: {\n * 'application/json': {\n * examples: {\n * limited: {\n * dataValue: { foo: 'bar' },\n * }\n * }\n * }\n * }\n * }\n *\n * ```\n */\n selectedExample?: string\n /**\n * Event bus\n */\n eventBus: WorkspaceEventBus\n /**\n * The security schemes which are applicable to this operation\n */\n securitySchemes: SecuritySchemeObjectSecret[]\n /**\n * HTTP method of the operation\n */\n method: HttpMethodType\n /**\n * Path of the operation\n */\n path: string\n /**\n * De-referenced OpenAPI Operation object\n */\n operation: OperationObject\n /**\n * If true and there's no example, we will display a small card with the method and path only\n */\n fallback?: boolean\n /**\n * A method to generate the label of the block, should return an html string\n */\n generateLabel?: () => string\n /**\n * If true, render this as a webhook request example\n */\n isWebhook?: boolean\n /**\n * Workspace + document cookies\n */\n globalCookies?: XScalarCookie[]\n /**\n * When the request body schema uses oneOf/anyOf, use these selected variants\n * for the example snippet (e.g. from the schema dropdowns in the API reference).\n */\n requestBodyCompositionSelection?: Record<string, number>\n}\n\n/**\n * Request Example\n *\n * The core component for rendering a request example block,\n * this component does not have much of its own state but operates on props and custom events\n *\n * @event workspace:update:selected-client - Emitted when the selected client changes\n * @event scalar-update-selected-example - removed for now, we can bring it back when we need it\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCard,\n ScalarCardFooter,\n ScalarCardHeader,\n ScalarCardSection,\n ScalarCodeBlock,\n ScalarCombobox,\n ScalarVirtualText,\n} from '@scalar/components'\nimport { freezeElement } from '@scalar/helpers/dom/freeze-element'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport { type AvailableClients } from '@scalar/snippetz'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { operationToHar } from '@v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport { filterClientsByQuery } from '@/v2/blocks/operation-code-sample/helpers/filter-clients-by-query'\nimport { findClient } from '@/v2/blocks/operation-code-sample/helpers/find-client'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '@/v2/blocks/operation-code-sample/types'\n\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport ExamplePicker from './ExamplePicker.vue'\n\nconst {\n integration,\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n requestBodyCompositionSelection,\n} = defineProps<OperationCodeSampleProps>()\n\ndefineSlots<{\n header: () => unknown\n footer: ({ exampleName }: { exampleName: string }) => unknown\n}>()\n\n/** Grab the examples for the given content type */\nconst requestBodyExamples = computed(() => {\n const content = getResolvedRef(operation.requestBody)?.content ?? {}\n const contentType = selectedContentType || Object.keys(content)[0]\n if (!contentType) return {}\n\n const examples = content[contentType]?.examples ?? {}\n\n return examples\n})\n\n/** The currently selected example key with v-model support */\nconst selectedExampleKey = defineModel<string>('selectedExample', {\n default: '',\n})\n\n// Set default value to the first example\nonBeforeMount(() => {\n selectedExampleKey.value ||= Object.keys(requestBodyExamples.value)[0] ?? ''\n})\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(customCodeSamples.value, clientOptions),\n)\n\n/** The locally selected client which would include code samples from this operation only */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/** If the globally selected client changes we can update the local one */\nwatch(\n () => selectedClient,\n (newClient) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n },\n)\n\n/** Generate HAR data for webhook requests */\nconst webhookHar = computed(() => {\n if (!isWebhook) return null\n\n try {\n return operationToHar({\n operation,\n method,\n path,\n example: selectedExampleKey.value,\n requestBodyCompositionSelection,\n defaultDisabledParameters: false,\n })\n } catch (error) {\n console.error('[webhookHar]', error)\n return null\n }\n})\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n defaultDisabledParameters: false,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExampleKey.value,\n globalCookies,\n requestBodyCompositionSelection,\n })\n})\n\n/** The language for the code block, used for syntax highlighting */\nconst codeBlockLanguage = computed(() => {\n if (isWebhook) {\n return webhookLanguage.value\n }\n\n return localSelectedClient.value?.lang\n})\n\n/** Determine the language for webhook content based on MIME type */\nconst webhookLanguage = computed<string>(() => {\n if (!webhookHar.value?.postData) return 'json'\n\n const contentType = webhookHar.value.postData.mimeType\n if (contentType?.includes('json')) return 'json'\n if (contentType?.includes('xml')) return 'xml'\n if (contentType?.includes('yaml') || contentType?.includes('yml'))\n return 'yaml'\n if (contentType?.includes('text/plain')) return 'text'\n\n return 'json'\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes))\n\n/** Grab the ref to freeze the ui as the clients change so there's no jump as the size of the dom changes */\nconst elem = ref<ComponentPublicInstance | null>(null)\n\n/** Set custom example, or update the selected HTTP client globally */\nconst selectClient = (option: ClientOption) => {\n // We need to freeze the ui to prevent scrolling as the clients change\n if (elem.value) {\n const unfreeze = freezeElement(elem.value.$el)\n setTimeout(() => {\n unfreeze()\n }, 300)\n }\n // Update to the local example\n localSelectedClient.value = option\n\n // Emit the change if it's not a custom example\n if (option && !option.id.startsWith('custom')) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n// Virtualize the code block if it's too large\n// This prevents the entire app from freezing up if there's a massive example\n// We set a lower threshold here as code examples can get quite large\nconst VIRTUALIZATION_THRESHOLD = 20_000\n\nconst shouldVirtualize = computed(\n () => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD,\n)\n\nconst id = useId()\n</script>\n<template>\n <ScalarCard\n v-if=\"generatedCode\"\n ref=\"elem\"\n class=\"request-card dark-mode\">\n <!-- Header -->\n <ScalarCardHeader class=\"pr-2.5\">\n <span class=\"sr-only\">Request Example for</span>\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <span\n v-if=\"generateLabel\"\n v-html=\"generateLabel()\" />\n <slot name=\"header\" />\n <!-- Client picker -->\n <template\n v-if=\"!isWebhook && clients.length\"\n #actions>\n <ScalarCombobox\n class=\"max-h-80\"\n :filterFn=\"filterClientsByQuery\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"ui-open:rotate-180 mt-px size-3 transition-transform duration-100\"\n weight=\"bold\" />\n </ScalarButton>\n </ScalarCombobox>\n </template>\n </ScalarCardHeader>\n\n <!-- Code snippet -->\n <ScalarCardSection class=\"request-editor-section custom-scroll p-0\">\n <div\n :id=\"`${id}-example`\"\n class=\"code-snippet\">\n <ScalarCodeBlock\n v-if=\"!shouldVirtualize\"\n class=\"bg-b-2 h-full\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n containerClass=\"custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen\"\n contentClass=\"language-plaintext whitespace-pre font-code text-base\"\n :lineHeight=\"20\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"Object.keys(requestBodyExamples).length > 1 || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"Object.keys(requestBodyExamples).length > 1\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n v-model=\"selectedExampleKey\"\n :examples=\"requestBodyExamples\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardFooter>\n </ScalarCard>\n\n <!-- Fallback card with just method and path in the case of no examples -->\n <ScalarCard\n v-else-if=\"fallback\"\n class=\"request-card dark-mode\">\n <ScalarCardSection class=\"request-card-simple\">\n <div class=\"request-header\">\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <slot name=\"header\" />\n </div>\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardSection>\n </ScalarCard>\n</template>\n<style scoped>\n.request-card {\n font-size: var(--scalar-font-size-3);\n}\n.request-method {\n font-family: var(--scalar-font-code);\n text-transform: uppercase;\n margin-right: 6px;\n}\n.request-card-footer {\n display: flex;\n justify-content: flex-end;\n padding: 6px;\n flex-shrink: 0;\n position: relative;\n}\n.request-card-footer-addon {\n display: flex;\n align-items: center;\n\n flex: 1;\n min-width: 0;\n}\n.request-editor-section {\n display: flex;\n flex: 1;\n}\n.request-card-simple {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 8px 8px 8px 12px;\n\n font-size: var(--scalar-small);\n}\n.code-snippet {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n</style>\n"],"mappings":""} | ||
| {"version":3,"file":"OperationCodeSample.vue.js","names":[],"sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type OperationCodeSampleProps = {\n /**\n * Integration type: determines if the code sample is displayed in a client environment\n * or in an API reference environment.\n */\n integration?: 'client' | 'reference'\n /**\n * List of all http clients formatted into option groups for the client selector\n */\n clientOptions: ClientOptionGroup[]\n /**\n * Pre-selected client, this will determine which client is initially selected in the dropdown\n *\n * @defaults to shell/curl or a custom sample if one is available\n */\n selectedClient?: AvailableClients[number]\n /**\n * Which server from the spec to use for the code example\n */\n selectedServer?: ServerObject | null\n /**\n * The selected content type from the requestBody.content, this will determine which examples are available\n * as well as the content type of the code example\n *\n * @defaults to the first content type if not provided\n */\n selectedContentType?: string\n /**\n * Example name to use for resolving example values for parameters AND requestBody\n *\n * @example \"limited\"\n * ```ts\n * parameters: {\n * name: 'foobar',\n * in: 'query',\n * examples: {\n * limited: {\n * dataValue: 10,\n * }\n * }\n * },\n * body: {\n * content: {\n * 'application/json': {\n * examples: {\n * limited: {\n * dataValue: { foo: 'bar' },\n * }\n * }\n * }\n * }\n * }\n *\n * ```\n */\n selectedExample?: string\n /**\n * Event bus\n */\n eventBus: WorkspaceEventBus\n /**\n * The security schemes which are applicable to this operation\n */\n securitySchemes: SecuritySchemeObjectSecret[]\n /**\n * HTTP method of the operation\n */\n method: HttpMethodType\n /**\n * Path of the operation\n */\n path: string\n /**\n * De-referenced OpenAPI Operation object\n */\n operation: OperationObject\n /**\n * If true and there's no example, we will display a small card with the method and path only\n */\n fallback?: boolean\n /**\n * A method to generate the label of the block, should return an html string\n */\n generateLabel?: () => string\n /**\n * If true, render this as a webhook request example\n */\n isWebhook?: boolean\n /**\n * Workspace + document cookies\n */\n globalCookies?: XScalarCookie[]\n /**\n * When the request body schema uses oneOf/anyOf, use these selected variants\n * for the example snippet (e.g. from the schema dropdowns in the API reference).\n */\n requestBodyCompositionSelection?: Record<string, number>\n}\n\n/**\n * Request Example\n *\n * The core component for rendering a request example block,\n * this component does not have much of its own state but operates on props and custom events\n *\n * @event workspace:update:selected-client - Emitted when the selected client changes\n * @event scalar-update-selected-example - removed for now, we can bring it back when we need it\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCard,\n ScalarCardFooter,\n ScalarCardHeader,\n ScalarCardSection,\n ScalarCodeBlock,\n ScalarCombobox,\n ScalarVirtualText,\n} from '@scalar/components'\nimport { freezeElement } from '@scalar/helpers/dom/freeze-element'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport { type AvailableClients } from '@scalar/snippetz'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { operationToHar } from '@v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport { filterClientsByQuery } from '@/v2/blocks/operation-code-sample/helpers/filter-clients-by-query'\nimport { findClient } from '@/v2/blocks/operation-code-sample/helpers/find-client'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '@/v2/blocks/operation-code-sample/types'\n\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport ExamplePicker from './ExamplePicker.vue'\n\nconst {\n integration,\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n requestBodyCompositionSelection,\n} = defineProps<OperationCodeSampleProps>()\n\ndefineSlots<{\n header: () => unknown\n footer: ({ exampleName }: { exampleName: string }) => unknown\n}>()\n\n/** Grab the examples for the given content type */\nconst requestBodyExamples = computed(() => {\n const content = getResolvedRef(operation.requestBody)?.content ?? {}\n const contentType = selectedContentType || Object.keys(content)[0]\n if (!contentType) return {}\n\n const examples = content[contentType]?.examples ?? {}\n\n return examples\n})\n\n/** The currently selected example key with v-model support */\nconst selectedExampleKey = defineModel<string>('selectedExample', {\n default: '',\n})\n\n// Set default value to the first example\nonBeforeMount(() => {\n selectedExampleKey.value ||= Object.keys(requestBodyExamples.value)[0] ?? ''\n})\n\n/** Reset the selected example key if the content type changes and the new content type doesn't have the previously selected example */\nwatch(\n () => selectedContentType,\n () => {\n if (\n !Object.keys(requestBodyExamples.value).includes(selectedExampleKey.value)\n ) {\n selectedExampleKey.value = Object.keys(requestBodyExamples.value)[0] ?? ''\n }\n },\n)\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(customCodeSamples.value, clientOptions),\n)\n\n/** The locally selected client which would include code samples from this operation only */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/** If the globally selected client changes we can update the local one */\nwatch(\n () => selectedClient,\n (newClient) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n },\n)\n\n/** Generate HAR data for webhook requests */\nconst webhookHar = computed(() => {\n if (!isWebhook) return null\n\n try {\n return operationToHar({\n operation,\n method,\n path,\n example: selectedExampleKey.value,\n requestBodyCompositionSelection,\n defaultDisabledParameters: false,\n })\n } catch (error) {\n console.error('[webhookHar]', error)\n return null\n }\n})\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n defaultDisabledParameters: false,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExampleKey.value,\n globalCookies,\n requestBodyCompositionSelection,\n })\n})\n\n/** The language for the code block, used for syntax highlighting */\nconst codeBlockLanguage = computed(() => {\n if (isWebhook) {\n return webhookLanguage.value\n }\n\n return localSelectedClient.value?.lang\n})\n\n/** Determine the language for webhook content based on MIME type */\nconst webhookLanguage = computed<string>(() => {\n if (!webhookHar.value?.postData) return 'json'\n\n const contentType = webhookHar.value.postData.mimeType\n if (contentType?.includes('json')) return 'json'\n if (contentType?.includes('xml')) return 'xml'\n if (contentType?.includes('yaml') || contentType?.includes('yml'))\n return 'yaml'\n if (contentType?.includes('text/plain')) return 'text'\n\n return 'json'\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes))\n\n/** Grab the ref to freeze the ui as the clients change so there's no jump as the size of the dom changes */\nconst elem = ref<ComponentPublicInstance | null>(null)\n\n/** Set custom example, or update the selected HTTP client globally */\nconst selectClient = (option: ClientOption) => {\n // We need to freeze the ui to prevent scrolling as the clients change\n if (elem.value) {\n const unfreeze = freezeElement(elem.value.$el)\n setTimeout(() => {\n unfreeze()\n }, 300)\n }\n // Update to the local example\n localSelectedClient.value = option\n\n // Emit the change if it's not a custom example\n if (option && !option.id.startsWith('custom')) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n// Virtualize the code block if it's too large\n// This prevents the entire app from freezing up if there's a massive example\n// We set a lower threshold here as code examples can get quite large\nconst VIRTUALIZATION_THRESHOLD = 20_000\n\nconst shouldVirtualize = computed(\n () => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD,\n)\n\nconst id = useId()\n</script>\n<template>\n <ScalarCard\n v-if=\"generatedCode\"\n ref=\"elem\"\n class=\"request-card dark-mode\">\n <!-- Header -->\n <ScalarCardHeader class=\"pr-2.5\">\n <span class=\"sr-only\">Request Example for</span>\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <span\n v-if=\"generateLabel\"\n v-html=\"generateLabel()\" />\n <slot name=\"header\" />\n <!-- Client picker -->\n <template\n v-if=\"!isWebhook && clients.length\"\n #actions>\n <ScalarCombobox\n class=\"max-h-80\"\n :filterFn=\"filterClientsByQuery\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"ui-open:rotate-180 mt-px size-3 transition-transform duration-100\"\n weight=\"bold\" />\n </ScalarButton>\n </ScalarCombobox>\n </template>\n </ScalarCardHeader>\n\n <!-- Code snippet -->\n <ScalarCardSection class=\"request-editor-section custom-scroll p-0\">\n <div\n :id=\"`${id}-example`\"\n class=\"code-snippet\">\n <ScalarCodeBlock\n v-if=\"!shouldVirtualize\"\n class=\"bg-b-2 h-full\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n containerClass=\"custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen\"\n contentClass=\"language-plaintext whitespace-pre font-code text-base\"\n :lineHeight=\"20\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"Object.keys(requestBodyExamples).length > 1 || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"Object.keys(requestBodyExamples).length > 1\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n v-model=\"selectedExampleKey\"\n :examples=\"requestBodyExamples\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardFooter>\n </ScalarCard>\n\n <!-- Fallback card with just method and path in the case of no examples -->\n <ScalarCard\n v-else-if=\"fallback\"\n class=\"request-card dark-mode\">\n <ScalarCardSection class=\"request-card-simple\">\n <div class=\"request-header\">\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <slot name=\"header\" />\n </div>\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardSection>\n </ScalarCard>\n</template>\n<style scoped>\n.request-card {\n font-size: var(--scalar-font-size-3);\n}\n.request-method {\n font-family: var(--scalar-font-code);\n text-transform: uppercase;\n margin-right: 6px;\n}\n.request-card-footer {\n display: flex;\n justify-content: flex-end;\n padding: 6px;\n flex-shrink: 0;\n position: relative;\n}\n.request-card-footer-addon {\n display: flex;\n align-items: center;\n\n flex: 1;\n min-width: 0;\n}\n.request-editor-section {\n display: flex;\n flex: 1;\n}\n.request-card-simple {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 8px 8px 8px 12px;\n\n font-size: var(--scalar-small);\n}\n.code-snippet {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n</style>\n"],"mappings":""} |
@@ -60,2 +60,6 @@ import ExamplePicker_default from "./ExamplePicker.vue.js"; | ||
| }); | ||
| /** Reset the selected example key if the content type changes and the new content type doesn't have the previously selected example */ | ||
| watch(() => __props.selectedContentType, () => { | ||
| if (!Object.keys(requestBodyExamples.value).includes(selectedExampleKey.value)) selectedExampleKey.value = Object.keys(requestBodyExamples.value)[0] ?? ""; | ||
| }); | ||
| /** Grab any custom code samples from the operation */ | ||
@@ -62,0 +66,0 @@ const customCodeSamples = computed(() => getCustomCodeSamples(__props.operation)); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OperationCodeSample.vue.script.js","names":["$slots"],"sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type OperationCodeSampleProps = {\n /**\n * Integration type: determines if the code sample is displayed in a client environment\n * or in an API reference environment.\n */\n integration?: 'client' | 'reference'\n /**\n * List of all http clients formatted into option groups for the client selector\n */\n clientOptions: ClientOptionGroup[]\n /**\n * Pre-selected client, this will determine which client is initially selected in the dropdown\n *\n * @defaults to shell/curl or a custom sample if one is available\n */\n selectedClient?: AvailableClients[number]\n /**\n * Which server from the spec to use for the code example\n */\n selectedServer?: ServerObject | null\n /**\n * The selected content type from the requestBody.content, this will determine which examples are available\n * as well as the content type of the code example\n *\n * @defaults to the first content type if not provided\n */\n selectedContentType?: string\n /**\n * Example name to use for resolving example values for parameters AND requestBody\n *\n * @example \"limited\"\n * ```ts\n * parameters: {\n * name: 'foobar',\n * in: 'query',\n * examples: {\n * limited: {\n * dataValue: 10,\n * }\n * }\n * },\n * body: {\n * content: {\n * 'application/json': {\n * examples: {\n * limited: {\n * dataValue: { foo: 'bar' },\n * }\n * }\n * }\n * }\n * }\n *\n * ```\n */\n selectedExample?: string\n /**\n * Event bus\n */\n eventBus: WorkspaceEventBus\n /**\n * The security schemes which are applicable to this operation\n */\n securitySchemes: SecuritySchemeObjectSecret[]\n /**\n * HTTP method of the operation\n */\n method: HttpMethodType\n /**\n * Path of the operation\n */\n path: string\n /**\n * De-referenced OpenAPI Operation object\n */\n operation: OperationObject\n /**\n * If true and there's no example, we will display a small card with the method and path only\n */\n fallback?: boolean\n /**\n * A method to generate the label of the block, should return an html string\n */\n generateLabel?: () => string\n /**\n * If true, render this as a webhook request example\n */\n isWebhook?: boolean\n /**\n * Workspace + document cookies\n */\n globalCookies?: XScalarCookie[]\n /**\n * When the request body schema uses oneOf/anyOf, use these selected variants\n * for the example snippet (e.g. from the schema dropdowns in the API reference).\n */\n requestBodyCompositionSelection?: Record<string, number>\n}\n\n/**\n * Request Example\n *\n * The core component for rendering a request example block,\n * this component does not have much of its own state but operates on props and custom events\n *\n * @event workspace:update:selected-client - Emitted when the selected client changes\n * @event scalar-update-selected-example - removed for now, we can bring it back when we need it\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCard,\n ScalarCardFooter,\n ScalarCardHeader,\n ScalarCardSection,\n ScalarCodeBlock,\n ScalarCombobox,\n ScalarVirtualText,\n} from '@scalar/components'\nimport { freezeElement } from '@scalar/helpers/dom/freeze-element'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport { type AvailableClients } from '@scalar/snippetz'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { operationToHar } from '@v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport { filterClientsByQuery } from '@/v2/blocks/operation-code-sample/helpers/filter-clients-by-query'\nimport { findClient } from '@/v2/blocks/operation-code-sample/helpers/find-client'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '@/v2/blocks/operation-code-sample/types'\n\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport ExamplePicker from './ExamplePicker.vue'\n\nconst {\n integration,\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n requestBodyCompositionSelection,\n} = defineProps<OperationCodeSampleProps>()\n\ndefineSlots<{\n header: () => unknown\n footer: ({ exampleName }: { exampleName: string }) => unknown\n}>()\n\n/** Grab the examples for the given content type */\nconst requestBodyExamples = computed(() => {\n const content = getResolvedRef(operation.requestBody)?.content ?? {}\n const contentType = selectedContentType || Object.keys(content)[0]\n if (!contentType) return {}\n\n const examples = content[contentType]?.examples ?? {}\n\n return examples\n})\n\n/** The currently selected example key with v-model support */\nconst selectedExampleKey = defineModel<string>('selectedExample', {\n default: '',\n})\n\n// Set default value to the first example\nonBeforeMount(() => {\n selectedExampleKey.value ||= Object.keys(requestBodyExamples.value)[0] ?? ''\n})\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(customCodeSamples.value, clientOptions),\n)\n\n/** The locally selected client which would include code samples from this operation only */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/** If the globally selected client changes we can update the local one */\nwatch(\n () => selectedClient,\n (newClient) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n },\n)\n\n/** Generate HAR data for webhook requests */\nconst webhookHar = computed(() => {\n if (!isWebhook) return null\n\n try {\n return operationToHar({\n operation,\n method,\n path,\n example: selectedExampleKey.value,\n requestBodyCompositionSelection,\n defaultDisabledParameters: false,\n })\n } catch (error) {\n console.error('[webhookHar]', error)\n return null\n }\n})\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n defaultDisabledParameters: false,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExampleKey.value,\n globalCookies,\n requestBodyCompositionSelection,\n })\n})\n\n/** The language for the code block, used for syntax highlighting */\nconst codeBlockLanguage = computed(() => {\n if (isWebhook) {\n return webhookLanguage.value\n }\n\n return localSelectedClient.value?.lang\n})\n\n/** Determine the language for webhook content based on MIME type */\nconst webhookLanguage = computed<string>(() => {\n if (!webhookHar.value?.postData) return 'json'\n\n const contentType = webhookHar.value.postData.mimeType\n if (contentType?.includes('json')) return 'json'\n if (contentType?.includes('xml')) return 'xml'\n if (contentType?.includes('yaml') || contentType?.includes('yml'))\n return 'yaml'\n if (contentType?.includes('text/plain')) return 'text'\n\n return 'json'\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes))\n\n/** Grab the ref to freeze the ui as the clients change so there's no jump as the size of the dom changes */\nconst elem = ref<ComponentPublicInstance | null>(null)\n\n/** Set custom example, or update the selected HTTP client globally */\nconst selectClient = (option: ClientOption) => {\n // We need to freeze the ui to prevent scrolling as the clients change\n if (elem.value) {\n const unfreeze = freezeElement(elem.value.$el)\n setTimeout(() => {\n unfreeze()\n }, 300)\n }\n // Update to the local example\n localSelectedClient.value = option\n\n // Emit the change if it's not a custom example\n if (option && !option.id.startsWith('custom')) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n// Virtualize the code block if it's too large\n// This prevents the entire app from freezing up if there's a massive example\n// We set a lower threshold here as code examples can get quite large\nconst VIRTUALIZATION_THRESHOLD = 20_000\n\nconst shouldVirtualize = computed(\n () => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD,\n)\n\nconst id = useId()\n</script>\n<template>\n <ScalarCard\n v-if=\"generatedCode\"\n ref=\"elem\"\n class=\"request-card dark-mode\">\n <!-- Header -->\n <ScalarCardHeader class=\"pr-2.5\">\n <span class=\"sr-only\">Request Example for</span>\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <span\n v-if=\"generateLabel\"\n v-html=\"generateLabel()\" />\n <slot name=\"header\" />\n <!-- Client picker -->\n <template\n v-if=\"!isWebhook && clients.length\"\n #actions>\n <ScalarCombobox\n class=\"max-h-80\"\n :filterFn=\"filterClientsByQuery\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"ui-open:rotate-180 mt-px size-3 transition-transform duration-100\"\n weight=\"bold\" />\n </ScalarButton>\n </ScalarCombobox>\n </template>\n </ScalarCardHeader>\n\n <!-- Code snippet -->\n <ScalarCardSection class=\"request-editor-section custom-scroll p-0\">\n <div\n :id=\"`${id}-example`\"\n class=\"code-snippet\">\n <ScalarCodeBlock\n v-if=\"!shouldVirtualize\"\n class=\"bg-b-2 h-full\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n containerClass=\"custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen\"\n contentClass=\"language-plaintext whitespace-pre font-code text-base\"\n :lineHeight=\"20\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"Object.keys(requestBodyExamples).length > 1 || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"Object.keys(requestBodyExamples).length > 1\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n v-model=\"selectedExampleKey\"\n :examples=\"requestBodyExamples\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardFooter>\n </ScalarCard>\n\n <!-- Fallback card with just method and path in the case of no examples -->\n <ScalarCard\n v-else-if=\"fallback\"\n class=\"request-card dark-mode\">\n <ScalarCardSection class=\"request-card-simple\">\n <div class=\"request-header\">\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <slot name=\"header\" />\n </div>\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardSection>\n </ScalarCard>\n</template>\n<style scoped>\n.request-card {\n font-size: var(--scalar-font-size-3);\n}\n.request-method {\n font-family: var(--scalar-font-code);\n text-transform: uppercase;\n margin-right: 6px;\n}\n.request-card-footer {\n display: flex;\n justify-content: flex-end;\n padding: 6px;\n flex-shrink: 0;\n position: relative;\n}\n.request-card-footer-addon {\n display: flex;\n align-items: center;\n\n flex: 1;\n min-width: 0;\n}\n.request-editor-section {\n display: flex;\n flex: 1;\n}\n.request-card-simple {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 8px 8px 8px 12px;\n\n font-size: var(--scalar-small);\n}\n.code-snippet {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n</style>\n"],"mappings":"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"} | ||
| {"version":3,"file":"OperationCodeSample.vue.script.js","names":["$slots"],"sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type OperationCodeSampleProps = {\n /**\n * Integration type: determines if the code sample is displayed in a client environment\n * or in an API reference environment.\n */\n integration?: 'client' | 'reference'\n /**\n * List of all http clients formatted into option groups for the client selector\n */\n clientOptions: ClientOptionGroup[]\n /**\n * Pre-selected client, this will determine which client is initially selected in the dropdown\n *\n * @defaults to shell/curl or a custom sample if one is available\n */\n selectedClient?: AvailableClients[number]\n /**\n * Which server from the spec to use for the code example\n */\n selectedServer?: ServerObject | null\n /**\n * The selected content type from the requestBody.content, this will determine which examples are available\n * as well as the content type of the code example\n *\n * @defaults to the first content type if not provided\n */\n selectedContentType?: string\n /**\n * Example name to use for resolving example values for parameters AND requestBody\n *\n * @example \"limited\"\n * ```ts\n * parameters: {\n * name: 'foobar',\n * in: 'query',\n * examples: {\n * limited: {\n * dataValue: 10,\n * }\n * }\n * },\n * body: {\n * content: {\n * 'application/json': {\n * examples: {\n * limited: {\n * dataValue: { foo: 'bar' },\n * }\n * }\n * }\n * }\n * }\n *\n * ```\n */\n selectedExample?: string\n /**\n * Event bus\n */\n eventBus: WorkspaceEventBus\n /**\n * The security schemes which are applicable to this operation\n */\n securitySchemes: SecuritySchemeObjectSecret[]\n /**\n * HTTP method of the operation\n */\n method: HttpMethodType\n /**\n * Path of the operation\n */\n path: string\n /**\n * De-referenced OpenAPI Operation object\n */\n operation: OperationObject\n /**\n * If true and there's no example, we will display a small card with the method and path only\n */\n fallback?: boolean\n /**\n * A method to generate the label of the block, should return an html string\n */\n generateLabel?: () => string\n /**\n * If true, render this as a webhook request example\n */\n isWebhook?: boolean\n /**\n * Workspace + document cookies\n */\n globalCookies?: XScalarCookie[]\n /**\n * When the request body schema uses oneOf/anyOf, use these selected variants\n * for the example snippet (e.g. from the schema dropdowns in the API reference).\n */\n requestBodyCompositionSelection?: Record<string, number>\n}\n\n/**\n * Request Example\n *\n * The core component for rendering a request example block,\n * this component does not have much of its own state but operates on props and custom events\n *\n * @event workspace:update:selected-client - Emitted when the selected client changes\n * @event scalar-update-selected-example - removed for now, we can bring it back when we need it\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCard,\n ScalarCardFooter,\n ScalarCardHeader,\n ScalarCardSection,\n ScalarCodeBlock,\n ScalarCombobox,\n ScalarVirtualText,\n} from '@scalar/components'\nimport { freezeElement } from '@scalar/helpers/dom/freeze-element'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport { type AvailableClients } from '@scalar/snippetz'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { operationToHar } from '@v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport { filterClientsByQuery } from '@/v2/blocks/operation-code-sample/helpers/filter-clients-by-query'\nimport { findClient } from '@/v2/blocks/operation-code-sample/helpers/find-client'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '@/v2/blocks/operation-code-sample/types'\n\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport ExamplePicker from './ExamplePicker.vue'\n\nconst {\n integration,\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n requestBodyCompositionSelection,\n} = defineProps<OperationCodeSampleProps>()\n\ndefineSlots<{\n header: () => unknown\n footer: ({ exampleName }: { exampleName: string }) => unknown\n}>()\n\n/** Grab the examples for the given content type */\nconst requestBodyExamples = computed(() => {\n const content = getResolvedRef(operation.requestBody)?.content ?? {}\n const contentType = selectedContentType || Object.keys(content)[0]\n if (!contentType) return {}\n\n const examples = content[contentType]?.examples ?? {}\n\n return examples\n})\n\n/** The currently selected example key with v-model support */\nconst selectedExampleKey = defineModel<string>('selectedExample', {\n default: '',\n})\n\n// Set default value to the first example\nonBeforeMount(() => {\n selectedExampleKey.value ||= Object.keys(requestBodyExamples.value)[0] ?? ''\n})\n\n/** Reset the selected example key if the content type changes and the new content type doesn't have the previously selected example */\nwatch(\n () => selectedContentType,\n () => {\n if (\n !Object.keys(requestBodyExamples.value).includes(selectedExampleKey.value)\n ) {\n selectedExampleKey.value = Object.keys(requestBodyExamples.value)[0] ?? ''\n }\n },\n)\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(customCodeSamples.value, clientOptions),\n)\n\n/** The locally selected client which would include code samples from this operation only */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/** If the globally selected client changes we can update the local one */\nwatch(\n () => selectedClient,\n (newClient) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n },\n)\n\n/** Generate HAR data for webhook requests */\nconst webhookHar = computed(() => {\n if (!isWebhook) return null\n\n try {\n return operationToHar({\n operation,\n method,\n path,\n example: selectedExampleKey.value,\n requestBodyCompositionSelection,\n defaultDisabledParameters: false,\n })\n } catch (error) {\n console.error('[webhookHar]', error)\n return null\n }\n})\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n defaultDisabledParameters: false,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExampleKey.value,\n globalCookies,\n requestBodyCompositionSelection,\n })\n})\n\n/** The language for the code block, used for syntax highlighting */\nconst codeBlockLanguage = computed(() => {\n if (isWebhook) {\n return webhookLanguage.value\n }\n\n return localSelectedClient.value?.lang\n})\n\n/** Determine the language for webhook content based on MIME type */\nconst webhookLanguage = computed<string>(() => {\n if (!webhookHar.value?.postData) return 'json'\n\n const contentType = webhookHar.value.postData.mimeType\n if (contentType?.includes('json')) return 'json'\n if (contentType?.includes('xml')) return 'xml'\n if (contentType?.includes('yaml') || contentType?.includes('yml'))\n return 'yaml'\n if (contentType?.includes('text/plain')) return 'text'\n\n return 'json'\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes))\n\n/** Grab the ref to freeze the ui as the clients change so there's no jump as the size of the dom changes */\nconst elem = ref<ComponentPublicInstance | null>(null)\n\n/** Set custom example, or update the selected HTTP client globally */\nconst selectClient = (option: ClientOption) => {\n // We need to freeze the ui to prevent scrolling as the clients change\n if (elem.value) {\n const unfreeze = freezeElement(elem.value.$el)\n setTimeout(() => {\n unfreeze()\n }, 300)\n }\n // Update to the local example\n localSelectedClient.value = option\n\n // Emit the change if it's not a custom example\n if (option && !option.id.startsWith('custom')) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n// Virtualize the code block if it's too large\n// This prevents the entire app from freezing up if there's a massive example\n// We set a lower threshold here as code examples can get quite large\nconst VIRTUALIZATION_THRESHOLD = 20_000\n\nconst shouldVirtualize = computed(\n () => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD,\n)\n\nconst id = useId()\n</script>\n<template>\n <ScalarCard\n v-if=\"generatedCode\"\n ref=\"elem\"\n class=\"request-card dark-mode\">\n <!-- Header -->\n <ScalarCardHeader class=\"pr-2.5\">\n <span class=\"sr-only\">Request Example for</span>\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <span\n v-if=\"generateLabel\"\n v-html=\"generateLabel()\" />\n <slot name=\"header\" />\n <!-- Client picker -->\n <template\n v-if=\"!isWebhook && clients.length\"\n #actions>\n <ScalarCombobox\n class=\"max-h-80\"\n :filterFn=\"filterClientsByQuery\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"ui-open:rotate-180 mt-px size-3 transition-transform duration-100\"\n weight=\"bold\" />\n </ScalarButton>\n </ScalarCombobox>\n </template>\n </ScalarCardHeader>\n\n <!-- Code snippet -->\n <ScalarCardSection class=\"request-editor-section custom-scroll p-0\">\n <div\n :id=\"`${id}-example`\"\n class=\"code-snippet\">\n <ScalarCodeBlock\n v-if=\"!shouldVirtualize\"\n class=\"bg-b-2 h-full\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n containerClass=\"custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen\"\n contentClass=\"language-plaintext whitespace-pre font-code text-base\"\n :lineHeight=\"20\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"Object.keys(requestBodyExamples).length > 1 || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"Object.keys(requestBodyExamples).length > 1\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n v-model=\"selectedExampleKey\"\n :examples=\"requestBodyExamples\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardFooter>\n </ScalarCard>\n\n <!-- Fallback card with just method and path in the case of no examples -->\n <ScalarCard\n v-else-if=\"fallback\"\n class=\"request-card dark-mode\">\n <ScalarCardSection class=\"request-card-simple\">\n <div class=\"request-header\">\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <slot name=\"header\" />\n </div>\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardSection>\n </ScalarCard>\n</template>\n<style scoped>\n.request-card {\n font-size: var(--scalar-font-size-3);\n}\n.request-method {\n font-family: var(--scalar-font-code);\n text-transform: uppercase;\n margin-right: 6px;\n}\n.request-card-footer {\n display: flex;\n justify-content: flex-end;\n padding: 6px;\n flex-shrink: 0;\n position: relative;\n}\n.request-card-footer-addon {\n display: flex;\n align-items: center;\n\n flex: 1;\n min-width: 0;\n}\n.request-editor-section {\n display: flex;\n flex: 1;\n}\n.request-card-simple {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 8px 8px 8px 12px;\n\n font-size: var(--scalar-small);\n}\n.code-snippet {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n</style>\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RequestBody.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"names":[],"mappings":"AAwSA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AAcrE,KAAK,WAAW,GAAG;IACjB,mBAAmB;IACnB,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzD,CAAC;AAigBF,QAAA,MAAM,YAAY;;;;;;;;;;;eAtf4B,MAAM;;;;;;;;;;;;;;;;;;eAAN,MAAM;;;;;;;kFAyflD,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} | ||
| {"version":3,"file":"RequestBody.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"names":[],"mappings":"AAySA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AAcrE,KAAK,WAAW,GAAG;IACjB,mBAAmB;IACnB,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzD,CAAC;AAmgBF,QAAA,MAAM,YAAY;;;;;;;;;;;eAxf4B,MAAM;;;;;;;;;;;;;;;;;;eAAN,MAAM;;;;;;;kFA2flD,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} |
@@ -5,3 +5,3 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_export-helper.js"; | ||
| //#region src/v2/blocks/request-block/components/RequestBody.vue | ||
| var RequestBody_default = /* @__PURE__ */ _plugin_vue_export_helper_default(RequestBody_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e861924b"]]); | ||
| var RequestBody_default = /* @__PURE__ */ _plugin_vue_export_helper_default(RequestBody_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-06778e40"]]); | ||
| //#endregion | ||
@@ -8,0 +8,0 @@ export { RequestBody_default as default }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RequestBody.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarListbox } from '@scalar/components'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n title,\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n}>()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/** Convert content types to options for the dropdown */\nconst contentTypeOptions = objectEntries(CONTENT_TYPES).map(([id, label]) => ({\n id,\n label,\n}))\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.find(\n (it) => it.id === selectedContentType.value,\n )\n return found ?? contentTypeOptions.at(-1)!\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const value = example.value.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema,\n )\n})\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{\n CONTENT_TYPES[\n selectedContentType as keyof typeof CONTENT_TYPES\n ] ?? selectedContentType\n }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>No Body</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n Delete\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <CodeInput\n class=\"border-t px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"\n contentTypeToLanguageMap[\n selectedContentType as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'\n \"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":""} | ||
| {"version":3,"file":"RequestBody.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarListbox } from '@scalar/components'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n title,\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n}>()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/** Convert content types to options for the dropdown */\nconst contentTypeOptions = objectEntries(CONTENT_TYPES).map(([id, label]) => ({\n id,\n label,\n}))\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.find(\n (it) => it.id === selectedContentType.value,\n )\n return found ?? contentTypeOptions.at(-1)!\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const value = example.value.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema,\n )\n})\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{\n CONTENT_TYPES[\n selectedContentType as keyof typeof CONTENT_TYPES\n ] ?? selectedContentType\n }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>No Body</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n Delete\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <CodeInput\n class=\"border-t px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"\n contentTypeToLanguageMap[\n selectedContentType as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'\n \"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":""} |
@@ -167,2 +167,3 @@ import { useFileDialog } from "../../../../hooks/use-file-dialog.js"; | ||
| modelValue: bodyValue.value, | ||
| withFakeData: "", | ||
| "onUpdate:modelValue": _cache[4] || (_cache[4] = (value) => emits("update:value", { | ||
@@ -169,0 +170,0 @@ payload: value, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RequestBody.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarListbox } from '@scalar/components'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n title,\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n}>()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/** Convert content types to options for the dropdown */\nconst contentTypeOptions = objectEntries(CONTENT_TYPES).map(([id, label]) => ({\n id,\n label,\n}))\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.find(\n (it) => it.id === selectedContentType.value,\n )\n return found ?? contentTypeOptions.at(-1)!\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const value = example.value.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema,\n )\n})\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{\n CONTENT_TYPES[\n selectedContentType as keyof typeof CONTENT_TYPES\n ] ?? selectedContentType\n }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>No Body</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n Delete\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <CodeInput\n class=\"border-t px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"\n contentTypeToLanguageMap[\n selectedContentType as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'\n \"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgDA,MAAM,QAAQ;EAqBd,MAAM,2BAA2B;GAC/B,oBAAoB;GACpB,mBAAmB;GACnB,oBAAoB;GACrB;;EAGD,MAAM,sBAAsB,eACpB,2BAA2B,QAAA,aAAa,QAAA,WAAW,IAAI,OAC/D;;EAGA,MAAM,qBAAqB,cAAc,cAAc,CAAC,KAAK,CAAC,IAAI,YAAY;GAC5E;GACA;GACD,EAAC;EAEF,MAAM,2BAA2B,SAAwC;GACvE,WAAW;AAIT,WAHc,mBAAmB,MAC9B,OAAO,GAAG,OAAO,oBAAoB,MACxC,IACgB,mBAAmB,GAAG,GAAG;;GAE3C,MAAM,MAAM;AACV,UAAM,sBAAsB,EAAE,OAAO,EAAE,IAAI,CAAA;;GAE9C,CAAA;EAED,SAAS,iBAAiB,UAAgC;GACxD,MAAM,EAAE,SAAS,cAAc;IAC7B,WAAW,UAAU;KACnB,MAAM,OAAO,QAAQ;AACrB,SAAI,KACF,UAAS,KAAI;;IAGjB,UAAU;IACV,QAAQ;IACT,CAAA;AACD,SAAK;;;EAIP,MAAM,UAAU,eAEZ,QAAA,eACA,mBACE,QAAA,aACA,oBAAoB,OACpB,QAAA,YACA,QAAA,gCACD,CACL;;EAGA,MAAM,YAAY,eAAe;AAC/B,OAAI,CAAC,QAAQ,MACX,QAAO;GAGT,MAAM,QAAQ,QAAQ,MAAM;AAC5B,OAAI,OAAO,UAAU,SACnB,QAAO;AAGT,UAAO,KAAK,UAAU,OAAO,MAAM,EAAC;IACrC;;EAGD,MAAM,aAAa,eAAyC;AAC1D,UAAO,QAAQ,OACb,QAAA,aAAa,UAAU,oBAAoB,QAAQ,OACrD;IACD;;uBAGC,YAkIqB,MAAA,2BAAA,EAAA,MAAA;IAjIR,OAAK,cAAY,CAAA,gBAAA,gBAAR,QAAA,MAAK,EAAA,EAAA,CAAA,CAAA;2BAgIb,CA/HZ,YA+HY,MAAA,kBAAA,EAAA;KA9HT,SAAS,CAAA,GAAI;KACd,gBAAA;;4BAqBkB,CApBlB,YAoBkB,MAAA,wBAAA,EAAA,EAnBhB,OAAM,+FAA6F,EAAA;6BAkBnF,CAjBhB,YAiBgB,MAAA,cAAA,EAAA;mBAhBL,yBAAA;6FAAwB,QAAA;OAChC,SAAS,MAAA,mBAAkB;OAC5B,UAAA;;8BAae,CAZf,YAYe,MAAA,aAAA,EAAA;QAXb,OAAM;QACN,WAAA;QACA,SAAQ;;+BAKC,CAJT,mBAIS,QAAA,MAAA,gBAHP,MAAA,cAAa,CAAkB,oBAAA,UAAqE,oBAAA,MAAmB,EAAA,EAAA,EAIzH,YAEc,MAAA,WAAA,EAAA;SADZ,MAAK;SACL,MAAK;;;;;;;SAIb,YAsGe,MAAA,qBAAA,EAAA,MAAA;6BA/FF,CALK,oBAAA,UAAmB,UAAA,WAAA,EACjC,mBAGM,OAHN,YAGM,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CADJ,mBAAoB,QAAA,MAAd,WAAO,GAAA,CAAA,EAAA,CAAA,IAMJ,oBAAA,UAAmB,8BAAA,WAAA,EAC9B,mBA6CM,OA7CN,YA6CM,CA1CqB,MAAA,YAAW,CAAC,MAAA,kBAAiB,CAAC,QAAA,OAAS,MAAK,CAAA,KAAO,KAAA,KAAA,WAAA,EAD5E,mBAoBW,UAAA,EAAA,KAAA,GAAA,EAAA,CAhBT,mBAGO,QAHP,YAGO,gBADF,MAAA,YAAW,CAAC,MAAA,kBAAiB,CAAC,QAAA,OAAS,MAAK,CAAA,CAAA,EAAA,EAAA,EAEjD,YAWe,MAAA,aAAA,EAAA;OAVb,OAAM;OACN,MAAK;OACL,SAAQ;OACP,SAAK,OAAA,OAAA,OAAA,MAAA,WAAqB,MAAK,gBAAA;iBAAgD,KAAA;qBAA4C,oBAAA;;;8BAO9H,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAFI,YAEJ,GAAA,CAAA,EAAA,CAAA;;gCAGA,YAmBe,MAAA,aAAA,EAAA;;OAlBb,OAAM;OACN,MAAK;OACL,SAAQ;OACP,SAAK,OAAA,OAAA,OAAA,WAA+C,kBAAkB,SAA+B,MAAK,gBAAA;iBAAoD;qBAA2C,oBAAA;;;8BASlL,CAAA,OAAA,OAAA,OAAA,KAAxB,mBAAwB,QAAA,MAAlB,eAAW,GAAA,GACjB,YAIoB,MAAA,WAAA,EAAA;QAHlB,OAAM;QACN,MAAK;QACL,MAAK;QACL,WAAU;;;eAQM,oBAAA,UAAmB,yBAA0C,oBAAA,UAAmB,uCAAA,WAAA,EAIxG,YAWM,yBAAA;;OAVH,YAAA,WAAA;OACA,aAAA,QAAA;OACA,SAAA,QAAA;OACA,qBAAA,oBAAA;OACA,sBAAgB,OAAA,OAAA,OAAA,MAAkB,YAA4B,MAAK,oBAAA;QAAyC;qBAAwC,oBAAA;;;;;;;0BAWvJ,YAkBM,MAAA,kBAAA,EAAA;;OAjBJ,OAAM;OACN,SAAQ;OACP,aAAa,QAAA;OACb,UAAyB,yBAA0C,oBAAA,UAAA;OAKpE,aAAA;OACA,MAAA;OACC,YAAY,UAAA;OACZ,uBAAiB,OAAA,OAAA,OAAA,MAAkB,UAA0B,MAAK,gBAAA;iBAA8C;qBAAsC,oBAAA"} | ||
| {"version":3,"file":"RequestBody.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarListbox } from '@scalar/components'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n title,\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n}>()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/** Convert content types to options for the dropdown */\nconst contentTypeOptions = objectEntries(CONTENT_TYPES).map(([id, label]) => ({\n id,\n label,\n}))\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.find(\n (it) => it.id === selectedContentType.value,\n )\n return found ?? contentTypeOptions.at(-1)!\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const value = example.value.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema,\n )\n})\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{\n CONTENT_TYPES[\n selectedContentType as keyof typeof CONTENT_TYPES\n ] ?? selectedContentType\n }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>No Body</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n Delete\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <CodeInput\n class=\"border-t px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"\n contentTypeToLanguageMap[\n selectedContentType as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'\n \"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RequestTableRow.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"names":[],"mappings":"AAmTA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAGxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAcrE,MAAM,MAAM,QAAQ,GAAG;IACrB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3B,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAA;IAC/C,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,wEAAwE;IACxE,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,eAAe,CAAA;CACpC,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAA;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,kBAAkB,CAAA;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAC;AAkmBF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;cArlBG,MAAM;eAAS,MAAM,GAAG,IAAI;oBAAc,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAjD,MAAM;eAAS,MAAM,GAAG,IAAI;oBAAc,OAAO;;;;;kFAwlBpE,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} | ||
| {"version":3,"file":"RequestTableRow.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"names":[],"mappings":"AAoTA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAGxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAcrE,MAAM,MAAM,QAAQ,GAAG;IACrB,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3B,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,WAAW,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAA;IAC/C,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,wEAAwE;IACxE,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,eAAe,CAAA;CACpC,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAA;IACd,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,kBAAkB,CAAA;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAC;AAomBF,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;cAvlBG,MAAM;eAAS,MAAM,GAAG,IAAI;oBAAc,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAjD,MAAM;eAAS,MAAM,GAAG,IAAI;oBAAc,OAAO;;;;;kFA0lBpE,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RequestTableRow.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarIconButton } from '@scalar/components'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n}\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsertRow',\n payload: { name: string; value: string | File; isDisabled: boolean },\n ): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n}>()\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => (name.value = newName ?? ''),\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst minimumValue = computed(() =>\n data.schema && 'minimum' in data.schema ? data.schema.minimum : undefined,\n)\nconst maximumValue = computed(() =>\n data.schema && 'maximum' in data.schema ? data.schema.maximum : undefined,\n)\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n }\n\n // Is disabled should always be false unless you explicitly set it to true\n isDisabled.value = payload.isDisabled ?? false\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n })\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Key`\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :environment=\"environment\"\n lineWrapping\n :modelValue=\"name\"\n placeholder=\"Key\"\n :required=\"Boolean(data.isRequired)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @selectVariable=\"(v: string) => handleUpdateRow({ name: v })\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Value`\"\n class=\"pr-6 group-hover:pr-10 group-has-[.cm-focused]:pr-10\"\n :default=\"defaultValue\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n lineWrapping\n :max=\"maximumValue\"\n :min=\"minimumValue\"\n :modelValue=\"displayValue\"\n placeholder=\"Value\"\n :type=\"typeValue\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n label=\"Global cookies are shared across the whole workspace. Click to navigate.\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n description=\"This is a readonly property and you can not modify it! If you want to change it you have to override it or disable it using the checkbox\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInput>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 filemask flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span>{{ displayValue }}</span>\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n Delete\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"RequestTableRow.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarIconButton } from '@scalar/components'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n}\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsertRow',\n payload: { name: string; value: string | File; isDisabled: boolean },\n ): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n}>()\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => (name.value = newName ?? ''),\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst minimumValue = computed(() =>\n data.schema && 'minimum' in data.schema ? data.schema.minimum : undefined,\n)\nconst maximumValue = computed(() =>\n data.schema && 'maximum' in data.schema ? data.schema.maximum : undefined,\n)\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n }\n\n // Is disabled should always be false unless you explicitly set it to true\n isDisabled.value = payload.isDisabled ?? false\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n })\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Key`\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :environment=\"environment\"\n lineWrapping\n :modelValue=\"name\"\n placeholder=\"Key\"\n :required=\"Boolean(data.isRequired)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @selectVariable=\"(v: string) => handleUpdateRow({ name: v })\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Value`\"\n class=\"pr-6 group-hover:pr-10 group-has-[.cm-focused]:pr-10\"\n :default=\"defaultValue\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n lineWrapping\n :max=\"maximumValue\"\n :min=\"minimumValue\"\n :modelValue=\"displayValue\"\n placeholder=\"Value\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n label=\"Global cookies are shared across the whole workspace. Click to navigate.\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n description=\"This is a readonly property and you can not modify it! If you want to change it you have to override it or disable it using the checkbox\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInput>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 filemask flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span>{{ displayValue }}</span>\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n Delete\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":""} |
@@ -140,2 +140,3 @@ import { getFileName } from "../helpers/files.js"; | ||
| type: typeValue.value, | ||
| withFakeData: "", | ||
| onNavigate: _cache[6] || (_cache[6] = (route) => emit("navigate", route)), | ||
@@ -142,0 +143,0 @@ "onUpdate:modelValue": _cache[7] || (_cache[7] = (v) => handleUpdateRow({ value: v })) |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarIconButton } from '@scalar/components'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n}\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsertRow',\n payload: { name: string; value: string | File; isDisabled: boolean },\n ): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n}>()\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => (name.value = newName ?? ''),\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst minimumValue = computed(() =>\n data.schema && 'minimum' in data.schema ? data.schema.minimum : undefined,\n)\nconst maximumValue = computed(() =>\n data.schema && 'maximum' in data.schema ? data.schema.maximum : undefined,\n)\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n }\n\n // Is disabled should always be false unless you explicitly set it to true\n isDisabled.value = payload.isDisabled ?? false\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n })\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Key`\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :environment=\"environment\"\n lineWrapping\n :modelValue=\"name\"\n placeholder=\"Key\"\n :required=\"Boolean(data.isRequired)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @selectVariable=\"(v: string) => handleUpdateRow({ name: v })\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Value`\"\n class=\"pr-6 group-hover:pr-10 group-has-[.cm-focused]:pr-10\"\n :default=\"defaultValue\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n lineWrapping\n :max=\"maximumValue\"\n :min=\"minimumValue\"\n :modelValue=\"displayValue\"\n placeholder=\"Value\"\n :type=\"typeValue\"\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n label=\"Global cookies are shared across the whole workspace. Click to navigate.\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n description=\"This is a readonly property and you can not modify it! If you want to change it you have to override it or disable it using the checkbox\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInput>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 filemask flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span>{{ displayValue }}</span>\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n Delete\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiEA,MAAM,OAAO;;;;;;;;;EAmBb,MAAM,OAAO,IAAY,QAAA,KAAK,QAAQ,GAAE;EACxC,MAAM,QAAQ,IAAmB,kBAAkB,QAAA,KAAK,MAAM,IAAI,GAAE;EACpE,MAAM,aAAa,IAAa,QAAA,KAAK,cAAc,MAAK;AAGxD,cACQ,QAAA,KAAK,OACV,YAAa,KAAK,QAAQ,WAAW,GACxC;AACA,cACQ,QAAA,KAAK,QACV,aAAc,MAAM,QAAQ,kBAAkB,SAAS,IAAI,GAC9D;AACA,cACQ,QAAA,KAAK,aACV,kBAAmB,WAAW,QAAQ,iBAAiB,MAC1D;;EAGA,MAAM,SAAS,eAAe,MAAM,iBAAiB,KAAI;;EAGzD,MAAM,eAAe,gBAEhB,OAAO,QACJ,YAAY,MAAM,MAAa,GAC9B,MAAM,UAAqB,GACpC;EAEA,MAAM,eAAe,eAAe,QAAA,KAAK,QAAQ,QAAiB;;EAGlE,MAAM,YAAY,eAAyB;AACzC,OAAI,CAAC,QAAA,KAAK,OACR,QAAO,EAAC;AAIV,OAAI,QAAA,KAAK,OAAO,KACd,QAAO,QAAA,KAAK,OAAO,KAAK,KAAK,SAAS,OAAO,KAAK,CAAA;AAIpD,OAAI,WAAW,QAAA,KAAK,QAAQ;IAC1B,MAAM,WAAW,QAAQ,OAAO,QAAA,KAAK,OAAO,MAAK;AACjD,QAAI,UAAU,KACZ,QAAO,SAAS,KAAK,KAAK,SAAS,OAAO,KAAK,CAAA;;AAInD,UAAO,EAAC;IACT;EAED,MAAM,eAAe,eACnB,QAAA,KAAK,UAAU,aAAa,QAAA,KAAK,SAAS,QAAA,KAAK,OAAO,UAAU,KAAA,EAClE;EACA,MAAM,eAAe,eACnB,QAAA,KAAK,UAAU,aAAa,QAAA,KAAK,SAAS,QAAA,KAAK,OAAO,UAAU,KAAA,EAClE;EACA,MAAM,YAAY,eAChB,QAAA,KAAK,UAAU,UAAU,QAAA,KAAK,SAAS,QAAA,KAAK,OAAO,OAAO,KAAA,EAC5D;EAEA,MAAM,mBAAmB,eACvB,kBAAkB,QAAA,KAAK,QAAQ,MAAM,MAAM,CAC7C;;EAGA,MAAM,mBACJ,YACS;AAET,OAAI,QAAQ,SAAS,KAAA,EACnB,MAAK,QAAQ,QAAQ;AAEvB,OAAI,QAAQ,UAAU,KAAA,EACpB,OAAM,QAAQ,QAAQ;AAIxB,cAAW,QAAQ,QAAQ,cAAc;AAGzC,QAAK,aAAa;IAChB,MAAM,KAAK;IACX,OAAO,MAAM;IACb,YAAY,WAAW;IACxB,CAAA;;;uBAKD,YA4He,MAAA,qBAAA,EAAA;IA3HZ,IAAI,QAAA,KAAK;IACT,OAAK,eAAA;YAAiB,iBAAA,MAAiB,OAAE;YAAyB,iBAAA,MAAiB,OAAE,SAAc,QAAA,eAAe,IAAI,QAAA,KAAK,KAAI;;;2BAQ5D;KAJpE,YAIoE,MAAA,0BAAA,EAAA;MAHlE,OAAM;MACL,UAAU,QAAA,uBAAmB;MAC7B,YAAU,CAAG,WAAA;MACb,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAM,gBAAe,EAAA,YAAA,CAAgB,GAAC,CAAA;;KAG7D,YAegB,MAAA,sBAAA,EAAA,MAAA;6BAD+C,CAb7D,YAa6D,MAAA,kBAAA,EAAA;OAZ1D,cAAU,GAAK,QAAA,MAAK;OACrB,sBAAA;OACC,UAAU,QAAA,KAAK;OAChB,cAAA;OACA,kBAAA;OACC,aAAa,QAAA;OACd,cAAA;OACC,YAAY,KAAA;OACb,aAAY;OACX,UAAU,QAAQ,QAAA,KAAK,WAAU;OACjC,YAAQ,OAAA,OAAA,OAAA,MAAG,UAAU,KAAI,YAAa,MAAK;OAC3C,kBAAc,OAAA,OAAA,OAAA,MAAG,MAAc,gBAAe,EAAA,MAAS,GAAC,CAAA;OACxD,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAM,gBAAe,EAAA,MAAS,GAAC,CAAA;;;;;;;;;;KAIxD,YA0DgB,MAAA,sBAAA,EAAA,MAAA;6BADF,CAxDZ,YAwDY,MAAA,kBAAA,EAAA;OAvDT,cAAU,GAAK,QAAA,MAAK;OACrB,OAAM;OACL,SAAS,aAAA;OACV,sBAAA;OACC,UAAU,QAAA,KAAK;OAChB,cAAA;OACA,kBAAA;OACC,MAAM,UAAA;OACN,aAAa,QAAA;OACb,UAAqB,QAAA,KAAK,QAAQ,UAAU,KAAK,YAAY,OAAO,QAAO,CAAA,IAAA,EAAA;OAG3E,aAAa,QAAA,KAAK;OACnB,cAAA;OACC,KAAK,aAAA;OACL,KAAK,aAAA;OACL,YAAY,aAAA;OACb,aAAY;OACX,MAAM,UAAA;OACN,YAAQ,OAAA,OAAA,OAAA,MAAG,UAAU,KAAI,YAAa,MAAK;OAC3C,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAM,gBAAe,EAAA,OAAU,GAAC,CAAA;;OAC1C,MAAI,cAYE;QAVQ,QAAQ,QAAA,KAAK,QAAQ,MAAA,MAAK,IAAA,CAAoB,QAAA,KAAK,cAA4B,QAAA,KAAK,eAAU,QAAA,WAAA,EADrH,YAWe,MAAA,aAAA,EAAA;;SALb,OAAM;SACN,MAAK;SACL,SAAQ;SACP,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,YAAA;;gCACwB,CAApC,YAAoC,MAAA,gBAAA,EAAA,EAAnB,OAAM,YAAU,CAAA,CAAA,CAAA;;;QAI3B,QAAA,KAAK,gBAAgB,KAAA,KAAA,WAAA,EAD7B,YAQgD,MAAA,iBAAA,EAAA;;SAN9C,OAAM;SACL,MAAM,MAAA,gBAAe;SACtB,OAAM;SACN,MAAK;SACL,SAAQ;SACR,SAAQ;SACP,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,YAAa,QAAA,KAAK,YAAW;;QAGnC,QAAA,KAAK,cAAA,WAAA,EADb,YAGkB,6BAAA;;SADhB,aAAY;SACX,OAAO;cAEG,QAAA,KAAK,UAAA,WAAA,EADlB,YAIW,6BAAA;;SAFR,aAAa,QAAA,KAAK;SAClB,QAAQ,QAAA,KAAK;SACb,OAAA,MAAA;;;;;;;;;;;;;;;;;;;;;;;KAOD,QAAA,oBAAA,WAAA,EADR,YA+BgB,MAAA,sBAAA,EAAA;;MA7Bd,OAAM;;6BAYK,CAXK,OAAA,SAAA,WAAA,EAAhB,mBAWW,UAAA,EAAA,KAAA,GAAA,EAAA,CAVT,mBAGM,OAHN,YAGM,CADJ,mBAA+B,QAAA,MAAA,gBAAtB,aAAA,MAAY,EAAA,EAAA,CAAA,CAAA,EAEvB,mBAKS,UAAA;OAJP,OAAM;OACN,MAAK;OACJ,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,aAAA;SAAgB,WAE9B,CAAA,EAAA,GAAA,KAAA,WAAA,EAGA,mBAaM,OAbN,YAaM,CAZJ,YAWe,MAAA,aAAA,EAAA;OAVb,OAAM;OACN,MAAK;OACL,SAAQ;OACP,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,aAAA;;8BACY,CAAA,OAAA,QAAA,OAAA,MAAxB,mBAAwB,QAAA,MAAlB,eAAW,GAAA,GACjB,YAIoB,MAAA,WAAA,EAAA;QAHlB,OAAM;QACN,MAAK;QACL,MAAK;QACL,WAAU"} | ||
| {"version":3,"file":"RequestTableRow.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestTableRow.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarIcon, ScalarIconButton } from '@scalar/components'\nimport { ScalarIconGlobe, ScalarIconTrash } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n ParameterObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { validateParameter } from '@/v2/blocks/request-block/helpers/validate-parameter'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTableCell,\n DataTableCheckbox,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nimport RequestTableTooltip from './RequestTableTooltip.vue'\n\nexport type TableRow = {\n /** The parameter or field name/key */\n name: string\n /** The parameter value, can be a string, file, or null */\n value: string | File | null\n /** Optional description for the parameter */\n description?: string\n /** Optional route for global parameters (e.g., cookies shared across workspace) */\n globalRoute?: ApiReferenceEvents['ui:navigate']\n /** Whether the parameter is disabled/inactive */\n isDisabled?: boolean\n /** OpenAPI schema object with type, validation rules, examples, etc. */\n schema?: SchemaObject\n /** Whether the parameter is required */\n isRequired?: boolean\n /**\n * Whether the parameter is readonly and can not be modifies directly\n * User can still override the parameter which is going to show up with the linethrough style\n */\n isReadonly?: boolean\n /** Whether the parameter is overridden later on */\n isOverridden?: boolean\n /** Track the original parameter so we can update it */\n originalParameter?: ParameterObject\n}\n\nconst {\n data,\n environment,\n hasCheckboxDisabled,\n invalidParams,\n showUploadButton,\n} = defineProps<{\n data: TableRow\n hasCheckboxDisabled?: boolean\n invalidParams?: Set<string>\n label?: string\n environment: XScalarEnvironment\n showUploadButton?: boolean\n}>()\n\nconst emit = defineEmits<{\n (\n e: 'upsertRow',\n payload: { name: string; value: string | File; isDisabled: boolean },\n ): void\n (e: 'deleteRow'): void\n (e: 'uploadFile'): void\n (e: 'removeFile'): void\n (e: 'navigate', route: NonNullable<TableRow['globalRoute']>): void\n}>()\n\n/**\n * Track local state for the row\n *\n * Now this is required because of the way we get default values from the schema.\n * If we have a default value in data.value, then we update isDisabled to true. We lose the default value since now\n * we have an example where value: ''. This is why we need to track the local state and update all of the params at the\n * same time.\n */\nconst name = ref<string>(data.name ?? '')\nconst value = ref<string | File>(unpackProxyObject(data.value) ?? '')\nconst isDisabled = ref<boolean>(data.isDisabled ?? false)\n\n// Keep the above state synced with the data prop\nwatch(\n () => data.name,\n (newName) => (name.value = newName ?? ''),\n)\nwatch(\n () => data.value,\n (newValue) => (value.value = unpackProxyObject(newValue) ?? ''),\n)\nwatch(\n () => data.isDisabled,\n (newIsDisabled) => (isDisabled.value = newIsDisabled ?? false),\n)\n\n/** Check if the value is a File instance */\nconst isFile = computed(() => value.value instanceof File)\n\n/** Display value handles File instances and shows filename instead */\nconst displayValue = computed(\n () =>\n (isFile.value\n ? getFileName(value.value as File)\n : (value.value as string)) ?? '',\n)\n\nconst defaultValue = computed(() => data.schema?.default as string)\n\n/** See if we can extract enum values from the schema */\nconst enumValue = computed<string[]>(() => {\n if (!data.schema) {\n return []\n }\n\n // Grab the enum from the schema\n if (data.schema.enum) {\n return data.schema.enum.map((item) => String(item))\n }\n\n // Grab the enum from the items schema\n if ('items' in data.schema) {\n const resolved = resolve.schema(data.schema.items)\n if (resolved?.enum) {\n return resolved.enum.map((item) => String(item))\n }\n }\n\n return []\n})\n\nconst minimumValue = computed(() =>\n data.schema && 'minimum' in data.schema ? data.schema.minimum : undefined,\n)\nconst maximumValue = computed(() =>\n data.schema && 'maximum' in data.schema ? data.schema.maximum : undefined,\n)\nconst typeValue = computed(() =>\n data.schema && 'type' in data.schema ? data.schema.type : undefined,\n)\n\nconst validationResult = computed(() =>\n validateParameter(data.schema, value.value),\n)\n\n/** Handle row updates while preserving existing properties */\nconst handleUpdateRow = (\n payload: Partial<{ name: string; value: string; isDisabled: boolean }>,\n): void => {\n // Update our local state\n if (payload.name !== undefined) {\n name.value = payload.name\n }\n if (payload.value !== undefined) {\n value.value = payload.value\n }\n\n // Is disabled should always be false unless you explicitly set it to true\n isDisabled.value = payload.isDisabled ?? false\n\n // Emit all of the local state\n emit('upsertRow', {\n name: name.value,\n value: value.value,\n isDisabled: isDisabled.value,\n })\n}\n</script>\n\n<template>\n <DataTableRow\n :id=\"data.name\"\n :class=\"{\n alert: validationResult.ok === false,\n error: validationResult.ok === false && invalidParams?.has(data.name),\n }\">\n <DataTableCheckbox\n class=\"!border-r\"\n :disabled=\"hasCheckboxDisabled ?? false\"\n :modelValue=\"!isDisabled\"\n @update:modelValue=\"(v) => handleUpdateRow({ isDisabled: !v })\" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Key`\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :environment=\"environment\"\n lineWrapping\n :modelValue=\"name\"\n placeholder=\"Key\"\n :required=\"Boolean(data.isRequired)\"\n @navigate=\"(route) => emit('navigate', route)\"\n @selectVariable=\"(v: string) => handleUpdateRow({ name: v })\"\n @update:modelValue=\"(v) => handleUpdateRow({ name: v })\" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n :aria-label=\"`${label} Value`\"\n class=\"pr-6 group-hover:pr-10 group-has-[.cm-focused]:pr-10\"\n :default=\"defaultValue\"\n disableCloseBrackets\n :disabled=\"data.isReadonly\"\n disableEnter\n disableTabIndent\n :enum=\"enumValue\"\n :environment=\"environment\"\n :examples=\"\n data.schema?.examples?.map((example) => String(example)) ?? []\n \"\n :linethrough=\"data.isOverridden\"\n lineWrapping\n :max=\"maximumValue\"\n :min=\"minimumValue\"\n :modelValue=\"displayValue\"\n placeholder=\"Value\"\n :type=\"typeValue\"\n withFakeData\n @navigate=\"(route) => emit('navigate', route)\"\n @update:modelValue=\"(v) => handleUpdateRow({ value: v })\">\n <template #icon>\n <ScalarButton\n v-if=\"\n Boolean(data.name || value) &&\n !data.isRequired &&\n data.isReadonly !== true\n \"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 hidden h-fit rounded p-1 group-hover:flex group-has-[.cm-focused]:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"emit('deleteRow')\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n\n <ScalarIconButton\n v-if=\"data.globalRoute !== undefined\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 z-context -mr-0.5 h-fit\"\n :icon=\"ScalarIconGlobe\"\n label=\"Global cookies are shared across the whole workspace. Click to navigate.\"\n size=\"xs\"\n tooltip=\"top\"\n variant=\"ghost\"\n @click=\"emit('navigate', data.globalRoute)\" />\n\n <RequestTableTooltip\n v-if=\"data.isReadonly\"\n description=\"This is a readonly property and you can not modify it! If you want to change it you have to override it or disable it using the checkbox\"\n :value=\"null\" />\n <RequestTableTooltip\n v-else-if=\"data.schema\"\n :description=\"data.description\"\n :schema=\"data.schema\"\n :value />\n </template>\n </CodeInput>\n </DataTableCell>\n\n <!-- File upload -->\n <DataTableCell\n v-if=\"showUploadButton\"\n class=\"group/upload flex items-center justify-center whitespace-nowrap\">\n <template v-if=\"isFile\">\n <div\n class=\"text-c-2 filemask flex w-full max-w-[100%] items-center justify-center overflow-hidden p-1\">\n <span>{{ displayValue }}</span>\n </div>\n <button\n class=\"bg-b-2 mt-1 block rounded p-0.5 text-center text-xs font-medium md:pointer-events-none md:absolute md:inset-x-1 md:top-1/2 md:mt-0 md:-translate-y-1/2 md:opacity-0 md:group-hover/upload:pointer-events-auto md:group-hover/upload:opacity-100\"\n type=\"button\"\n @click=\"emit('removeFile')\">\n Delete\n </button>\n </template>\n <template v-else>\n <div class=\"p-0.5\">\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 h-fit border-0 py-px shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"emit('uploadFile')\">\n <span>Select File</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </div>\n </template>\n </DataTableCell>\n </DataTableRow>\n</template>\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RequestBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/request-block/RequestBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components'\nimport { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n filterGlobalCookie,\n getEnvironmentVariables,\n getExample,\n getResolvedUrl,\n type MergedSecuritySchemes,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId, watch } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ClientOptionGroup } from '@/v2/blocks/operation-code-sample'\nimport RequestBody from '@/v2/blocks/request-block/components/RequestBody.vue'\nimport RequestCodeSnippet from '@/v2/blocks/request-block/components/RequestCodeSnippet.vue'\nimport RequestParams from '@/v2/blocks/request-block/components/RequestParams.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { createParameterHandlers } from '@/v2/blocks/request-block/helpers/create-parameter-handlers'\nimport { getParameterSchema } from '@/v2/blocks/request-block/helpers/get-parameter-schema'\nimport { groupBy } from '@/v2/blocks/request-block/helpers/group-by'\nimport { isParamDisabled } from '@/v2/blocks/request-block/helpers/is-param-disabled'\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\ntype Filter =\n | 'All'\n | 'Auth'\n | 'Variables'\n | 'Cookies'\n | 'Headers'\n | 'Query'\n | 'Body'\n\nexport type RequestBlockProps = {\n authMeta: AuthMeta\n clientOptions: ClientOptionGroup[]\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n exampleKey: string\n workspaceCookies: XScalarCookie[]\n documentCookies: XScalarCookie[]\n layout: ClientLayout\n method: HttpMethod\n operation: OperationObject\n path: string\n plugins: ClientPlugin[]\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n requestBodyCompositionSelection?: Record<string, number>\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n selectedSecurity: SelectedSecurity\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n server: ServerObject | null\n defaultHeaders: Record<string, string>\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}\n\nconst {\n authMeta = { type: 'document' },\n clientOptions,\n environment,\n eventBus,\n exampleKey,\n workspaceCookies,\n documentCookies,\n layout,\n method,\n operation,\n path,\n plugins,\n proxyUrl,\n requestBodyCompositionSelection,\n securityRequirements,\n securitySchemes,\n selectedClient,\n selectedSecurity,\n selectedSecuritySchemes,\n server,\n defaultHeaders: autoGeneratedHeaders,\n} = defineProps<RequestBlockProps>()\n\n/** Operation metadata used across event emissions */\nconst meta = computed(() => ({\n method,\n path,\n exampleKey,\n}))\n\n/** Parameters grouped by type (path, query, header, cookie) */\nconst sections = computed(() =>\n groupBy(\n operation.parameters?.map((param) => getResolvedRef(param)) ?? [],\n 'in',\n (param) => {\n const example = getExample(param, exampleKey, undefined)\n\n return {\n name: param.name,\n value: example?.value ?? '',\n description: param.description,\n schema: getParameterSchema(param),\n isRequired: param.required,\n isDisabled: isParamDisabled(param, example),\n originalParameter: param,\n } as TableRow\n },\n ),\n)\n\n// Generate a reverse map for fast lookup of headers by the name\nconst headersMap = computed(() =>\n groupBy(\n sections.value.header?.map((it) => ({\n ...it,\n name: it.name.toLowerCase(),\n })) ?? [],\n 'name',\n ),\n)\n\nconst defaultHeaders = computed(() => {\n const disableParameters =\n operation['x-scalar-disable-parameters']?.['default-headers']?.[\n exampleKey\n ] ?? {}\n\n const isOverridden = (name: string) => {\n const header = headersMap.value[name.toLowerCase()]?.[0]\n\n if (!header) {\n return false\n }\n\n return !header.isDisabled\n }\n\n return Object.entries(autoGeneratedHeaders).map(([name, value]) => {\n return {\n name,\n value,\n schema: undefined,\n isOverridden: isOverridden(name),\n isReadonly: true,\n isDisabled: disableParameters[name.toLowerCase()] ?? false,\n } satisfies TableRow\n })\n})\n\nconst headers = computed(() => [\n ...defaultHeaders.value,\n ...(sections.value.header ?? []),\n])\n\nconst defaultCookies = computed(() => {\n const environmentVariables = getEnvironmentVariables(environment)\n const resolvedUrl = getResolvedUrl({\n server,\n path,\n })\n const url = replaceEnvVariables(resolvedUrl, environmentVariables)\n\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[\n exampleKey\n ] ?? {}\n\n const transform = (\n cookie: XScalarCookie,\n location: 'document' | 'workspace',\n ) => {\n return {\n name: cookie.name,\n value: cookie.value,\n globalRoute: { page: location, path: 'cookies' } as const,\n isReadonly: true,\n isDisabled: disabledGlobalCookies[cookie.name.toLowerCase()] ?? false,\n } satisfies TableRow\n }\n\n const globalCookies = [\n {\n location: 'workspace',\n cookies: workspaceCookies,\n },\n {\n location: 'document',\n cookies: documentCookies,\n },\n ] as const\n\n return globalCookies.flatMap(({ location, cookies }) => {\n return cookies\n .filter((cookie) =>\n filterGlobalCookie({\n cookie,\n url,\n disabledGlobalCookies: {},\n }),\n )\n .map((cookie) => transform(cookie, location))\n })\n})\n\nconst cookies = computed(() => [\n ...(defaultCookies.value ?? []),\n ...(sections.value.cookie ?? []),\n])\n\n/** Currently selected filter for the request sections */\nconst selectedFilter = ref<Filter>('All')\n\n/** Available operation sections */\nconst OPERATION_SECTIONS: readonly Filter[] = [\n 'Auth',\n 'Variables',\n 'Cookies',\n 'Headers',\n 'Query',\n 'Body',\n] as const\n\n/**\n * Pre-generated stable IDs for all possible filter sections.\n * These are created once at setup time to avoid regenerating IDs on re-render.\n */\nconst sectionIds: Record<Filter, string> = {\n All: useId(),\n Auth: useId(),\n Variables: useId(),\n Cookies: useId(),\n Headers: useId(),\n Query: useId(),\n Body: useId(),\n}\n\n/** Filters available based on operation state */\nconst filters = computed<Filter[]>(() => {\n const availableFilters = new Set<Filter>(['All', ...OPERATION_SECTIONS])\n\n if (!sections.value.path?.length) {\n availableFilters.delete('Variables')\n }\n if (!canMethodHaveBody(method)) {\n availableFilters.delete('Body')\n }\n if (isAuthHidden.value) {\n availableFilters.delete('Auth')\n }\n\n return [...availableFilters]\n})\n\n/**\n * Map available filters to their pre-generated stable IDs.\n * Only includes IDs for filters that are currently available.\n */\nconst filterIds = computed(\n () =>\n Object.fromEntries(\n filters.value.map((section) => [section, sectionIds[section]]),\n ) as Record<Filter, string>,\n)\n\n/**\n * Hide auth selector in readonly mode when no security schemes are defined.\n * This keeps the UI clean when there are no authentication options available.\n */\nconst isAuthHidden = computed(\n () => layout === 'modal' && !Object.keys(securitySchemes ?? {}).length,\n)\n\n/**\n * Keep auth available for unauthenticated operations, but collapse it by default\n * in readonly modal layouts unless a requirement or manual selection exists.\n */\nconst isAuthDefaultOpen = computed(\n () =>\n layout !== 'modal' ||\n Boolean(\n securityRequirements?.length || selectedSecurity.selectedSchemes.length,\n ),\n)\n\n/** Get a sensible placeholder for the request name input */\nconst requestNamePlaceholder = computed(() => {\n if (operation.summary) {\n return operation.summary\n }\n const cleanPath = path.replace(REGEX.PROTOCOL, '')\n return cleanPath || 'Request Name'\n})\n\n/** Check if the section should be shown based on the selected filter */\nconst isSectionVisible = (section: Filter): boolean => {\n return selectedFilter.value === 'All' || selectedFilter.value === section\n}\n\n/**\n * Reset filter to 'All' if Body filter is selected but method changes to one that cannot have a body.\n * This prevents showing an empty Body section when switching methods.\n */\nwatch(\n () => method,\n (newMethod) => {\n if (selectedFilter.value === 'Body' && !canMethodHaveBody(newMethod)) {\n selectedFilter.value = 'All'\n }\n },\n)\n\n/** Handle operation summary updates */\nconst handleSummaryUpdate = (event: Event): void => {\n const summary = (event.target as HTMLInputElement).value\n eventBus.emit('operation:update:meta', {\n meta: meta.value,\n payload: { summary: summary.trim() },\n })\n}\n\n/** Parameter handlers */\nconst parameterHandlers = computed(() => ({\n path: createParameterHandlers('path', eventBus, meta.value, {\n context: sections.value.path ?? [],\n }),\n cookie: createParameterHandlers('cookie', eventBus, meta.value, {\n context: cookies.value ?? [],\n globalParameters: defaultCookies.value.length,\n }),\n header: createParameterHandlers('header', eventBus, meta.value, {\n context: headers.value,\n defaultParameters: defaultHeaders.value.length,\n }),\n query: createParameterHandlers('query', eventBus, meta.value, {\n context: sections.value.query ?? [],\n }),\n}))\n\n/** Handle request body content type update */\nconst handleUpdateContentType = (payload: { value: string }): void =>\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType: payload.value },\n meta: meta.value,\n })\n\n/** Handle request body value update */\nconst handleUpdateBodyValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey =\n typeof payload === 'string'\n ? `update:requestBody:value-${contentType}`\n : undefined\n\n eventBus.emit(\n 'operation:update:requestBody:value',\n {\n payload,\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/** Handle request body value update */\nconst handleUpdateBodyFormValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey = `update:requestBody:${contentType}-form-value`\n\n eventBus.emit(\n 'operation:update:requestBody:formValue',\n {\n payload: payload.map((row) => unpackProxyObject(row, { depth: 1 })),\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\nconst labelRequestNameId = useId()\n\nconst globalCookies = computed(() => [...workspaceCookies, ...documentCookies])\n\n/** Allow updating the operation extensions for the plugins */\nconst updateOperationExtension = (\n payload: ApiReferenceEvents['operation:update:extension']['payload'],\n): void =>\n eventBus.emit('operation:update:extension', { payload, meta: meta.value })\n</script>\n<template>\n <ViewLayoutSection :aria-label=\"`Request: ${operation.summary}`\">\n <template #title>\n <div\n class=\"group pointer-events-none flex flex-1 items-center gap-1 lg:pr-24\">\n <label\n v-if=\"layout !== 'modal'\"\n class=\"pointer-events-auto absolute top-0 left-0 h-full w-full cursor-text opacity-0\"\n :for=\"labelRequestNameId\" />\n <input\n v-if=\"layout !== 'modal'\"\n :id=\"labelRequestNameId\"\n class=\"text-c-1 group-hover-input pointer-events-auto relative z-10 -ml-0.5 h-8 w-full rounded pl-1.25 has-[:focus-visible]:outline md:-ml-1.25\"\n :placeholder=\"requestNamePlaceholder\"\n :value=\"operation.summary\"\n @blur=\"handleSummaryUpdate\" />\n <span\n v-else\n class=\"text-c-1 flex h-8 items-center\">\n {{ operation.summary }}\n </span>\n </div>\n <SectionFilter\n v-model=\"selectedFilter\"\n :filterIds=\"filterIds\"\n :filters=\"filters\" />\n </template>\n\n <div\n :id=\"filterIds.All\"\n class=\"request-section-content custom-scroll relative flex flex-1 flex-col\"\n :role=\"selectedFilter === 'All' ? 'tabpanel' : 'none'\">\n <!-- Auth Selector -->\n <AuthSelector\n v-show=\"isSectionVisible('Auth') && !isAuthHidden\"\n :id=\"filterIds.Auth\"\n :createAnySecurityScheme=\"layout !== 'modal'\"\n :defaultOpen=\"isAuthDefaultOpen\"\n :environment\n :eventBus\n :meta=\"authMeta\"\n :options\n :proxyUrl\n :securityRequirements\n :securitySchemes\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n title=\"Authentication\" />\n\n <!-- Variables (Path Parameters) -->\n <RequestParams\n v-show=\"isSectionVisible('Variables') && sections.path?.length\"\n :id=\"filterIds.Variables\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.path ?? []\"\n :showAddRowPlaceholder=\"false\"\n title=\"Variables\"\n v-on=\"parameterHandlers.path\" />\n\n <!-- Cookies -->\n <RequestParams\n v-show=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"cookies ?? []\"\n :showAddRowPlaceholder=\"true\"\n title=\"Cookies\"\n v-on=\"parameterHandlers.cookie\" />\n\n <!-- Headers -->\n <RequestParams\n v-show=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"headers ?? []\"\n title=\"Headers\"\n v-on=\"parameterHandlers.header\" />\n\n <!-- Query Parameters -->\n <RequestParams\n v-show=\"isSectionVisible('Query')\"\n :id=\"filterIds.Query\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.query ?? []\"\n title=\"Query Parameters\"\n v-on=\"parameterHandlers.query\" />\n\n <!-- Request Body -->\n <RequestBody\n v-show=\"isSectionVisible('Body') && canMethodHaveBody(method)\"\n :id=\"filterIds.Body\"\n :environment\n :exampleKey\n :requestBody=\"getResolvedRef(operation.requestBody)\"\n :requestBodyCompositionSelection\n title=\"Request Body\"\n @update:contentType=\"handleUpdateContentType\"\n @update:formValue=\"handleUpdateBodyFormValue\"\n @update:value=\"handleUpdateBodyValue\" />\n\n <!-- Inject request section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.request.component\"\n v-if=\"plugin?.components?.request\"\n v-show=\"selectedFilter === 'All'\"\n :operation\n v-bind=\"plugin.components.request.additionalProps\"\n @operation:update:extension=\"updateOperationExtension\" />\n </ScalarErrorBoundary>\n\n <!-- Spacer -->\n <div class=\"flex grow\" />\n <!-- Code Snippet -->\n <RequestCodeSnippet\n v-show=\"selectedFilter === 'All'\"\n :clientOptions\n :eventBus\n :globalCookies\n integration=\"client\"\n :method\n :operation\n :path\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"\n getResolvedRef(operation.requestBody)?.[\n 'x-scalar-selected-content-type'\n ]?.[exampleKey]\n \"\n :selectedServer=\"server ?? undefined\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.request-section-content {\n --scalar-border-width: 0.5px;\n}\n.request-section-content-filter {\n box-shadow: 0 -10px 0 10px var(--scalar-background-1);\n}\n.request-item:focus-within .request-meta-buttons {\n opacity: 1;\n}\n.group-hover-input {\n border-width: var(--scalar-border-width);\n border-color: transparent;\n}\n.group:hover .group-hover-input {\n background: color-mix(\n in srgb,\n var(--scalar-background-1),\n var(--scalar-background-2)\n );\n border-color: var(--scalar-border-color);\n}\n.group-hover-input:focus {\n background: transparent !important;\n border-color: var(--scalar-border-color) !important;\n}\n</style>\n"],"mappings":"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"} | ||
| {"version":3,"file":"RequestBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/request-block/RequestBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components'\nimport { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n filterGlobalCookie,\n getEnvironmentVariables,\n getExample,\n getResolvedUrl,\n type MergedSecuritySchemes,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId, watch } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ClientOptionGroup } from '@/v2/blocks/operation-code-sample'\nimport RequestBody from '@/v2/blocks/request-block/components/RequestBody.vue'\nimport RequestCodeSnippet from '@/v2/blocks/request-block/components/RequestCodeSnippet.vue'\nimport RequestParams from '@/v2/blocks/request-block/components/RequestParams.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { createParameterHandlers } from '@/v2/blocks/request-block/helpers/create-parameter-handlers'\nimport { getParameterSchema } from '@/v2/blocks/request-block/helpers/get-parameter-schema'\nimport { groupBy } from '@/v2/blocks/request-block/helpers/group-by'\nimport { isParamDisabled } from '@/v2/blocks/request-block/helpers/is-param-disabled'\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\ntype Filter =\n | 'All'\n | 'Auth'\n | 'Variables'\n | 'Cookies'\n | 'Headers'\n | 'Query'\n | 'Body'\n\nexport type RequestBlockProps = {\n authMeta: AuthMeta\n clientOptions: ClientOptionGroup[]\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n exampleKey: string\n workspaceCookies: XScalarCookie[]\n documentCookies: XScalarCookie[]\n layout: ClientLayout\n method: HttpMethod\n operation: OperationObject\n path: string\n plugins: ClientPlugin[]\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n requestBodyCompositionSelection?: Record<string, number>\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n selectedSecurity: SelectedSecurity\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n server: ServerObject | null\n defaultHeaders: Record<string, string>\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}\n\nconst {\n authMeta = { type: 'document' },\n clientOptions,\n environment,\n eventBus,\n exampleKey,\n workspaceCookies,\n documentCookies,\n layout,\n method,\n operation,\n path,\n plugins,\n proxyUrl,\n requestBodyCompositionSelection,\n securityRequirements,\n securitySchemes,\n selectedClient,\n selectedSecurity,\n selectedSecuritySchemes,\n server,\n defaultHeaders: autoGeneratedHeaders,\n} = defineProps<RequestBlockProps>()\n\n/** Operation metadata used across event emissions */\nconst meta = computed(() => ({\n method,\n path,\n exampleKey,\n}))\n\n/** Parameters grouped by type (path, query, header, cookie) */\nconst sections = computed(() =>\n groupBy(\n operation.parameters?.map((param) => getResolvedRef(param)) ?? [],\n 'in',\n (param) => {\n const example = getExample(param, exampleKey, undefined)\n\n return {\n name: param.name,\n value: example?.value ?? '',\n description: param.description,\n schema: getParameterSchema(param),\n isRequired: param.required,\n isDisabled: isParamDisabled(param, example),\n originalParameter: param,\n } as TableRow\n },\n ),\n)\n\n// Generate a reverse map for fast lookup of headers by the name\nconst headersMap = computed(() =>\n groupBy(\n sections.value.header?.map((it) => ({\n ...it,\n name: it.name.toLowerCase(),\n })) ?? [],\n 'name',\n ),\n)\n\nconst defaultHeaders = computed(() => {\n const disableParameters =\n operation['x-scalar-disable-parameters']?.['default-headers']?.[\n exampleKey\n ] ?? {}\n\n const isOverridden = (name: string) => {\n const header = headersMap.value[name.toLowerCase()]?.[0]\n\n if (!header) {\n return false\n }\n\n return !header.isDisabled\n }\n\n return Object.entries(autoGeneratedHeaders).map(([name, value]) => {\n return {\n name,\n value,\n schema: undefined,\n isOverridden: isOverridden(name),\n isReadonly: true,\n isDisabled: disableParameters[name.toLowerCase()] ?? false,\n } satisfies TableRow\n })\n})\n\nconst headers = computed(() => [\n ...defaultHeaders.value,\n ...(sections.value.header ?? []),\n])\n\nconst defaultCookies = computed(() => {\n const environmentVariables = getEnvironmentVariables(environment)\n const resolvedUrl = getResolvedUrl({\n server,\n path,\n })\n const url = replaceEnvVariables(resolvedUrl, environmentVariables)\n\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[\n exampleKey\n ] ?? {}\n\n const transform = (\n cookie: XScalarCookie,\n location: 'document' | 'workspace',\n ) => {\n return {\n name: cookie.name,\n value: cookie.value,\n globalRoute: { page: location, path: 'cookies' } as const,\n isReadonly: true,\n isDisabled: disabledGlobalCookies[cookie.name.toLowerCase()] ?? false,\n } satisfies TableRow\n }\n\n const globalCookies = [\n {\n location: 'workspace',\n cookies: workspaceCookies,\n },\n {\n location: 'document',\n cookies: documentCookies,\n },\n ] as const\n\n return globalCookies.flatMap(({ location, cookies }) => {\n return cookies\n .filter((cookie) =>\n filterGlobalCookie({\n cookie,\n url,\n disabledGlobalCookies: {},\n }),\n )\n .map((cookie) => transform(cookie, location))\n })\n})\n\nconst cookies = computed(() => [\n ...(defaultCookies.value ?? []),\n ...(sections.value.cookie ?? []),\n])\n\n/** Currently selected filter for the request sections */\nconst selectedFilter = ref<Filter>('All')\n\n/** Available operation sections */\nconst OPERATION_SECTIONS: readonly Filter[] = [\n 'Auth',\n 'Variables',\n 'Cookies',\n 'Headers',\n 'Query',\n 'Body',\n] as const\n\n/**\n * Pre-generated stable IDs for all possible filter sections.\n * These are created once at setup time to avoid regenerating IDs on re-render.\n */\nconst sectionIds: Record<Filter, string> = {\n All: useId(),\n Auth: useId(),\n Variables: useId(),\n Cookies: useId(),\n Headers: useId(),\n Query: useId(),\n Body: useId(),\n}\n\n/** Filters available based on operation state */\nconst filters = computed<Filter[]>(() => {\n const availableFilters = new Set<Filter>(['All', ...OPERATION_SECTIONS])\n\n if (!sections.value.path?.length) {\n availableFilters.delete('Variables')\n }\n if (!canMethodHaveBody(method)) {\n availableFilters.delete('Body')\n }\n if (isAuthHidden.value) {\n availableFilters.delete('Auth')\n }\n\n return [...availableFilters]\n})\n\n/**\n * Map available filters to their pre-generated stable IDs.\n * Only includes IDs for filters that are currently available.\n */\nconst filterIds = computed(\n () =>\n Object.fromEntries(\n filters.value.map((section) => [section, sectionIds[section]]),\n ) as Record<Filter, string>,\n)\n\n/**\n * Hide auth selector in readonly mode when no security schemes are defined.\n * This keeps the UI clean when there are no authentication options available.\n */\nconst isAuthHidden = computed(\n () => layout === 'modal' && !Object.keys(securitySchemes ?? {}).length,\n)\n\n/**\n * Keep auth available for unauthenticated operations, but collapse it by default\n * in readonly modal layouts unless a requirement or manual selection exists.\n */\nconst isAuthDefaultOpen = computed(\n () =>\n layout !== 'modal' ||\n Boolean(\n securityRequirements?.length || selectedSecurity.selectedSchemes.length,\n ),\n)\n\n/** Get a sensible placeholder for the request name input */\nconst requestNamePlaceholder = computed(() => {\n if (operation.summary) {\n return operation.summary\n }\n const cleanPath = path.replace(REGEX.PROTOCOL, '')\n return cleanPath || 'Request Name'\n})\n\n/** Check if the section should be shown based on the selected filter */\nconst isSectionVisible = (section: Filter): boolean => {\n return selectedFilter.value === 'All' || selectedFilter.value === section\n}\n\n/**\n * Reset filter to 'All' if Body filter is selected but method changes to one that cannot have a body.\n * This prevents showing an empty Body section when switching methods.\n */\nwatch(\n () => method,\n (newMethod) => {\n if (selectedFilter.value === 'Body' && !canMethodHaveBody(newMethod)) {\n selectedFilter.value = 'All'\n }\n },\n)\n\n/** Handle operation summary updates */\nconst handleSummaryUpdate = (event: Event): void => {\n const summary = (event.target as HTMLInputElement).value\n eventBus.emit('operation:update:meta', {\n meta: meta.value,\n payload: { summary: summary.trim() },\n })\n}\n\n/** Parameter handlers */\nconst parameterHandlers = computed(() => ({\n path: createParameterHandlers('path', eventBus, meta.value, {\n context: sections.value.path ?? [],\n }),\n cookie: createParameterHandlers('cookie', eventBus, meta.value, {\n context: cookies.value ?? [],\n globalParameters: defaultCookies.value.length,\n }),\n header: createParameterHandlers('header', eventBus, meta.value, {\n context: headers.value,\n defaultParameters: defaultHeaders.value.length,\n }),\n query: createParameterHandlers('query', eventBus, meta.value, {\n context: sections.value.query ?? [],\n }),\n}))\n\n/** Handle request body content type update */\nconst handleUpdateContentType = (payload: { value: string }): void =>\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType: payload.value },\n meta: meta.value,\n })\n\n/** Handle request body value update */\nconst handleUpdateBodyValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey =\n typeof payload === 'string'\n ? `update:requestBody:value-${contentType}`\n : undefined\n\n eventBus.emit(\n 'operation:update:requestBody:value',\n {\n payload,\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/** Handle request body value update */\nconst handleUpdateBodyFormValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey = `update:requestBody:${contentType}-form-value`\n\n eventBus.emit(\n 'operation:update:requestBody:formValue',\n {\n payload: payload.map((row) => unpackProxyObject(row, { depth: 1 })),\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\nconst labelRequestNameId = useId()\n\nconst globalCookies = computed(() => [...workspaceCookies, ...documentCookies])\n\n/** Allow updating the operation extensions for the plugins */\nconst updateOperationExtension = (\n payload: ApiReferenceEvents['operation:update:extension']['payload'],\n): void =>\n eventBus.emit('operation:update:extension', { payload, meta: meta.value })\n</script>\n<template>\n <ViewLayoutSection :aria-label=\"`Request: ${operation.summary}`\">\n <template #title>\n <div\n class=\"group pointer-events-none flex flex-1 items-center gap-1 lg:pr-24\">\n <label\n v-if=\"layout !== 'modal'\"\n class=\"pointer-events-auto absolute top-0 left-0 h-full w-full cursor-text opacity-0\"\n :for=\"labelRequestNameId\" />\n <input\n v-if=\"layout !== 'modal'\"\n :id=\"labelRequestNameId\"\n class=\"text-c-1 group-hover-input pointer-events-auto relative z-10 -ml-0.5 h-8 w-full rounded pl-1.25 has-[:focus-visible]:outline md:-ml-1.25\"\n :placeholder=\"requestNamePlaceholder\"\n :value=\"operation.summary\"\n @blur=\"handleSummaryUpdate\" />\n <span\n v-else\n class=\"text-c-1 flex h-8 items-center\">\n {{ operation.summary }}\n </span>\n </div>\n <SectionFilter\n v-model=\"selectedFilter\"\n :filterIds=\"filterIds\"\n :filters=\"filters\" />\n </template>\n\n <div\n :id=\"filterIds.All\"\n class=\"request-section-content custom-scroll relative flex flex-1 flex-col\"\n :role=\"selectedFilter === 'All' ? 'tabpanel' : 'none'\">\n <!-- Auth Selector -->\n <AuthSelector\n v-show=\"isSectionVisible('Auth') && !isAuthHidden\"\n :id=\"filterIds.Auth\"\n :createAnySecurityScheme=\"layout !== 'modal'\"\n :defaultOpen=\"isAuthDefaultOpen\"\n :environment\n :eventBus\n :meta=\"authMeta\"\n :options\n :proxyUrl\n :securityRequirements\n :securitySchemes\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n title=\"Authentication\" />\n\n <!-- Variables (Path Parameters) -->\n <RequestParams\n v-show=\"isSectionVisible('Variables') && sections.path?.length\"\n :id=\"filterIds.Variables\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.path ?? []\"\n :showAddRowPlaceholder=\"false\"\n title=\"Variables\"\n v-on=\"parameterHandlers.path\" />\n\n <!-- Cookies -->\n <RequestParams\n v-show=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"cookies ?? []\"\n :showAddRowPlaceholder=\"true\"\n title=\"Cookies\"\n v-on=\"parameterHandlers.cookie\" />\n\n <!-- Headers -->\n <RequestParams\n v-show=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"headers ?? []\"\n title=\"Headers\"\n v-on=\"parameterHandlers.header\" />\n\n <!-- Query Parameters -->\n <RequestParams\n v-show=\"isSectionVisible('Query')\"\n :id=\"filterIds.Query\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.query ?? []\"\n title=\"Query Parameters\"\n v-on=\"parameterHandlers.query\" />\n\n <!-- Request Body -->\n <RequestBody\n v-show=\"isSectionVisible('Body') && canMethodHaveBody(method)\"\n :id=\"filterIds.Body\"\n :environment\n :exampleKey\n :requestBody=\"getResolvedRef(operation.requestBody)\"\n :requestBodyCompositionSelection\n title=\"Request Body\"\n @update:contentType=\"handleUpdateContentType\"\n @update:formValue=\"handleUpdateBodyFormValue\"\n @update:value=\"handleUpdateBodyValue\" />\n\n <!-- Inject request section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.request.component\"\n v-if=\"plugin?.components?.request\"\n v-show=\"selectedFilter === 'All'\"\n :operation\n v-bind=\"plugin.components.request.additionalProps\"\n @operation:update:extension=\"updateOperationExtension\" />\n </ScalarErrorBoundary>\n\n <!-- Spacer -->\n <div class=\"flex grow\" />\n <!-- Code Snippet -->\n <RequestCodeSnippet\n v-show=\"selectedFilter === 'All'\"\n :clientOptions\n :eventBus\n :globalCookies\n integration=\"client\"\n :method\n :operation\n :path\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"\n getResolvedRef(operation.requestBody)?.[\n 'x-scalar-selected-content-type'\n ]?.[exampleKey]\n \"\n :selectedServer=\"server ?? undefined\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.request-section-content {\n --scalar-border-width: 0.5px;\n}\n.request-section-content-filter {\n box-shadow: 0 -10px 0 10px var(--scalar-background-1);\n}\n.request-item:focus-within .request-meta-buttons {\n opacity: 1;\n}\n.group-hover-input {\n border-width: var(--scalar-border-width);\n border-color: transparent;\n}\n.group:hover .group-hover-input {\n background: color-mix(\n in srgb,\n var(--scalar-background-1),\n var(--scalar-background-2)\n );\n border-color: var(--scalar-border-color);\n}\n.group-hover-input:focus {\n background: transparent !important;\n border-color: var(--scalar-border-color) !important;\n}\n</style>\n"],"mappings":"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"} |
@@ -35,3 +35,3 @@ import type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'; | ||
| declare const __VLS_export: import("vue").DefineComponent<AddressBarProps, { | ||
| methodConflict: import("vue").Ref<"delete" | "head" | "get" | "options" | "put" | "post" | "patch" | "trace" | null, "delete" | "head" | "get" | "options" | "put" | "post" | "patch" | "trace" | null>; | ||
| methodConflict: import("vue").Ref<"head" | "delete" | "get" | "options" | "patch" | "post" | "put" | "trace" | null, "head" | "delete" | "get" | "options" | "patch" | "post" | "put" | "trace" | null>; | ||
| pathConflict: import("vue").Ref<string | null, string | null>; | ||
@@ -38,0 +38,0 @@ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"EnvironmentSelector.vue.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst { environments = [], activeEnvironment } = defineProps<{\n /** List of available environments */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when an environment is selected */\n (e: 'select:environment', environmentName: string): void\n /** Emitted when user wants to add a new environment */\n (e: 'add:environment'): void\n}>()\n\n/** Whether an environment is currently active */\nconst hasActiveEnvironment = computed(() => !!activeEnvironment)\n\n/** Whether environments exist */\nconst hasEnvironments = computed(() => environments.length > 0)\n\n/** Whether the currently selected environment exists in the dropdown options */\nconst hasSelectedEnvironmentInOptions = computed(() => {\n if (!activeEnvironment) {\n return false\n }\n\n return environments.includes(activeEnvironment)\n})\n\n/** True when an environment is selected but unavailable in the current context */\nconst hasMissingActiveEnvironment = computed(\n () => hasActiveEnvironment.value && !hasSelectedEnvironmentInOptions.value,\n)\n\n/** Display text for the button */\nconst displayText = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return `${activeEnvironment} (Unavailable)`\n }\n\n if (hasActiveEnvironment.value) {\n return activeEnvironment\n }\n if (!hasEnvironments.value) {\n return 'Add Environment'\n }\n return 'Select Environment'\n})\n\n/** Button styling based on state */\nconst buttonClass = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return 'hover:bg-b-2 text-c-2 border-transparent'\n }\n\n if (hasActiveEnvironment.value) {\n return 'bg-c-accent/10 text-c-accent hover:bg-c-accent/20 border-c-accent/30'\n }\n if (!hasEnvironments.value) {\n return 'hover:bg-b-2 text-c-3 border-transparent'\n }\n return 'hover:bg-b-2 text-c-2 border-transparent'\n})\n\nconst handleAddEnvironment = () => {\n emit('add:environment')\n}\n\nconst handleSelectEnvironment = (environmentName: string) => {\n emit('select:environment', environmentName)\n}\n</script>\n\n<template>\n <div class=\"relative flex items-center\">\n <!-- Environment indicator badge (only show when active) -->\n\n <ScalarDropdown>\n <ScalarButton\n :aria-label=\"`Current environment: ${displayText}`\"\n class=\"line-clamp-1 h-full w-fit justify-start border px-2 py-1 font-normal transition-colors\"\n :class=\"buttonClass\"\n size=\"sm\"\n variant=\"ghost\">\n <div class=\"flex max-w-[220px] min-w-0 items-center gap-1.5\">\n <!-- Icon indicator -->\n <ScalarIcon\n class=\"shrink-0\"\n :class=\"\n hasActiveEnvironment && !hasMissingActiveEnvironment\n ? 'text-c-accent'\n : 'text-c-3'\n \"\n icon=\"Globe\"\n size=\"sm\" />\n\n <!-- Environment name -->\n <span\n class=\"text-xxs block max-w-[160px] min-w-0 truncate text-left font-medium\">\n {{ displayText }}\n </span>\n\n <!-- Dropdown arrow -->\n <ScalarIcon\n class=\"shrink-0\"\n icon=\"ChevronDown\"\n size=\"xs\" />\n </div>\n </ScalarButton>\n\n <template #items>\n <!-- No environment option (clear selection) -->\n <ScalarDropdownItem\n v-if=\"hasActiveEnvironment\"\n class=\"group/item flex w-full items-center gap-1.5\"\n @click.stop=\"handleSelectEnvironment('')\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n !activeEnvironment\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"text-c-2\">No Environment</span>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasActiveEnvironment && hasEnvironments\" />\n\n <!-- Environment list -->\n <ScalarDropdownItem\n v-for=\"environmentName in environments\"\n :key=\"environmentName\"\n class=\"group/item flex w-full min-w-0 items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click.stop=\"handleSelectEnvironment(environmentName)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeEnvironment === environmentName\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"min-w-0 flex-1 truncate\">{{ environmentName }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider v-if=\"hasMissingActiveEnvironment\" />\n\n <ScalarDropdownItem\n v-if=\"hasMissingActiveEnvironment\"\n class=\"group/item flex h-auto w-full min-w-0 items-start gap-1.5 overflow-hidden\"\n disabled>\n <div\n class=\"bg-c-accent text-b-1 mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full p-[3px]\">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <div class=\"min-w-0 flex-1 text-left\">\n <span class=\"block truncate\">\n {{ activeEnvironment }}\n </span>\n <span class=\"text-c-3 block truncate text-xs\">\n Not available in this context\n </span>\n </div>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasEnvironments\" />\n\n <!-- Add new environment button -->\n <ScalarDropdownItem\n class=\"text-c-accent flex items-center gap-1.5\"\n @click=\"handleAddEnvironment\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>{{\n hasEnvironments ? 'New Environment' : 'Create Environment'\n }}</span>\n </ScalarDropdownItem>\n\n <!-- Helper text for empty state -->\n <div\n v-if=\"!hasEnvironments && !hasActiveEnvironment\"\n class=\"text-c-3 px-2 py-1.5 text-xs\">\n <p class=\"mb-1\">\n Environments let you manage variables like API keys and base URLs\n across different contexts.\n </p>\n </div>\n </template>\n </ScalarDropdown>\n </div>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"EnvironmentSelector.vue.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst { environments = [], activeEnvironment } = defineProps<{\n /** List of available environments */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when an environment is selected */\n (e: 'select:environment', environmentName: string): void\n /** Emitted when user wants to add a new environment */\n (e: 'add:environment'): void\n}>()\n\n/** Whether an environment is currently active */\nconst hasActiveEnvironment = computed(() => !!activeEnvironment)\n\n/** Whether environments exist */\nconst hasEnvironments = computed(() => environments.length > 0)\n\n/** Whether the currently selected environment exists in the dropdown options */\nconst hasSelectedEnvironmentInOptions = computed(() => {\n if (!activeEnvironment) {\n return false\n }\n\n return environments.includes(activeEnvironment)\n})\n\n/** True when an environment is selected but unavailable in the current context */\nconst hasMissingActiveEnvironment = computed(\n () => hasActiveEnvironment.value && !hasSelectedEnvironmentInOptions.value,\n)\n\n/** Display text for the button */\nconst displayText = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return `${activeEnvironment} (Unavailable)`\n }\n\n if (hasActiveEnvironment.value) {\n return activeEnvironment\n }\n if (!hasEnvironments.value) {\n return 'Add Environment'\n }\n return 'Select Environment'\n})\n\n/** Button styling based on state */\nconst buttonClass = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return 'hover:bg-b-2 text-c-2 border-transparent'\n }\n\n if (hasActiveEnvironment.value) {\n return 'bg-c-accent/10 text-c-accent hover:bg-c-accent/20 border-c-accent/30'\n }\n if (!hasEnvironments.value) {\n return 'hover:bg-b-2 text-c-3 border-transparent'\n }\n return 'hover:bg-b-2 text-c-2 border-transparent'\n})\n\nconst handleAddEnvironment = () => {\n emit('add:environment')\n}\n\nconst handleSelectEnvironment = (environmentName: string) => {\n emit('select:environment', environmentName)\n}\n</script>\n\n<template>\n <div class=\"relative flex items-center\">\n <!-- Environment indicator badge (only show when active) -->\n\n <ScalarDropdown>\n <ScalarButton\n :aria-label=\"`Current environment: ${displayText}`\"\n class=\"line-clamp-1 h-full w-fit justify-start border px-2 py-1 font-normal transition-colors\"\n :class=\"buttonClass\"\n size=\"sm\"\n variant=\"ghost\">\n <div class=\"flex max-w-[220px] min-w-0 items-center gap-1.5\">\n <!-- Icon indicator -->\n <ScalarIcon\n class=\"shrink-0\"\n :class=\"\n hasActiveEnvironment && !hasMissingActiveEnvironment\n ? 'text-c-accent'\n : 'text-c-3'\n \"\n icon=\"Globe\"\n size=\"sm\" />\n\n <!-- Environment name -->\n <span\n class=\"text-xxs block max-w-[160px] min-w-0 truncate text-left font-medium\">\n {{ displayText }}\n </span>\n\n <!-- Dropdown arrow -->\n <ScalarIcon\n class=\"shrink-0\"\n icon=\"ChevronDown\"\n size=\"xs\" />\n </div>\n </ScalarButton>\n\n <template #items>\n <!-- No environment option (clear selection) -->\n <ScalarDropdownItem\n v-if=\"hasActiveEnvironment\"\n class=\"group/item flex w-full items-center gap-1.5\"\n @click=\"handleSelectEnvironment('')\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n !activeEnvironment\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"text-c-2\">No Environment</span>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasActiveEnvironment && hasEnvironments\" />\n\n <!-- Environment list -->\n <ScalarDropdownItem\n v-for=\"environmentName in environments\"\n :key=\"environmentName\"\n class=\"group/item flex w-full min-w-0 items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click=\"handleSelectEnvironment(environmentName)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeEnvironment === environmentName\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"min-w-0 flex-1 truncate\">{{ environmentName }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider v-if=\"hasMissingActiveEnvironment\" />\n\n <ScalarDropdownItem\n v-if=\"hasMissingActiveEnvironment\"\n class=\"group/item flex h-auto w-full min-w-0 items-start gap-1.5 overflow-hidden\"\n disabled>\n <div\n class=\"bg-c-accent text-b-1 mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full p-[3px]\">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <div class=\"min-w-0 flex-1 text-left\">\n <span class=\"block truncate\">\n {{ activeEnvironment }}\n </span>\n <span class=\"text-c-3 block truncate text-xs\">\n Not available in this context\n </span>\n </div>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasEnvironments\" />\n\n <!-- Add new environment button -->\n <ScalarDropdownItem\n class=\"text-c-accent flex items-center gap-1.5\"\n @click=\"handleAddEnvironment\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>{{\n hasEnvironments ? 'New Environment' : 'Create Environment'\n }}</span>\n </ScalarDropdownItem>\n\n <!-- Helper text for empty state -->\n <div\n v-if=\"!hasEnvironments && !hasActiveEnvironment\"\n class=\"text-c-3 px-2 py-1.5 text-xs\">\n <p class=\"mb-1\">\n Environments let you manage variables like API keys and base URLs\n across different contexts.\n </p>\n </div>\n </template>\n </ScalarDropdown>\n </div>\n</template>\n"],"mappings":""} |
@@ -1,2 +0,2 @@ | ||
| import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, openBlock, renderList, toDisplayString, unref, withCtx, withModifiers } from "vue"; | ||
| import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, openBlock, renderList, toDisplayString, unref, withCtx } from "vue"; | ||
| import { ScalarButton, ScalarDropdown, ScalarDropdownDivider, ScalarDropdownItem, ScalarIcon } from "@scalar/components"; | ||
@@ -62,3 +62,3 @@ //#region src/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue?vue&type=script&setup=true&lang.ts | ||
| class: "group/item flex w-full items-center gap-1.5", | ||
| onClick: _cache[0] || (_cache[0] = withModifiers(($event) => handleSelectEnvironment(""), ["stop"])) | ||
| onClick: _cache[0] || (_cache[0] = ($event) => handleSelectEnvironment("")) | ||
| }, { | ||
@@ -77,3 +77,3 @@ default: withCtx(() => [createElementVNode("div", { class: normalizeClass(["flex h-4 w-4 items-center justify-center rounded-full p-[3px]", !__props.activeEnvironment ? "bg-c-accent text-b-1" : "shadow-border text-transparent"]) }, [createVNode(unref(ScalarIcon), { | ||
| class: "group/item flex w-full min-w-0 items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap", | ||
| onClick: withModifiers(($event) => handleSelectEnvironment(environmentName), ["stop"]) | ||
| onClick: ($event) => handleSelectEnvironment(environmentName) | ||
| }, { | ||
@@ -80,0 +80,0 @@ default: withCtx(() => [createElementVNode("div", { class: normalizeClass(["flex h-4 w-4 items-center justify-center rounded-full p-[3px]", __props.activeEnvironment === environmentName ? "bg-c-accent text-b-1" : "shadow-border text-transparent"]) }, [createVNode(unref(ScalarIcon), { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"EnvironmentSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst { environments = [], activeEnvironment } = defineProps<{\n /** List of available environments */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when an environment is selected */\n (e: 'select:environment', environmentName: string): void\n /** Emitted when user wants to add a new environment */\n (e: 'add:environment'): void\n}>()\n\n/** Whether an environment is currently active */\nconst hasActiveEnvironment = computed(() => !!activeEnvironment)\n\n/** Whether environments exist */\nconst hasEnvironments = computed(() => environments.length > 0)\n\n/** Whether the currently selected environment exists in the dropdown options */\nconst hasSelectedEnvironmentInOptions = computed(() => {\n if (!activeEnvironment) {\n return false\n }\n\n return environments.includes(activeEnvironment)\n})\n\n/** True when an environment is selected but unavailable in the current context */\nconst hasMissingActiveEnvironment = computed(\n () => hasActiveEnvironment.value && !hasSelectedEnvironmentInOptions.value,\n)\n\n/** Display text for the button */\nconst displayText = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return `${activeEnvironment} (Unavailable)`\n }\n\n if (hasActiveEnvironment.value) {\n return activeEnvironment\n }\n if (!hasEnvironments.value) {\n return 'Add Environment'\n }\n return 'Select Environment'\n})\n\n/** Button styling based on state */\nconst buttonClass = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return 'hover:bg-b-2 text-c-2 border-transparent'\n }\n\n if (hasActiveEnvironment.value) {\n return 'bg-c-accent/10 text-c-accent hover:bg-c-accent/20 border-c-accent/30'\n }\n if (!hasEnvironments.value) {\n return 'hover:bg-b-2 text-c-3 border-transparent'\n }\n return 'hover:bg-b-2 text-c-2 border-transparent'\n})\n\nconst handleAddEnvironment = () => {\n emit('add:environment')\n}\n\nconst handleSelectEnvironment = (environmentName: string) => {\n emit('select:environment', environmentName)\n}\n</script>\n\n<template>\n <div class=\"relative flex items-center\">\n <!-- Environment indicator badge (only show when active) -->\n\n <ScalarDropdown>\n <ScalarButton\n :aria-label=\"`Current environment: ${displayText}`\"\n class=\"line-clamp-1 h-full w-fit justify-start border px-2 py-1 font-normal transition-colors\"\n :class=\"buttonClass\"\n size=\"sm\"\n variant=\"ghost\">\n <div class=\"flex max-w-[220px] min-w-0 items-center gap-1.5\">\n <!-- Icon indicator -->\n <ScalarIcon\n class=\"shrink-0\"\n :class=\"\n hasActiveEnvironment && !hasMissingActiveEnvironment\n ? 'text-c-accent'\n : 'text-c-3'\n \"\n icon=\"Globe\"\n size=\"sm\" />\n\n <!-- Environment name -->\n <span\n class=\"text-xxs block max-w-[160px] min-w-0 truncate text-left font-medium\">\n {{ displayText }}\n </span>\n\n <!-- Dropdown arrow -->\n <ScalarIcon\n class=\"shrink-0\"\n icon=\"ChevronDown\"\n size=\"xs\" />\n </div>\n </ScalarButton>\n\n <template #items>\n <!-- No environment option (clear selection) -->\n <ScalarDropdownItem\n v-if=\"hasActiveEnvironment\"\n class=\"group/item flex w-full items-center gap-1.5\"\n @click.stop=\"handleSelectEnvironment('')\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n !activeEnvironment\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"text-c-2\">No Environment</span>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasActiveEnvironment && hasEnvironments\" />\n\n <!-- Environment list -->\n <ScalarDropdownItem\n v-for=\"environmentName in environments\"\n :key=\"environmentName\"\n class=\"group/item flex w-full min-w-0 items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click.stop=\"handleSelectEnvironment(environmentName)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeEnvironment === environmentName\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"min-w-0 flex-1 truncate\">{{ environmentName }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider v-if=\"hasMissingActiveEnvironment\" />\n\n <ScalarDropdownItem\n v-if=\"hasMissingActiveEnvironment\"\n class=\"group/item flex h-auto w-full min-w-0 items-start gap-1.5 overflow-hidden\"\n disabled>\n <div\n class=\"bg-c-accent text-b-1 mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full p-[3px]\">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <div class=\"min-w-0 flex-1 text-left\">\n <span class=\"block truncate\">\n {{ activeEnvironment }}\n </span>\n <span class=\"text-c-3 block truncate text-xs\">\n Not available in this context\n </span>\n </div>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasEnvironments\" />\n\n <!-- Add new environment button -->\n <ScalarDropdownItem\n class=\"text-c-accent flex items-center gap-1.5\"\n @click=\"handleAddEnvironment\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>{{\n hasEnvironments ? 'New Environment' : 'Create Environment'\n }}</span>\n </ScalarDropdownItem>\n\n <!-- Helper text for empty state -->\n <div\n v-if=\"!hasEnvironments && !hasActiveEnvironment\"\n class=\"text-c-3 px-2 py-1.5 text-xs\">\n <p class=\"mb-1\">\n Environments let you manage variables like API keys and base URLs\n across different contexts.\n </p>\n </div>\n </template>\n </ScalarDropdown>\n </div>\n</template>\n"],"mappings":"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"} | ||
| {"version":3,"file":"EnvironmentSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst { environments = [], activeEnvironment } = defineProps<{\n /** List of available environments */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when an environment is selected */\n (e: 'select:environment', environmentName: string): void\n /** Emitted when user wants to add a new environment */\n (e: 'add:environment'): void\n}>()\n\n/** Whether an environment is currently active */\nconst hasActiveEnvironment = computed(() => !!activeEnvironment)\n\n/** Whether environments exist */\nconst hasEnvironments = computed(() => environments.length > 0)\n\n/** Whether the currently selected environment exists in the dropdown options */\nconst hasSelectedEnvironmentInOptions = computed(() => {\n if (!activeEnvironment) {\n return false\n }\n\n return environments.includes(activeEnvironment)\n})\n\n/** True when an environment is selected but unavailable in the current context */\nconst hasMissingActiveEnvironment = computed(\n () => hasActiveEnvironment.value && !hasSelectedEnvironmentInOptions.value,\n)\n\n/** Display text for the button */\nconst displayText = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return `${activeEnvironment} (Unavailable)`\n }\n\n if (hasActiveEnvironment.value) {\n return activeEnvironment\n }\n if (!hasEnvironments.value) {\n return 'Add Environment'\n }\n return 'Select Environment'\n})\n\n/** Button styling based on state */\nconst buttonClass = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return 'hover:bg-b-2 text-c-2 border-transparent'\n }\n\n if (hasActiveEnvironment.value) {\n return 'bg-c-accent/10 text-c-accent hover:bg-c-accent/20 border-c-accent/30'\n }\n if (!hasEnvironments.value) {\n return 'hover:bg-b-2 text-c-3 border-transparent'\n }\n return 'hover:bg-b-2 text-c-2 border-transparent'\n})\n\nconst handleAddEnvironment = () => {\n emit('add:environment')\n}\n\nconst handleSelectEnvironment = (environmentName: string) => {\n emit('select:environment', environmentName)\n}\n</script>\n\n<template>\n <div class=\"relative flex items-center\">\n <!-- Environment indicator badge (only show when active) -->\n\n <ScalarDropdown>\n <ScalarButton\n :aria-label=\"`Current environment: ${displayText}`\"\n class=\"line-clamp-1 h-full w-fit justify-start border px-2 py-1 font-normal transition-colors\"\n :class=\"buttonClass\"\n size=\"sm\"\n variant=\"ghost\">\n <div class=\"flex max-w-[220px] min-w-0 items-center gap-1.5\">\n <!-- Icon indicator -->\n <ScalarIcon\n class=\"shrink-0\"\n :class=\"\n hasActiveEnvironment && !hasMissingActiveEnvironment\n ? 'text-c-accent'\n : 'text-c-3'\n \"\n icon=\"Globe\"\n size=\"sm\" />\n\n <!-- Environment name -->\n <span\n class=\"text-xxs block max-w-[160px] min-w-0 truncate text-left font-medium\">\n {{ displayText }}\n </span>\n\n <!-- Dropdown arrow -->\n <ScalarIcon\n class=\"shrink-0\"\n icon=\"ChevronDown\"\n size=\"xs\" />\n </div>\n </ScalarButton>\n\n <template #items>\n <!-- No environment option (clear selection) -->\n <ScalarDropdownItem\n v-if=\"hasActiveEnvironment\"\n class=\"group/item flex w-full items-center gap-1.5\"\n @click=\"handleSelectEnvironment('')\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n !activeEnvironment\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"text-c-2\">No Environment</span>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasActiveEnvironment && hasEnvironments\" />\n\n <!-- Environment list -->\n <ScalarDropdownItem\n v-for=\"environmentName in environments\"\n :key=\"environmentName\"\n class=\"group/item flex w-full min-w-0 items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click=\"handleSelectEnvironment(environmentName)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeEnvironment === environmentName\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"min-w-0 flex-1 truncate\">{{ environmentName }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider v-if=\"hasMissingActiveEnvironment\" />\n\n <ScalarDropdownItem\n v-if=\"hasMissingActiveEnvironment\"\n class=\"group/item flex h-auto w-full min-w-0 items-start gap-1.5 overflow-hidden\"\n disabled>\n <div\n class=\"bg-c-accent text-b-1 mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full p-[3px]\">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <div class=\"min-w-0 flex-1 text-left\">\n <span class=\"block truncate\">\n {{ activeEnvironment }}\n </span>\n <span class=\"text-c-3 block truncate text-xs\">\n Not available in this context\n </span>\n </div>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasEnvironments\" />\n\n <!-- Add new environment button -->\n <ScalarDropdownItem\n class=\"text-c-accent flex items-center gap-1.5\"\n @click=\"handleAddEnvironment\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>{{\n hasEnvironments ? 'New Environment' : 'Create Environment'\n }}</span>\n </ScalarDropdownItem>\n\n <!-- Helper text for empty state -->\n <div\n v-if=\"!hasEnvironments && !hasActiveEnvironment\"\n class=\"text-c-3 px-2 py-1.5 text-xs\">\n <p class=\"mb-1\">\n Environments let you manage variables like API keys and base URLs\n across different contexts.\n </p>\n </div>\n </template>\n </ScalarDropdown>\n </div>\n</template>\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AuthSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarComboboxMultiselect,\n ScalarIconButton,\n ScalarListboxCheckbox,\n useModal,\n type Icon,\n type ScalarButton as ScalarButtonType,\n} from '@scalar/components'\nimport { ScalarIconCaretDown, ScalarIconTrash } from '@scalar/icons'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n isAuthOptional,\n type MergedSecuritySchemes,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n OpenApiDocument,\n SecurityRequirementObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId } from 'vue'\n\nimport DeleteRequestAuthModal from '@/v2/blocks/scalar-auth-selector-block/components/DeleteRequestAuthModal.vue'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport {\n formatComplexScheme,\n formatScheme,\n getSecuritySchemeOptions,\n type SecuritySchemeOption,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/security-scheme'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nimport RequestAuthDataTable from './RequestAuthDataTable.vue'\n\nconst {\n environment,\n eventBus,\n createAnySecurityScheme = false,\n defaultOpen = true,\n isStatic = false,\n meta,\n proxyUrl,\n securityRequirements,\n securitySchemes,\n selectedSecurity,\n server,\n title,\n options,\n} = defineProps<{\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n /** Allows adding authentication which is not in the document */\n createAnySecurityScheme?: boolean\n /** Whether the authentication disclosure should start expanded */\n defaultOpen?: boolean\n /** Creates a static disclosure that cannot be collapsed */\n isStatic?: boolean\n meta: AuthMeta\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n selectedSecurity: SelectedSecurity | undefined\n server: ServerObject | null\n title: string\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst titleId = useId()\nconst comboboxButtonRef = ref<typeof ScalarButtonType | null>(null)\nconst isDisclosureOpen = ref(false)\n\nconst deleteModal = useModal()\nconst schemeToDelete = ref<{\n label: string\n payload: SecurityRequirementObject\n} | null>(null)\n\n/**\n * Determines if authentication is required or optional\n *\n * Auth is optional when there is an empty security requirement and no complex requirements.\n * Complex requirements have multiple auth schemes combined (e.g., API key + OAuth).\n */\nconst authIndicator = computed<{ icon: Icon; text: string } | null>(() => {\n if (!securityRequirements?.length) {\n return null\n }\n\n const isOptional = isAuthOptional(securityRequirements)\n\n return {\n icon: isOptional ? 'Unlock' : 'Lock',\n text: isOptional ? 'Optional' : 'Required',\n }\n})\n\n/** All available auth scheme options for the dropdown */\nconst availableSchemeOptions = computed(() =>\n getSecuritySchemeOptions(\n securityRequirements ?? [],\n securitySchemes ?? {},\n selectedSecurity?.selectedSchemes ?? [],\n createAnySecurityScheme,\n ),\n)\n\n/** Currently active auth schemes selected for this operation or collection */\nconst activeSchemeOptions = computed<SecuritySchemeOption[]>(() => {\n const schemes = selectedSecurity?.selectedSchemes\n if (!schemes?.length) {\n return []\n }\n\n return schemes.flatMap((requirement) => {\n const schemeNames = Object.keys(requirement)\n\n if (schemeNames.length === 0) {\n return []\n }\n\n // Complex auth requirement with multiple schemes\n if (schemeNames.length > 1) {\n return formatComplexScheme(requirement)\n }\n\n // Simple auth requirement with single scheme\n const schemeName = schemeNames[0]\n if (!schemeName) {\n return []\n }\n\n const scheme = getResolvedRef(securitySchemes?.[schemeName])\n if (!scheme) {\n return []\n }\n\n return formatScheme({\n name: schemeName,\n value: requirement,\n })\n })\n})\n\n/**\n * Opens the combobox dropdown when clicking the auth indicator badge.\n * Prevents the disclosure from toggling if it is already open.\n */\nconst handleAuthIndicatorClick = (event: Event): void => {\n if (isDisclosureOpen.value) {\n event.stopPropagation()\n }\n comboboxButtonRef.value?.$el.click()\n}\n\n/**\n * Updates the selected auth schemes.\n * Separates existing schemes from newly created ones for the event payload.\n */\nconst handleSchemeSelection = (selected: SecuritySchemeOption[]): void => {\n const existingSchemes = selected\n .filter((option) => option.payload === undefined)\n .map((option) => unpackProxyObject(option.value, { depth: 2 }))\n\n const newSchemes = selected\n .filter((option) => option.payload !== undefined)\n .map((option) => ({\n name: option.label,\n scheme: option.payload!,\n }))\n\n eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: existingSchemes,\n newSchemes,\n meta,\n })\n}\n\n/** Shows the delete confirmation modal for the selected scheme */\nconst handleDeleteRequest = (option: {\n label: string\n value: SecurityRequirementObject\n}): void => {\n schemeToDelete.value = { label: option.label, payload: option.value }\n deleteModal.show()\n}\n\n/** Deletes the selected auth scheme after confirmation */\nconst handleDeleteConfirm = (): void => {\n if (!schemeToDelete.value) {\n return\n }\n\n eventBus.emit('auth:delete:security-scheme', {\n names: Object.keys(schemeToDelete.value.payload),\n })\n\n schemeToDelete.value = null\n deleteModal.hide()\n}\n\ndefineExpose({\n authIndicator,\n selectedSchemeOptions: activeSchemeOptions,\n schemeOptions: availableSchemeOptions,\n})\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params relative\"\n :defaultOpen\n :isStatic=\"isStatic\"\n :itemCount=\"activeSchemeOptions.length\"\n @update:modelValue=\"(open) => (isDisclosureOpen = open)\">\n <template #title>\n <div\n :id=\"titleId\"\n class=\"inline-flex items-center gap-0.5 leading-[20px]\">\n <span>{{ title }}</span>\n\n <span\n v-if=\"authIndicator\"\n class=\"text-c-3 hover:bg-b-3 hover:text-c-1 -my-0.5 -mr-1 cursor-pointer rounded px-1 py-0.5 leading-[normal] font-normal\"\n :class=\"{ 'text-c-1': authIndicator.text === 'Required' }\"\n data-testid=\"auth-indicator\"\n @click=\"handleAuthIndicatorClick\">\n {{ authIndicator.text }}\n </span>\n </div>\n </template>\n\n <!-- Auth Dropdown (hidden when only one scheme is available) -->\n <template #actions>\n <ScalarComboboxMultiselect\n class=\"w-72 text-xs\"\n :modelValue=\"activeSchemeOptions\"\n multiple\n :options=\"availableSchemeOptions\"\n placement=\"bottom-end\"\n teleport\n @delete=\"handleDeleteRequest\"\n @update:modelValue=\"handleSchemeSelection\">\n <ScalarButton\n ref=\"comboboxButtonRef\"\n :aria-describedby=\"titleId\"\n class=\"group/combobox-button hover:text-c-1 text-c-2 flex h-fit w-full items-center gap-1 px-0.75 py-0.25 text-base font-normal\"\n variant=\"ghost\">\n <!-- Single auth scheme selected -->\n <template v-if=\"activeSchemeOptions.length === 1\">\n <span class=\"sr-only\">Selected Auth Type:</span>\n {{ activeSchemeOptions[0]?.label }}\n </template>\n\n <!-- Multiple auth schemes selected -->\n <template v-else-if=\"activeSchemeOptions.length > 1\">\n Multiple\n <span class=\"sr-only\">Auth Types Selected</span>\n </template>\n\n <!-- No auth schemes selected -->\n <template v-else>\n <span class=\"sr-only\">Select</span>\n Auth Type\n </template>\n\n <ScalarIconCaretDown\n class=\"size-3 shrink-0 transition-transform duration-100 group-aria-expanded/combobox-button:rotate-180\"\n weight=\"bold\" />\n </ScalarButton>\n\n <template #option=\"{ option, selected }\">\n <ScalarListboxCheckbox\n multiselect\n :selected=\"selected\" />\n <div class=\"min-w-0 flex-1 truncate\">\n {{ option.label }}\n </div>\n <ScalarIconButton\n v-if=\"option.isDeletable\"\n class=\"-m-0.5 shrink-0 p-0.5 opacity-0 group-hover/item:opacity-100\"\n :icon=\"ScalarIconTrash\"\n :label=\"`Delete ${option.label}`\"\n size=\"xs\"\n @click.stop=\"handleDeleteRequest(option)\" />\n </template>\n </ScalarComboboxMultiselect>\n </template>\n\n <!-- Auth Table -->\n <RequestAuthDataTable\n :activeAuthIndex=\"selectedSecurity?.selectedIndex ?? 0\"\n :environment\n :eventBus\n :isStatic\n :meta\n :options\n :proxyUrl\n :securitySchemes\n :selectedSchemeOptions=\"activeSchemeOptions\"\n :server />\n\n <!-- Delete Auth Modal -->\n <DeleteRequestAuthModal\n v-if=\"schemeToDelete\"\n :label=\"schemeToDelete.label\"\n :scheme=\"schemeToDelete\"\n :state=\"deleteModal\"\n @close=\"deleteModal.hide()\"\n @delete=\"handleDeleteConfirm\" />\n </CollapsibleSection>\n</template>\n"],"mappings":"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"} | ||
| {"version":3,"file":"AuthSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarComboboxMultiselect,\n ScalarIconButton,\n ScalarListboxCheckbox,\n useModal,\n type Icon,\n type ScalarButton as ScalarButtonType,\n} from '@scalar/components'\nimport { ScalarIconCaretDown, ScalarIconTrash } from '@scalar/icons'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n isAuthOptional,\n type MergedSecuritySchemes,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n OpenApiDocument,\n SecurityRequirementObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId } from 'vue'\n\nimport DeleteRequestAuthModal from '@/v2/blocks/scalar-auth-selector-block/components/DeleteRequestAuthModal.vue'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport {\n formatComplexScheme,\n formatScheme,\n getSecuritySchemeOptions,\n type SecuritySchemeOption,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/security-scheme'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nimport RequestAuthDataTable from './RequestAuthDataTable.vue'\n\nconst {\n environment,\n eventBus,\n createAnySecurityScheme = false,\n defaultOpen = true,\n isStatic = false,\n meta,\n proxyUrl,\n securityRequirements,\n securitySchemes,\n selectedSecurity,\n server,\n title,\n options,\n} = defineProps<{\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n /** Allows adding authentication which is not in the document */\n createAnySecurityScheme?: boolean\n /** Whether the authentication disclosure should start expanded */\n defaultOpen?: boolean\n /** Creates a static disclosure that cannot be collapsed */\n isStatic?: boolean\n meta: AuthMeta\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n selectedSecurity: SelectedSecurity | undefined\n server: ServerObject | null\n title: string\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst titleId = useId()\nconst comboboxButtonRef = ref<typeof ScalarButtonType | null>(null)\nconst isDisclosureOpen = ref(false)\n\nconst deleteModal = useModal()\nconst schemeToDelete = ref<{\n label: string\n payload: SecurityRequirementObject\n} | null>(null)\n\n/**\n * Determines if authentication is required or optional\n *\n * Auth is optional when there is an empty security requirement and no complex requirements.\n * Complex requirements have multiple auth schemes combined (e.g., API key + OAuth).\n */\nconst authIndicator = computed<{ icon: Icon; text: string } | null>(() => {\n if (!securityRequirements?.length) {\n return null\n }\n\n const isOptional = isAuthOptional(securityRequirements)\n\n return {\n icon: isOptional ? 'Unlock' : 'Lock',\n text: isOptional ? 'Optional' : 'Required',\n }\n})\n\n/** All available auth scheme options for the dropdown */\nconst availableSchemeOptions = computed(() =>\n getSecuritySchemeOptions(\n securityRequirements ?? [],\n securitySchemes ?? {},\n selectedSecurity?.selectedSchemes ?? [],\n createAnySecurityScheme,\n ),\n)\n\n/** Currently active auth schemes selected for this operation or collection */\nconst activeSchemeOptions = computed<SecuritySchemeOption[]>(() => {\n const schemes = selectedSecurity?.selectedSchemes\n if (!schemes?.length) {\n return []\n }\n\n return schemes.flatMap((requirement) => {\n const schemeNames = Object.keys(requirement)\n\n if (schemeNames.length === 0) {\n return []\n }\n\n // Complex auth requirement with multiple schemes\n if (schemeNames.length > 1) {\n return formatComplexScheme(requirement)\n }\n\n // Simple auth requirement with single scheme\n const schemeName = schemeNames[0]\n if (!schemeName) {\n return []\n }\n\n const scheme = getResolvedRef(securitySchemes?.[schemeName])\n if (!scheme) {\n return []\n }\n\n return formatScheme({\n name: schemeName,\n value: requirement,\n })\n })\n})\n\n/**\n * Opens the combobox dropdown when clicking the auth indicator badge.\n * Prevents the disclosure from toggling if it is already open.\n */\nconst handleAuthIndicatorClick = (event: Event): void => {\n if (isDisclosureOpen.value) {\n event.stopPropagation()\n }\n comboboxButtonRef.value?.$el.click()\n}\n\n/**\n * Updates the selected auth schemes.\n * Separates existing schemes from newly created ones for the event payload.\n */\nconst handleSchemeSelection = (selected: SecuritySchemeOption[]): void => {\n const existingSchemes = selected\n .filter((option) => option.payload === undefined)\n .map((option) => unpackProxyObject(option.value, { depth: 2 }))\n\n const newSchemes = selected\n .filter((option) => option.payload !== undefined)\n .map((option) => ({\n name: option.label,\n scheme: option.payload!,\n }))\n\n eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: existingSchemes,\n newSchemes,\n meta,\n })\n}\n\n/** Shows the delete confirmation modal for the selected scheme */\nconst handleDeleteRequest = (option: {\n label: string\n value: SecurityRequirementObject\n}): void => {\n schemeToDelete.value = { label: option.label, payload: option.value }\n deleteModal.show()\n}\n\n/** Deletes the selected auth scheme after confirmation */\nconst handleDeleteConfirm = (): void => {\n if (!schemeToDelete.value) {\n return\n }\n\n eventBus.emit('auth:delete:security-scheme', {\n names: Object.keys(schemeToDelete.value.payload),\n })\n\n schemeToDelete.value = null\n deleteModal.hide()\n}\n\ndefineExpose({\n authIndicator,\n selectedSchemeOptions: activeSchemeOptions,\n schemeOptions: availableSchemeOptions,\n})\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params relative\"\n :defaultOpen\n :isStatic=\"isStatic\"\n :itemCount=\"activeSchemeOptions.length\"\n @update:modelValue=\"(open) => (isDisclosureOpen = open)\">\n <template #title>\n <div\n :id=\"titleId\"\n class=\"inline-flex items-center gap-0.5 leading-[20px]\">\n <span>{{ title }}</span>\n\n <span\n v-if=\"authIndicator\"\n class=\"text-c-3 hover:bg-b-3 hover:text-c-1 -my-0.5 -mr-1 cursor-pointer rounded px-1 py-0.5 leading-[normal] font-normal\"\n :class=\"{ 'text-c-1': authIndicator.text === 'Required' }\"\n data-testid=\"auth-indicator\"\n @click=\"handleAuthIndicatorClick\">\n {{ authIndicator.text }}\n </span>\n </div>\n </template>\n\n <!-- Auth Dropdown (hidden when only one scheme is available) -->\n <template #actions>\n <ScalarComboboxMultiselect\n class=\"w-72 text-xs\"\n :modelValue=\"activeSchemeOptions\"\n multiple\n :options=\"availableSchemeOptions\"\n placement=\"bottom-end\"\n teleport\n @delete=\"handleDeleteRequest\"\n @update:modelValue=\"handleSchemeSelection\">\n <ScalarButton\n ref=\"comboboxButtonRef\"\n :aria-describedby=\"titleId\"\n class=\"group/combobox-button hover:text-c-1 text-c-2 flex h-fit w-full items-center gap-1 px-0.75 py-0.25 text-base font-normal\"\n variant=\"ghost\">\n <!-- Single auth scheme selected -->\n <template v-if=\"activeSchemeOptions.length === 1\">\n <span class=\"sr-only\">Selected Auth Type:</span>\n {{ activeSchemeOptions[0]?.label }}\n </template>\n\n <!-- Multiple auth schemes selected -->\n <template v-else-if=\"activeSchemeOptions.length > 1\">\n Multiple\n <span class=\"sr-only\">Auth Types Selected</span>\n </template>\n\n <!-- No auth schemes selected -->\n <template v-else>\n <span class=\"sr-only\">Select</span>\n Auth Type\n </template>\n\n <ScalarIconCaretDown\n class=\"size-3 shrink-0 transition-transform duration-100 group-aria-expanded/combobox-button:rotate-180\"\n weight=\"bold\" />\n </ScalarButton>\n\n <template #option=\"{ option, selected }\">\n <ScalarListboxCheckbox\n multiselect\n :selected=\"selected\" />\n <div class=\"min-w-0 flex-1 truncate\">\n {{ option.label }}\n </div>\n <ScalarIconButton\n v-if=\"option.isDeletable\"\n class=\"-m-0.5 shrink-0 p-0.5 opacity-0 group-hover/item:opacity-100\"\n :icon=\"ScalarIconTrash\"\n :label=\"`Delete ${option.label}`\"\n size=\"xs\"\n @click.stop=\"handleDeleteRequest(option)\" />\n </template>\n </ScalarComboboxMultiselect>\n </template>\n\n <!-- Auth Table -->\n <RequestAuthDataTable\n :activeAuthIndex=\"selectedSecurity?.selectedIndex ?? 0\"\n :environment\n :eventBus\n :isStatic\n :meta\n :options\n :proxyUrl\n :securitySchemes\n :selectedSchemeOptions=\"activeSchemeOptions\"\n :server />\n\n <!-- Delete Auth Modal -->\n <DeleteRequestAuthModal\n v-if=\"schemeToDelete\"\n :label=\"schemeToDelete.label\"\n :scheme=\"schemeToDelete\"\n :state=\"deleteModal\"\n @close=\"deleteModal.hide()\"\n @delete=\"handleDeleteConfirm\" />\n </CollapsibleSection>\n</template>\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OAuth2.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"names":[],"mappings":"AAyaA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAIzE,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAKL,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAChC,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAO,KAAK,EAEV,YAAY,EACb,MAAM,8DAA8D,CAAA;AAWrE,uDAAuD;AACvD,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAA;wBACxD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEhB,wCAAwC;iBAC3B,kBAAkB;IAC/B,kBAAkB;WACX,sBAAsB;IAC7B,6BAA6B;UACvB,MAAM,sBAAsB;IAClC,sBAAsB;oBACN,MAAM,EAAE;IACxB,sBAAsB;YACd,0BAA0B;IAClC,mCAAmC;YAC3B,YAAY,GAAG,IAAI;IAC3B,gBAAgB;cACN,MAAM;IAChB,kCAAkC;UAC5B,MAAM;IACZ,2CAA2C;cACjC,iBAAiB;IAC3B,uDAAuD;cAC7C,aAAa;;;;;;;;;;;;;;IAnBvB,wCAAwC;iBAC3B,kBAAkB;IAC/B,kBAAkB;WACX,sBAAsB;IAC7B,6BAA6B;UACvB,MAAM,sBAAsB;IAClC,sBAAsB;oBACN,MAAM,EAAE;IACxB,sBAAsB;YACd,0BAA0B;IAClC,mCAAmC;YAC3B,YAAY,GAAG,IAAI;IAC3B,gBAAgB;cACN,MAAM;IAChB,kCAAkC;UAC5B,MAAM;IACZ,2CAA2C;cACjC,iBAAiB;IAC3B,uDAAuD;cAC7C,aAAa;;;;;;;;;;;;;kFAmxBrB,CAAC"} | ||
| {"version":3,"file":"OAuth2.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"names":[],"mappings":"AAqhBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAIzE,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAKL,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAChC,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAO,KAAK,EAEV,YAAY,EACb,MAAM,8DAA8D,CAAA;AAcrE,uDAAuD;AACvD,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAA;wBACxD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEhB,wCAAwC;iBAC3B,kBAAkB;IAC/B,kBAAkB;WACX,sBAAsB;IAC7B,6BAA6B;UACvB,MAAM,sBAAsB;IAClC,sBAAsB;oBACN,MAAM,EAAE;IACxB,sBAAsB;YACd,0BAA0B;IAClC,mCAAmC;YAC3B,YAAY,GAAG,IAAI;IAC3B,gBAAgB;cACN,MAAM;IAChB,kCAAkC;UAC5B,MAAM;IACZ,2CAA2C;cACjC,iBAAiB;IAC3B,uDAAuD;cAC7C,aAAa;;;;;;;;;;;;;;IAnBvB,wCAAwC;iBAC3B,kBAAkB;IAC/B,kBAAkB;WACX,sBAAsB;IAC7B,6BAA6B;UACvB,MAAM,sBAAsB;IAClC,sBAAsB;oBACN,MAAM,EAAE;IACxB,sBAAsB;YACd,0BAA0B;IAClC,mCAAmC;YAC3B,YAAY,GAAG,IAAI;IAC3B,gBAAgB;cACN,MAAM;IAChB,kCAAkC;UAC5B,MAAM;IACZ,2CAA2C;cACjC,iBAAiB;IAC3B,uDAAuD;cAC7C,aAAa;;;;;;;;;;;;;kFAq7BrB,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OAuth2.vue.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport { authorizeOauth2 } from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void =>\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n\n/** Track if we have set the redirect uri */\nconst hasPrefilledRedirectUri = ref(false)\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () =>\n (flow.value as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ],\n (newRedirectUri) => {\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n if (\n hasPrefilledRedirectUri.value ||\n newRedirectUri ||\n !defaultRedirectUri ||\n !('x-scalar-secret-redirect-uri' in flow.value)\n ) {\n return\n }\n hasPrefilledRedirectUri.value = true\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n \">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"https://galaxy.scalar.com/callback\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"OAuth2.vue.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport {\n authorizeOauth2,\n refreshOauth2Token,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void => {\n if (loader.isLoading) {\n return\n }\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n}\n\n/** Clears stored access and refresh tokens (authorized state) */\nconst handleClearAccessTokens = (): void => {\n if (loader.isLoading) {\n return\n }\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n}\n\n/** Track redirect URI prefill per flow instance to support document switching */\nconst prefilledFlowIdentity = ref<string | null>(null)\nconst hasHandledRedirectPrefill = ref(false)\n\nconst resolveFlowIdentity = (\n currentFlow: OAuthFlowsObjectSecret[keyof OAuthFlowsObjectSecret] | undefined,\n): string =>\n JSON.stringify({\n type,\n authorizationUrl:\n currentFlow && 'authorizationUrl' in currentFlow\n ? currentFlow.authorizationUrl\n : '',\n tokenUrl:\n currentFlow && 'tokenUrl' in currentFlow ? currentFlow.tokenUrl : '',\n refreshUrl: currentFlow?.refreshUrl ?? '',\n scopes: Object.keys(currentFlow?.scopes ?? {}),\n })\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () => flow.value,\n (currentFlow) => {\n if (!currentFlow || !('x-scalar-secret-redirect-uri' in currentFlow)) {\n return\n }\n\n const flowIdentity = resolveFlowIdentity(currentFlow)\n if (prefilledFlowIdentity.value !== flowIdentity) {\n prefilledFlowIdentity.value = flowIdentity\n hasHandledRedirectPrefill.value = false\n }\n\n if (hasHandledRedirectPrefill.value) {\n return\n }\n\n const newRedirectUri = (currentFlow as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ]\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n hasHandledRedirectPrefill.value = true\n\n if (newRedirectUri || !defaultRedirectUri) {\n return\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Whether the current flow supports refreshing the access token */\nconst supportsRefreshToken = computed(() => type !== 'implicit')\n\n/**\n * Refresh URL placeholder, shows tokenUrl as hint if refreshUrl is not specified.\n * This helps users understand that tokenUrl will be used as fallback.\n */\nconst refreshUrlPlaceholder = computed(() => {\n if ('tokenUrl' in flow.value && flow.value.tokenUrl) {\n return flow.value.tokenUrl\n }\n return 'https://galaxy.scalar.com/oauth/refresh'\n})\n\n/**\n * Uses the stored refresh token to obtain a new access token\n * via grant_type=refresh_token.\n */\nconst handleRefresh = async (): Promise<void> => {\n if (loader.isLoading || type === 'implicit') {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await refreshOauth2Token(\n flows,\n type,\n proxyUrl,\n server,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to refresh token', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"supportsRefreshToken\">\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow.refreshUrl ?? ''\"\n :placeholder=\"refreshUrlPlaceholder\"\n @update:modelValue=\"(v) => handleOauth2Update({ refreshUrl: v })\">\n Refresh URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n v-if=\"supportsRefreshToken\"\n class=\"p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleRefresh\">\n Refresh\n </ScalarButton>\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleClearAccessTokens\">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"Optional redirect URL\"\n @update:modelValue=\"\n (v) => {\n hasHandledRedirectPrefill = true\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":""} |
| import DataTableRow_default from "../../../components/data-table/DataTableRow.vue.js"; | ||
| import OAuthScopesInput_default from "./OAuthScopesInput.vue.js"; | ||
| import { authorizeOauth2 } from "../helpers/oauth.js"; | ||
| import { authorizeOauth2, refreshOauth2Token } from "../helpers/oauth.js"; | ||
| import { resolveDefaultOAuth2RedirectUri } from "../helpers/resolve-default-oauth2-redirect-url.js"; | ||
@@ -56,10 +56,37 @@ import RequestAuthDataTableInput_default from "./RequestAuthDataTableInput.vue.js"; | ||
| /** Clears the flow secrets */ | ||
| const clearOauth2Secrets = () => __props.eventBus.emit("auth:clear:security-scheme-secrets", { name: __props.name }); | ||
| /** Track if we have set the redirect uri */ | ||
| const hasPrefilledRedirectUri = ref(false); | ||
| const clearOauth2Secrets = () => { | ||
| if (loader.isLoading) return; | ||
| __props.eventBus.emit("auth:clear:security-scheme-secrets", { name: __props.name }); | ||
| }; | ||
| /** Clears stored access and refresh tokens (authorized state) */ | ||
| const handleClearAccessTokens = () => { | ||
| if (loader.isLoading) return; | ||
| handleOauth2SecretsUpdate({ | ||
| "x-scalar-secret-token": "", | ||
| "x-scalar-secret-refresh-token": "" | ||
| }); | ||
| }; | ||
| /** Track redirect URI prefill per flow instance to support document switching */ | ||
| const prefilledFlowIdentity = ref(null); | ||
| const hasHandledRedirectPrefill = ref(false); | ||
| const resolveFlowIdentity = (currentFlow) => JSON.stringify({ | ||
| type: __props.type, | ||
| authorizationUrl: currentFlow && "authorizationUrl" in currentFlow ? currentFlow.authorizationUrl : "", | ||
| tokenUrl: currentFlow && "tokenUrl" in currentFlow ? currentFlow.tokenUrl : "", | ||
| refreshUrl: currentFlow?.refreshUrl ?? "", | ||
| scopes: Object.keys(currentFlow?.scopes ?? {}) | ||
| }); | ||
| /** Default the redirect-uri to the current origin if we have access to window */ | ||
| watch(() => flow.value["x-scalar-secret-redirect-uri"], (newRedirectUri) => { | ||
| watch(() => flow.value, (currentFlow) => { | ||
| if (!currentFlow || !("x-scalar-secret-redirect-uri" in currentFlow)) return; | ||
| const flowIdentity = resolveFlowIdentity(currentFlow); | ||
| if (prefilledFlowIdentity.value !== flowIdentity) { | ||
| prefilledFlowIdentity.value = flowIdentity; | ||
| hasHandledRedirectPrefill.value = false; | ||
| } | ||
| if (hasHandledRedirectPrefill.value) return; | ||
| const newRedirectUri = currentFlow["x-scalar-secret-redirect-uri"]; | ||
| const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(__props.options); | ||
| if (hasPrefilledRedirectUri.value || newRedirectUri || !defaultRedirectUri || !("x-scalar-secret-redirect-uri" in flow.value)) return; | ||
| hasPrefilledRedirectUri.value = true; | ||
| hasHandledRedirectPrefill.value = true; | ||
| if (newRedirectUri || !defaultRedirectUri) return; | ||
| handleOauth2SecretsUpdate({ "x-scalar-secret-redirect-uri": defaultRedirectUri }); | ||
@@ -85,2 +112,30 @@ }, { immediate: true }); | ||
| }; | ||
| /** Whether the current flow supports refreshing the access token */ | ||
| const supportsRefreshToken = computed(() => __props.type !== "implicit"); | ||
| /** | ||
| * Refresh URL placeholder, shows tokenUrl as hint if refreshUrl is not specified. | ||
| * This helps users understand that tokenUrl will be used as fallback. | ||
| */ | ||
| const refreshUrlPlaceholder = computed(() => { | ||
| if ("tokenUrl" in flow.value && flow.value.tokenUrl) return flow.value.tokenUrl; | ||
| return "https://galaxy.scalar.com/oauth/refresh"; | ||
| }); | ||
| /** | ||
| * Uses the stored refresh token to obtain a new access token | ||
| * via grant_type=refresh_token. | ||
| */ | ||
| const handleRefresh = async () => { | ||
| if (loader.isLoading || __props.type === "implicit") return; | ||
| loader.start(); | ||
| const [error, tokens] = await refreshOauth2Token(__props.flows, __props.type, __props.proxyUrl, __props.server, getEnvironmentVariables(__props.environment)); | ||
| await loader.clear(); | ||
| if (tokens?.accessToken) handleOauth2SecretsUpdate({ | ||
| "x-scalar-secret-token": tokens.accessToken, | ||
| ...tokens.refreshToken ? { "x-scalar-secret-refresh-token": tokens.refreshToken } : {} | ||
| }); | ||
| else { | ||
| console.error(error); | ||
| toast(error?.message ?? "Failed to refresh token", "error"); | ||
| } | ||
| }; | ||
| /** Updates the secret location */ | ||
@@ -93,31 +148,58 @@ const handleSecretLocationUpdate = (value) => { | ||
| return (_ctx, _cache) => { | ||
| return Boolean(flow.value["x-scalar-secret-token"]) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(unref(DataTableRow_default), null, { | ||
| default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, { | ||
| class: "border-r-transparent", | ||
| environment: __props.environment, | ||
| modelValue: flow.value["x-scalar-secret-token"], | ||
| placeholder: "QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT", | ||
| type: "password", | ||
| "onUpdate:modelValue": _cache[0] || (_cache[0] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-token": v })) | ||
| }, { | ||
| default: withCtx(() => [..._cache[12] || (_cache[12] = [createTextVNode(" Access Token ", -1)])]), | ||
| return Boolean(flow.value["x-scalar-secret-token"]) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [ | ||
| createVNode(unref(DataTableRow_default), null, { | ||
| default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, { | ||
| class: "border-r-transparent", | ||
| environment: __props.environment, | ||
| modelValue: flow.value["x-scalar-secret-token"], | ||
| placeholder: "QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT", | ||
| type: "password", | ||
| "onUpdate:modelValue": _cache[0] || (_cache[0] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-token": v })) | ||
| }, { | ||
| default: withCtx(() => [..._cache[12] || (_cache[12] = [createTextVNode(" Access Token ", -1)])]), | ||
| _: 1 | ||
| }, 8, ["environment", "modelValue"])]), | ||
| _: 1 | ||
| }, 8, ["environment", "modelValue"])]), | ||
| _: 1 | ||
| }), createVNode(unref(DataTableRow_default), { class: "min-w-full" }, { | ||
| default: withCtx(() => [createElementVNode("div", _hoisted_1, [createVNode(unref(ScalarButton), { | ||
| class: "mr-1 p-0 px-2 py-0.5", | ||
| loader: unref(loader), | ||
| size: "sm", | ||
| variant: "outlined", | ||
| onClick: _cache[1] || (_cache[1] = () => handleOauth2SecretsUpdate({ | ||
| "x-scalar-secret-token": "", | ||
| "x-scalar-secret-refresh-token": "" | ||
| })) | ||
| }, { | ||
| default: withCtx(() => [..._cache[13] || (_cache[13] = [createTextVNode(" Clear ", -1)])]), | ||
| }), | ||
| supportsRefreshToken.value ? (openBlock(), createBlock(unref(DataTableRow_default), { key: 0 }, { | ||
| default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, { | ||
| class: "border-r-transparent", | ||
| environment: __props.environment, | ||
| modelValue: flow.value.refreshUrl ?? "", | ||
| placeholder: refreshUrlPlaceholder.value, | ||
| "onUpdate:modelValue": _cache[1] || (_cache[1] = (v) => handleOauth2Update({ refreshUrl: v })) | ||
| }, { | ||
| default: withCtx(() => [..._cache[13] || (_cache[13] = [createTextVNode(" Refresh URL ", -1)])]), | ||
| _: 1 | ||
| }, 8, [ | ||
| "environment", | ||
| "modelValue", | ||
| "placeholder" | ||
| ])]), | ||
| _: 1 | ||
| }, 8, ["loader"])])]), | ||
| _: 1 | ||
| })], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [ | ||
| })) : createCommentVNode("", true), | ||
| createVNode(unref(DataTableRow_default), { class: "min-w-full" }, { | ||
| default: withCtx(() => [createElementVNode("div", _hoisted_1, [supportsRefreshToken.value ? (openBlock(), createBlock(unref(ScalarButton), { | ||
| key: 0, | ||
| class: "p-0 px-2 py-0.5", | ||
| loader: unref(loader), | ||
| size: "sm", | ||
| variant: "outlined", | ||
| onClick: handleRefresh | ||
| }, { | ||
| default: withCtx(() => [..._cache[14] || (_cache[14] = [createTextVNode(" Refresh ", -1)])]), | ||
| _: 1 | ||
| }, 8, ["loader"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), { | ||
| class: "mr-1 p-0 px-2 py-0.5", | ||
| disabled: unref(loader).isLoading, | ||
| size: "sm", | ||
| variant: "outlined", | ||
| onClick: handleClearAccessTokens | ||
| }, { | ||
| default: withCtx(() => [..._cache[15] || (_cache[15] = [createTextVNode(" Clear ", -1)])]), | ||
| _: 1 | ||
| }, 8, ["disabled"])])]), | ||
| _: 1 | ||
| }) | ||
| ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [ | ||
| createVNode(unref(DataTableRow_default), null, { | ||
@@ -135,3 +217,3 @@ default: withCtx(() => ["authorizationUrl" in flow.value ? (openBlock(), createBlock(RequestAuthDataTableInput_default, { | ||
| }, { | ||
| default: withCtx(() => [..._cache[14] || (_cache[14] = [createTextVNode(" Auth URL ", -1)])]), | ||
| default: withCtx(() => [..._cache[16] || (_cache[16] = [createTextVNode(" Auth URL ", -1)])]), | ||
| _: 1 | ||
@@ -148,3 +230,3 @@ }, 8, ["environment", "modelValue"])) : createCommentVNode("", true), "tokenUrl" in flow.value ? (openBlock(), createBlock(RequestAuthDataTableInput_default, { | ||
| }, { | ||
| default: withCtx(() => [..._cache[15] || (_cache[15] = [createTextVNode(" Token URL ", -1)])]), | ||
| default: withCtx(() => [..._cache[17] || (_cache[17] = [createTextVNode(" Token URL ", -1)])]), | ||
| _: 1 | ||
@@ -158,8 +240,9 @@ }, 8, ["environment", "modelValue"])) : createCommentVNode("", true)]), | ||
| modelValue: flow.value["x-scalar-secret-redirect-uri"], | ||
| placeholder: "https://galaxy.scalar.com/callback", | ||
| placeholder: "Optional redirect URL", | ||
| "onUpdate:modelValue": _cache[4] || (_cache[4] = (v) => { | ||
| hasHandledRedirectPrefill.value = true; | ||
| handleOauth2SecretsUpdate({ "x-scalar-secret-redirect-uri": v }); | ||
| }) | ||
| }, { | ||
| default: withCtx(() => [..._cache[16] || (_cache[16] = [createTextVNode(" Redirect URL ", -1)])]), | ||
| default: withCtx(() => [..._cache[18] || (_cache[18] = [createTextVNode(" Redirect URL ", -1)])]), | ||
| _: 1 | ||
@@ -177,3 +260,3 @@ }, 8, ["environment", "modelValue"])]), | ||
| }, { | ||
| default: withCtx(() => [..._cache[17] || (_cache[17] = [createTextVNode(" Username ", -1)])]), | ||
| default: withCtx(() => [..._cache[19] || (_cache[19] = [createTextVNode(" Username ", -1)])]), | ||
| _: 1 | ||
@@ -190,3 +273,3 @@ }, 8, ["environment", "modelValue"])]), | ||
| }, { | ||
| default: withCtx(() => [..._cache[18] || (_cache[18] = [createTextVNode(" Password ", -1)])]), | ||
| default: withCtx(() => [..._cache[20] || (_cache[20] = [createTextVNode(" Password ", -1)])]), | ||
| _: 1 | ||
@@ -203,3 +286,3 @@ }, 8, ["environment", "modelValue"])]), | ||
| }, { | ||
| default: withCtx(() => [..._cache[19] || (_cache[19] = [createTextVNode(" Client ID ", -1)])]), | ||
| default: withCtx(() => [..._cache[21] || (_cache[21] = [createTextVNode(" Client ID ", -1)])]), | ||
| _: 1 | ||
@@ -217,3 +300,3 @@ }, 8, ["environment", "modelValue"])]), | ||
| }, { | ||
| default: withCtx(() => [..._cache[20] || (_cache[20] = [createTextVNode(" Client Secret ", -1)])]), | ||
| default: withCtx(() => [..._cache[22] || (_cache[22] = [createTextVNode(" Client Secret ", -1)])]), | ||
| _: 1 | ||
@@ -231,3 +314,3 @@ }, 8, ["environment", "modelValue"])]), | ||
| }, { | ||
| default: withCtx(() => [..._cache[21] || (_cache[21] = [createTextVNode(" Use PKCE ", -1)])]), | ||
| default: withCtx(() => [..._cache[23] || (_cache[23] = [createTextVNode(" Use PKCE ", -1)])]), | ||
| _: 1 | ||
@@ -250,3 +333,3 @@ }, 8, [ | ||
| }, { | ||
| default: withCtx(() => [..._cache[22] || (_cache[22] = [createTextVNode(" Credentials Location ", -1)])]), | ||
| default: withCtx(() => [..._cache[24] || (_cache[24] = [createTextVNode(" Credentials Location ", -1)])]), | ||
| _: 1 | ||
@@ -273,3 +356,3 @@ }, 8, ["environment", "modelValue"])]), | ||
| class: "mr-1 p-0 px-2 py-0.5", | ||
| loader: unref(loader), | ||
| disabled: unref(loader).isLoading, | ||
| size: "sm", | ||
@@ -279,5 +362,5 @@ variant: "outlined", | ||
| }, { | ||
| default: withCtx(() => [..._cache[23] || (_cache[23] = [createTextVNode(" Clear ", -1)])]), | ||
| default: withCtx(() => [..._cache[25] || (_cache[25] = [createTextVNode(" Clear ", -1)])]), | ||
| _: 1 | ||
| }, 8, ["loader"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), { | ||
| }, 8, ["disabled"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), { | ||
| class: "mr-0.75 p-0 px-2 py-0.5", | ||
@@ -289,3 +372,3 @@ loader: unref(loader), | ||
| }, { | ||
| default: withCtx(() => [..._cache[24] || (_cache[24] = [createTextVNode(" Authorize ", -1)])]), | ||
| default: withCtx(() => [..._cache[26] || (_cache[26] = [createTextVNode(" Authorize ", -1)])]), | ||
| _: 1 | ||
@@ -292,0 +375,0 @@ }, 8, ["loader"])])]), |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OAuth2.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport { authorizeOauth2 } from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void =>\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n\n/** Track if we have set the redirect uri */\nconst hasPrefilledRedirectUri = ref(false)\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () =>\n (flow.value as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ],\n (newRedirectUri) => {\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n if (\n hasPrefilledRedirectUri.value ||\n newRedirectUri ||\n !defaultRedirectUri ||\n !('x-scalar-secret-redirect-uri' in flow.value)\n ) {\n return\n }\n hasPrefilledRedirectUri.value = true\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n \">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"https://galaxy.scalar.com/callback\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":"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"} | ||
| {"version":3,"file":"OAuth2.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport {\n authorizeOauth2,\n refreshOauth2Token,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void => {\n if (loader.isLoading) {\n return\n }\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n}\n\n/** Clears stored access and refresh tokens (authorized state) */\nconst handleClearAccessTokens = (): void => {\n if (loader.isLoading) {\n return\n }\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n}\n\n/** Track redirect URI prefill per flow instance to support document switching */\nconst prefilledFlowIdentity = ref<string | null>(null)\nconst hasHandledRedirectPrefill = ref(false)\n\nconst resolveFlowIdentity = (\n currentFlow: OAuthFlowsObjectSecret[keyof OAuthFlowsObjectSecret] | undefined,\n): string =>\n JSON.stringify({\n type,\n authorizationUrl:\n currentFlow && 'authorizationUrl' in currentFlow\n ? currentFlow.authorizationUrl\n : '',\n tokenUrl:\n currentFlow && 'tokenUrl' in currentFlow ? currentFlow.tokenUrl : '',\n refreshUrl: currentFlow?.refreshUrl ?? '',\n scopes: Object.keys(currentFlow?.scopes ?? {}),\n })\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () => flow.value,\n (currentFlow) => {\n if (!currentFlow || !('x-scalar-secret-redirect-uri' in currentFlow)) {\n return\n }\n\n const flowIdentity = resolveFlowIdentity(currentFlow)\n if (prefilledFlowIdentity.value !== flowIdentity) {\n prefilledFlowIdentity.value = flowIdentity\n hasHandledRedirectPrefill.value = false\n }\n\n if (hasHandledRedirectPrefill.value) {\n return\n }\n\n const newRedirectUri = (currentFlow as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ]\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n hasHandledRedirectPrefill.value = true\n\n if (newRedirectUri || !defaultRedirectUri) {\n return\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Whether the current flow supports refreshing the access token */\nconst supportsRefreshToken = computed(() => type !== 'implicit')\n\n/**\n * Refresh URL placeholder, shows tokenUrl as hint if refreshUrl is not specified.\n * This helps users understand that tokenUrl will be used as fallback.\n */\nconst refreshUrlPlaceholder = computed(() => {\n if ('tokenUrl' in flow.value && flow.value.tokenUrl) {\n return flow.value.tokenUrl\n }\n return 'https://galaxy.scalar.com/oauth/refresh'\n})\n\n/**\n * Uses the stored refresh token to obtain a new access token\n * via grant_type=refresh_token.\n */\nconst handleRefresh = async (): Promise<void> => {\n if (loader.isLoading || type === 'implicit') {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await refreshOauth2Token(\n flows,\n type,\n proxyUrl,\n server,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to refresh token', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"supportsRefreshToken\">\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow.refreshUrl ?? ''\"\n :placeholder=\"refreshUrlPlaceholder\"\n @update:modelValue=\"(v) => handleOauth2Update({ refreshUrl: v })\">\n Refresh URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n v-if=\"supportsRefreshToken\"\n class=\"p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleRefresh\">\n Refresh\n </ScalarButton>\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleClearAccessTokens\">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"Optional redirect URL\"\n @update:modelValue=\"\n (v) => {\n hasHandledRedirectPrefill = true\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":"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"} |
@@ -7,2 +7,3 @@ import { type ModalState } from '@scalar/components'; | ||
| declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { | ||
| cancel: () => any; | ||
| submit: (scopeData: { | ||
@@ -12,4 +13,4 @@ name: string; | ||
| }) => any; | ||
| cancel: () => any; | ||
| }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{ | ||
| onCancel?: (() => any) | undefined; | ||
| onSubmit?: ((scopeData: { | ||
@@ -19,3 +20,2 @@ name: string; | ||
| }) => any) | undefined; | ||
| onCancel?: (() => any) | undefined; | ||
| }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; | ||
@@ -22,0 +22,0 @@ declare const _default: typeof __VLS_export; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OAuthScopesAddModal.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuthScopesAddModal.vue"],"names":[],"mappings":"AAuGA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AASjE,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAC;AAmLF,QAAA,MAAM,YAAY;;cA1KN,MAAM;qBACC,MAAM;;;;;cADb,MAAM;qBACC,MAAM;;;kFA4KvB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} | ||
| {"version":3,"file":"OAuthScopesAddModal.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuthScopesAddModal.vue"],"names":[],"mappings":"AAuGA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AASjE,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAC;AAmLF,QAAA,MAAM,YAAY;;;cA1KN,MAAM;qBACC,MAAM;;;;;cADb,MAAM;qBACC,MAAM;;kFA4KvB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"extract-security-scheme-secrets.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAA2C,MAAM,uCAAuC,CAAA;AAC/G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAA;AAClF,OAAO,KAAK,EAUV,0BAA0B,EAC3B,MAAM,yCAAyC,CAAA;AAQhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8DAA8D,CAAA;AAExG,wGAAwG;AACxG,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,WAAW,CAAC,cAAc,CAAC,CAAA;AAyKjF,6DAA6D;AAC7D,eAAO,MAAM,4BAA4B,GAEvC,QAAQ,oBAAoB,GAAG,WAAW,CAAC,cAAc,CAAC,EAC1D,WAAW,SAAS,EACpB,MAAM,MAAM,EACZ,cAAc,MAAM,KACnB,0BA2DF,CAAA"} | ||
| {"version":3,"file":"extract-security-scheme-secrets.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAA2C,MAAM,uCAAuC,CAAA;AAC/G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAA;AAClF,OAAO,KAAK,EAUV,0BAA0B,EAC3B,MAAM,yCAAyC,CAAA;AAQhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8DAA8D,CAAA;AAExG,wGAAwG;AACxG,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,WAAW,CAAC,cAAc,CAAC,CAAA;AAkLjF,6DAA6D;AAC7D,eAAO,MAAM,4BAA4B,GAEvC,QAAQ,oBAAoB,GAAG,WAAW,CAAC,cAAc,CAAC,EAC1D,WAAW,SAAS,EACpB,MAAM,MAAM,EACZ,cAAc,MAAM,KACnB,0BA2DF,CAAA"} |
@@ -8,2 +8,4 @@ import type { ErrorResponse } from '@scalar/helpers/errors/normalize-error'; | ||
| }; | ||
| /** Flow types that support token refresh (all except implicit) */ | ||
| type RefreshableFlows = Exclude<keyof OAuthFlowsObjectSecret, 'implicit'>; | ||
| /** | ||
@@ -21,2 +23,16 @@ * Authorize oauth2 flow | ||
| environmentVariables?: Record<string, string>) => Promise<ErrorResponse<OAuth2Tokens>>; | ||
| /** | ||
| * Exchange a refresh token for a new access token using the `grant_type=refresh_token` flow. | ||
| * | ||
| * Uses the stored refresh token, client credentials, and the token URL (or refreshUrl when available) | ||
| * to request fresh tokens from the authorization server per RFC 6749 Section 6. | ||
| */ | ||
| export declare const refreshOauth2Token: (flows: OAuthFlowsObjectSecret, type: RefreshableFlows, | ||
| /** If we want to use the proxy */ | ||
| proxyUrl: string, | ||
| /** We use the active server to set a base for relative URLs */ | ||
| activeServer: ServerObject | null, | ||
| /** Flattened environment variables used to resolve server URL templates */ | ||
| environmentVariables?: Record<string, string>) => Promise<ErrorResponse<OAuth2Tokens>>; | ||
| export {}; | ||
| //# sourceMappingURL=oauth.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAK3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAErF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAYhG,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AA4DD;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,sBAAsB,EAC7B,MAAM,MAAM,sBAAsB,EAClC,gBAAgB,MAAM,EAAE;AACxB,wEAAwE;AACxE,cAAc,YAAY,GAAG,IAAI;AACjC,kCAAkC;AAClC,UAAU,MAAM;AAChB,6FAA6F;AAC7F,uBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAChD,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAwLrC,CAAA"} | ||
| {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAK3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAErF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAYhG,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,kEAAkE;AAClE,KAAK,gBAAgB,GAAG,OAAO,CAAC,MAAM,sBAAsB,EAAE,UAAU,CAAC,CAAA;AA4DzE;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,sBAAsB,EAC7B,MAAM,MAAM,sBAAsB,EAClC,gBAAgB,MAAM,EAAE;AACxB,wEAAwE;AACxE,cAAc,YAAY,GAAG,IAAI;AACjC,kCAAkC;AAClC,UAAU,MAAM;AAChB,6FAA6F;AAC7F,uBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAChD,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAwLrC,CAAA;AA2HD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,sBAAsB,EAC7B,MAAM,gBAAgB;AACtB,kCAAkC;AAClC,UAAU,MAAM;AAChB,+DAA+D;AAC/D,cAAc,YAAY,GAAG,IAAI;AACjC,2EAA2E;AAC3E,uBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAChD,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CA+ErC,CAAA"} |
@@ -184,5 +184,47 @@ import { makeUrlAbsolute } from "@scalar/helpers/url/make-url-absolute"; | ||
| }; | ||
| /** | ||
| * Exchange a refresh token for a new access token using the `grant_type=refresh_token` flow. | ||
| * | ||
| * Uses the stored refresh token, client credentials, and the token URL (or refreshUrl when available) | ||
| * to request fresh tokens from the authorization server per RFC 6749 Section 6. | ||
| */ | ||
| var refreshOauth2Token = async (flows, type, proxyUrl, activeServer, environmentVariables = {}) => { | ||
| const flow = flows[type]; | ||
| if (!flow) return [/* @__PURE__ */ new Error("OAuth2 flow was not defined"), null]; | ||
| const refreshToken = flow["x-scalar-secret-refresh-token"]; | ||
| if (!refreshToken) return [/* @__PURE__ */ new Error("No refresh token available"), null]; | ||
| const formData = new URLSearchParams(); | ||
| formData.set("grant_type", "refresh_token"); | ||
| formData.set("refresh_token", refreshToken); | ||
| const addCredentialsToBody = flow["x-scalar-credentials-location"] === "body"; | ||
| const hasClientSecret = Boolean(flow["x-scalar-secret-client-secret"]); | ||
| if (addCredentialsToBody || type === "authorizationCode" && !hasClientSecret) formData.set("client_id", flow["x-scalar-secret-client-id"]); | ||
| if (addCredentialsToBody && hasClientSecret) formData.set("client_secret", flow["x-scalar-secret-client-secret"]); | ||
| if (flow["x-scalar-security-body"]) Object.entries(flow["x-scalar-security-body"]).forEach(([key, value]) => { | ||
| if (value !== void 0 && value !== null) formData.set(key, String(value)); | ||
| }); | ||
| try { | ||
| const headers = { "Content-Type": "application/x-www-form-urlencoded" }; | ||
| if (!addCredentialsToBody && hasClientSecret) headers.Authorization = `Basic ${encode(`${flow["x-scalar-secret-client-id"]}:${flow["x-scalar-secret-client-secret"]}`)}`; | ||
| const absoluteRefreshUrl = makeUrlAbsolute(flow.refreshUrl || flow["x-scalar-secret-token-url"] || flow.tokenUrl, getActiveServerBase(activeServer, environmentVariables)); | ||
| const url = shouldUseProxy(proxyUrl, absoluteRefreshUrl) ? `${proxyUrl}?${new URLSearchParams([["scalar_url", absoluteRefreshUrl]]).toString()}` : absoluteRefreshUrl; | ||
| const responseData = await (await fetch(url, { | ||
| method: "POST", | ||
| headers, | ||
| body: formData | ||
| })).json(); | ||
| const accessToken = responseData[flow["x-tokenName"] || "access_token"]; | ||
| const newRefreshToken = responseData.refresh_token; | ||
| if (!accessToken) return [new Error(responseData.error_description ?? responseData.error ?? "Token refresh failed"), null]; | ||
| return [null, { | ||
| accessToken, | ||
| ...typeof newRefreshToken === "string" ? { refreshToken: newRefreshToken } : { refreshToken } | ||
| }]; | ||
| } catch { | ||
| return [/* @__PURE__ */ new Error("Failed to refresh the access token. Please re-authorize."), null]; | ||
| } | ||
| }; | ||
| //#endregion | ||
| export { authorizeOauth2 }; | ||
| export { authorizeOauth2, refreshOauth2Token }; | ||
| //# sourceMappingURL=oauth.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"oauth.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/oauth.ts"],"sourcesContent":["import type { ErrorResponse } from '@scalar/helpers/errors/normalize-error'\nimport { replaceEnvVariables, replacePathVariables } from '@scalar/helpers/regex/replace-variables'\nimport { isRelativePath } from '@scalar/helpers/url/is-relative-path'\nimport { makeUrlAbsolute } from '@scalar/helpers/url/make-url-absolute'\nimport { shouldUseProxy } from '@scalar/helpers/url/redirect-to-proxy'\nimport type { OAuthFlowsObjectSecret } from '@scalar/workspace-store/request-example'\nimport { getServerVariables } from '@scalar/workspace-store/request-example'\nimport type { ServerObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { encode, fromUint8Array } from 'js-base64'\n\n/** Oauth2 security schemes which are not implicit */\ntype NonImplicitFlows = Omit<OAuthFlowsObjectSecret, 'implicit'>\n\ntype PKCEState = {\n codeVerifier: string\n codeChallenge: string\n codeChallengeMethod: string\n}\n\nexport type OAuth2Tokens = {\n accessToken: string\n refreshToken?: string\n}\n\nconst getServerUrl = (activeServer: ServerObject | null, environmentVariables: Record<string, string> = {}) => {\n return replaceEnvVariables(\n replacePathVariables(activeServer?.url ?? '', getServerVariables(activeServer)),\n environmentVariables,\n )\n}\n\nconst getActiveServerBase = (activeServer: ServerObject | null, environmentVariables: Record<string, string> = {}) => {\n const serverUrl = getServerUrl(activeServer, environmentVariables)\n\n if (!serverUrl) {\n return {}\n }\n\n if (isRelativePath(serverUrl)) {\n return typeof window === 'undefined' ? {} : { basePath: serverUrl }\n }\n\n return { baseUrl: serverUrl }\n}\n\n/**\n * Generates a random string for PKCE code verifier\n *\n * @see https://www.rfc-editor.org/rfc/rfc7636#page-8\n */\nconst generateCodeVerifier = (): string => {\n // Generate 32 random bytes\n const buffer = new Uint8Array(32)\n crypto.getRandomValues(buffer)\n\n // Base64URL encode the bytes\n return fromUint8Array(buffer, true)\n}\n\n/**\n * Creates a code challenge from the code verifier\n */\nconst generateCodeChallenge = async (verifier: string, encoding: 'SHA-256' | 'plain'): Promise<string> => {\n if (encoding === 'plain') {\n return verifier\n }\n\n // If crypto.subtle.digest is not a function, we cannot use SHA-256\n if (typeof crypto?.subtle?.digest !== 'function') {\n console.warn('SHA-256 is only supported when using https, using a plain text code challenge instead.')\n return verifier\n }\n\n // ASCII encoding is just taking the lower 8 bits of each character\n const encoder = new TextEncoder()\n const data = encoder.encode(verifier)\n const digest = await crypto.subtle.digest('SHA-256', data)\n\n // Base64URL encode the bytes\n return fromUint8Array(new Uint8Array(digest), true)\n}\n\n/**\n * Authorize oauth2 flow\n *\n * @returns the resolved oauth2 tokens\n */\nexport const authorizeOauth2 = async (\n flows: OAuthFlowsObjectSecret,\n type: keyof OAuthFlowsObjectSecret,\n selectedScopes: string[],\n /** We use the active server to set a base for relative redirect uris */\n activeServer: ServerObject | null,\n /** If we want to use the proxy */\n proxyUrl: string,\n /** Flattened environment variables used to resolve server URL templates like `{protocol}` */\n environmentVariables: Record<string, string> = {},\n): Promise<ErrorResponse<OAuth2Tokens>> => {\n const flow = flows[type]\n\n try {\n if (!flow) {\n return [new Error('Flow not found'), null]\n }\n\n const scopes = selectedScopes.join(' ')\n\n // Client Credentials or Password Flow\n if (type === 'clientCredentials' || type === 'password') {\n return authorizeServers(\n flows,\n type,\n scopes,\n {\n proxyUrl,\n },\n activeServer,\n environmentVariables,\n )\n }\n\n // Generate a random state string with the length of 8 characters\n const state = (Math.random() + 1).toString(36).substring(2, 10)\n\n const authorizationUrl = makeUrlAbsolute(\n flows[type]!['x-scalar-secret-auth-url'] ?? flows[type]!.authorizationUrl,\n getActiveServerBase(activeServer, environmentVariables),\n )\n\n const url = new URL(authorizationUrl)\n\n /** Special PKCE state */\n let pkce: PKCEState | null = null\n\n // Params unique to the flows\n if (type === 'implicit') {\n url.searchParams.set('response_type', 'token')\n } else if (type === 'authorizationCode') {\n const typedFlow = flows[type]! // Safe to assert due to earlier check\n\n url.searchParams.set('response_type', 'code')\n\n // PKCE\n if (typedFlow['x-usePkce'] !== 'no') {\n const codeVerifier = generateCodeVerifier()\n const codeChallenge = await generateCodeChallenge(codeVerifier, typedFlow['x-usePkce'])\n\n // Set state for later verification\n pkce = {\n codeVerifier,\n codeChallenge,\n codeChallengeMethod: typedFlow['x-usePkce'] === 'SHA-256' ? 'S256' : 'plain',\n }\n\n // Set the code challenge and method on the url\n url.searchParams.set('code_challenge', codeChallenge)\n url.searchParams.set('code_challenge_method', pkce.codeChallengeMethod)\n }\n }\n\n const typedFlow = flows[type]! // Safe to assert due to earlier check\n\n // Handle relative redirect uris\n if (typedFlow['x-scalar-secret-redirect-uri'].startsWith('/')) {\n const baseUrl =\n getServerUrl(activeServer, environmentVariables) || window.location.origin + window.location.pathname\n const redirectUri = new URL(typedFlow['x-scalar-secret-redirect-uri'], baseUrl).toString()\n\n url.searchParams.set('redirect_uri', redirectUri)\n } else {\n url.searchParams.set('redirect_uri', typedFlow['x-scalar-secret-redirect-uri'])\n }\n\n if (flow['x-scalar-security-query']) {\n Object.keys(flow['x-scalar-security-query']).forEach((key: string): void => {\n const value = flow['x-scalar-security-query']?.[key]\n if (!value) {\n return\n }\n url.searchParams.set(key, value)\n })\n }\n\n // Common to all flows\n url.searchParams.set('client_id', flow['x-scalar-secret-client-id'])\n url.searchParams.set('state', state)\n if (scopes) {\n url.searchParams.set('scope', scopes)\n }\n\n const windowFeatures = 'left=100,top=100,width=800,height=600'\n const authWindow = window.open(url, 'openAuth2Window', windowFeatures)\n\n // Open up a window and poll until closed or we have the data we want\n if (authWindow) {\n // We need to return a promise here due to the setInterval\n return new Promise<ErrorResponse<OAuth2Tokens>>((resolve) => {\n const checkWindowClosed = setInterval(() => {\n let accessToken: string | null = null\n let refreshToken: string | null = null\n let code: string | null = null\n let error: string | null = null\n let errorDescription: string | null = null\n\n try {\n const urlParams = new URL(authWindow.location.href).searchParams\n const tokenName = flow['x-tokenName'] || 'access_token'\n accessToken = urlParams.get(tokenName)\n refreshToken = urlParams.get('refresh_token')\n code = urlParams.get('code')\n\n error = urlParams.get('error')\n errorDescription = urlParams.get('error_description')\n\n // We may get the properties in a hash\n const hashParams = new URLSearchParams(authWindow.location.href.split('#')[1])\n accessToken ||= hashParams.get(tokenName)\n refreshToken ||= hashParams.get('refresh_token')\n code ||= hashParams.get('code')\n error ||= hashParams.get('error')\n errorDescription ||= hashParams.get('error_description')\n } catch (_e) {\n // Ignore CORS error from popup\n }\n\n // The window has closed OR we have what we are looking for so we stop polling\n if (authWindow.closed || accessToken || code || error) {\n clearInterval(checkWindowClosed)\n authWindow.close()\n\n if (error) {\n resolve([new Error(`OAuth error: ${error}${errorDescription ? ` (${errorDescription})` : ''}`), null])\n }\n\n // Implicit Flow\n else if (accessToken) {\n // State is a hash fragment and cannot be found through search params\n const _state = authWindow.location.href.match(/state=([^&]*)/)?.[1]\n\n if (_state === state) {\n resolve([null, { accessToken, ...(refreshToken ? { refreshToken } : {}) }])\n } else {\n resolve([new Error('State mismatch'), null])\n }\n }\n\n // Authorization Code Server Flow\n else if (code && type === 'authorizationCode') {\n const _state = new URL(authWindow.location.href).searchParams.get('state')\n\n if (_state === state) {\n // biome-ignore lint/nursery/noFloatingPromises: output of authorizeServers must be returned\n authorizeServers(\n flows,\n type,\n scopes,\n {\n code,\n pkce,\n proxyUrl,\n },\n activeServer,\n environmentVariables,\n ).then(resolve)\n } else {\n resolve([new Error('State mismatch'), null])\n }\n }\n // User closed window without authorizing\n else {\n clearInterval(checkWindowClosed)\n resolve([new Error('Window was closed without granting authorization'), null])\n }\n }\n }, 200)\n })\n }\n return [new Error('Failed to open auth window'), null]\n } catch (_) {\n return [new Error('Failed to authorize oauth2 flow'), null]\n }\n}\n\n/**\n * Makes the BE authorization call to grab the token server to server\n * Used for clientCredentials and authorizationCode\n */\nconst authorizeServers = async (\n flows: NonImplicitFlows,\n type: keyof NonImplicitFlows,\n scopes: string,\n {\n code,\n pkce,\n proxyUrl,\n }: {\n code?: string\n pkce?: PKCEState | null\n proxyUrl?: string\n } = {},\n activeServer: ServerObject | null,\n environmentVariables: Record<string, string> = {},\n): Promise<ErrorResponse<OAuth2Tokens>> => {\n const flow = flows[type]\n\n if (!flow) {\n return [new Error('OAuth2 flow was not defined'), null]\n }\n\n const formData = new URLSearchParams()\n\n // Only client credentials and password flows support scopes in the token request\n if (scopes && (type === 'clientCredentials' || type === 'password')) {\n formData.set('scope', scopes)\n }\n\n /** Where to add the credentials */\n const addCredentialsToBody = flow['x-scalar-credentials-location'] === 'body'\n const hasClientSecret = Boolean(flow['x-scalar-secret-client-secret'])\n /**\n * Public authorization-code clients still need client_id in the token body.\n * We only send it implicitly for that case to avoid conflicting with Basic auth.\n */\n const shouldSendClientIdInBody = addCredentialsToBody || (type === 'authorizationCode' && !hasClientSecret)\n\n if (shouldSendClientIdInBody) {\n formData.set('client_id', flow['x-scalar-secret-client-id'])\n }\n if (addCredentialsToBody && hasClientSecret) {\n formData.set('client_secret', flow['x-scalar-secret-client-secret'])\n }\n if ('x-scalar-secret-redirect-uri' in flow && flow['x-scalar-secret-redirect-uri']) {\n formData.set('redirect_uri', flow['x-scalar-secret-redirect-uri'])\n }\n\n // Authorization Code\n if (code) {\n formData.set('code', code)\n formData.set('grant_type', 'authorization_code')\n\n // PKCE\n if (pkce) {\n formData.set('code_verifier', pkce.codeVerifier)\n }\n }\n // Password\n else if (type === 'password') {\n const typedFlow = flows[type]! // Safe to assert due to earlier check\n formData.set('grant_type', 'password')\n formData.set('username', typedFlow['x-scalar-secret-username'])\n formData.set('password', typedFlow['x-scalar-secret-password'])\n }\n // Client Credentials\n else {\n formData.set('grant_type', 'client_credentials')\n }\n\n // Additional request body parameters\n if (flow['x-scalar-security-body']) {\n Object.entries(flow['x-scalar-security-body']).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n formData.set(key, String(value))\n }\n })\n }\n\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n }\n\n // Add client id + secret to headers for confidential clients.\n if (!addCredentialsToBody && hasClientSecret) {\n headers.Authorization = `Basic ${encode(`${flow['x-scalar-secret-client-id']}:${flow['x-scalar-secret-client-secret']}`)}`\n }\n\n // Check if we should use the proxy\n const tokenUrl = makeUrlAbsolute(\n flow['x-scalar-secret-token-url'] ?? flow.tokenUrl,\n getActiveServerBase(activeServer, environmentVariables),\n )\n const url = shouldUseProxy(proxyUrl, tokenUrl)\n ? `${proxyUrl}?${new URLSearchParams([['scalar_url', tokenUrl]]).toString()}`\n : tokenUrl\n\n // Make the call\n const resp = await fetch(url, {\n method: 'POST',\n headers,\n body: formData,\n })\n const responseData = await resp.json()\n\n // Use custom token name if specified, otherwise default to access_token\n const tokenName = flow['x-tokenName'] || 'access_token'\n const accessToken = responseData[tokenName]\n const refreshToken = responseData.refresh_token\n\n return [null, { accessToken, ...(typeof refreshToken === 'string' ? { refreshToken } : {}) }]\n } catch {\n return [new Error('Failed to get an access token. Please check your credentials.'), null]\n }\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"oauth.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/oauth.ts"],"sourcesContent":["import type { ErrorResponse } from '@scalar/helpers/errors/normalize-error'\nimport { replaceEnvVariables, replacePathVariables } from '@scalar/helpers/regex/replace-variables'\nimport { isRelativePath } from '@scalar/helpers/url/is-relative-path'\nimport { makeUrlAbsolute } from '@scalar/helpers/url/make-url-absolute'\nimport { shouldUseProxy } from '@scalar/helpers/url/redirect-to-proxy'\nimport type { OAuthFlowsObjectSecret } from '@scalar/workspace-store/request-example'\nimport { getServerVariables } from '@scalar/workspace-store/request-example'\nimport type { ServerObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { encode, fromUint8Array } from 'js-base64'\n\n/** Oauth2 security schemes which are not implicit */\ntype NonImplicitFlows = Omit<OAuthFlowsObjectSecret, 'implicit'>\n\ntype PKCEState = {\n codeVerifier: string\n codeChallenge: string\n codeChallengeMethod: string\n}\n\nexport type OAuth2Tokens = {\n accessToken: string\n refreshToken?: string\n}\n\n/** Flow types that support token refresh (all except implicit) */\ntype RefreshableFlows = Exclude<keyof OAuthFlowsObjectSecret, 'implicit'>\n\nconst getServerUrl = (activeServer: ServerObject | null, environmentVariables: Record<string, string> = {}) => {\n return replaceEnvVariables(\n replacePathVariables(activeServer?.url ?? '', getServerVariables(activeServer)),\n environmentVariables,\n )\n}\n\nconst getActiveServerBase = (activeServer: ServerObject | null, environmentVariables: Record<string, string> = {}) => {\n const serverUrl = getServerUrl(activeServer, environmentVariables)\n\n if (!serverUrl) {\n return {}\n }\n\n if (isRelativePath(serverUrl)) {\n return typeof window === 'undefined' ? {} : { basePath: serverUrl }\n }\n\n return { baseUrl: serverUrl }\n}\n\n/**\n * Generates a random string for PKCE code verifier\n *\n * @see https://www.rfc-editor.org/rfc/rfc7636#page-8\n */\nconst generateCodeVerifier = (): string => {\n // Generate 32 random bytes\n const buffer = new Uint8Array(32)\n crypto.getRandomValues(buffer)\n\n // Base64URL encode the bytes\n return fromUint8Array(buffer, true)\n}\n\n/**\n * Creates a code challenge from the code verifier\n */\nconst generateCodeChallenge = async (verifier: string, encoding: 'SHA-256' | 'plain'): Promise<string> => {\n if (encoding === 'plain') {\n return verifier\n }\n\n // If crypto.subtle.digest is not a function, we cannot use SHA-256\n if (typeof crypto?.subtle?.digest !== 'function') {\n console.warn('SHA-256 is only supported when using https, using a plain text code challenge instead.')\n return verifier\n }\n\n // ASCII encoding is just taking the lower 8 bits of each character\n const encoder = new TextEncoder()\n const data = encoder.encode(verifier)\n const digest = await crypto.subtle.digest('SHA-256', data)\n\n // Base64URL encode the bytes\n return fromUint8Array(new Uint8Array(digest), true)\n}\n\n/**\n * Authorize oauth2 flow\n *\n * @returns the resolved oauth2 tokens\n */\nexport const authorizeOauth2 = async (\n flows: OAuthFlowsObjectSecret,\n type: keyof OAuthFlowsObjectSecret,\n selectedScopes: string[],\n /** We use the active server to set a base for relative redirect uris */\n activeServer: ServerObject | null,\n /** If we want to use the proxy */\n proxyUrl: string,\n /** Flattened environment variables used to resolve server URL templates like `{protocol}` */\n environmentVariables: Record<string, string> = {},\n): Promise<ErrorResponse<OAuth2Tokens>> => {\n const flow = flows[type]\n\n try {\n if (!flow) {\n return [new Error('Flow not found'), null]\n }\n\n const scopes = selectedScopes.join(' ')\n\n // Client Credentials or Password Flow\n if (type === 'clientCredentials' || type === 'password') {\n return authorizeServers(\n flows,\n type,\n scopes,\n {\n proxyUrl,\n },\n activeServer,\n environmentVariables,\n )\n }\n\n // Generate a random state string with the length of 8 characters\n const state = (Math.random() + 1).toString(36).substring(2, 10)\n\n const authorizationUrl = makeUrlAbsolute(\n flows[type]!['x-scalar-secret-auth-url'] ?? flows[type]!.authorizationUrl,\n getActiveServerBase(activeServer, environmentVariables),\n )\n\n const url = new URL(authorizationUrl)\n\n /** Special PKCE state */\n let pkce: PKCEState | null = null\n\n // Params unique to the flows\n if (type === 'implicit') {\n url.searchParams.set('response_type', 'token')\n } else if (type === 'authorizationCode') {\n const typedFlow = flows[type]! // Safe to assert due to earlier check\n\n url.searchParams.set('response_type', 'code')\n\n // PKCE\n if (typedFlow['x-usePkce'] !== 'no') {\n const codeVerifier = generateCodeVerifier()\n const codeChallenge = await generateCodeChallenge(codeVerifier, typedFlow['x-usePkce'])\n\n // Set state for later verification\n pkce = {\n codeVerifier,\n codeChallenge,\n codeChallengeMethod: typedFlow['x-usePkce'] === 'SHA-256' ? 'S256' : 'plain',\n }\n\n // Set the code challenge and method on the url\n url.searchParams.set('code_challenge', codeChallenge)\n url.searchParams.set('code_challenge_method', pkce.codeChallengeMethod)\n }\n }\n\n const typedFlow = flows[type]! // Safe to assert due to earlier check\n\n // Handle relative redirect uris\n if (typedFlow['x-scalar-secret-redirect-uri'].startsWith('/')) {\n const baseUrl =\n getServerUrl(activeServer, environmentVariables) || window.location.origin + window.location.pathname\n const redirectUri = new URL(typedFlow['x-scalar-secret-redirect-uri'], baseUrl).toString()\n\n url.searchParams.set('redirect_uri', redirectUri)\n } else {\n url.searchParams.set('redirect_uri', typedFlow['x-scalar-secret-redirect-uri'])\n }\n\n if (flow['x-scalar-security-query']) {\n Object.keys(flow['x-scalar-security-query']).forEach((key: string): void => {\n const value = flow['x-scalar-security-query']?.[key]\n if (!value) {\n return\n }\n url.searchParams.set(key, value)\n })\n }\n\n // Common to all flows\n url.searchParams.set('client_id', flow['x-scalar-secret-client-id'])\n url.searchParams.set('state', state)\n if (scopes) {\n url.searchParams.set('scope', scopes)\n }\n\n const windowFeatures = 'left=100,top=100,width=800,height=600'\n const authWindow = window.open(url, 'openAuth2Window', windowFeatures)\n\n // Open up a window and poll until closed or we have the data we want\n if (authWindow) {\n // We need to return a promise here due to the setInterval\n return new Promise<ErrorResponse<OAuth2Tokens>>((resolve) => {\n const checkWindowClosed = setInterval(() => {\n let accessToken: string | null = null\n let refreshToken: string | null = null\n let code: string | null = null\n let error: string | null = null\n let errorDescription: string | null = null\n\n try {\n const urlParams = new URL(authWindow.location.href).searchParams\n const tokenName = flow['x-tokenName'] || 'access_token'\n accessToken = urlParams.get(tokenName)\n refreshToken = urlParams.get('refresh_token')\n code = urlParams.get('code')\n\n error = urlParams.get('error')\n errorDescription = urlParams.get('error_description')\n\n // We may get the properties in a hash\n const hashParams = new URLSearchParams(authWindow.location.href.split('#')[1])\n accessToken ||= hashParams.get(tokenName)\n refreshToken ||= hashParams.get('refresh_token')\n code ||= hashParams.get('code')\n error ||= hashParams.get('error')\n errorDescription ||= hashParams.get('error_description')\n } catch (_e) {\n // Ignore CORS error from popup\n }\n\n // The window has closed OR we have what we are looking for so we stop polling\n if (authWindow.closed || accessToken || code || error) {\n clearInterval(checkWindowClosed)\n authWindow.close()\n\n if (error) {\n resolve([new Error(`OAuth error: ${error}${errorDescription ? ` (${errorDescription})` : ''}`), null])\n }\n\n // Implicit Flow\n else if (accessToken) {\n // State is a hash fragment and cannot be found through search params\n const _state = authWindow.location.href.match(/state=([^&]*)/)?.[1]\n\n if (_state === state) {\n resolve([null, { accessToken, ...(refreshToken ? { refreshToken } : {}) }])\n } else {\n resolve([new Error('State mismatch'), null])\n }\n }\n\n // Authorization Code Server Flow\n else if (code && type === 'authorizationCode') {\n const _state = new URL(authWindow.location.href).searchParams.get('state')\n\n if (_state === state) {\n // biome-ignore lint/nursery/noFloatingPromises: output of authorizeServers must be returned\n authorizeServers(\n flows,\n type,\n scopes,\n {\n code,\n pkce,\n proxyUrl,\n },\n activeServer,\n environmentVariables,\n ).then(resolve)\n } else {\n resolve([new Error('State mismatch'), null])\n }\n }\n // User closed window without authorizing\n else {\n clearInterval(checkWindowClosed)\n resolve([new Error('Window was closed without granting authorization'), null])\n }\n }\n }, 200)\n })\n }\n return [new Error('Failed to open auth window'), null]\n } catch (_) {\n return [new Error('Failed to authorize oauth2 flow'), null]\n }\n}\n\n/**\n * Makes the BE authorization call to grab the token server to server\n * Used for clientCredentials and authorizationCode\n */\nconst authorizeServers = async (\n flows: NonImplicitFlows,\n type: keyof NonImplicitFlows,\n scopes: string,\n {\n code,\n pkce,\n proxyUrl,\n }: {\n code?: string\n pkce?: PKCEState | null\n proxyUrl?: string\n } = {},\n activeServer: ServerObject | null,\n environmentVariables: Record<string, string> = {},\n): Promise<ErrorResponse<OAuth2Tokens>> => {\n const flow = flows[type]\n\n if (!flow) {\n return [new Error('OAuth2 flow was not defined'), null]\n }\n\n const formData = new URLSearchParams()\n\n // Only client credentials and password flows support scopes in the token request\n if (scopes && (type === 'clientCredentials' || type === 'password')) {\n formData.set('scope', scopes)\n }\n\n /** Where to add the credentials */\n const addCredentialsToBody = flow['x-scalar-credentials-location'] === 'body'\n const hasClientSecret = Boolean(flow['x-scalar-secret-client-secret'])\n /**\n * Public authorization-code clients still need client_id in the token body.\n * We only send it implicitly for that case to avoid conflicting with Basic auth.\n */\n const shouldSendClientIdInBody = addCredentialsToBody || (type === 'authorizationCode' && !hasClientSecret)\n\n if (shouldSendClientIdInBody) {\n formData.set('client_id', flow['x-scalar-secret-client-id'])\n }\n if (addCredentialsToBody && hasClientSecret) {\n formData.set('client_secret', flow['x-scalar-secret-client-secret'])\n }\n if ('x-scalar-secret-redirect-uri' in flow && flow['x-scalar-secret-redirect-uri']) {\n formData.set('redirect_uri', flow['x-scalar-secret-redirect-uri'])\n }\n\n // Authorization Code\n if (code) {\n formData.set('code', code)\n formData.set('grant_type', 'authorization_code')\n\n // PKCE\n if (pkce) {\n formData.set('code_verifier', pkce.codeVerifier)\n }\n }\n // Password\n else if (type === 'password') {\n const typedFlow = flows[type]! // Safe to assert due to earlier check\n formData.set('grant_type', 'password')\n formData.set('username', typedFlow['x-scalar-secret-username'])\n formData.set('password', typedFlow['x-scalar-secret-password'])\n }\n // Client Credentials\n else {\n formData.set('grant_type', 'client_credentials')\n }\n\n // Additional request body parameters\n if (flow['x-scalar-security-body']) {\n Object.entries(flow['x-scalar-security-body']).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n formData.set(key, String(value))\n }\n })\n }\n\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n }\n\n // Add client id + secret to headers for confidential clients.\n if (!addCredentialsToBody && hasClientSecret) {\n headers.Authorization = `Basic ${encode(`${flow['x-scalar-secret-client-id']}:${flow['x-scalar-secret-client-secret']}`)}`\n }\n\n // Check if we should use the proxy\n const tokenUrl = makeUrlAbsolute(\n flow['x-scalar-secret-token-url'] ?? flow.tokenUrl,\n getActiveServerBase(activeServer, environmentVariables),\n )\n const url = shouldUseProxy(proxyUrl, tokenUrl)\n ? `${proxyUrl}?${new URLSearchParams([['scalar_url', tokenUrl]]).toString()}`\n : tokenUrl\n\n // Make the call\n const resp = await fetch(url, {\n method: 'POST',\n headers,\n body: formData,\n })\n const responseData = await resp.json()\n\n // Use custom token name if specified, otherwise default to access_token\n const tokenName = flow['x-tokenName'] || 'access_token'\n const accessToken = responseData[tokenName]\n const refreshToken = responseData.refresh_token\n\n return [null, { accessToken, ...(typeof refreshToken === 'string' ? { refreshToken } : {}) }]\n } catch {\n return [new Error('Failed to get an access token. Please check your credentials.'), null]\n }\n}\n\n/**\n * Exchange a refresh token for a new access token using the `grant_type=refresh_token` flow.\n *\n * Uses the stored refresh token, client credentials, and the token URL (or refreshUrl when available)\n * to request fresh tokens from the authorization server per RFC 6749 Section 6.\n */\nexport const refreshOauth2Token = async (\n flows: OAuthFlowsObjectSecret,\n type: RefreshableFlows,\n /** If we want to use the proxy */\n proxyUrl: string,\n /** We use the active server to set a base for relative URLs */\n activeServer: ServerObject | null,\n /** Flattened environment variables used to resolve server URL templates */\n environmentVariables: Record<string, string> = {},\n): Promise<ErrorResponse<OAuth2Tokens>> => {\n const flow = flows[type]\n\n if (!flow) {\n return [new Error('OAuth2 flow was not defined'), null]\n }\n\n const refreshToken = flow['x-scalar-secret-refresh-token']\n if (!refreshToken) {\n return [new Error('No refresh token available'), null]\n }\n\n const formData = new URLSearchParams()\n formData.set('grant_type', 'refresh_token')\n formData.set('refresh_token', refreshToken)\n\n const addCredentialsToBody = flow['x-scalar-credentials-location'] === 'body'\n const hasClientSecret = Boolean(flow['x-scalar-secret-client-secret'])\n /**\n * Public authorization-code clients still need client_id in the refresh body per RFC 6749 Section 6.\n * We only send it implicitly for that case to avoid conflicting with Basic auth.\n */\n const shouldSendClientIdInBody = addCredentialsToBody || (type === 'authorizationCode' && !hasClientSecret)\n\n if (shouldSendClientIdInBody) {\n formData.set('client_id', flow['x-scalar-secret-client-id'])\n }\n if (addCredentialsToBody && hasClientSecret) {\n formData.set('client_secret', flow['x-scalar-secret-client-secret'])\n }\n\n if (flow['x-scalar-security-body']) {\n Object.entries(flow['x-scalar-security-body']).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n formData.set(key, String(value))\n }\n })\n }\n\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n }\n\n if (!addCredentialsToBody && hasClientSecret) {\n headers.Authorization = `Basic ${encode(`${flow['x-scalar-secret-client-id']}:${flow['x-scalar-secret-client-secret']}`)}`\n }\n\n const refreshUrl = flow.refreshUrl || flow['x-scalar-secret-token-url'] || flow.tokenUrl\n const absoluteRefreshUrl = makeUrlAbsolute(refreshUrl, getActiveServerBase(activeServer, environmentVariables))\n const url = shouldUseProxy(proxyUrl, absoluteRefreshUrl)\n ? `${proxyUrl}?${new URLSearchParams([['scalar_url', absoluteRefreshUrl]]).toString()}`\n : absoluteRefreshUrl\n\n const resp = await fetch(url, {\n method: 'POST',\n headers,\n body: formData,\n })\n const responseData = await resp.json()\n\n const tokenName = flow['x-tokenName'] || 'access_token'\n const accessToken = responseData[tokenName]\n const newRefreshToken = responseData.refresh_token\n\n if (!accessToken) {\n return [new Error(responseData.error_description ?? responseData.error ?? 'Token refresh failed'), null]\n }\n\n return [\n null,\n {\n accessToken,\n ...(typeof newRefreshToken === 'string' ? { refreshToken: newRefreshToken } : { refreshToken }),\n },\n ]\n } catch {\n return [new Error('Failed to refresh the access token. Please re-authorize.'), null]\n }\n}\n"],"mappings":"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"} |
@@ -79,2 +79,4 @@ import { type CodeMirrorLanguage, type Extension } from '@scalar/use-codemirror'; | ||
| withVariables?: boolean; | ||
| /** Enable fake data suggestions like $guid, $timestamp, etc. Should only be enabled for parameters and request bodies */ | ||
| withFakeData?: boolean; | ||
| /** Emit change event even if the value is the same */ | ||
@@ -107,5 +109,5 @@ alwaysEmitChange?: boolean; | ||
| }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, { | ||
| blur: (value: string, event: FocusEvent) => any; | ||
| submit: (value: string, event: FocusEvent | KeyboardEvent) => any; | ||
| "update:modelValue": (value: string) => any; | ||
| blur: (value: string, event: FocusEvent) => any; | ||
| navigate: (route: { | ||
@@ -161,2 +163,4 @@ page: "document"; | ||
| withVariables?: boolean; | ||
| /** Enable fake data suggestions like $guid, $timestamp, etc. Should only be enabled for parameters and request bodies */ | ||
| withFakeData?: boolean; | ||
| /** Emit change event even if the value is the same */ | ||
@@ -171,5 +175,5 @@ alwaysEmitChange?: boolean; | ||
| }> & Readonly<{ | ||
| onBlur?: ((value: string, event: FocusEvent) => any) | undefined; | ||
| onSubmit?: ((value: string, event: FocusEvent | KeyboardEvent) => any) | undefined; | ||
| "onUpdate:modelValue"?: ((value: string) => any) | undefined; | ||
| onBlur?: ((value: string, event: FocusEvent) => any) | undefined; | ||
| onNavigate?: ((route: { | ||
@@ -176,0 +180,0 @@ page: "document"; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"CodeInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"CodeInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/code-input/CodeInput.vue"],"names":[],"mappings":"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"} |
@@ -6,3 +6,3 @@ import _plugin_vue_export_helper_default from "../../../_virtual/_plugin-vue_export-helper.js"; | ||
| //#region src/v2/components/code-input/CodeInput.vue | ||
| var CodeInput_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CodeInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-167b1bd5"]]); | ||
| var CodeInput_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CodeInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-6499ec1f"]]); | ||
| //#endregion | ||
@@ -9,0 +9,0 @@ export { CodeInput_default as default }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"CodeInput.vue.js","names":[],"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 /** 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 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 CONTEXT_FUNCTION_NAMES.map((key) => ({\n key,\n description: getContextFunctionComment(key),\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 */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n Boolean(environment)\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 && environment\"\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":""} | ||
| {"version":3,"file":"CodeInput.vue.js","names":[],"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":""} |
@@ -104,2 +104,6 @@ import DataTableInputSelect_default from "../data-table/DataTableInputSelect.vue.js"; | ||
| }, | ||
| withFakeData: { | ||
| type: Boolean, | ||
| default: false | ||
| }, | ||
| alwaysEmitChange: { | ||
@@ -186,6 +190,6 @@ type: Boolean, | ||
| */ | ||
| const contextFunctionDropdownItems = computed(() => CONTEXT_FUNCTION_NAMES.map((key) => ({ | ||
| const contextFunctionDropdownItems = computed(() => __props.withFakeData ? CONTEXT_FUNCTION_NAMES.map((key) => ({ | ||
| key, | ||
| description: getContextFunctionComment(key) | ||
| }))); | ||
| })) : []); | ||
| const pillPluginExtension = computed(() => pillPlugin({ | ||
@@ -251,5 +255,6 @@ environment: __props.environment, | ||
| * Determines if the environment variable dropdown should be visible. | ||
| * Shows when environment is defined (for env vars) or withFakeData is true (for context functions) | ||
| */ | ||
| const displayVariablesDropdown = computed(() => { | ||
| return showDropdown.value && __props.withVariables && __props.layout !== "modal" && Boolean(__props.environment); | ||
| return showDropdown.value && __props.withVariables && __props.layout !== "modal" && (Boolean(__props.environment) || __props.withFakeData); | ||
| }); | ||
@@ -369,3 +374,3 @@ /** | ||
| __props.required ? (openBlock(), createElementBlock("div", _hoisted_6, " Required ")) : createCommentVNode("", true), | ||
| displayVariablesDropdown.value && __props.environment ? (openBlock(), createBlock(EnvironmentVariablesDropdown_default, { | ||
| displayVariablesDropdown.value ? (openBlock(), createBlock(EnvironmentVariablesDropdown_default, { | ||
| key: 8, | ||
@@ -372,0 +377,0 @@ ref_key: "dropdownRef", |
@@ -1,1 +0,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 /** 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 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 CONTEXT_FUNCTION_NAMES.map((key) => ({\n key,\n description: getContextFunctionComment(key),\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 */\nconst displayVariablesDropdown = computed((): boolean => {\n return (\n showDropdown.value &&\n withVariables &&\n layout !== 'modal' &&\n Boolean(environment)\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 && environment\"\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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"} | ||
| {"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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"} |
@@ -19,2 +19,4 @@ import type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'; | ||
| lineWrapping?: boolean; | ||
| /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */ | ||
| withFakeData?: boolean; | ||
| }; | ||
@@ -42,2 +44,3 @@ declare var __VLS_8: {}, __VLS_28: {}, __VLS_30: {}; | ||
| lineWrapping: boolean; | ||
| withFakeData: boolean; | ||
| canAddCustomEnumValue: boolean; | ||
@@ -44,0 +47,0 @@ readOnly: boolean; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"DataTableInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"names":[],"mappings":"AAwMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAM/C,KAAK,WAAW,GAAG;IACf,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,sEAAsE;IACtE,cAAc,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,kBAAkB,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAC;AAmWJ,QAAA,IAAI,OAAO,IAAU,EAAuB,QAAQ,IAAW,EAAE,QAAQ,IAAY,CAAE;AACvF,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC5C;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,GAC7C;IAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAO7C,QAAA,MAAM,UAAU;;;;;;;;;;;cAzXD,OAAO;kBAUH,OAAO;2BAPE,OAAO;cACpB,OAAO;6EAyXpB,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"} | ||
| {"version":3,"file":"DataTableInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"names":[],"mappings":"AA4MA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAM/C,KAAK,WAAW,GAAG;IACf,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,sEAAsE;IACtE,cAAc,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,kBAAkB,CAAA;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAC;AAuWJ,QAAA,IAAI,OAAO,IAAU,EAAuB,QAAQ,IAAW,EAAE,QAAQ,IAAY,CAAE;AACvF,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC5C;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,GAC7C;IAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAO7C,QAAA,MAAM,UAAU;;;;;;;;;;;cA/XD,OAAO;kBAUH,OAAO;kBAEP,OAAO;2BATE,OAAO;cACpB,OAAO;6EA+XpB,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"} |
@@ -5,3 +5,3 @@ import _plugin_vue_export_helper_default from "../../../_virtual/_plugin-vue_export-helper.js"; | ||
| //#region src/v2/components/data-table/DataTableInput.vue | ||
| var DataTableInput_default = /* @__PURE__ */ _plugin_vue_export_helper_default(DataTableInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-3157c3c7"]]); | ||
| var DataTableInput_default = /* @__PURE__ */ _plugin_vue_export_helper_default(DataTableInput_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-819cea32"]]); | ||
| //#endregion | ||
@@ -8,0 +8,0 @@ export { DataTableInput_default as default }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"DataTableInput.vue.js","names":[],"sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIconButton } from '@scalar/components'\nimport { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from '@scalar/icons'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport type { VueClassProp } from '@/types/vue'\nimport { CodeInput } from '@/v2/components/code-input'\n\nimport DataTableCell from './DataTableCell.vue'\nimport DataTableInputSelect from './DataTableInputSelect.vue'\n\nconst props = withDefaults(\n defineProps<{\n id?: string\n type?: string | undefined\n /** Class for the wrapping cell because attrs is bound to the input */\n containerClass?: VueClassProp | undefined\n required?: boolean\n modelValue: string\n /** Allows adding a custom value to the enum dropdown, defaults to true */\n canAddCustomEnumValue?: boolean\n readOnly?: boolean\n enum?: string[]\n min?: number\n max?: number\n environment: XScalarEnvironment\n description?: string | undefined\n lineWrapping?: boolean\n }>(),\n {\n canAddCustomEnumValue: true,\n required: false,\n readOnly: false,\n lineWrapping: false,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: string | number): void\n (e: 'inputFocus'): void\n (e: 'inputBlur'): void\n (e: 'selectVariable', value: string): void\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst mask = ref(true)\nconst interactingWithDropdown = ref(false)\nconst codeInput = useTemplateRef('codeInput')\n\nconst handleBlur = () => !interactingWithDropdown.value && emit('inputBlur')\n\nconst inputType = computed(() =>\n props.type === 'password' ? 'text' : (props.type ?? 'text'),\n)\n\n// If not an enum nor read only, focus the code input\nconst handleLabelClick = () => {\n if (!props.enum?.length && !props.readOnly) {\n codeInput.value?.focus()\n }\n}\n</script>\n<template>\n <DataTableCell\n class=\"relative flex\"\n :class=\"containerClass\">\n <div\n v-if=\"$slots.default\"\n class=\"text-c-1 flex items-center pr-0 pl-3\"\n :for=\"id ?? ''\"\n @click=\"handleLabelClick\">\n <slot />:\n </div>\n <div class=\"relative flex min-w-0 flex-1\">\n <template v-if=\"props.enum && props.enum.length\">\n <DataTableInputSelect\n :canAddCustomValue=\"props.canAddCustomEnumValue\"\n :modelValue=\"props.modelValue\"\n :value=\"props.enum\"\n @update:modelValue=\"emit('update:modelValue', $event)\" />\n </template>\n <template v-else>\n <input\n v-if=\"mask && type === 'password'\"\n v-bind=\"id ? { ...$attrs, id: id } : $attrs\"\n autocomplete=\"off\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none px-2 py-1.25 -outline-offset-1\"\n :class=\"{ 'scalar-password-input': type === 'password' }\"\n data-1p-ignore\n :readOnly=\"readOnly\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :value=\"modelValue\"\n @input=\"\n emit(\n 'update:modelValue',\n ($event.target as HTMLInputElement).value ?? '',\n )\n \" />\n <CodeInput\n v-else\n v-bind=\"$attrs\"\n :id=\"id\"\n ref=\"codeInput\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none -outline-offset-1\"\n :class=\"[\n type === 'password' && description && 'pr-12',\n description && 'pr-8',\n type === 'password' && 'scalar-password-input',\n ]\"\n :description=\"description\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"environment\"\n :lineWrapping=\"Boolean(lineWrapping)\"\n :max=\"max\"\n :min=\"min\"\n :modelValue=\"modelValue ?? ''\"\n :readOnly=\"readOnly\"\n :required=\"Boolean(required)\"\n spellcheck=\"false\"\n :type=\"inputType\"\n @blur=\"handleBlur\"\n @focus=\"emit('inputFocus')\"\n @update:modelValue=\"(value) => emit('update:modelValue', value)\" />\n </template>\n </div>\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 <slot name=\"icon\" />\n <!-- Clear -->\n <ScalarIconButton\n v-if=\"modelValue\"\n class=\"-ml-.25 h-6 w-6 self-center p-1.25\"\n :icon=\"ScalarIconX\"\n label=\"Clear Value\"\n @click=\"emit('update:modelValue', '')\" />\n <!-- Toggle Visibility -->\n <ScalarIconButton\n v-if=\"type === 'password'\"\n class=\"-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25\"\n data-testid=\"data-table-password-toggle\"\n :icon=\"mask ? ScalarIconEye : ScalarIconEyeSlash\"\n :label=\"mask ? 'Show Password' : 'Hide Password'\"\n @click=\"mask = !mask\" />\n </DataTableCell>\n</template>\n\n<style scoped>\n:deep(.cm-editor) {\n padding: 0;\n}\n:deep(.cm-content) {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n width: 100%;\n}\n:deep(.cm-content):has(.cm-pill) {\n padding: 5px 8px;\n}\n:deep(.cm-content .cm-pill:not(:last-of-type)) {\n margin-right: 0.5px;\n}\n:deep(.cm-content .cm-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n:deep(.cm-line) {\n overflow: hidden;\n padding: 0;\n text-overflow: ellipsis;\n word-break: break-word;\n}\n.required::after {\n content: 'Required';\n}\n/* Tailwind placeholder is busted */\ninput::placeholder {\n color: var(--scalar-color-3);\n}\n/* we want our inputs to look like a password input but not be one */\n.scalar-password-input {\n text-security: disc;\n -webkit-text-security: disc;\n -moz-text-security: disc;\n}\n</style>\n"],"mappings":""} | ||
| {"version":3,"file":"DataTableInput.vue.js","names":[],"sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIconButton } from '@scalar/components'\nimport { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from '@scalar/icons'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport type { VueClassProp } from '@/types/vue'\nimport { CodeInput } from '@/v2/components/code-input'\n\nimport DataTableCell from './DataTableCell.vue'\nimport DataTableInputSelect from './DataTableInputSelect.vue'\n\nconst props = withDefaults(\n defineProps<{\n id?: string\n type?: string | undefined\n /** Class for the wrapping cell because attrs is bound to the input */\n containerClass?: VueClassProp | undefined\n required?: boolean\n modelValue: string\n /** Allows adding a custom value to the enum dropdown, defaults to true */\n canAddCustomEnumValue?: boolean\n readOnly?: boolean\n enum?: string[]\n min?: number\n max?: number\n environment: XScalarEnvironment\n description?: string | undefined\n lineWrapping?: boolean\n /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */\n withFakeData?: boolean\n }>(),\n {\n canAddCustomEnumValue: true,\n required: false,\n readOnly: false,\n lineWrapping: false,\n withFakeData: true,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: string | number): void\n (e: 'inputFocus'): void\n (e: 'inputBlur'): void\n (e: 'selectVariable', value: string): void\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst mask = ref(true)\nconst interactingWithDropdown = ref(false)\nconst codeInput = useTemplateRef('codeInput')\n\nconst handleBlur = () => !interactingWithDropdown.value && emit('inputBlur')\n\nconst inputType = computed(() =>\n props.type === 'password' ? 'text' : (props.type ?? 'text'),\n)\n\n// If not an enum nor read only, focus the code input\nconst handleLabelClick = () => {\n if (!props.enum?.length && !props.readOnly) {\n codeInput.value?.focus()\n }\n}\n</script>\n<template>\n <DataTableCell\n class=\"relative flex\"\n :class=\"containerClass\">\n <div\n v-if=\"$slots.default\"\n class=\"text-c-1 flex items-center pr-0 pl-3\"\n :for=\"id ?? ''\"\n @click=\"handleLabelClick\">\n <slot />:\n </div>\n <div class=\"relative flex min-w-0 flex-1\">\n <template v-if=\"props.enum && props.enum.length\">\n <DataTableInputSelect\n :canAddCustomValue=\"props.canAddCustomEnumValue\"\n :modelValue=\"props.modelValue\"\n :value=\"props.enum\"\n @update:modelValue=\"emit('update:modelValue', $event)\" />\n </template>\n <template v-else>\n <input\n v-if=\"mask && type === 'password'\"\n v-bind=\"id ? { ...$attrs, id: id } : $attrs\"\n autocomplete=\"off\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none px-2 py-1.25 -outline-offset-1\"\n :class=\"{ 'scalar-password-input': type === 'password' }\"\n data-1p-ignore\n :readOnly=\"readOnly\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :value=\"modelValue\"\n @input=\"\n emit(\n 'update:modelValue',\n ($event.target as HTMLInputElement).value ?? '',\n )\n \" />\n <CodeInput\n v-else\n v-bind=\"$attrs\"\n :id=\"id\"\n ref=\"codeInput\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none -outline-offset-1\"\n :class=\"[\n type === 'password' && description && 'pr-12',\n description && 'pr-8',\n type === 'password' && 'scalar-password-input',\n ]\"\n :description=\"description\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"environment\"\n :lineWrapping=\"Boolean(lineWrapping)\"\n :max=\"max\"\n :min=\"min\"\n :modelValue=\"modelValue ?? ''\"\n :readOnly=\"readOnly\"\n :required=\"Boolean(required)\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :withFakeData=\"withFakeData\"\n @blur=\"handleBlur\"\n @focus=\"emit('inputFocus')\"\n @update:modelValue=\"(value) => emit('update:modelValue', value)\" />\n </template>\n </div>\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 <slot name=\"icon\" />\n <!-- Clear -->\n <ScalarIconButton\n v-if=\"modelValue\"\n class=\"-ml-.25 h-6 w-6 self-center p-1.25\"\n :icon=\"ScalarIconX\"\n label=\"Clear Value\"\n @click=\"emit('update:modelValue', '')\" />\n <!-- Toggle Visibility -->\n <ScalarIconButton\n v-if=\"type === 'password'\"\n class=\"-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25\"\n data-testid=\"data-table-password-toggle\"\n :icon=\"mask ? ScalarIconEye : ScalarIconEyeSlash\"\n :label=\"mask ? 'Show Password' : 'Hide Password'\"\n @click=\"mask = !mask\" />\n </DataTableCell>\n</template>\n\n<style scoped>\n:deep(.cm-editor) {\n padding: 0;\n}\n:deep(.cm-content) {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n width: 100%;\n}\n:deep(.cm-content):has(.cm-pill) {\n padding: 5px 8px;\n}\n:deep(.cm-content .cm-pill:not(:last-of-type)) {\n margin-right: 0.5px;\n}\n:deep(.cm-content .cm-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n:deep(.cm-line) {\n overflow: hidden;\n padding: 0;\n text-overflow: ellipsis;\n word-break: break-word;\n}\n.required::after {\n content: 'Required';\n}\n/* Tailwind placeholder is busted */\ninput::placeholder {\n color: var(--scalar-color-3);\n}\n/* we want our inputs to look like a password input but not be one */\n.scalar-password-input {\n text-security: disc;\n -webkit-text-security: disc;\n -moz-text-security: disc;\n}\n</style>\n"],"mappings":""} |
@@ -47,2 +47,6 @@ import DataTableInputSelect_default from "./DataTableInputSelect.vue.js"; | ||
| default: false | ||
| }, | ||
| withFakeData: { | ||
| type: Boolean, | ||
| default: true | ||
| } | ||
@@ -119,2 +123,3 @@ }, | ||
| type: inputType.value, | ||
| withFakeData: __props.withFakeData, | ||
| onBlur: handleBlur, | ||
@@ -134,3 +139,4 @@ onFocus: _cache[2] || (_cache[2] = ($event) => emit("inputFocus")), | ||
| "required", | ||
| "type" | ||
| "type", | ||
| "withFakeData" | ||
| ]))], 64))]), | ||
@@ -137,0 +143,0 @@ _ctx.$slots.warning ? (openBlock(), createElementBlock("div", _hoisted_4, [renderSlot(_ctx.$slots, "warning", {}, void 0, true)])) : createCommentVNode("", true), |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"DataTableInput.vue.script.js","names":["$slots","$attrs"],"sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIconButton } from '@scalar/components'\nimport { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from '@scalar/icons'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport type { VueClassProp } from '@/types/vue'\nimport { CodeInput } from '@/v2/components/code-input'\n\nimport DataTableCell from './DataTableCell.vue'\nimport DataTableInputSelect from './DataTableInputSelect.vue'\n\nconst props = withDefaults(\n defineProps<{\n id?: string\n type?: string | undefined\n /** Class for the wrapping cell because attrs is bound to the input */\n containerClass?: VueClassProp | undefined\n required?: boolean\n modelValue: string\n /** Allows adding a custom value to the enum dropdown, defaults to true */\n canAddCustomEnumValue?: boolean\n readOnly?: boolean\n enum?: string[]\n min?: number\n max?: number\n environment: XScalarEnvironment\n description?: string | undefined\n lineWrapping?: boolean\n }>(),\n {\n canAddCustomEnumValue: true,\n required: false,\n readOnly: false,\n lineWrapping: false,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: string | number): void\n (e: 'inputFocus'): void\n (e: 'inputBlur'): void\n (e: 'selectVariable', value: string): void\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst mask = ref(true)\nconst interactingWithDropdown = ref(false)\nconst codeInput = useTemplateRef('codeInput')\n\nconst handleBlur = () => !interactingWithDropdown.value && emit('inputBlur')\n\nconst inputType = computed(() =>\n props.type === 'password' ? 'text' : (props.type ?? 'text'),\n)\n\n// If not an enum nor read only, focus the code input\nconst handleLabelClick = () => {\n if (!props.enum?.length && !props.readOnly) {\n codeInput.value?.focus()\n }\n}\n</script>\n<template>\n <DataTableCell\n class=\"relative flex\"\n :class=\"containerClass\">\n <div\n v-if=\"$slots.default\"\n class=\"text-c-1 flex items-center pr-0 pl-3\"\n :for=\"id ?? ''\"\n @click=\"handleLabelClick\">\n <slot />:\n </div>\n <div class=\"relative flex min-w-0 flex-1\">\n <template v-if=\"props.enum && props.enum.length\">\n <DataTableInputSelect\n :canAddCustomValue=\"props.canAddCustomEnumValue\"\n :modelValue=\"props.modelValue\"\n :value=\"props.enum\"\n @update:modelValue=\"emit('update:modelValue', $event)\" />\n </template>\n <template v-else>\n <input\n v-if=\"mask && type === 'password'\"\n v-bind=\"id ? { ...$attrs, id: id } : $attrs\"\n autocomplete=\"off\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none px-2 py-1.25 -outline-offset-1\"\n :class=\"{ 'scalar-password-input': type === 'password' }\"\n data-1p-ignore\n :readOnly=\"readOnly\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :value=\"modelValue\"\n @input=\"\n emit(\n 'update:modelValue',\n ($event.target as HTMLInputElement).value ?? '',\n )\n \" />\n <CodeInput\n v-else\n v-bind=\"$attrs\"\n :id=\"id\"\n ref=\"codeInput\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none -outline-offset-1\"\n :class=\"[\n type === 'password' && description && 'pr-12',\n description && 'pr-8',\n type === 'password' && 'scalar-password-input',\n ]\"\n :description=\"description\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"environment\"\n :lineWrapping=\"Boolean(lineWrapping)\"\n :max=\"max\"\n :min=\"min\"\n :modelValue=\"modelValue ?? ''\"\n :readOnly=\"readOnly\"\n :required=\"Boolean(required)\"\n spellcheck=\"false\"\n :type=\"inputType\"\n @blur=\"handleBlur\"\n @focus=\"emit('inputFocus')\"\n @update:modelValue=\"(value) => emit('update:modelValue', value)\" />\n </template>\n </div>\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 <slot name=\"icon\" />\n <!-- Clear -->\n <ScalarIconButton\n v-if=\"modelValue\"\n class=\"-ml-.25 h-6 w-6 self-center p-1.25\"\n :icon=\"ScalarIconX\"\n label=\"Clear Value\"\n @click=\"emit('update:modelValue', '')\" />\n <!-- Toggle Visibility -->\n <ScalarIconButton\n v-if=\"type === 'password'\"\n class=\"-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25\"\n data-testid=\"data-table-password-toggle\"\n :icon=\"mask ? ScalarIconEye : ScalarIconEyeSlash\"\n :label=\"mask ? 'Show Password' : 'Hide Password'\"\n @click=\"mask = !mask\" />\n </DataTableCell>\n</template>\n\n<style scoped>\n:deep(.cm-editor) {\n padding: 0;\n}\n:deep(.cm-content) {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n width: 100%;\n}\n:deep(.cm-content):has(.cm-pill) {\n padding: 5px 8px;\n}\n:deep(.cm-content .cm-pill:not(:last-of-type)) {\n margin-right: 0.5px;\n}\n:deep(.cm-content .cm-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n:deep(.cm-line) {\n overflow: hidden;\n padding: 0;\n text-overflow: ellipsis;\n word-break: break-word;\n}\n.required::after {\n content: 'Required';\n}\n/* Tailwind placeholder is busted */\ninput::placeholder {\n color: var(--scalar-color-3);\n}\n/* we want our inputs to look like a password input but not be one */\n.scalar-password-input {\n text-security: disc;\n -webkit-text-security: disc;\n -moz-text-security: disc;\n}\n</style>\n"],"mappings":"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"} | ||
| {"version":3,"file":"DataTableInput.vue.script.js","names":["$slots","$attrs"],"sources":["../../../../src/v2/components/data-table/DataTableInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIconButton } from '@scalar/components'\nimport { ScalarIconEye, ScalarIconEyeSlash, ScalarIconX } from '@scalar/icons'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport type { VueClassProp } from '@/types/vue'\nimport { CodeInput } from '@/v2/components/code-input'\n\nimport DataTableCell from './DataTableCell.vue'\nimport DataTableInputSelect from './DataTableInputSelect.vue'\n\nconst props = withDefaults(\n defineProps<{\n id?: string\n type?: string | undefined\n /** Class for the wrapping cell because attrs is bound to the input */\n containerClass?: VueClassProp | undefined\n required?: boolean\n modelValue: string\n /** Allows adding a custom value to the enum dropdown, defaults to true */\n canAddCustomEnumValue?: boolean\n readOnly?: boolean\n enum?: string[]\n min?: number\n max?: number\n environment: XScalarEnvironment\n description?: string | undefined\n lineWrapping?: boolean\n /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */\n withFakeData?: boolean\n }>(),\n {\n canAddCustomEnumValue: true,\n required: false,\n readOnly: false,\n lineWrapping: false,\n withFakeData: true,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: string | number): void\n (e: 'inputFocus'): void\n (e: 'inputBlur'): void\n (e: 'selectVariable', value: string): void\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst mask = ref(true)\nconst interactingWithDropdown = ref(false)\nconst codeInput = useTemplateRef('codeInput')\n\nconst handleBlur = () => !interactingWithDropdown.value && emit('inputBlur')\n\nconst inputType = computed(() =>\n props.type === 'password' ? 'text' : (props.type ?? 'text'),\n)\n\n// If not an enum nor read only, focus the code input\nconst handleLabelClick = () => {\n if (!props.enum?.length && !props.readOnly) {\n codeInput.value?.focus()\n }\n}\n</script>\n<template>\n <DataTableCell\n class=\"relative flex\"\n :class=\"containerClass\">\n <div\n v-if=\"$slots.default\"\n class=\"text-c-1 flex items-center pr-0 pl-3\"\n :for=\"id ?? ''\"\n @click=\"handleLabelClick\">\n <slot />:\n </div>\n <div class=\"relative flex min-w-0 flex-1\">\n <template v-if=\"props.enum && props.enum.length\">\n <DataTableInputSelect\n :canAddCustomValue=\"props.canAddCustomEnumValue\"\n :modelValue=\"props.modelValue\"\n :value=\"props.enum\"\n @update:modelValue=\"emit('update:modelValue', $event)\" />\n </template>\n <template v-else>\n <input\n v-if=\"mask && type === 'password'\"\n v-bind=\"id ? { ...$attrs, id: id } : $attrs\"\n autocomplete=\"off\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none px-2 py-1.25 -outline-offset-1\"\n :class=\"{ 'scalar-password-input': type === 'password' }\"\n data-1p-ignore\n :readOnly=\"readOnly\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :value=\"modelValue\"\n @input=\"\n emit(\n 'update:modelValue',\n ($event.target as HTMLInputElement).value ?? '',\n )\n \" />\n <CodeInput\n v-else\n v-bind=\"$attrs\"\n :id=\"id\"\n ref=\"codeInput\"\n class=\"text-c-1 disabled:text-c-2 peer w-full min-w-0 border-none -outline-offset-1\"\n :class=\"[\n type === 'password' && description && 'pr-12',\n description && 'pr-8',\n type === 'password' && 'scalar-password-input',\n ]\"\n :description=\"description\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"environment\"\n :lineWrapping=\"Boolean(lineWrapping)\"\n :max=\"max\"\n :min=\"min\"\n :modelValue=\"modelValue ?? ''\"\n :readOnly=\"readOnly\"\n :required=\"Boolean(required)\"\n spellcheck=\"false\"\n :type=\"inputType\"\n :withFakeData=\"withFakeData\"\n @blur=\"handleBlur\"\n @focus=\"emit('inputFocus')\"\n @update:modelValue=\"(value) => emit('update:modelValue', value)\" />\n </template>\n </div>\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 <slot name=\"icon\" />\n <!-- Clear -->\n <ScalarIconButton\n v-if=\"modelValue\"\n class=\"-ml-.25 h-6 w-6 self-center p-1.25\"\n :icon=\"ScalarIconX\"\n label=\"Clear Value\"\n @click=\"emit('update:modelValue', '')\" />\n <!-- Toggle Visibility -->\n <ScalarIconButton\n v-if=\"type === 'password'\"\n class=\"-ml-.5 mr-1.25 h-6 w-6 self-center p-1.25\"\n data-testid=\"data-table-password-toggle\"\n :icon=\"mask ? ScalarIconEye : ScalarIconEyeSlash\"\n :label=\"mask ? 'Show Password' : 'Hide Password'\"\n @click=\"mask = !mask\" />\n </DataTableCell>\n</template>\n\n<style scoped>\n:deep(.cm-editor) {\n padding: 0;\n}\n:deep(.cm-content) {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n width: 100%;\n}\n:deep(.cm-content):has(.cm-pill) {\n padding: 5px 8px;\n}\n:deep(.cm-content .cm-pill:not(:last-of-type)) {\n margin-right: 0.5px;\n}\n:deep(.cm-content .cm-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n:deep(.cm-line) {\n overflow: hidden;\n padding: 0;\n text-overflow: ellipsis;\n word-break: break-word;\n}\n.required::after {\n content: 'Required';\n}\n/* Tailwind placeholder is busted */\ninput::placeholder {\n color: var(--scalar-color-3);\n}\n/* we want our inputs to look like a password input but not be one */\n.scalar-password-input {\n text-security: disc;\n -webkit-text-security: disc;\n -moz-text-security: disc;\n}\n</style>\n"],"mappings":"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"} |
@@ -12,7 +12,7 @@ type __VLS_Props = { | ||
| declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { | ||
| cancel: () => any; | ||
| submit: () => any; | ||
| cancel: () => any; | ||
| }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{ | ||
| onCancel?: (() => any) | undefined; | ||
| onSubmit?: (() => any) | undefined; | ||
| onCancel?: (() => any) | undefined; | ||
| }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; | ||
@@ -19,0 +19,0 @@ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>; |
| //#region src/v2/constants.ts | ||
| /** 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')). */ | ||
| var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "3.1.0"; | ||
| var APP_VERSION = typeof OVERRIDE_PACKAGE_VERSION !== "undefined" ? OVERRIDE_PACKAGE_VERSION : "3.2.0"; | ||
| //#endregion | ||
@@ -5,0 +5,0 @@ export { APP_VERSION }; |
@@ -7,2 +7,3 @@ import type { ScalarListboxOption, WorkspaceGroup } from '@scalar/components'; | ||
| import { type WorkspaceStore } from '@scalar/workspace-store/client'; | ||
| import type { ApiClientAppOptions } from '../../../v2/features/app/helpers/create-api-client-app.js'; | ||
| import { type WorkspaceEventBus } from '@scalar/workspace-store/events'; | ||
@@ -97,2 +98,4 @@ import type { WorkspaceDocument } from '@scalar/workspace-store/schemas'; | ||
| loading: Ref<boolean>; | ||
| /** Runtime behaviour overrides */ | ||
| options?: ApiClientAppOptions; | ||
| /** The currently active entities */ | ||
@@ -137,3 +140,3 @@ activeEntities: { | ||
| }; | ||
| export declare const createAppState: ({ router, fileLoader, fallbackThemeSlug, customThemes, telemetryDefault, }: { | ||
| export declare const createAppState: ({ router, fileLoader, fallbackThemeSlug, customThemes, telemetryDefault, options, }: { | ||
| router: Router; | ||
@@ -144,4 +147,6 @@ fileLoader?: LoaderPlugin; | ||
| telemetryDefault?: boolean; | ||
| /** Runtime behaviour overrides */ | ||
| options?: ApiClientAppOptions; | ||
| }) => Promise<AppState>; | ||
| export {}; | ||
| //# sourceMappingURL=app-state.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"app-state.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/app/app-state.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"app-state.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/app/app-state.ts"],"names":[],"mappings":"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"} |
@@ -27,3 +27,3 @@ import { slugify } from "../../helpers/slugify.js"; | ||
| var DEFAULT_SIDEBAR_WIDTH = 288; | ||
| var createAppState = async ({ router, fileLoader, fallbackThemeSlug = () => "default", customThemes = () => [], telemetryDefault }) => { | ||
| var createAppState = async ({ router, fileLoader, fallbackThemeSlug = () => "default", customThemes = () => [], telemetryDefault, options }) => { | ||
| /** Workspace event bus for handling workspace-level events. */ | ||
@@ -107,3 +107,4 @@ const eventBus = createWorkspaceEventBus({ debug: false }); | ||
| })], | ||
| fileLoader | ||
| fileLoader, | ||
| fetch: options?.customFetch | ||
| }); | ||
@@ -625,3 +626,4 @@ }; | ||
| }, | ||
| telemetry | ||
| telemetry, | ||
| options | ||
| }; | ||
@@ -628,0 +630,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"app-state.js","names":[],"sources":["../../../../src/v2/features/app/app-state.ts"],"sourcesContent":["import type { ScalarListboxOption, WorkspaceGroup } from '@scalar/components'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport { sortByOrder } from '@scalar/helpers/array/sort-by-order'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport type { LoaderPlugin } from '@scalar/json-magic/bundle'\nimport { migrateLocalStorageToIndexDb } from '@scalar/oas-utils/migrations'\nimport { createSidebarState, generateReverseIndex } from '@scalar/sidebar'\nimport type { Theme } from '@scalar/themes'\nimport { type WorkspaceStore, createWorkspaceStore } from '@scalar/workspace-store/client'\nimport {\n type OperationExampleMeta,\n type WorkspaceEventBus,\n createWorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { generateUniqueValue } from '@scalar/workspace-store/helpers/generate-unique-value'\nimport { getParentEntry } from '@scalar/workspace-store/navigation'\nimport { createWorkspaceStorePersistence, getWorkspaceId } from '@scalar/workspace-store/persistence'\nimport { persistencePlugin } from '@scalar/workspace-store/plugins/client'\nimport { getActiveEnvironment } from '@scalar/workspace-store/request-example'\nimport type { Workspace, WorkspaceDocument } from '@scalar/workspace-store/schemas'\nimport { extensions } from '@scalar/workspace-store/schemas/extensions'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { Tab } from '@scalar/workspace-store/schemas/extensions/workspace/x-scalar-tabs'\nimport type { TraversedEntry } from '@scalar/workspace-store/schemas/navigation'\nimport {\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n type ShallowRef,\n computed,\n readonly,\n ref,\n shallowRef,\n watch,\n} from 'vue'\nimport type { RouteLocationNormalizedGeneric, RouteLocationRaw, Router } from 'vue-router'\n\nimport { getRouteParam } from '@/v2/features/app/helpers/get-route-param'\nimport { groupWorkspacesByTeam } from '@/v2/features/app/helpers/group-workspaces'\nimport { useTheme } from '@/v2/features/app/hooks/use-theme'\nimport { getTabDetails } from '@/v2/helpers/get-tab-details'\nimport { slugify } from '@/v2/helpers/slugify'\nimport { workspaceStorage } from '@/v2/helpers/storage'\n\nimport { initializeAppEventHandlers } from './app-events'\nimport { canLoadWorkspace, filterWorkspacesByTeam } from './helpers/filter-workspaces'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\nexport type GetEntryByLocation = (location: {\n document: string\n path?: string\n method?: HttpMethod\n example?: string\n}) =>\n | (TraversedEntry & {\n parent?: TraversedEntry | undefined\n })\n | undefined\n\ntype WorkspaceOption = ScalarListboxOption & { teamUid: string; namespace: string; slug: string }\n\n/** Defines the overall application state structure and its main feature modules */\nexport type AppState = {\n /** The workspace store */\n store: ShallowRef<WorkspaceStore | null>\n /** The sidebar management */\n sidebar: {\n /** The sidebar state */\n state: ReturnType<typeof createSidebarState<TraversedEntry>>\n /** The width of the sidebar */\n width: ComputedRef<number>\n /** Whether the sidebar is open */\n isOpen: Ref<boolean>\n /** Handles the selection of an item in the sidebar */\n handleSelectItem: (id: string) => void\n /** Handles the width update of the sidebar */\n handleSidebarWidthUpdate: (width: number) => void\n /** Gets the entry by location */\n getEntryByLocation: GetEntryByLocation\n }\n /** The tabs management */\n tabs: {\n /** The tabs state */\n state: Ref<Tab[]>\n /** The active tab index */\n activeTabIndex: Ref<number>\n /** Copies the URL of the tab at the given index to the clipboard */\n copyTabUrl: (index: number) => Promise<void>\n }\n /** The workspace management */\n workspace: {\n /** Creates a new workspace and navigates to it */\n create: (payload: {\n teamUid?: string\n namespace?: string\n slug?: string\n name: string\n }) => Promise<{ name: string; namespace: string; slug: string; teamUid: string } | undefined>\n /** All workspace list */\n workspaceList: Ref<WorkspaceOption[]>\n /** Filtered workspace list, based on the current teamUid */\n filteredWorkspaceList: ComputedRef<WorkspaceOption[]>\n /**\n * Groups workspaces into team and local categories for display in the workspace picker.\n * Team workspaces are shown first (when not on local team), followed by local workspaces.\n */\n workspaceGroups: ComputedRef<WorkspaceGroup[]>\n /** The currently active workspace */\n activeWorkspace: ShallowRef<{ id: string; label: string } | null>\n /** Navigates to the specified workspace */\n navigateToWorkspace: (namespace?: string, slug?: string) => Promise<void>\n /** Whether the workspace page is open */\n isOpen: ComputedRef<boolean>\n }\n /** The workspace event bus for handling workspace-level events */\n eventBus: WorkspaceEventBus\n /** The router instance */\n router: Router\n /** The current route derived from the router */\n currentRoute: Ref<RouteLocationNormalizedGeneric | null>\n /** Whether the workspace is currently syncing */\n loading: Ref<boolean>\n /** The currently active entities */\n activeEntities: {\n /** The namespace of the current entity, e.g. \"default\" or a custom namespace */\n namespace: Ref<string | undefined>\n /** The slug identifying the current workspace */\n workspaceSlug: Ref<string | undefined>\n /** The slug of the currently selected document in the workspace */\n documentSlug: Ref<string | undefined>\n /** The API path currently selected (e.g. \"/users/{id}\") */\n path: Ref<string | undefined>\n /** The HTTP method for the currently selected API path (e.g. GET, POST) */\n method: Ref<HttpMethod | undefined>\n /** The name of the currently selected example (for examples within an endpoint) */\n exampleName: Ref<string | undefined>\n /** The unique identifier for the selected team context (read-only; use setTeamUid to change) */\n teamUid: Readonly<Ref<string>>\n /** Sets the current team context by team UID */\n setTeamUid: (value: string) => void\n }\n /** The currently active environment */\n environment: ComputedRef<XScalarEnvironment>\n /** The currently active document */\n document: ComputedRef<WorkspaceDocument | null>\n /** Whether the current color mode is dark */\n isDarkMode: ComputedRef<boolean>\n /** The currently active theme */\n theme: {\n /** The computed CSS styles for the current theme, as a string */\n styles: ComputedRef<{ themeStyles: string; themeSlug: string }>\n /** The computed value for the <style> tag containing the current theme styles */\n themeStyleTag: ComputedRef<string>\n /** The custom themes to use */\n customThemes: MaybeRefOrGetter<Theme[]>\n }\n telemetry: Ref<boolean>\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n/** Default debounce delay in milliseconds for workspace store persistence. */\nconst DEFAULT_DEBOUNCE_DELAY = 1000\n/** Default sidebar width in pixels. */\nconst DEFAULT_SIDEBAR_WIDTH = 288\n\n// ---------------------------------------------------------------------------\n// App State\n// ---------------------------------------------------------------------------\nexport const createAppState = async ({\n router,\n fileLoader,\n fallbackThemeSlug = () => 'default',\n customThemes = () => [],\n telemetryDefault,\n}: {\n router: Router\n fileLoader?: LoaderPlugin\n customThemes?: MaybeRefOrGetter<Theme[]>\n fallbackThemeSlug?: MaybeRefOrGetter<string>\n telemetryDefault?: boolean\n}): Promise<AppState> => {\n /** Workspace event bus for handling workspace-level events. */\n const eventBus = createWorkspaceEventBus({\n debug: import.meta.env.DEV,\n })\n\n const { workspace: persistence } = await createWorkspaceStorePersistence()\n\n /**\n * Run migration from localStorage to IndexedDB if needed\n * This happens once per user and transforms old data structure to new workspace format\n */\n await migrateLocalStorageToIndexDb()\n\n // ---------------------------------------------------------------------------\n // Active entities\n // ---------------------------------------------------------------------------\n const teamUid = ref<string>('local')\n const namespace = ref<string | undefined>(undefined)\n const workspaceSlug = ref<string | undefined>(undefined)\n const documentSlug = ref<string | undefined>(undefined)\n const method = ref<HttpMethod | undefined>(undefined)\n const path = ref<string | undefined>(undefined)\n const exampleName = ref<string | undefined>(undefined)\n\n // ---------------------------------------------------------------------------\n // Loading states\n const isSyncingWorkspace = ref(false)\n\n // ---------------------------------------------------------------------------\n // Router state\n router.afterEach((to) => handleRouteChange(to))\n const currentRoute = computed(() => router.currentRoute.value ?? null)\n\n // ---------------------------------------------------------------------------\n // Workspace persistence state management\n const activeWorkspace = shallowRef<{ id: string; label: string } | null>(null)\n const workspaces = ref<WorkspaceOption[]>([])\n const filteredWorkspaces = computed(() => filterWorkspacesByTeam(workspaces.value, teamUid.value))\n const workspaceGroups = computed(() => groupWorkspacesByTeam(filteredWorkspaces.value, teamUid.value))\n const store = shallowRef<WorkspaceStore | null>(null)\n\n // Load persisted telemetry preference, falling back to the provided default\n const persistedTelemetry = workspaceStorage.getTelemetry()\n const telemetry = ref(persistedTelemetry !== null ? persistedTelemetry : Boolean(telemetryDefault))\n watch(telemetry, (value) => workspaceStorage.setTelemetry(value))\n\n const activeDocument = computed(() => {\n return store.value?.workspace.documents[documentSlug.value ?? ''] || null\n })\n\n /**\n * Merged environment variables from workspace and document levels.\n * Variables from both sources are combined, with document variables\n * taking precedence in case of naming conflicts.\n */\n const environment = computed<XScalarEnvironment>(\n () => getActiveEnvironment(store.value, activeDocument.value).environment,\n )\n\n /** Update the workspace list when the component is mounted */\n workspaces.value = await persistence.getAll().then((w) =>\n w.map(({ teamUid, namespace, slug, name }) => ({\n id: getWorkspaceId(namespace, slug),\n teamUid,\n namespace,\n slug,\n label: name,\n })),\n )\n\n /**\n * Renames the currently active workspace.\n * Updates the workspace name in persistence and updates activeWorkspace if successful.\n * Returns early if namespace or workspaceSlug is not set, or if update fails.\n */\n const renameWorkspace = async (name: string) => {\n const namespaceValue = namespace.value\n const slugValue = workspaceSlug.value\n if (!namespaceValue || !slugValue) {\n return\n }\n const workspaceId = getWorkspaceId(namespaceValue, slugValue)\n const updateResult = await persistence.updateName({ namespace: namespaceValue, slug: slugValue }, name)\n\n // If the update fails, return early\n if (updateResult === undefined) {\n return\n }\n\n // Update the workspace list\n workspaces.value = workspaces.value.map((workspace) => {\n // If the workspace is the currently active workspace, update the label\n if (workspace.id === workspaceId) {\n return { ...workspace, label: name }\n }\n return workspace\n })\n activeWorkspace.value = { id: workspaceId, label: name }\n }\n\n /**\n * Creates a client-side workspace store with persistence enabled for the given workspace id.\n */\n const createClientStore = async ({\n namespace,\n slug,\n }: {\n namespace: string\n slug: string\n }): Promise<WorkspaceStore> => {\n return createWorkspaceStore({\n plugins: [\n await persistencePlugin({\n workspaceId: getWorkspaceId(namespace, slug),\n debounceDelay: DEFAULT_DEBOUNCE_DELAY,\n }),\n ],\n fileLoader,\n })\n }\n\n /**\n * Attempts to load and activate a workspace by id.\n * Returns true when the workspace was found and activated.\n */\n const loadWorkspace = async (\n namespace: string,\n slug: string,\n ): Promise<{ success: true; workspace: Workspace } | { success: false }> => {\n const workspace = await persistence.getItem({ namespace, slug })\n\n if (!workspace) {\n return {\n success: false,\n }\n }\n\n const client = await createClientStore({ namespace, slug })\n client.loadWorkspace(workspace.workspace)\n activeWorkspace.value = { id: getWorkspaceId(workspace.namespace, workspace.slug), label: workspace.name }\n store.value = client\n\n return {\n success: true,\n workspace: client.workspace,\n }\n }\n\n /**\n * Creates and persists the default workspace with a blank draft document.\n * Used when no workspaces exist yet.\n */\n const createAndPersistWorkspace = async ({\n name,\n teamUid,\n namespace,\n slug,\n }: {\n name: string\n teamUid?: string\n namespace?: string\n slug: string\n }) => {\n const draftStore = createWorkspaceStore()\n await draftStore.addDocument({\n name: 'drafts',\n document: {\n openapi: '3.1.0',\n info: {\n title: 'Drafts',\n version: '1.0.0',\n },\n paths: {\n '/': {\n get: {},\n },\n },\n 'x-scalar-original-document-hash': 'drafts',\n 'x-scalar-icon': 'interface-edit-tool-pencil',\n },\n })\n\n // Persist the workspace\n const workspace = await persistence.setItem(\n { namespace, slug },\n {\n name: name,\n teamUid,\n workspace: draftStore.exportWorkspace(),\n },\n )\n\n // Update the workspace list\n workspaces.value.push({\n id: getWorkspaceId(workspace.namespace, workspace.slug),\n teamUid: workspace.teamUid,\n namespace: workspace.namespace,\n slug: workspace.slug,\n label: workspace.name,\n })\n return workspace\n }\n\n /**\n * Navigates to the overview page of the specified workspace.\n *\n * @param namespace - The workspace namespace.\n * @param slug - The unique workspace slug (identifier).\n */\n const navigateToWorkspace = async (namespace?: string, slug?: string): Promise<void> => {\n if (!namespace || !slug) {\n await router.push('/')\n return\n }\n\n // We should always have this drafts document available in a new workspace\n await router.push({\n name: 'example',\n params: {\n namespace,\n workspaceSlug: slug,\n documentSlug: 'drafts',\n pathEncoded: encodeURIComponent('/'),\n method: 'get',\n exampleName: 'default',\n },\n })\n }\n\n /**\n * Creates a new workspace with the provided name.\n * - Generates a unique slug for the workspace (uses the provided slug if it is unique, otherwise generates a unique slug).\n * - Adds a default blank document (\"drafts\") to the workspace.\n * - Persists the workspace and navigates to it.\n *\n * Example usage:\n * await createWorkspace({ name: 'My Awesome API' })\n * // -> Navigates to /workspace/my-awesome-api (if available)\n */\n const createWorkspace = async ({\n teamUid,\n namespace,\n slug,\n name,\n }: {\n teamUid?: string\n namespace?: string\n slug?: string\n name: string\n }) => {\n // Clear up the current store, in order to show the loading state\n store.value = null\n\n // Generate a unique slug/id for the workspace, based on the name.\n const newWorkspaceSlug = await generateUniqueValue({\n defaultValue: slug ?? name, // Use the provided id if it exists, otherwise use the name\n validation: async (value) => !(await persistence.has({ namespace: namespace ?? 'local', slug: value })),\n maxRetries: 100,\n transformation: slugify,\n })\n\n // Failed to generate a unique workspace id, so we can't create the workspace.\n if (!newWorkspaceSlug) {\n return undefined\n }\n\n const newWorkspaceDetails = {\n teamUid,\n namespace,\n slug: newWorkspaceSlug,\n name,\n }\n\n // Create a new client store with the workspace ID and add a default document.\n const createdWorkspace = await createAndPersistWorkspace(newWorkspaceDetails)\n\n // Navigate to the newly created workspace.\n await navigateToWorkspace(createdWorkspace.namespace, createdWorkspace.slug)\n return createdWorkspace\n }\n\n /**\n * Handles changing the active workspace when the workspace slug changes in the route.\n * This function:\n * - Clears the current workspace store and sets loading state.\n * - Attempts to load the workspace by slug.\n * - If found, navigates to the active tab path (if available).\n * - If not found, creates the default workspace and navigates to it.\n */\n const changeWorkspace = async (namespace: string, slug: string) => {\n // Clear the current store and set loading to true before loading new workspace.\n store.value = null\n isSyncingWorkspace.value = true\n\n // Try to load the workspace\n const result = await loadWorkspace(namespace, slug)\n\n if (result.success) {\n // Navigate to the correct tab if the workspace has a tab already\n const index = result.workspace['x-scalar-active-tab'] ?? 0\n const tabs = result.workspace['x-scalar-tabs']\n const tab = tabs?.[index]\n\n if (tab) {\n // Preserve query parameters when navigating to the active tab\n await router.replace({\n path: tab.path,\n query: currentRoute.value?.query ?? {},\n })\n }\n\n // Heal the active tab index if it is out of bounds\n if (tabs && index >= tabs.length) {\n eventBus.emit('tabs:update:tabs', {\n 'x-scalar-active-tab': 0,\n })\n }\n\n // Initialize the tabs if they does not exist\n if (!tabs) {\n eventBus.emit('tabs:update:tabs', {\n 'x-scalar-tabs': [createTabFromRoute(currentRoute.value)],\n 'x-scalar-active-tab': 0,\n })\n }\n\n isSyncingWorkspace.value = false\n return\n }\n\n // Navigate to the default workspace, or fall back to the first available workspace\n const targetWorkspace =\n filteredWorkspaces.value.find((workspace) => workspace.teamUid === 'local' && workspace.slug === 'default') ??\n filteredWorkspaces.value[0]\n\n if (targetWorkspace) {\n return navigateToWorkspace(targetWorkspace.namespace, targetWorkspace.slug)\n }\n\n // If loading failed (workspace does not exist), create the default workspace and navigate to it.\n const createResult = await createWorkspace({\n name: 'Default Workspace',\n slug: 'default',\n })\n\n isSyncingWorkspace.value = false\n\n if (!createResult) {\n return console.error('Failed to create the default workspace, something went wrong, can not load the workspace')\n }\n\n // Must reset the sidebar state when the workspace changes\n sidebarState.reset()\n }\n\n /**\n * Sets the current team context. If the active workspace is not accessible\n * with the new team, navigates to the default workspace for that team.\n */\n const setTeamUid = (value: string) => {\n // Update the new teamUid\n teamUid.value = value\n\n // Find the current workspace\n const workspace = filteredWorkspaces.value.find(\n (w) => w.namespace === namespace.value && w.slug === workspaceSlug.value,\n )\n\n // Check if new teamUid is accessible to the current workspace\n if (workspace && canLoadWorkspace(workspace.teamUid, value)) {\n return\n }\n\n return navigateToWorkspace('local', 'default')\n }\n\n // ---------------------------------------------------------------------------\n // Sidebar state management\n\n const entries = computed(() => {\n const activeStore = store.value\n if (!activeStore) {\n return []\n }\n\n const order = activeStore.workspace['x-scalar-order'] ?? Object.keys(activeStore.workspace.documents)\n\n return sortByOrder(Object.keys(activeStore.workspace.documents), order, (item) => item)\n .map((doc) => activeStore.workspace.documents[doc]?.['x-scalar-navigation'])\n .filter(isDefined) as TraversedEntry[]\n })\n\n const sidebarState = createSidebarState(entries)\n\n /**\n * Generates a unique string ID for an API location, based on the document, path, method, and example.\n * Filters out undefined values and serializes the composite array into a stable string.\n *\n * @param params - An object containing document, path, method, and optional example name.\n * @returns A stringified array representing the unique location identifier.\n *\n * Example:\n * generateId({ document: 'mydoc', path: '/users', method: 'get', example: 'default' })\n * // => '[\"mydoc\",\"/users\",\"get\",\"default\"]'\n */\n const generateId = ({\n document,\n path,\n method,\n example,\n }: {\n document: string\n path?: string\n method?: HttpMethod\n example?: string\n }) => {\n return JSON.stringify([document, path, method, example].filter(isDefined))\n }\n\n /**\n * Computed index for fast lookup of sidebar nodes by their unique API location.\n *\n * - Only indexes nodes of type 'document', 'operation', or 'example'.\n * - The lookup key is a serialized array of: [documentName, operationPath, operationMethod, exampleName?].\n * - Supports precise resolution of sidebar entries given an API \"location\".\n */\n const locationIndex = computed(() =>\n generateReverseIndex({\n items: entries.value,\n nestedKey: 'children',\n filter: (node) => node.type === 'document' || node.type === 'operation' || node.type === 'example',\n getId: (node) => {\n const document = getParentEntry('document', node)\n const operation = getParentEntry('operation', node)\n return generateId({\n document: document?.name ?? '',\n path: operation?.path,\n method: operation?.method,\n example: node.type === 'example' ? node.name : undefined,\n })\n },\n }),\n )\n\n /**\n * Looks up a sidebar entry by its unique API location.\n * - First tries to find an entry matching all provided properties (including example).\n * - If not found, falls back to matching only the operation (ignores example field).\n * This allows resolving either examples, operations, or documents as appropriate.\n *\n * @param location - Object specifying the document name, path, method, and optional example name.\n * @returns The matching sidebar entry, or undefined if none found.\n *\n * Example:\n * const entry = getEntryByLocation({\n * document: 'pets',\n * path: '/pets',\n * method: 'get',\n * example: 'default',\n * })\n */\n const getEntryByLocation: GetEntryByLocation = (location) => {\n // Try to find an entry with the most-specific location (including example)\n const entryWithExample = locationIndex.value.get(generateId(location))\n\n if (entryWithExample) {\n return entryWithExample\n }\n\n // Fallback to the operation (ignoring example) if an example wasn't found or specified\n return locationIndex.value.get(\n generateId({\n document: location.document,\n path: location.path,\n method: location.method,\n }),\n )\n }\n\n /**\n * Handles item selection from the sidebar and routes navigation accordingly.\n *\n * Example:\n * handleSelectItem('id-of-entry')\n */\n const handleSelectItem = (id: string) => {\n const entry = sidebarState.getEntryById(id)\n\n if (!entry) {\n console.warn(`Could not find sidebar entry with id ${id} to select`)\n return\n }\n\n /** Close sidebar and navigate. Used for every branch that performs navigation. */\n const navigate = (route: RouteLocationRaw) => {\n isSidebarOpen.value = false\n return router.push(route)\n }\n\n // Navigate to the document overview page\n if (entry.type === 'document') {\n // If we are already in the document, just toggle expansion\n if (sidebarState.selectedItem.value === id) {\n sidebarState.setExpanded(id, !sidebarState.isExpanded(id))\n return\n }\n\n // Otherwise, select it\n sidebarState.setSelected(id)\n sidebarState.setExpanded(id, true)\n return navigate({\n name: 'document.overview',\n params: { documentSlug: entry.name },\n })\n }\n\n // Navigate to the example page\n if (entry.type === 'operation') {\n // If we are already in an operation child we just want to toggle the explanstion\n if (sidebarState.isSelected(id) && sidebarState.selectedItem.value !== id) {\n sidebarState.setExpanded(id, !sidebarState.isExpanded(id))\n return\n }\n\n // Otherwise, select the first example\n const firstExample = entry.children?.find((child) => child.type === 'example')\n\n if (firstExample) {\n sidebarState.setSelected(firstExample.id)\n sidebarState.setExpanded(firstExample.id, true)\n } else {\n sidebarState.setSelected(id)\n }\n\n return navigate({\n name: 'example',\n params: {\n documentSlug: getParentEntry('document', entry)?.name,\n pathEncoded: encodeURIComponent(entry.path),\n method: entry.method,\n exampleName: firstExample?.name ?? 'default',\n },\n })\n }\n\n // Navigate to the example page\n if (entry.type === 'example') {\n sidebarState.setSelected(id)\n const operation = getParentEntry('operation', entry)\n return navigate({\n name: 'example',\n params: {\n documentSlug: getParentEntry('document', entry)?.name,\n pathEncoded: encodeURIComponent(operation?.path ?? ''),\n method: operation?.method,\n exampleName: entry.name,\n },\n })\n }\n\n if (entry.type === 'text') {\n return navigate({\n name: 'document.overview',\n params: {\n documentSlug: getParentEntry('document', entry)?.name,\n },\n })\n }\n\n sidebarState.setExpanded(id, !sidebarState.isExpanded(id))\n return\n }\n\n /**\n * Navigates to the currently active tab's path using the router.\n * Returns early if the workspace store or active tab is unavailable.\n */\n const navigateToCurrentTab = async (): Promise<void> => {\n if (!store.value) {\n return\n }\n\n const activeTabIndex = store.value.workspace['x-scalar-active-tab'] ?? 0\n const activeTab = store.value.workspace['x-scalar-tabs']?.[activeTabIndex]\n if (!activeTab) {\n return\n }\n\n await router.replace(activeTab.path)\n }\n\n /**\n * Rebuilds the sidebar for the given document.\n * This is used to refresh the sidebar state after structural changes (e.g. after adding or removing items).\n *\n * @param documentName - The name (id) of the document for which to rebuild the sidebar\n */\n const rebuildSidebar = (documentName: string | undefined) => {\n if (documentName) {\n store.value?.buildSidebar(documentName)\n }\n }\n\n /**\n * Ensures the sidebar is refreshed after a new example is created.\n *\n * If the sidebar entry for the new example does not exist or is of a different type,\n * this will rebuild the sidebar for the current document. This helps keep the sidebar state\n * consistent (e.g., after adding a new example via the UI).\n */\n const refreshSidebarAfterExampleCreation = (payload: OperationExampleMeta & { documentName?: string }) => {\n const documentName = payload.documentName ?? activeDocument.value?.['x-scalar-navigation']?.name\n if (!documentName) {\n return\n }\n\n const entry = getEntryByLocation({\n document: documentName,\n path: payload.path,\n method: payload.method,\n example: payload.exampleKey,\n })\n\n if (!entry || entry.type !== 'example') {\n // Sidebar entry for this example doesn't exist, so rebuild sidebar for consistency.\n rebuildSidebar(documentName)\n if (currentRoute.value) {\n syncSidebar(currentRoute.value)\n }\n }\n return\n }\n\n /** Width of the sidebar, with fallback to default. */\n const sidebarWidth = computed(() => store.value?.workspace?.['x-scalar-sidebar-width'] ?? DEFAULT_SIDEBAR_WIDTH)\n\n /** Handler for sidebar width changes. */\n const handleSidebarWidthUpdate = (width: number) => store.value?.update('x-scalar-sidebar-width', width)\n\n /** Controls the visibility of the sidebar. */\n const isSidebarOpen = ref(false)\n // ---------------------------------------------------------------------------\n // Tab Management\n\n /** Constants for workspace store keys */\n const TABS_KEY = 'x-scalar-tabs' as const\n const ACTIVE_TAB_KEY = 'x-scalar-active-tab' as const\n\n /**\n * Creates a tab object based on the current route and workspace state.\n * Used as a fallback when no tabs exist or when creating new tabs.\n */\n const createTabFromRoute = (to: RouteLocationNormalizedGeneric | null): Tab => {\n const method = getRouteParam('method', to)\n const path = getRouteParam('pathEncoded', to)\n const document = getRouteParam('documentSlug', to)\n const workspace = getRouteParam('workspaceSlug', to)\n return {\n ...getTabDetails({\n workspace,\n document,\n path,\n method,\n getEntryByLocation,\n }),\n path: currentRoute.value?.path ?? '',\n }\n }\n\n const tabs = computed(() => {\n return store.value?.workspace[TABS_KEY] ?? [createTabFromRoute(currentRoute.value)]\n })\n\n const activeTabIndex = computed(() => {\n return store.value?.workspace[ACTIVE_TAB_KEY] ?? 0\n })\n\n /**\n * Copies the URL of the tab at the given index to the clipboard.\n * Constructs the full URL using the current origin and the tab path.\n *\n * Note: Will silently fail if clipboard API is unavailable or the tab does not exist.\n */\n const copyTabUrl = async (index: number): Promise<void> => {\n const tab = tabs.value[index]\n\n if (!tab) {\n console.warn(`Cannot copy URL: tab at index ${index} does not exist`)\n return\n }\n\n const url = `${window.location.origin}${tab.path}`\n\n try {\n await navigator.clipboard.writeText(url)\n } catch (error) {\n console.error('Failed to copy URL to clipboard:', error)\n }\n }\n\n // ---------------------------------------------------------------------------\n // Path syncing\n\n /** When the route changes we need to update the active entities in the store */\n const handleRouteChange = (to: RouteLocationNormalizedGeneric) => {\n const slug = getRouteParam('workspaceSlug', to)\n const document = getRouteParam('documentSlug', to)\n const namespaceValue = getRouteParam('namespace', to)\n\n // Must have an active workspace to syncs\n if (!namespaceValue || !slug) {\n return\n }\n\n // Try to see if the user can load this workspace based on the teamUid and namespace\n const workspace = workspaces.value.find(\n (workspace) => workspace.slug === slug && workspace.namespace === namespaceValue,\n )\n\n // If the workspace is not found or the teamUid does not match, try to redirect to the default workspace\n if (workspace && !canLoadWorkspace(workspace.teamUid, teamUid.value)) {\n // try to redirect to the default workspace\n return navigateToWorkspace('local', 'default')\n }\n\n namespace.value = namespaceValue\n workspaceSlug.value = slug\n documentSlug.value = document\n method.value = getRouteParam('method', to)\n path.value = getRouteParam('pathEncoded', to)\n exampleName.value = getRouteParam('exampleName', to)\n\n // Save the current path to the persistence storage\n if (to.path !== '') {\n workspaceStorage.setCurrentPath(to.path)\n }\n\n if (getWorkspaceId(namespace.value, slug) !== activeWorkspace.value?.id) {\n return changeWorkspace(namespace.value, slug)\n }\n\n // Update the active document if the document slug has changes\n if (document && document !== store.value?.workspace[extensions.workspace.activeDocument]) {\n store?.value?.update('x-scalar-active-document', document)\n }\n\n syncTabs(to)\n syncSidebar(to)\n return\n }\n\n /** Aligns the tabs with any potential slug changes */\n const syncTabs = (to: RouteLocationNormalizedGeneric) => {\n const tabs = store.value?.workspace['x-scalar-tabs'] ?? []\n const index = store.value?.workspace['x-scalar-active-tab'] ?? 0\n\n const tab = tabs[index]\n\n // If there is no tab or the tab path is the same we leave the tab state alone\n if (!tab || tab.path === to.path) {\n // Already on the correct path, do nothing\n return\n }\n\n // Otherwise we replace the tab content with the new route\n tabs[index] = createTabFromRoute(to)\n }\n\n /** Aligns the sidebar state with any potential slug changes */\n const syncSidebar = (to: RouteLocationNormalizedGeneric) => {\n const document = getRouteParam('documentSlug', to)\n\n if (!document) {\n // Reset selection if no document is selected\n sidebarState.setSelected(null)\n return\n }\n\n const entry = getEntryByLocation({\n document,\n path: getRouteParam('pathEncoded', to),\n method: getRouteParam('method', to),\n example: getRouteParam('exampleName', to),\n })\n\n if (entry) {\n sidebarState.setSelected(entry.id)\n sidebarState.setExpanded(entry.id, true)\n }\n }\n\n // ---------------------------------------------------------------------------\n // Events handling\n\n initializeAppEventHandlers({\n eventBus,\n router,\n store,\n navigateToCurrentTab,\n rebuildSidebar,\n onAfterExampleCreation: refreshSidebarAfterExampleCreation,\n onSelectSidebarItem: handleSelectItem,\n onCopyTabUrl: (index) => copyTabUrl(index),\n onToggleSidebar: () => (isSidebarOpen.value = !isSidebarOpen.value),\n closeSidebar: () => (isSidebarOpen.value = false),\n renameWorkspace,\n })\n\n const theme = useTheme({\n fallbackThemeSlug,\n customThemes,\n store: store,\n })\n\n const isDarkMode = computed(() => {\n const colorMode = store.value?.workspace['x-scalar-color-mode'] ?? 'system'\n if (colorMode === 'system') {\n return window.matchMedia?.('(prefers-color-scheme: dark)')?.matches ?? false\n }\n return colorMode === 'dark'\n })\n\n return {\n /** Active workspace store */\n store,\n sidebar: {\n state: sidebarState,\n width: sidebarWidth,\n isOpen: isSidebarOpen,\n handleSelectItem,\n handleSidebarWidthUpdate,\n getEntryByLocation,\n },\n tabs: {\n state: tabs,\n activeTabIndex,\n copyTabUrl,\n },\n workspace: {\n create: createWorkspace,\n workspaceList: workspaces,\n filteredWorkspaceList: filteredWorkspaces,\n workspaceGroups,\n activeWorkspace,\n navigateToWorkspace,\n isOpen: computed(() => Boolean(workspaceSlug.value && !documentSlug.value)),\n },\n eventBus,\n router,\n currentRoute,\n loading: isSyncingWorkspace,\n activeEntities: {\n namespace,\n workspaceSlug,\n documentSlug,\n path,\n method,\n exampleName,\n teamUid: readonly(teamUid),\n setTeamUid,\n },\n environment,\n document: activeDocument,\n isDarkMode,\n theme: {\n styles: theme.themeStyles,\n themeStyleTag: theme.themeStyleTag,\n customThemes,\n },\n telemetry,\n }\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"app-state.js","names":[],"sources":["../../../../src/v2/features/app/app-state.ts"],"sourcesContent":["import type { ScalarListboxOption, WorkspaceGroup } from '@scalar/components'\nimport { isDefined } from '@scalar/helpers/array/is-defined'\nimport { sortByOrder } from '@scalar/helpers/array/sort-by-order'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport type { LoaderPlugin } from '@scalar/json-magic/bundle'\nimport { migrateLocalStorageToIndexDb } from '@scalar/oas-utils/migrations'\nimport { createSidebarState, generateReverseIndex } from '@scalar/sidebar'\nimport type { Theme } from '@scalar/themes'\nimport { type WorkspaceStore, createWorkspaceStore } from '@scalar/workspace-store/client'\n\nimport type { ApiClientAppOptions } from '@/v2/features/app/helpers/create-api-client-app'\nimport {\n type OperationExampleMeta,\n type WorkspaceEventBus,\n createWorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { generateUniqueValue } from '@scalar/workspace-store/helpers/generate-unique-value'\nimport { getParentEntry } from '@scalar/workspace-store/navigation'\nimport { createWorkspaceStorePersistence, getWorkspaceId } from '@scalar/workspace-store/persistence'\nimport { persistencePlugin } from '@scalar/workspace-store/plugins/client'\nimport { getActiveEnvironment } from '@scalar/workspace-store/request-example'\nimport type { Workspace, WorkspaceDocument } from '@scalar/workspace-store/schemas'\nimport { extensions } from '@scalar/workspace-store/schemas/extensions'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { Tab } from '@scalar/workspace-store/schemas/extensions/workspace/x-scalar-tabs'\nimport type { TraversedEntry } from '@scalar/workspace-store/schemas/navigation'\nimport {\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n type ShallowRef,\n computed,\n readonly,\n ref,\n shallowRef,\n watch,\n} from 'vue'\nimport type { RouteLocationNormalizedGeneric, RouteLocationRaw, Router } from 'vue-router'\n\nimport { getRouteParam } from '@/v2/features/app/helpers/get-route-param'\nimport { groupWorkspacesByTeam } from '@/v2/features/app/helpers/group-workspaces'\nimport { useTheme } from '@/v2/features/app/hooks/use-theme'\nimport { getTabDetails } from '@/v2/helpers/get-tab-details'\nimport { slugify } from '@/v2/helpers/slugify'\nimport { workspaceStorage } from '@/v2/helpers/storage'\n\nimport { initializeAppEventHandlers } from './app-events'\nimport { canLoadWorkspace, filterWorkspacesByTeam } from './helpers/filter-workspaces'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\nexport type GetEntryByLocation = (location: {\n document: string\n path?: string\n method?: HttpMethod\n example?: string\n}) =>\n | (TraversedEntry & {\n parent?: TraversedEntry | undefined\n })\n | undefined\n\ntype WorkspaceOption = ScalarListboxOption & { teamUid: string; namespace: string; slug: string }\n\n/** Defines the overall application state structure and its main feature modules */\nexport type AppState = {\n /** The workspace store */\n store: ShallowRef<WorkspaceStore | null>\n /** The sidebar management */\n sidebar: {\n /** The sidebar state */\n state: ReturnType<typeof createSidebarState<TraversedEntry>>\n /** The width of the sidebar */\n width: ComputedRef<number>\n /** Whether the sidebar is open */\n isOpen: Ref<boolean>\n /** Handles the selection of an item in the sidebar */\n handleSelectItem: (id: string) => void\n /** Handles the width update of the sidebar */\n handleSidebarWidthUpdate: (width: number) => void\n /** Gets the entry by location */\n getEntryByLocation: GetEntryByLocation\n }\n /** The tabs management */\n tabs: {\n /** The tabs state */\n state: Ref<Tab[]>\n /** The active tab index */\n activeTabIndex: Ref<number>\n /** Copies the URL of the tab at the given index to the clipboard */\n copyTabUrl: (index: number) => Promise<void>\n }\n /** The workspace management */\n workspace: {\n /** Creates a new workspace and navigates to it */\n create: (payload: {\n teamUid?: string\n namespace?: string\n slug?: string\n name: string\n }) => Promise<{ name: string; namespace: string; slug: string; teamUid: string } | undefined>\n /** All workspace list */\n workspaceList: Ref<WorkspaceOption[]>\n /** Filtered workspace list, based on the current teamUid */\n filteredWorkspaceList: ComputedRef<WorkspaceOption[]>\n /**\n * Groups workspaces into team and local categories for display in the workspace picker.\n * Team workspaces are shown first (when not on local team), followed by local workspaces.\n */\n workspaceGroups: ComputedRef<WorkspaceGroup[]>\n /** The currently active workspace */\n activeWorkspace: ShallowRef<{ id: string; label: string } | null>\n /** Navigates to the specified workspace */\n navigateToWorkspace: (namespace?: string, slug?: string) => Promise<void>\n /** Whether the workspace page is open */\n isOpen: ComputedRef<boolean>\n }\n /** The workspace event bus for handling workspace-level events */\n eventBus: WorkspaceEventBus\n /** The router instance */\n router: Router\n /** The current route derived from the router */\n currentRoute: Ref<RouteLocationNormalizedGeneric | null>\n /** Whether the workspace is currently syncing */\n loading: Ref<boolean>\n /** Runtime behaviour overrides */\n options?: ApiClientAppOptions\n /** The currently active entities */\n activeEntities: {\n /** The namespace of the current entity, e.g. \"default\" or a custom namespace */\n namespace: Ref<string | undefined>\n /** The slug identifying the current workspace */\n workspaceSlug: Ref<string | undefined>\n /** The slug of the currently selected document in the workspace */\n documentSlug: Ref<string | undefined>\n /** The API path currently selected (e.g. \"/users/{id}\") */\n path: Ref<string | undefined>\n /** The HTTP method for the currently selected API path (e.g. GET, POST) */\n method: Ref<HttpMethod | undefined>\n /** The name of the currently selected example (for examples within an endpoint) */\n exampleName: Ref<string | undefined>\n /** The unique identifier for the selected team context (read-only; use setTeamUid to change) */\n teamUid: Readonly<Ref<string>>\n /** Sets the current team context by team UID */\n setTeamUid: (value: string) => void\n }\n /** The currently active environment */\n environment: ComputedRef<XScalarEnvironment>\n /** The currently active document */\n document: ComputedRef<WorkspaceDocument | null>\n /** Whether the current color mode is dark */\n isDarkMode: ComputedRef<boolean>\n /** The currently active theme */\n theme: {\n /** The computed CSS styles for the current theme, as a string */\n styles: ComputedRef<{ themeStyles: string; themeSlug: string }>\n /** The computed value for the <style> tag containing the current theme styles */\n themeStyleTag: ComputedRef<string>\n /** The custom themes to use */\n customThemes: MaybeRefOrGetter<Theme[]>\n }\n telemetry: Ref<boolean>\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n/** Default debounce delay in milliseconds for workspace store persistence. */\nconst DEFAULT_DEBOUNCE_DELAY = 1000\n/** Default sidebar width in pixels. */\nconst DEFAULT_SIDEBAR_WIDTH = 288\n\n// ---------------------------------------------------------------------------\n// App State\n// ---------------------------------------------------------------------------\nexport const createAppState = async ({\n router,\n fileLoader,\n fallbackThemeSlug = () => 'default',\n customThemes = () => [],\n telemetryDefault,\n options,\n}: {\n router: Router\n fileLoader?: LoaderPlugin\n customThemes?: MaybeRefOrGetter<Theme[]>\n fallbackThemeSlug?: MaybeRefOrGetter<string>\n telemetryDefault?: boolean\n /** Runtime behaviour overrides */\n options?: ApiClientAppOptions\n}): Promise<AppState> => {\n /** Workspace event bus for handling workspace-level events. */\n const eventBus = createWorkspaceEventBus({\n debug: import.meta.env.DEV,\n })\n\n const { workspace: persistence } = await createWorkspaceStorePersistence()\n\n /**\n * Run migration from localStorage to IndexedDB if needed\n * This happens once per user and transforms old data structure to new workspace format\n */\n await migrateLocalStorageToIndexDb()\n\n // ---------------------------------------------------------------------------\n // Active entities\n // ---------------------------------------------------------------------------\n const teamUid = ref<string>('local')\n const namespace = ref<string | undefined>(undefined)\n const workspaceSlug = ref<string | undefined>(undefined)\n const documentSlug = ref<string | undefined>(undefined)\n const method = ref<HttpMethod | undefined>(undefined)\n const path = ref<string | undefined>(undefined)\n const exampleName = ref<string | undefined>(undefined)\n\n // ---------------------------------------------------------------------------\n // Loading states\n const isSyncingWorkspace = ref(false)\n\n // ---------------------------------------------------------------------------\n // Router state\n router.afterEach((to) => handleRouteChange(to))\n const currentRoute = computed(() => router.currentRoute.value ?? null)\n\n // ---------------------------------------------------------------------------\n // Workspace persistence state management\n const activeWorkspace = shallowRef<{ id: string; label: string } | null>(null)\n const workspaces = ref<WorkspaceOption[]>([])\n const filteredWorkspaces = computed(() => filterWorkspacesByTeam(workspaces.value, teamUid.value))\n const workspaceGroups = computed(() => groupWorkspacesByTeam(filteredWorkspaces.value, teamUid.value))\n const store = shallowRef<WorkspaceStore | null>(null)\n\n // Load persisted telemetry preference, falling back to the provided default\n const persistedTelemetry = workspaceStorage.getTelemetry()\n const telemetry = ref(persistedTelemetry !== null ? persistedTelemetry : Boolean(telemetryDefault))\n watch(telemetry, (value) => workspaceStorage.setTelemetry(value))\n\n const activeDocument = computed(() => {\n return store.value?.workspace.documents[documentSlug.value ?? ''] || null\n })\n\n /**\n * Merged environment variables from workspace and document levels.\n * Variables from both sources are combined, with document variables\n * taking precedence in case of naming conflicts.\n */\n const environment = computed<XScalarEnvironment>(\n () => getActiveEnvironment(store.value, activeDocument.value).environment,\n )\n\n /** Update the workspace list when the component is mounted */\n workspaces.value = await persistence.getAll().then((w) =>\n w.map(({ teamUid, namespace, slug, name }) => ({\n id: getWorkspaceId(namespace, slug),\n teamUid,\n namespace,\n slug,\n label: name,\n })),\n )\n\n /**\n * Renames the currently active workspace.\n * Updates the workspace name in persistence and updates activeWorkspace if successful.\n * Returns early if namespace or workspaceSlug is not set, or if update fails.\n */\n const renameWorkspace = async (name: string) => {\n const namespaceValue = namespace.value\n const slugValue = workspaceSlug.value\n if (!namespaceValue || !slugValue) {\n return\n }\n const workspaceId = getWorkspaceId(namespaceValue, slugValue)\n const updateResult = await persistence.updateName({ namespace: namespaceValue, slug: slugValue }, name)\n\n // If the update fails, return early\n if (updateResult === undefined) {\n return\n }\n\n // Update the workspace list\n workspaces.value = workspaces.value.map((workspace) => {\n // If the workspace is the currently active workspace, update the label\n if (workspace.id === workspaceId) {\n return { ...workspace, label: name }\n }\n return workspace\n })\n activeWorkspace.value = { id: workspaceId, label: name }\n }\n\n /**\n * Creates a client-side workspace store with persistence enabled for the given workspace id.\n */\n const createClientStore = async ({\n namespace,\n slug,\n }: {\n namespace: string\n slug: string\n }): Promise<WorkspaceStore> => {\n return createWorkspaceStore({\n plugins: [\n await persistencePlugin({\n workspaceId: getWorkspaceId(namespace, slug),\n debounceDelay: DEFAULT_DEBOUNCE_DELAY,\n }),\n ],\n fileLoader,\n fetch: options?.customFetch,\n })\n }\n\n /**\n * Attempts to load and activate a workspace by id.\n * Returns true when the workspace was found and activated.\n */\n const loadWorkspace = async (\n namespace: string,\n slug: string,\n ): Promise<{ success: true; workspace: Workspace } | { success: false }> => {\n const workspace = await persistence.getItem({ namespace, slug })\n\n if (!workspace) {\n return {\n success: false,\n }\n }\n\n const client = await createClientStore({ namespace, slug })\n client.loadWorkspace(workspace.workspace)\n activeWorkspace.value = { id: getWorkspaceId(workspace.namespace, workspace.slug), label: workspace.name }\n store.value = client\n\n return {\n success: true,\n workspace: client.workspace,\n }\n }\n\n /**\n * Creates and persists the default workspace with a blank draft document.\n * Used when no workspaces exist yet.\n */\n const createAndPersistWorkspace = async ({\n name,\n teamUid,\n namespace,\n slug,\n }: {\n name: string\n teamUid?: string\n namespace?: string\n slug: string\n }) => {\n const draftStore = createWorkspaceStore()\n await draftStore.addDocument({\n name: 'drafts',\n document: {\n openapi: '3.1.0',\n info: {\n title: 'Drafts',\n version: '1.0.0',\n },\n paths: {\n '/': {\n get: {},\n },\n },\n 'x-scalar-original-document-hash': 'drafts',\n 'x-scalar-icon': 'interface-edit-tool-pencil',\n },\n })\n\n // Persist the workspace\n const workspace = await persistence.setItem(\n { namespace, slug },\n {\n name: name,\n teamUid,\n workspace: draftStore.exportWorkspace(),\n },\n )\n\n // Update the workspace list\n workspaces.value.push({\n id: getWorkspaceId(workspace.namespace, workspace.slug),\n teamUid: workspace.teamUid,\n namespace: workspace.namespace,\n slug: workspace.slug,\n label: workspace.name,\n })\n return workspace\n }\n\n /**\n * Navigates to the overview page of the specified workspace.\n *\n * @param namespace - The workspace namespace.\n * @param slug - The unique workspace slug (identifier).\n */\n const navigateToWorkspace = async (namespace?: string, slug?: string): Promise<void> => {\n if (!namespace || !slug) {\n await router.push('/')\n return\n }\n\n // We should always have this drafts document available in a new workspace\n await router.push({\n name: 'example',\n params: {\n namespace,\n workspaceSlug: slug,\n documentSlug: 'drafts',\n pathEncoded: encodeURIComponent('/'),\n method: 'get',\n exampleName: 'default',\n },\n })\n }\n\n /**\n * Creates a new workspace with the provided name.\n * - Generates a unique slug for the workspace (uses the provided slug if it is unique, otherwise generates a unique slug).\n * - Adds a default blank document (\"drafts\") to the workspace.\n * - Persists the workspace and navigates to it.\n *\n * Example usage:\n * await createWorkspace({ name: 'My Awesome API' })\n * // -> Navigates to /workspace/my-awesome-api (if available)\n */\n const createWorkspace = async ({\n teamUid,\n namespace,\n slug,\n name,\n }: {\n teamUid?: string\n namespace?: string\n slug?: string\n name: string\n }) => {\n // Clear up the current store, in order to show the loading state\n store.value = null\n\n // Generate a unique slug/id for the workspace, based on the name.\n const newWorkspaceSlug = await generateUniqueValue({\n defaultValue: slug ?? name, // Use the provided id if it exists, otherwise use the name\n validation: async (value) => !(await persistence.has({ namespace: namespace ?? 'local', slug: value })),\n maxRetries: 100,\n transformation: slugify,\n })\n\n // Failed to generate a unique workspace id, so we can't create the workspace.\n if (!newWorkspaceSlug) {\n return undefined\n }\n\n const newWorkspaceDetails = {\n teamUid,\n namespace,\n slug: newWorkspaceSlug,\n name,\n }\n\n // Create a new client store with the workspace ID and add a default document.\n const createdWorkspace = await createAndPersistWorkspace(newWorkspaceDetails)\n\n // Navigate to the newly created workspace.\n await navigateToWorkspace(createdWorkspace.namespace, createdWorkspace.slug)\n return createdWorkspace\n }\n\n /**\n * Handles changing the active workspace when the workspace slug changes in the route.\n * This function:\n * - Clears the current workspace store and sets loading state.\n * - Attempts to load the workspace by slug.\n * - If found, navigates to the active tab path (if available).\n * - If not found, creates the default workspace and navigates to it.\n */\n const changeWorkspace = async (namespace: string, slug: string) => {\n // Clear the current store and set loading to true before loading new workspace.\n store.value = null\n isSyncingWorkspace.value = true\n\n // Try to load the workspace\n const result = await loadWorkspace(namespace, slug)\n\n if (result.success) {\n // Navigate to the correct tab if the workspace has a tab already\n const index = result.workspace['x-scalar-active-tab'] ?? 0\n const tabs = result.workspace['x-scalar-tabs']\n const tab = tabs?.[index]\n\n if (tab) {\n // Preserve query parameters when navigating to the active tab\n await router.replace({\n path: tab.path,\n query: currentRoute.value?.query ?? {},\n })\n }\n\n // Heal the active tab index if it is out of bounds\n if (tabs && index >= tabs.length) {\n eventBus.emit('tabs:update:tabs', {\n 'x-scalar-active-tab': 0,\n })\n }\n\n // Initialize the tabs if they does not exist\n if (!tabs) {\n eventBus.emit('tabs:update:tabs', {\n 'x-scalar-tabs': [createTabFromRoute(currentRoute.value)],\n 'x-scalar-active-tab': 0,\n })\n }\n\n isSyncingWorkspace.value = false\n return\n }\n\n // Navigate to the default workspace, or fall back to the first available workspace\n const targetWorkspace =\n filteredWorkspaces.value.find((workspace) => workspace.teamUid === 'local' && workspace.slug === 'default') ??\n filteredWorkspaces.value[0]\n\n if (targetWorkspace) {\n return navigateToWorkspace(targetWorkspace.namespace, targetWorkspace.slug)\n }\n\n // If loading failed (workspace does not exist), create the default workspace and navigate to it.\n const createResult = await createWorkspace({\n name: 'Default Workspace',\n slug: 'default',\n })\n\n isSyncingWorkspace.value = false\n\n if (!createResult) {\n return console.error('Failed to create the default workspace, something went wrong, can not load the workspace')\n }\n\n // Must reset the sidebar state when the workspace changes\n sidebarState.reset()\n }\n\n /**\n * Sets the current team context. If the active workspace is not accessible\n * with the new team, navigates to the default workspace for that team.\n */\n const setTeamUid = (value: string) => {\n // Update the new teamUid\n teamUid.value = value\n\n // Find the current workspace\n const workspace = filteredWorkspaces.value.find(\n (w) => w.namespace === namespace.value && w.slug === workspaceSlug.value,\n )\n\n // Check if new teamUid is accessible to the current workspace\n if (workspace && canLoadWorkspace(workspace.teamUid, value)) {\n return\n }\n\n return navigateToWorkspace('local', 'default')\n }\n\n // ---------------------------------------------------------------------------\n // Sidebar state management\n\n const entries = computed(() => {\n const activeStore = store.value\n if (!activeStore) {\n return []\n }\n\n const order = activeStore.workspace['x-scalar-order'] ?? Object.keys(activeStore.workspace.documents)\n\n return sortByOrder(Object.keys(activeStore.workspace.documents), order, (item) => item)\n .map((doc) => activeStore.workspace.documents[doc]?.['x-scalar-navigation'])\n .filter(isDefined) as TraversedEntry[]\n })\n\n const sidebarState = createSidebarState(entries)\n\n /**\n * Generates a unique string ID for an API location, based on the document, path, method, and example.\n * Filters out undefined values and serializes the composite array into a stable string.\n *\n * @param params - An object containing document, path, method, and optional example name.\n * @returns A stringified array representing the unique location identifier.\n *\n * Example:\n * generateId({ document: 'mydoc', path: '/users', method: 'get', example: 'default' })\n * // => '[\"mydoc\",\"/users\",\"get\",\"default\"]'\n */\n const generateId = ({\n document,\n path,\n method,\n example,\n }: {\n document: string\n path?: string\n method?: HttpMethod\n example?: string\n }) => {\n return JSON.stringify([document, path, method, example].filter(isDefined))\n }\n\n /**\n * Computed index for fast lookup of sidebar nodes by their unique API location.\n *\n * - Only indexes nodes of type 'document', 'operation', or 'example'.\n * - The lookup key is a serialized array of: [documentName, operationPath, operationMethod, exampleName?].\n * - Supports precise resolution of sidebar entries given an API \"location\".\n */\n const locationIndex = computed(() =>\n generateReverseIndex({\n items: entries.value,\n nestedKey: 'children',\n filter: (node) => node.type === 'document' || node.type === 'operation' || node.type === 'example',\n getId: (node) => {\n const document = getParentEntry('document', node)\n const operation = getParentEntry('operation', node)\n return generateId({\n document: document?.name ?? '',\n path: operation?.path,\n method: operation?.method,\n example: node.type === 'example' ? node.name : undefined,\n })\n },\n }),\n )\n\n /**\n * Looks up a sidebar entry by its unique API location.\n * - First tries to find an entry matching all provided properties (including example).\n * - If not found, falls back to matching only the operation (ignores example field).\n * This allows resolving either examples, operations, or documents as appropriate.\n *\n * @param location - Object specifying the document name, path, method, and optional example name.\n * @returns The matching sidebar entry, or undefined if none found.\n *\n * Example:\n * const entry = getEntryByLocation({\n * document: 'pets',\n * path: '/pets',\n * method: 'get',\n * example: 'default',\n * })\n */\n const getEntryByLocation: GetEntryByLocation = (location) => {\n // Try to find an entry with the most-specific location (including example)\n const entryWithExample = locationIndex.value.get(generateId(location))\n\n if (entryWithExample) {\n return entryWithExample\n }\n\n // Fallback to the operation (ignoring example) if an example wasn't found or specified\n return locationIndex.value.get(\n generateId({\n document: location.document,\n path: location.path,\n method: location.method,\n }),\n )\n }\n\n /**\n * Handles item selection from the sidebar and routes navigation accordingly.\n *\n * Example:\n * handleSelectItem('id-of-entry')\n */\n const handleSelectItem = (id: string) => {\n const entry = sidebarState.getEntryById(id)\n\n if (!entry) {\n console.warn(`Could not find sidebar entry with id ${id} to select`)\n return\n }\n\n /** Close sidebar and navigate. Used for every branch that performs navigation. */\n const navigate = (route: RouteLocationRaw) => {\n isSidebarOpen.value = false\n return router.push(route)\n }\n\n // Navigate to the document overview page\n if (entry.type === 'document') {\n // If we are already in the document, just toggle expansion\n if (sidebarState.selectedItem.value === id) {\n sidebarState.setExpanded(id, !sidebarState.isExpanded(id))\n return\n }\n\n // Otherwise, select it\n sidebarState.setSelected(id)\n sidebarState.setExpanded(id, true)\n return navigate({\n name: 'document.overview',\n params: { documentSlug: entry.name },\n })\n }\n\n // Navigate to the example page\n if (entry.type === 'operation') {\n // If we are already in an operation child we just want to toggle the explanstion\n if (sidebarState.isSelected(id) && sidebarState.selectedItem.value !== id) {\n sidebarState.setExpanded(id, !sidebarState.isExpanded(id))\n return\n }\n\n // Otherwise, select the first example\n const firstExample = entry.children?.find((child) => child.type === 'example')\n\n if (firstExample) {\n sidebarState.setSelected(firstExample.id)\n sidebarState.setExpanded(firstExample.id, true)\n } else {\n sidebarState.setSelected(id)\n }\n\n return navigate({\n name: 'example',\n params: {\n documentSlug: getParentEntry('document', entry)?.name,\n pathEncoded: encodeURIComponent(entry.path),\n method: entry.method,\n exampleName: firstExample?.name ?? 'default',\n },\n })\n }\n\n // Navigate to the example page\n if (entry.type === 'example') {\n sidebarState.setSelected(id)\n const operation = getParentEntry('operation', entry)\n return navigate({\n name: 'example',\n params: {\n documentSlug: getParentEntry('document', entry)?.name,\n pathEncoded: encodeURIComponent(operation?.path ?? ''),\n method: operation?.method,\n exampleName: entry.name,\n },\n })\n }\n\n if (entry.type === 'text') {\n return navigate({\n name: 'document.overview',\n params: {\n documentSlug: getParentEntry('document', entry)?.name,\n },\n })\n }\n\n sidebarState.setExpanded(id, !sidebarState.isExpanded(id))\n return\n }\n\n /**\n * Navigates to the currently active tab's path using the router.\n * Returns early if the workspace store or active tab is unavailable.\n */\n const navigateToCurrentTab = async (): Promise<void> => {\n if (!store.value) {\n return\n }\n\n const activeTabIndex = store.value.workspace['x-scalar-active-tab'] ?? 0\n const activeTab = store.value.workspace['x-scalar-tabs']?.[activeTabIndex]\n if (!activeTab) {\n return\n }\n\n await router.replace(activeTab.path)\n }\n\n /**\n * Rebuilds the sidebar for the given document.\n * This is used to refresh the sidebar state after structural changes (e.g. after adding or removing items).\n *\n * @param documentName - The name (id) of the document for which to rebuild the sidebar\n */\n const rebuildSidebar = (documentName: string | undefined) => {\n if (documentName) {\n store.value?.buildSidebar(documentName)\n }\n }\n\n /**\n * Ensures the sidebar is refreshed after a new example is created.\n *\n * If the sidebar entry for the new example does not exist or is of a different type,\n * this will rebuild the sidebar for the current document. This helps keep the sidebar state\n * consistent (e.g., after adding a new example via the UI).\n */\n const refreshSidebarAfterExampleCreation = (payload: OperationExampleMeta & { documentName?: string }) => {\n const documentName = payload.documentName ?? activeDocument.value?.['x-scalar-navigation']?.name\n if (!documentName) {\n return\n }\n\n const entry = getEntryByLocation({\n document: documentName,\n path: payload.path,\n method: payload.method,\n example: payload.exampleKey,\n })\n\n if (!entry || entry.type !== 'example') {\n // Sidebar entry for this example doesn't exist, so rebuild sidebar for consistency.\n rebuildSidebar(documentName)\n if (currentRoute.value) {\n syncSidebar(currentRoute.value)\n }\n }\n return\n }\n\n /** Width of the sidebar, with fallback to default. */\n const sidebarWidth = computed(() => store.value?.workspace?.['x-scalar-sidebar-width'] ?? DEFAULT_SIDEBAR_WIDTH)\n\n /** Handler for sidebar width changes. */\n const handleSidebarWidthUpdate = (width: number) => store.value?.update('x-scalar-sidebar-width', width)\n\n /** Controls the visibility of the sidebar. */\n const isSidebarOpen = ref(false)\n // ---------------------------------------------------------------------------\n // Tab Management\n\n /** Constants for workspace store keys */\n const TABS_KEY = 'x-scalar-tabs' as const\n const ACTIVE_TAB_KEY = 'x-scalar-active-tab' as const\n\n /**\n * Creates a tab object based on the current route and workspace state.\n * Used as a fallback when no tabs exist or when creating new tabs.\n */\n const createTabFromRoute = (to: RouteLocationNormalizedGeneric | null): Tab => {\n const method = getRouteParam('method', to)\n const path = getRouteParam('pathEncoded', to)\n const document = getRouteParam('documentSlug', to)\n const workspace = getRouteParam('workspaceSlug', to)\n return {\n ...getTabDetails({\n workspace,\n document,\n path,\n method,\n getEntryByLocation,\n }),\n path: currentRoute.value?.path ?? '',\n }\n }\n\n const tabs = computed(() => {\n return store.value?.workspace[TABS_KEY] ?? [createTabFromRoute(currentRoute.value)]\n })\n\n const activeTabIndex = computed(() => {\n return store.value?.workspace[ACTIVE_TAB_KEY] ?? 0\n })\n\n /**\n * Copies the URL of the tab at the given index to the clipboard.\n * Constructs the full URL using the current origin and the tab path.\n *\n * Note: Will silently fail if clipboard API is unavailable or the tab does not exist.\n */\n const copyTabUrl = async (index: number): Promise<void> => {\n const tab = tabs.value[index]\n\n if (!tab) {\n console.warn(`Cannot copy URL: tab at index ${index} does not exist`)\n return\n }\n\n const url = `${window.location.origin}${tab.path}`\n\n try {\n await navigator.clipboard.writeText(url)\n } catch (error) {\n console.error('Failed to copy URL to clipboard:', error)\n }\n }\n\n // ---------------------------------------------------------------------------\n // Path syncing\n\n /** When the route changes we need to update the active entities in the store */\n const handleRouteChange = (to: RouteLocationNormalizedGeneric) => {\n const slug = getRouteParam('workspaceSlug', to)\n const document = getRouteParam('documentSlug', to)\n const namespaceValue = getRouteParam('namespace', to)\n\n // Must have an active workspace to syncs\n if (!namespaceValue || !slug) {\n return\n }\n\n // Try to see if the user can load this workspace based on the teamUid and namespace\n const workspace = workspaces.value.find(\n (workspace) => workspace.slug === slug && workspace.namespace === namespaceValue,\n )\n\n // If the workspace is not found or the teamUid does not match, try to redirect to the default workspace\n if (workspace && !canLoadWorkspace(workspace.teamUid, teamUid.value)) {\n // try to redirect to the default workspace\n return navigateToWorkspace('local', 'default')\n }\n\n namespace.value = namespaceValue\n workspaceSlug.value = slug\n documentSlug.value = document\n method.value = getRouteParam('method', to)\n path.value = getRouteParam('pathEncoded', to)\n exampleName.value = getRouteParam('exampleName', to)\n\n // Save the current path to the persistence storage\n if (to.path !== '') {\n workspaceStorage.setCurrentPath(to.path)\n }\n\n if (getWorkspaceId(namespace.value, slug) !== activeWorkspace.value?.id) {\n return changeWorkspace(namespace.value, slug)\n }\n\n // Update the active document if the document slug has changes\n if (document && document !== store.value?.workspace[extensions.workspace.activeDocument]) {\n store?.value?.update('x-scalar-active-document', document)\n }\n\n syncTabs(to)\n syncSidebar(to)\n return\n }\n\n /** Aligns the tabs with any potential slug changes */\n const syncTabs = (to: RouteLocationNormalizedGeneric) => {\n const tabs = store.value?.workspace['x-scalar-tabs'] ?? []\n const index = store.value?.workspace['x-scalar-active-tab'] ?? 0\n\n const tab = tabs[index]\n\n // If there is no tab or the tab path is the same we leave the tab state alone\n if (!tab || tab.path === to.path) {\n // Already on the correct path, do nothing\n return\n }\n\n // Otherwise we replace the tab content with the new route\n tabs[index] = createTabFromRoute(to)\n }\n\n /** Aligns the sidebar state with any potential slug changes */\n const syncSidebar = (to: RouteLocationNormalizedGeneric) => {\n const document = getRouteParam('documentSlug', to)\n\n if (!document) {\n // Reset selection if no document is selected\n sidebarState.setSelected(null)\n return\n }\n\n const entry = getEntryByLocation({\n document,\n path: getRouteParam('pathEncoded', to),\n method: getRouteParam('method', to),\n example: getRouteParam('exampleName', to),\n })\n\n if (entry) {\n sidebarState.setSelected(entry.id)\n sidebarState.setExpanded(entry.id, true)\n }\n }\n\n // ---------------------------------------------------------------------------\n // Events handling\n\n initializeAppEventHandlers({\n eventBus,\n router,\n store,\n navigateToCurrentTab,\n rebuildSidebar,\n onAfterExampleCreation: refreshSidebarAfterExampleCreation,\n onSelectSidebarItem: handleSelectItem,\n onCopyTabUrl: (index) => copyTabUrl(index),\n onToggleSidebar: () => (isSidebarOpen.value = !isSidebarOpen.value),\n closeSidebar: () => (isSidebarOpen.value = false),\n renameWorkspace,\n })\n\n const theme = useTheme({\n fallbackThemeSlug,\n customThemes,\n store: store,\n })\n\n const isDarkMode = computed(() => {\n const colorMode = store.value?.workspace['x-scalar-color-mode'] ?? 'system'\n if (colorMode === 'system') {\n return window.matchMedia?.('(prefers-color-scheme: dark)')?.matches ?? false\n }\n return colorMode === 'dark'\n })\n\n return {\n /** Active workspace store */\n store,\n sidebar: {\n state: sidebarState,\n width: sidebarWidth,\n isOpen: isSidebarOpen,\n handleSelectItem,\n handleSidebarWidthUpdate,\n getEntryByLocation,\n },\n tabs: {\n state: tabs,\n activeTabIndex,\n copyTabUrl,\n },\n workspace: {\n create: createWorkspace,\n workspaceList: workspaces,\n filteredWorkspaceList: filteredWorkspaces,\n workspaceGroups,\n activeWorkspace,\n navigateToWorkspace,\n isOpen: computed(() => Boolean(workspaceSlug.value && !documentSlug.value)),\n },\n eventBus,\n router,\n currentRoute,\n loading: isSyncingWorkspace,\n activeEntities: {\n namespace,\n workspaceSlug,\n documentSlug,\n path,\n method,\n exampleName,\n teamUid: readonly(teamUid),\n setTeamUid,\n },\n environment,\n document: activeDocument,\n isDarkMode,\n theme: {\n styles: theme.themeStyles,\n themeStyleTag: theme.themeStyleTag,\n customThemes,\n },\n telemetry,\n options,\n }\n}\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"App.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/app/App.vue"],"names":[],"mappings":"AAsRA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAW7D,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;AAK3C;;;;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;;;;YAL1C,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC;cAC5B,YAAY,EAAE;iBACX,MAAM,QAAQ;4BACH,MAAM,mBAAmB;IACjD,+FAA+F;4BACvE,0BAA0B;;IAYlD;;;OAGG;4BACqB,MAAM,OAAO;IACrC;;;OAGG;yBACkB,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,UAAU,CAAA;KAAE,KAAK,OAAO;EAsX9D,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"} | ||
| {"version":3,"file":"App.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/app/App.vue"],"names":[],"mappings":"AAuRA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAW7D,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;AAK3C;;;;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;;;;YAL1C,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC;cAC5B,YAAY,EAAE;iBACX,MAAM,QAAQ;4BACH,MAAM,mBAAmB;IACjD,+FAA+F;4BACvE,0BAA0B;;IAYlD;;;OAGG;4BACqB,MAAM,OAAO;IACrC;;;OAGG;yBACkB,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,UAAU,CAAA;KAAE,KAAK,OAAO;EAuX9D,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"} |
@@ -1,1 +0,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 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 { 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 AppSidebar from './components/AppSidebar.vue'\nimport DesktopTabs from './components/DesktopTabs.vue'\n\nconst {\n layout,\n plugins = [],\n getAppState,\n getCommandPaletteState,\n fetchRegistryDocument,\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\ndefineSlots<{\n /**\n * Slot for customizing the actions section of the sidebar menu.\n * This slot is used to render custom actions or components within the actions section.\n */\n 'sidebar-menu-actions': () => unknown\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\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 }\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-1 flex-col\">\n <SidebarToggle\n v-model=\"app.sidebar.isOpen.value\"\n class=\"absolute top-4 left-3 z-[60] md:hidden\" />\n <div class=\"flex min-h-0 flex-1 flex-row\">\n <!-- App sidebar -->\n <AppSidebar\n v-model:isSidebarOpen=\"app.sidebar.isOpen.value\"\n :activeWorkspace=\"app.workspace.activeWorkspace.value\"\n :eventBus=\"app.eventBus\"\n :isWorkspaceOpen=\"app.workspace.isOpen.value\"\n :layout\n :sidebarState=\"app.sidebar.state\"\n :sidebarWidth=\"app.sidebar.width.value\"\n :store=\"app.store.value!\"\n :workspaces=\"app.workspace.workspaceGroups.value\"\n @click:workspace=\"navigateToWorkspaceOverview\"\n @create:workspace=\"createWorkspaceModalState.show()\"\n @select:workspace=\"setActiveWorkspace\"\n @selectItem=\"app.sidebar.handleSelectItem\"\n @update:sidebarWidth=\"app.sidebar.handleSidebarWidthUpdate\">\n <template #sidebarMenuActions>\n <slot name=\"sidebar-menu-actions\" />\n </template>\n </AppSidebar>\n\n <div class=\"flex 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\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":""} | ||
| {"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 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 { 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 AppSidebar from './components/AppSidebar.vue'\nimport DesktopTabs from './components/DesktopTabs.vue'\n\nconst {\n layout,\n plugins = [],\n getAppState,\n getCommandPaletteState,\n fetchRegistryDocument,\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\ndefineSlots<{\n /**\n * Slot for customizing the actions section of the sidebar menu.\n * This slot is used to render custom actions or components within the actions section.\n */\n 'sidebar-menu-actions': () => unknown\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\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-1 flex-col\">\n <SidebarToggle\n v-model=\"app.sidebar.isOpen.value\"\n class=\"absolute top-4 left-3 z-[60] md:hidden\" />\n <div class=\"flex min-h-0 flex-1 flex-row\">\n <!-- App sidebar -->\n <AppSidebar\n v-model:isSidebarOpen=\"app.sidebar.isOpen.value\"\n :activeWorkspace=\"app.workspace.activeWorkspace.value\"\n :eventBus=\"app.eventBus\"\n :isWorkspaceOpen=\"app.workspace.isOpen.value\"\n :layout\n :sidebarState=\"app.sidebar.state\"\n :sidebarWidth=\"app.sidebar.width.value\"\n :store=\"app.store.value!\"\n :workspaces=\"app.workspace.workspaceGroups.value\"\n @click:workspace=\"navigateToWorkspaceOverview\"\n @create:workspace=\"createWorkspaceModalState.show()\"\n @select:workspace=\"setActiveWorkspace\"\n @selectItem=\"app.sidebar.handleSelectItem\"\n @update:sidebarWidth=\"app.sidebar.handleSidebarWidthUpdate\">\n <template #sidebarMenuActions>\n <slot name=\"sidebar-menu-actions\" />\n </template>\n </AppSidebar>\n\n <div class=\"flex 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\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":""} |
@@ -108,3 +108,4 @@ import TheCommandPalette_default from "../command-palette/TheCommandPalette.vue.js"; | ||
| app.telemetry.value = value; | ||
| } | ||
| }, | ||
| options: app.options | ||
| }; | ||
@@ -111,0 +112,0 @@ }); |
@@ -1,1 +0,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 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 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 { 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 AppSidebar from './components/AppSidebar.vue'\nimport DesktopTabs from './components/DesktopTabs.vue'\n\nconst {\n layout,\n plugins = [],\n getAppState,\n getCommandPaletteState,\n fetchRegistryDocument,\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\ndefineSlots<{\n /**\n * Slot for customizing the actions section of the sidebar menu.\n * This slot is used to render custom actions or components within the actions section.\n */\n 'sidebar-menu-actions': () => unknown\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\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 }\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-1 flex-col\">\n <SidebarToggle\n v-model=\"app.sidebar.isOpen.value\"\n class=\"absolute top-4 left-3 z-[60] md:hidden\" />\n <div class=\"flex min-h-0 flex-1 flex-row\">\n <!-- App sidebar -->\n <AppSidebar\n v-model:isSidebarOpen=\"app.sidebar.isOpen.value\"\n :activeWorkspace=\"app.workspace.activeWorkspace.value\"\n :eventBus=\"app.eventBus\"\n :isWorkspaceOpen=\"app.workspace.isOpen.value\"\n :layout\n :sidebarState=\"app.sidebar.state\"\n :sidebarWidth=\"app.sidebar.width.value\"\n :store=\"app.store.value!\"\n :workspaces=\"app.workspace.workspaceGroups.value\"\n @click:workspace=\"navigateToWorkspaceOverview\"\n @create:workspace=\"createWorkspaceModalState.show()\"\n @select:workspace=\"setActiveWorkspace\"\n @selectItem=\"app.sidebar.handleSelectItem\"\n @update:sidebarWidth=\"app.sidebar.handleSidebarWidthUpdate\">\n <template #sidebarMenuActions>\n <slot name=\"sidebar-menu-actions\" />\n </template>\n </AppSidebar>\n\n <div class=\"flex 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\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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"} | ||
| {"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 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 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 { 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 AppSidebar from './components/AppSidebar.vue'\nimport DesktopTabs from './components/DesktopTabs.vue'\n\nconst {\n layout,\n plugins = [],\n getAppState,\n getCommandPaletteState,\n fetchRegistryDocument,\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\ndefineSlots<{\n /**\n * Slot for customizing the actions section of the sidebar menu.\n * This slot is used to render custom actions or components within the actions section.\n */\n 'sidebar-menu-actions': () => unknown\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\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-1 flex-col\">\n <SidebarToggle\n v-model=\"app.sidebar.isOpen.value\"\n class=\"absolute top-4 left-3 z-[60] md:hidden\" />\n <div class=\"flex min-h-0 flex-1 flex-row\">\n <!-- App sidebar -->\n <AppSidebar\n v-model:isSidebarOpen=\"app.sidebar.isOpen.value\"\n :activeWorkspace=\"app.workspace.activeWorkspace.value\"\n :eventBus=\"app.eventBus\"\n :isWorkspaceOpen=\"app.workspace.isOpen.value\"\n :layout\n :sidebarState=\"app.sidebar.state\"\n :sidebarWidth=\"app.sidebar.width.value\"\n :store=\"app.store.value!\"\n :workspaces=\"app.workspace.workspaceGroups.value\"\n @click:workspace=\"navigateToWorkspaceOverview\"\n @create:workspace=\"createWorkspaceModalState.show()\"\n @select:workspace=\"setActiveWorkspace\"\n @selectItem=\"app.sidebar.handleSelectItem\"\n @update:sidebarWidth=\"app.sidebar.handleSidebarWidthUpdate\">\n <template #sidebarMenuActions>\n <slot name=\"sidebar-menu-actions\" />\n </template>\n </AppSidebar>\n\n <div class=\"flex 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\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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"} |
@@ -13,4 +13,4 @@ import type { Tab } from '@scalar/workspace-store/schemas/extensions/workspace'; | ||
| declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { | ||
| click: () => any; | ||
| close: () => any; | ||
| click: () => any; | ||
| copyUrl: () => any; | ||
@@ -20,4 +20,4 @@ newTab: () => any; | ||
| }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{ | ||
| onClick?: (() => any) | undefined; | ||
| onClose?: (() => any) | undefined; | ||
| onClick?: (() => any) | undefined; | ||
| onCopyUrl?: (() => any) | undefined; | ||
@@ -24,0 +24,0 @@ onNewTab?: (() => any) | undefined; |
@@ -5,2 +5,3 @@ import type { ClientPlugin } from '@scalar/oas-utils/helpers'; | ||
| import type { ClientLayout } from '../../../../v2/types/layout'; | ||
| import type { ApiClientOptions } from '../../../../v2/types/options'; | ||
| type CreateApiClientOptions = { | ||
@@ -36,4 +37,11 @@ /** | ||
| telemetry?: boolean; | ||
| /** Runtime behaviour overrides */ | ||
| options?: ApiClientAppOptions; | ||
| }; | ||
| /** | ||
| * Runtime behaviour overrides shared between createApiClientApp and createAppState. | ||
| * Derived from the canonical ApiClientOptions to guarantee structural compatibility. | ||
| */ | ||
| export type ApiClientAppOptions = Pick<ApiClientOptions, 'customFetch' | 'oauth2RedirectUri'>; | ||
| /** | ||
| * Creates the appropriate router with the appropriate routes based on the layout | ||
@@ -45,3 +53,3 @@ */ | ||
| */ | ||
| export declare const createApiClientApp: (el: HTMLElement | null, { layout, plugins, customThemes, fallbackThemeSlug, fetchRegistryDocument, telemetry, }: CreateApiClientOptions) => Promise<{ | ||
| export declare const createApiClientApp: (el: HTMLElement | null, { layout, plugins, customThemes, fallbackThemeSlug, fetchRegistryDocument, telemetry, options, }: CreateApiClientOptions) => Promise<{ | ||
| app: import("vue").App<Element>; | ||
@@ -48,0 +56,0 @@ state: import("../../../../v2/features/app/app-state.js").AppState; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create-api-client-app.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/app/helpers/create-api-client-app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAO3C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIrD,KAAK,sBAAsB,GAAG;IAC5B;;;;;OAKG;IACH,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IACtC;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,EAAE,CAAA;IACtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAA;IAChC;;;OAGG;IACH,qBAAqB,CAAC,EAAE,0BAA0B,CAAA;IAClD;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,sBAAsB,CAAC,QAAQ,CAAC,gCAQvE,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,IAAI,WAAW,GAAG,IAAI,EACtB,yFAOG,sBAAsB;;;cAsC1B,CAAA"} | ||
| {"version":3,"file":"create-api-client-app.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/app/helpers/create-api-client-app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAO3C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAI1D,KAAK,sBAAsB,GAAG;IAC5B;;;;;OAKG;IACH,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IACtC;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,EAAE,CAAA;IACtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAA;IAChC;;;OAGG;IACH,qBAAqB,CAAC,EAAE,0BAA0B,CAAA;IAClD;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kCAAkC;IAClC,OAAO,CAAC,EAAE,mBAAmB,CAAA;CAC9B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,EAAE,aAAa,GAAG,mBAAmB,CAAC,CAAA;AAE7F;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,sBAAsB,CAAC,QAAQ,CAAC,gCAQvE,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,IAAI,WAAW,GAAG,IAAI,EACtB,kGAQG,sBAAsB;;;cAuC1B,CAAA"} |
@@ -24,3 +24,3 @@ import { createAppState } from "../app-state.js"; | ||
| */ | ||
| var createApiClientApp = async (el, { layout = "desktop", plugins, customThemes, fallbackThemeSlug, fetchRegistryDocument, telemetry = true }) => { | ||
| var createApiClientApp = async (el, { layout = "desktop", plugins, customThemes, fallbackThemeSlug, fetchRegistryDocument, telemetry = true, options }) => { | ||
| const router = createAppRouter(layout); | ||
@@ -31,3 +31,4 @@ const state = await createAppState({ | ||
| fallbackThemeSlug, | ||
| telemetryDefault: telemetry | ||
| telemetryDefault: telemetry, | ||
| options | ||
| }); | ||
@@ -34,0 +35,0 @@ const commandPaletteState = useCommandPaletteState(); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create-api-client-app.js","names":[],"sources":["../../../../../src/v2/features/app/helpers/create-api-client-app.ts"],"sourcesContent":["import type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { Theme } from '@scalar/themes'\nimport { createApp } from 'vue'\nimport { createRouter as createVueRouter, createWebHashHistory, createWebHistory } from 'vue-router'\n\nimport App from '@/v2/features/app/App.vue'\nimport { createAppState } from '@/v2/features/app/app-state'\nimport { ROUTES } from '@/v2/features/app/helpers/routes'\nimport type { ImportDocumentFromRegistry } from '@/v2/types/configuration'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport { useCommandPaletteState } from '../../command-palette/hooks/use-command-palette-state'\n\ntype CreateApiClientOptions = {\n /**\n * The layout of the client, limited to web or desktop in app\n * @see {@link ClientLayout}\n *\n * @default 'desktop'\n */\n layout: Exclude<ClientLayout, 'modal'>\n /**\n * Api client plugins to include in the app\n */\n plugins?: ClientPlugin[]\n /**\n * Custom themes to include in the app\n */\n customThemes?: Theme[]\n /**\n * Fallback theme slug to use if no theme is selected for the workspace\n * @default 'default'\n */\n fallbackThemeSlug?: () => string\n /**\n * Fetches the full document from registry by meta. When set, registry meta takes priority\n * over x-scalar-original-source-url when syncing. Returns the document as a plain object.\n */\n fetchRegistryDocument?: ImportDocumentFromRegistry\n /**\n * Whether or not to send telemetry events.\n */\n telemetry?: boolean\n}\n\n/**\n * Creates the appropriate router with the appropriate routes based on the layout\n */\nexport const createAppRouter = (layout: CreateApiClientOptions['layout']) => {\n // Web uses the standard HTML5 history API\n if (layout === 'web') {\n return createVueRouter({ history: createWebHistory(), routes: ROUTES })\n }\n\n // Electron app has to use the webHashHistory due to file routing\n return createVueRouter({ history: createWebHashHistory(), routes: ROUTES })\n}\n\n/**\n * Create the API Client with router and passes in the workspace store as a prop\n */\nexport const createApiClientApp = async (\n el: HTMLElement | null,\n {\n layout = 'desktop',\n plugins,\n customThemes,\n fallbackThemeSlug,\n fetchRegistryDocument,\n telemetry = true,\n }: CreateApiClientOptions,\n) => {\n // Add the router\n const router = createAppRouter(layout)\n const state = await createAppState({\n router,\n customThemes,\n fallbackThemeSlug,\n telemetryDefault: telemetry,\n })\n const commandPaletteState = useCommandPaletteState()\n\n // Pass in our initial props at the top level\n const app = createApp(App, {\n layout,\n plugins,\n getAppState: () => state,\n getCommandPaletteState: () => commandPaletteState,\n fetchRegistryDocument,\n })\n app.use(router)\n\n // Mount the vue app\n if (!el) {\n console.error(\n '[@scalar/api-client-modal] Could not create the API client.',\n 'Invalid HTML element provided.',\n 'Read more: https://github.com/scalar/scalar/tree/main/packages/api-client',\n )\n\n return\n }\n app.mount(el)\n\n return {\n app,\n state,\n }\n}\n"],"mappings":";;;;;;;;;;AAgDA,IAAa,mBAAmB,WAA6C;AAE3E,KAAI,WAAW,MACb,QAAO,aAAgB;EAAE,SAAS,kBAAkB;EAAE,QAAQ;EAAQ,CAAC;AAIzE,QAAO,aAAgB;EAAE,SAAS,sBAAsB;EAAE,QAAQ;EAAQ,CAAC;;;;;AAM7E,IAAa,qBAAqB,OAChC,IACA,EACE,SAAS,WACT,SACA,cACA,mBACA,uBACA,YAAY,WAEX;CAEH,MAAM,SAAS,gBAAgB,OAAO;CACtC,MAAM,QAAQ,MAAM,eAAe;EACjC;EACA;EACA;EACA,kBAAkB;EACnB,CAAC;CACF,MAAM,sBAAsB,wBAAwB;CAGpD,MAAM,MAAM,UAAU,aAAK;EACzB;EACA;EACA,mBAAmB;EACnB,8BAA8B;EAC9B;EACD,CAAC;AACF,KAAI,IAAI,OAAO;AAGf,KAAI,CAAC,IAAI;AACP,UAAQ,MACN,+DACA,kCACA,4EACD;AAED;;AAEF,KAAI,MAAM,GAAG;AAEb,QAAO;EACL;EACA;EACD"} | ||
| {"version":3,"file":"create-api-client-app.js","names":[],"sources":["../../../../../src/v2/features/app/helpers/create-api-client-app.ts"],"sourcesContent":["import type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { Theme } from '@scalar/themes'\nimport { createApp } from 'vue'\nimport { createRouter as createVueRouter, createWebHashHistory, createWebHistory } from 'vue-router'\n\nimport App from '@/v2/features/app/App.vue'\nimport { createAppState } from '@/v2/features/app/app-state'\nimport { ROUTES } from '@/v2/features/app/helpers/routes'\nimport type { ImportDocumentFromRegistry } from '@/v2/types/configuration'\nimport type { ClientLayout } from '@/v2/types/layout'\nimport type { ApiClientOptions } from '@/v2/types/options'\n\nimport { useCommandPaletteState } from '../../command-palette/hooks/use-command-palette-state'\n\ntype CreateApiClientOptions = {\n /**\n * The layout of the client, limited to web or desktop in app\n * @see {@link ClientLayout}\n *\n * @default 'desktop'\n */\n layout: Exclude<ClientLayout, 'modal'>\n /**\n * Api client plugins to include in the app\n */\n plugins?: ClientPlugin[]\n /**\n * Custom themes to include in the app\n */\n customThemes?: Theme[]\n /**\n * Fallback theme slug to use if no theme is selected for the workspace\n * @default 'default'\n */\n fallbackThemeSlug?: () => string\n /**\n * Fetches the full document from registry by meta. When set, registry meta takes priority\n * over x-scalar-original-source-url when syncing. Returns the document as a plain object.\n */\n fetchRegistryDocument?: ImportDocumentFromRegistry\n /**\n * Whether or not to send telemetry events.\n */\n telemetry?: boolean\n /** Runtime behaviour overrides */\n options?: ApiClientAppOptions\n}\n\n/**\n * Runtime behaviour overrides shared between createApiClientApp and createAppState.\n * Derived from the canonical ApiClientOptions to guarantee structural compatibility.\n */\nexport type ApiClientAppOptions = Pick<ApiClientOptions, 'customFetch' | 'oauth2RedirectUri'>\n\n/**\n * Creates the appropriate router with the appropriate routes based on the layout\n */\nexport const createAppRouter = (layout: CreateApiClientOptions['layout']) => {\n // Web uses the standard HTML5 history API\n if (layout === 'web') {\n return createVueRouter({ history: createWebHistory(), routes: ROUTES })\n }\n\n // Electron app has to use the webHashHistory due to file routing\n return createVueRouter({ history: createWebHashHistory(), routes: ROUTES })\n}\n\n/**\n * Create the API Client with router and passes in the workspace store as a prop\n */\nexport const createApiClientApp = async (\n el: HTMLElement | null,\n {\n layout = 'desktop',\n plugins,\n customThemes,\n fallbackThemeSlug,\n fetchRegistryDocument,\n telemetry = true,\n options,\n }: CreateApiClientOptions,\n) => {\n // Add the router\n const router = createAppRouter(layout)\n const state = await createAppState({\n router,\n customThemes,\n fallbackThemeSlug,\n telemetryDefault: telemetry,\n options,\n })\n const commandPaletteState = useCommandPaletteState()\n\n // Pass in our initial props at the top level\n const app = createApp(App, {\n layout,\n plugins,\n getAppState: () => state,\n getCommandPaletteState: () => commandPaletteState,\n fetchRegistryDocument,\n })\n app.use(router)\n\n // Mount the vue app\n if (!el) {\n console.error(\n '[@scalar/api-client-modal] Could not create the API client.',\n 'Invalid HTML element provided.',\n 'Read more: https://github.com/scalar/scalar/tree/main/packages/api-client',\n )\n\n return\n }\n app.mount(el)\n\n return {\n app,\n state,\n }\n}\n"],"mappings":";;;;;;;;;;AAyDA,IAAa,mBAAmB,WAA6C;AAE3E,KAAI,WAAW,MACb,QAAO,aAAgB;EAAE,SAAS,kBAAkB;EAAE,QAAQ;EAAQ,CAAC;AAIzE,QAAO,aAAgB;EAAE,SAAS,sBAAsB;EAAE,QAAQ;EAAQ,CAAC;;;;;AAM7E,IAAa,qBAAqB,OAChC,IACA,EACE,SAAS,WACT,SACA,cACA,mBACA,uBACA,YAAY,MACZ,cAEC;CAEH,MAAM,SAAS,gBAAgB,OAAO;CACtC,MAAM,QAAQ,MAAM,eAAe;EACjC;EACA;EACA;EACA,kBAAkB;EAClB;EACD,CAAC;CACF,MAAM,sBAAsB,wBAAwB;CAGpD,MAAM,MAAM,UAAU,aAAK;EACzB;EACA;EACA,mBAAmB;EACnB,8BAA8B;EAC9B;EACD,CAAC;AACF,KAAI,IAAI,OAAO;AAGf,KAAI,CAAC,IAAI;AACP,UAAQ,MACN,+DACA,kCACA,4EACD;AAED;;AAEF,KAAI,MAAM,GAAG;AAEb,QAAO;EACL;EACA;EACD"} |
@@ -8,2 +8,4 @@ import type { HttpMethod } from '@scalar/helpers/http/http-methods'; | ||
| import type { WorkspaceDocument } from '@scalar/workspace-store/schemas/workspace'; | ||
| import type { MaybeRefOrGetter } from 'vue'; | ||
| import type { ApiClientOptions } from '../../../../v2/types/options'; | ||
| import type { ImportDocumentFromRegistry } from '../../../../v2/types/configuration'; | ||
@@ -53,2 +55,4 @@ import type { ClientLayout } from '../../../../v2/types/layout'; | ||
| onUpdateTelemetry?: (value: boolean) => void; | ||
| /** App or modal options forwarded to operation/auth blocks */ | ||
| options?: MaybeRefOrGetter<ApiClientOptions>; | ||
| }; | ||
@@ -75,6 +79,4 @@ /** When in the collections pages */ | ||
| component: import("vue").DefineComponent<RouteProps & { | ||
| options?: import("../../modal/helpers/types").ApiClientModalOptionsRef; | ||
| requestBodyCompositionSelection?: Record<string, number>; | ||
| }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<RouteProps & { | ||
| options?: import("../../modal/helpers/types").ApiClientModalOptionsRef; | ||
| requestBodyCompositionSelection?: Record<string, number>; | ||
@@ -81,0 +83,0 @@ }> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/app/helpers/routes.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/app/helpers/routes.ts"],"names":[],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"routes.js","names":[],"sources":["../../../../../src/v2/features/app/helpers/routes.ts"],"sourcesContent":["import type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { mergeSearchParams } from '@scalar/helpers/url/merge-urls'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { Theme } from '@scalar/themes'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { WorkspaceDocument } from '@scalar/workspace-store/schemas/workspace'\nimport type { RouteRecordRaw } from 'vue-router'\n\nimport Authentication from '@/v2/features/collection/components/Authentication.vue'\nimport Cookies from '@/v2/features/collection/components/Cookies.vue'\nimport { Editor } from '@/v2/features/collection/components/Editor'\nimport Environment from '@/v2/features/collection/components/Environment.vue'\nimport Overview from '@/v2/features/collection/components/Overview.vue'\nimport { Runner } from '@/v2/features/collection/components/Runner'\nimport Servers from '@/v2/features/collection/components/Servers.vue'\nimport Settings from '@/v2/features/collection/components/Settings.vue'\nimport DocumentCollection from '@/v2/features/collection/DocumentCollection.vue'\nimport OperationCollection from '@/v2/features/collection/OperationCollection.vue'\nimport WorkspaceCollection from '@/v2/features/collection/WorkspaceCollection.vue'\nimport { Operation } from '@/v2/features/operation'\nimport { workspaceStorage } from '@/v2/helpers/storage'\nimport type { ImportDocumentFromRegistry } from '@/v2/types/configuration'\nimport type { ClientLayout } from '@/v2/types/layout'\n\n/** These props are provided at the route level */\nexport type RouteProps = {\n /** The slug of the currently selected document in the workspace */\n documentSlug: string\n /** The currently active document */\n document: WorkspaceDocument | null\n /** The workspace event bus */\n eventBus: WorkspaceEventBus\n /** The layout of the client */\n layout: ClientLayout\n /** The API path currently selected (e.g. \"/users/{id}\") */\n path?: string\n /** The HTTP method for the currently selected API path (e.g. GET, POST) */\n method?: HttpMethod\n /** The name of the currently selected example (for examples within an endpoint) */\n exampleName?: string\n /** The currently active environment */\n environment: XScalarEnvironment\n /** The workspace store */\n workspaceStore: WorkspaceStore\n /** The currently active workspace */\n activeWorkspace: { id: string; label: string }\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Custom themes available to the team */\n customThemes?: Theme[]\n /** The currently selected theme styles string */\n currentTheme?: string\n /** Whether the current color mode is dark */\n isDarkMode?: boolean\n /**\n * Fetches the full document from registry by meta. When provided, registry meta takes priority\n * over x-scalar-original-source-url when syncing. Returns the document as a plain object.\n */\n fetchRegistryDocument?: ImportDocumentFromRegistry\n /** Whether telemetry is enabled */\n telemetry?: boolean\n /** Updates the telemetry enabled state */\n onUpdateTelemetry?: (value: boolean) => void\n}\n\n/** When in the collections pages */\nexport type CollectionProps = RouteProps &\n (\n | {\n collectionType: 'document' | 'operation'\n document: WorkspaceDocument\n }\n | {\n collectionType: 'workspace'\n document: null\n }\n )\n\nexport type ScalarClientAppRouteParams =\n | 'namespace'\n | 'workspaceSlug'\n | 'documentSlug'\n | 'pathEncoded'\n | 'method'\n | 'exampleName'\n\n/** Routes for the API client app and web, the same as modal + workspace routes */\nexport const ROUTES = [\n {\n path: '/@:namespace/:workspaceSlug',\n children: [\n {\n path: 'document/:documentSlug',\n children: [\n // Example page\n {\n path: 'path/:pathEncoded/method/:method',\n children: [\n {\n name: 'example',\n path: 'example/:exampleName',\n component: Operation,\n },\n {\n name: 'operation',\n path: '',\n component: OperationCollection,\n redirect: {\n name: 'operation.overview',\n },\n children: [\n {\n name: 'operation.overview',\n path: 'overview',\n component: Overview,\n },\n {\n name: 'operation.servers',\n path: 'servers',\n component: Servers,\n },\n {\n name: 'operation.authentication',\n path: 'authentication',\n component: Authentication,\n },\n {\n name: 'operation.editor',\n path: 'editor',\n component: Editor,\n },\n ],\n },\n ],\n },\n // Document Page\n {\n name: 'document',\n path: '',\n component: DocumentCollection,\n children: [\n // Redirect to overview\n {\n name: 'document.redirect',\n path: '',\n redirect: {\n name: 'document.overview',\n },\n },\n // Document overview\n {\n name: 'document.overview',\n path: 'overview',\n component: Overview,\n },\n // Document servers\n {\n name: 'document.servers',\n path: 'servers',\n component: Servers,\n },\n // Document environment\n {\n name: 'document.environment',\n path: 'environment',\n component: Environment,\n },\n // Document authentication\n {\n name: 'document.authentication',\n path: 'authentication',\n component: Authentication,\n },\n // Document cookies\n {\n name: 'document.cookies',\n path: 'cookies',\n component: Cookies,\n },\n // Document scripts (pre-request / post-response)\n {\n name: 'document.scripts',\n path: 'scripts',\n component: () => import('@/v2/features/collection/components/Scripts.vue'),\n },\n // Document runner\n {\n name: 'document.runner',\n path: 'runner',\n component: Runner,\n },\n // Document settings\n {\n name: 'document.settings',\n path: 'settings',\n component: Settings,\n },\n ],\n },\n ],\n },\n // Workspace page\n {\n name: 'workspace',\n path: '',\n component: WorkspaceCollection,\n children: [\n // Workspace environment\n {\n name: 'workspace.environment',\n path: 'environment',\n component: Environment,\n },\n // Workspace cookies\n {\n name: 'workspace.cookies',\n path: 'cookies',\n component: Cookies,\n },\n // Workspace settings\n {\n name: 'workspace.settings',\n path: 'settings',\n component: Settings,\n },\n ],\n },\n ],\n },\n {\n path: '/:pathMatch(.*)*',\n redirect: () => {\n const DEFAULT_PATH = '/@local/default/document/drafts/overview'\n const lastPath = workspaceStorage.getLastPath() ?? DEFAULT_PATH\n\n // Set the default path to the last path so we don't go to an inifite loop if the last path is invalid\n workspaceStorage.setCurrentPath(DEFAULT_PATH)\n\n const url = new URL(lastPath, 'http://example.com')\n\n const queryParameters = new URLSearchParams(window.location.search)\n\n //Merge the query parameters with the last path\n const mergedSearchParams = mergeSearchParams(url.searchParams, queryParameters)\n\n // Preserve all query paramters\n return `${url.pathname}?${mergedSearchParams.toString()}`\n },\n },\n] satisfies RouteRecordRaw[]\n"],"mappings":";;;;;;;;;;;;;;;;AAyFA,IAAa,SAAS,CACpB;CACE,MAAM;CACN,UAAU,CACR;EACE,MAAM;EACN,UAAU,CAER;GACE,MAAM;GACN,UAAU,CACR;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACZ,EACD;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACX,UAAU,EACR,MAAM,sBACP;IACD,UAAU;KACR;MACE,MAAM;MACN,MAAM;MACN,WAAW;MACZ;KACD;MACE,MAAM;MACN,MAAM;MACN,WAAW;MACZ;KACD;MACE,MAAM;MACN,MAAM;MACN,WAAW;MACZ;KACD;MACE,MAAM;MACN,MAAM;MACN,WAAW;MACZ;KACF;IACF,CACF;GACF,EAED;GACE,MAAM;GACN,MAAM;GACN,WAAW;GACX,UAAU;IAER;KACE,MAAM;KACN,MAAM;KACN,UAAU,EACR,MAAM,qBACP;KACF;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,iBAAiB,OAAO;KACzB;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IACF;GACF,CACF;EACF,EAED;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,UAAU;GAER;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACZ;GAED;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACZ;GAED;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACZ;GACF;EACF,CACF;CACF,EACD;CACE,MAAM;CACN,gBAAgB;EACd,MAAM,eAAe;EACrB,MAAM,WAAW,iBAAiB,aAAa,IAAI;AAGnD,mBAAiB,eAAe,aAAa;EAE7C,MAAM,MAAM,IAAI,IAAI,UAAU,qBAAqB;EAEnD,MAAM,kBAAkB,IAAI,gBAAgB,OAAO,SAAS,OAAO;EAGnE,MAAM,qBAAqB,kBAAkB,IAAI,cAAc,gBAAgB;AAG/E,SAAO,GAAG,IAAI,SAAS,GAAG,mBAAmB,UAAU;;CAE1D,CACF"} | ||
| {"version":3,"file":"routes.js","names":[],"sources":["../../../../../src/v2/features/app/helpers/routes.ts"],"sourcesContent":["import type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { mergeSearchParams } from '@scalar/helpers/url/merge-urls'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { Theme } from '@scalar/themes'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { WorkspaceDocument } from '@scalar/workspace-store/schemas/workspace'\nimport type { MaybeRefOrGetter } from 'vue'\nimport type { RouteRecordRaw } from 'vue-router'\n\nimport Authentication from '@/v2/features/collection/components/Authentication.vue'\nimport Cookies from '@/v2/features/collection/components/Cookies.vue'\nimport { Editor } from '@/v2/features/collection/components/Editor'\nimport Environment from '@/v2/features/collection/components/Environment.vue'\nimport Overview from '@/v2/features/collection/components/Overview.vue'\nimport { Runner } from '@/v2/features/collection/components/Runner'\nimport Servers from '@/v2/features/collection/components/Servers.vue'\nimport Settings from '@/v2/features/collection/components/Settings.vue'\nimport DocumentCollection from '@/v2/features/collection/DocumentCollection.vue'\nimport OperationCollection from '@/v2/features/collection/OperationCollection.vue'\nimport WorkspaceCollection from '@/v2/features/collection/WorkspaceCollection.vue'\nimport type { ApiClientOptions } from '@/v2/types/options'\nimport { Operation } from '@/v2/features/operation'\nimport { workspaceStorage } from '@/v2/helpers/storage'\nimport type { ImportDocumentFromRegistry } from '@/v2/types/configuration'\nimport type { ClientLayout } from '@/v2/types/layout'\n\n/** These props are provided at the route level */\nexport type RouteProps = {\n /** The slug of the currently selected document in the workspace */\n documentSlug: string\n /** The currently active document */\n document: WorkspaceDocument | null\n /** The workspace event bus */\n eventBus: WorkspaceEventBus\n /** The layout of the client */\n layout: ClientLayout\n /** The API path currently selected (e.g. \"/users/{id}\") */\n path?: string\n /** The HTTP method for the currently selected API path (e.g. GET, POST) */\n method?: HttpMethod\n /** The name of the currently selected example (for examples within an endpoint) */\n exampleName?: string\n /** The currently active environment */\n environment: XScalarEnvironment\n /** The workspace store */\n workspaceStore: WorkspaceStore\n /** The currently active workspace */\n activeWorkspace: { id: string; label: string }\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Custom themes available to the team */\n customThemes?: Theme[]\n /** The currently selected theme styles string */\n currentTheme?: string\n /** Whether the current color mode is dark */\n isDarkMode?: boolean\n /**\n * Fetches the full document from registry by meta. When provided, registry meta takes priority\n * over x-scalar-original-source-url when syncing. Returns the document as a plain object.\n */\n fetchRegistryDocument?: ImportDocumentFromRegistry\n /** Whether telemetry is enabled */\n telemetry?: boolean\n /** Updates the telemetry enabled state */\n onUpdateTelemetry?: (value: boolean) => void\n /** App or modal options forwarded to operation/auth blocks */\n options?: MaybeRefOrGetter<ApiClientOptions>\n}\n\n/** When in the collections pages */\nexport type CollectionProps = RouteProps &\n (\n | {\n collectionType: 'document' | 'operation'\n document: WorkspaceDocument\n }\n | {\n collectionType: 'workspace'\n document: null\n }\n )\n\nexport type ScalarClientAppRouteParams =\n | 'namespace'\n | 'workspaceSlug'\n | 'documentSlug'\n | 'pathEncoded'\n | 'method'\n | 'exampleName'\n\n/** Routes for the API client app and web, the same as modal + workspace routes */\nexport const ROUTES = [\n {\n path: '/@:namespace/:workspaceSlug',\n children: [\n {\n path: 'document/:documentSlug',\n children: [\n // Example page\n {\n path: 'path/:pathEncoded/method/:method',\n children: [\n {\n name: 'example',\n path: 'example/:exampleName',\n component: Operation,\n },\n {\n name: 'operation',\n path: '',\n component: OperationCollection,\n redirect: {\n name: 'operation.overview',\n },\n children: [\n {\n name: 'operation.overview',\n path: 'overview',\n component: Overview,\n },\n {\n name: 'operation.servers',\n path: 'servers',\n component: Servers,\n },\n {\n name: 'operation.authentication',\n path: 'authentication',\n component: Authentication,\n },\n {\n name: 'operation.editor',\n path: 'editor',\n component: Editor,\n },\n ],\n },\n ],\n },\n // Document Page\n {\n name: 'document',\n path: '',\n component: DocumentCollection,\n children: [\n // Redirect to overview\n {\n name: 'document.redirect',\n path: '',\n redirect: {\n name: 'document.overview',\n },\n },\n // Document overview\n {\n name: 'document.overview',\n path: 'overview',\n component: Overview,\n },\n // Document servers\n {\n name: 'document.servers',\n path: 'servers',\n component: Servers,\n },\n // Document environment\n {\n name: 'document.environment',\n path: 'environment',\n component: Environment,\n },\n // Document authentication\n {\n name: 'document.authentication',\n path: 'authentication',\n component: Authentication,\n },\n // Document cookies\n {\n name: 'document.cookies',\n path: 'cookies',\n component: Cookies,\n },\n // Document scripts (pre-request / post-response)\n {\n name: 'document.scripts',\n path: 'scripts',\n component: () => import('@/v2/features/collection/components/Scripts.vue'),\n },\n // Document runner\n {\n name: 'document.runner',\n path: 'runner',\n component: Runner,\n },\n // Document settings\n {\n name: 'document.settings',\n path: 'settings',\n component: Settings,\n },\n ],\n },\n ],\n },\n // Workspace page\n {\n name: 'workspace',\n path: '',\n component: WorkspaceCollection,\n children: [\n // Workspace environment\n {\n name: 'workspace.environment',\n path: 'environment',\n component: Environment,\n },\n // Workspace cookies\n {\n name: 'workspace.cookies',\n path: 'cookies',\n component: Cookies,\n },\n // Workspace settings\n {\n name: 'workspace.settings',\n path: 'settings',\n component: Settings,\n },\n ],\n },\n ],\n },\n {\n path: '/:pathMatch(.*)*',\n redirect: () => {\n const DEFAULT_PATH = '/@local/default/document/drafts/overview'\n const lastPath = workspaceStorage.getLastPath() ?? DEFAULT_PATH\n\n // Set the default path to the last path so we don't go to an inifite loop if the last path is invalid\n workspaceStorage.setCurrentPath(DEFAULT_PATH)\n\n const url = new URL(lastPath, 'http://example.com')\n\n const queryParameters = new URLSearchParams(window.location.search)\n\n //Merge the query parameters with the last path\n const mergedSearchParams = mergeSearchParams(url.searchParams, queryParameters)\n\n // Preserve all query paramters\n return `${url.pathname}?${mergedSearchParams.toString()}`\n },\n },\n] satisfies RouteRecordRaw[]\n"],"mappings":";;;;;;;;;;;;;;;;AA6FA,IAAa,SAAS,CACpB;CACE,MAAM;CACN,UAAU,CACR;EACE,MAAM;EACN,UAAU,CAER;GACE,MAAM;GACN,UAAU,CACR;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACZ,EACD;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACX,UAAU,EACR,MAAM,sBACP;IACD,UAAU;KACR;MACE,MAAM;MACN,MAAM;MACN,WAAW;MACZ;KACD;MACE,MAAM;MACN,MAAM;MACN,WAAW;MACZ;KACD;MACE,MAAM;MACN,MAAM;MACN,WAAW;MACZ;KACD;MACE,MAAM;MACN,MAAM;MACN,WAAW;MACZ;KACF;IACF,CACF;GACF,EAED;GACE,MAAM;GACN,MAAM;GACN,WAAW;GACX,UAAU;IAER;KACE,MAAM;KACN,MAAM;KACN,UAAU,EACR,MAAM,qBACP;KACF;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,iBAAiB,OAAO;KACzB;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IAED;KACE,MAAM;KACN,MAAM;KACN,WAAW;KACZ;IACF;GACF,CACF;EACF,EAED;EACE,MAAM;EACN,MAAM;EACN,WAAW;EACX,UAAU;GAER;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACZ;GAED;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACZ;GAED;IACE,MAAM;IACN,MAAM;IACN,WAAW;IACZ;GACF;EACF,CACF;CACF,EACD;CACE,MAAM;CACN,gBAAgB;EACd,MAAM,eAAe;EACrB,MAAM,WAAW,iBAAiB,aAAa,IAAI;AAGnD,mBAAiB,eAAe,aAAa;EAE7C,MAAM,MAAM,IAAI,IAAI,UAAU,qBAAqB;EAEnD,MAAM,kBAAkB,IAAI,gBAAgB,OAAO,SAAS,OAAO;EAGnE,MAAM,qBAAqB,kBAAkB,IAAI,cAAc,gBAAgB;AAG/E,SAAO,GAAG,IAAI,SAAS,GAAG,mBAAmB,UAAU;;CAE1D,CACF"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Authentication.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/collection/components/Authentication.vue"],"names":[],"mappings":"AA+jBA,QAAA,MAAM,YAAY;;;;;;;;;;;;kGAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} | ||
| {"version":3,"file":"Authentication.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/collection/components/Authentication.vue"],"names":[],"mappings":"AA+lBA,QAAA,MAAM,YAAY;;;;;;;;;;;;kGAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} |
@@ -5,3 +5,3 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_export-helper.js"; | ||
| //#region src/v2/features/collection/components/Authentication.vue | ||
| var Authentication_default = /* @__PURE__ */ _plugin_vue_export_helper_default(Authentication_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-6bba6b78"]]); | ||
| var Authentication_default = /* @__PURE__ */ _plugin_vue_export_helper_default(Authentication_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-d3bc49bd"]]); | ||
| //#endregion | ||
@@ -8,0 +8,0 @@ export { Authentication_default as default }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Authentication.vue.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Authentication.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarToggle } from '@scalar/components'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport type { AuthMeta } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getActiveProxyUrl,\n getSelectedSecurity,\n getServers,\n mergeSecurity,\n} from '@scalar/workspace-store/request-example'\nimport { computed, ref, watchEffect } from 'vue'\n\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { getDefaultOperationSecurityToggle } from '@/v2/features/collection/helpers/get-default-operation-security-toggle'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst {\n document,\n eventBus,\n environment,\n workspaceStore,\n documentSlug,\n path,\n method,\n collectionType,\n layout,\n} = defineProps<CollectionProps>()\n\n/**\n * Compute the authentication metadata based on the current collection type.\n * If we're working with an operation, include its path and method; otherwise, use the document scope.\n */\nconst authMeta = computed<AuthMeta>(() => {\n if (collectionType === 'operation') {\n return {\n type: 'operation',\n path: path ?? '',\n method: method ?? 'get',\n }\n }\n return { type: 'document' }\n})\n\n/**\n * Compute the operation object based on the current collection type.\n */\nconst operation = computed(() => {\n if (collectionType === 'operation') {\n // Operation not found\n if (!path || !isHttpMethod(method)) {\n return null\n }\n // Operation found, return the servers\n return getResolvedRef(document?.paths?.[path]?.[method])\n }\n return null\n})\n\n/**\n * If enabled we use/set the selected security schemes on the operation level\n */\nconst useOperationSecurity = ref(false)\nwatchEffect(() => {\n useOperationSecurity.value = getDefaultOperationSecurityToggle({\n authStore: workspaceStore.auth,\n documentName: documentSlug,\n ...authMeta.value,\n })\n})\n\nconst securitySchemes = computed(() =>\n mergeSecurity(\n document?.components?.securitySchemes ?? {},\n {},\n workspaceStore.auth,\n documentSlug,\n ),\n)\n\n/** Resolved selected security for the current collection (operation or document), with defaults applied */\nconst selectedSecurity = computed(() => {\n if (collectionType === 'operation') {\n const fromStore = workspaceStore.auth.getAuthSelectedSchemas({\n type: 'operation',\n documentName: documentSlug,\n path: path ?? '',\n method: method ?? 'get',\n })\n return getSelectedSecurity(\n undefined,\n fromStore,\n operation.value?.security ?? [],\n securitySchemes.value,\n )\n }\n const fromStore = workspaceStore.auth.getAuthSelectedSchemas({\n type: 'document',\n documentName: documentSlug,\n })\n return getSelectedSecurity(\n fromStore,\n undefined,\n document?.security ?? [],\n securitySchemes.value,\n )\n})\n\n/** Compute the security requirements for the operation or document based on the current collection type */\nconst securityRequirements = computed(() => {\n if (collectionType === 'operation') {\n return operation.value?.security ?? []\n }\n return document?.security ?? []\n})\n\n/** Compute the proxy URL for the current layout (for the electron we don't want to use the proxy by default) */\nconst proxyUrl = computed(\n () =>\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n ) ?? '',\n)\n\nconst servers = computed(() => {\n return getServers(operation.value?.servers ?? document?.servers, {\n documentUrl: document?.['x-scalar-original-source-url'],\n })\n})\n\n/** Grab the currently selected server for relative auth URIs */\nconst server = computed(() => {\n const documentServer = document?.['x-scalar-selected-server']\n const operationServer = operation.value?.['x-scalar-selected-server']\n const selectedServerUrl = operationServer ?? documentServer\n return (\n servers.value.find(({ url }) => url === selectedServerUrl) ??\n servers.value[0] ??\n null\n )\n})\n\n/**\n * Handles toggling operation-level security authentication. (Only for operation collections)\n * When enabled (`value` is true), overrides document-level authentication for the current operation.\n * When disabled (`value` is false), reverts to using document-level authentication instead.\n */\nconst handleToggleOperationSecurity = (value: boolean) => {\n if (authMeta.value.type !== 'operation') {\n return\n }\n\n useOperationSecurity.value = value\n\n if (value) {\n // Use the same resolved selection as the UI; unpack so the event payload is plain objects\n const { selectedSchemes } = selectedSecurity.value\n return eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: unpackProxyObject(selectedSchemes, { depth: 1 }),\n newSchemes: [],\n meta: authMeta.value,\n })\n }\n\n // Clear the operation security so document level authentication is used\n return eventBus.emit('auth:clear:selected-security-schemes', {\n meta: authMeta.value,\n })\n}\n</script>\n\n<template>\n <Section>\n <template #title>Authentication</template>\n <template #description>\n <template v-if=\"collectionType === 'operation'\">\n <span class=\"block\">\n Override authentication for this operation with the toggle.\n </span>\n <span class=\"mt-1 block\">\n <strong>On</strong> — Authentication below applies only to this\n operation.\n </span>\n <span class=\"mt-1 block\">\n <strong>Off</strong> — This operation uses document-level\n authentication from the OpenAPI spec.\n </span>\n </template>\n <template v-else>\n Configure authentication for this document. Selected authentication\n applies to all operations unless overridden at the operation level.\n </template>\n </template>\n <template\n v-if=\"collectionType === 'operation'\"\n #actions>\n <div class=\"flex h-8 items-center\">\n <ScalarToggle\n class=\"w-4\"\n :modelValue=\"useOperationSecurity\"\n @update:modelValue=\"handleToggleOperationSecurity\" />\n </div>\n </template>\n\n <!-- Auth Selector -->\n <div\n :class=\"\n collectionType === 'operation' &&\n !useOperationSecurity &&\n 'cursor-not-allowed'\n \">\n <AuthSelector\n class=\"scalar-collection-auth border-none!\"\n :class=\"\n collectionType === 'operation' &&\n !useOperationSecurity &&\n 'pointer-events-none opacity-50 mix-blend-luminosity'\n \"\n :createAnySecurityScheme=\"true\"\n :environment\n :eventBus=\"eventBus\"\n isStatic\n :meta=\"authMeta\"\n :proxyUrl=\"proxyUrl\"\n :securityRequirements=\"securityRequirements\"\n :securitySchemes\n :selectedSecurity=\"selectedSecurity\"\n :server\n title=\"Authentication\" />\n </div>\n </Section>\n</template>\n<style scoped>\n.scalar-collection-auth {\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius-lg);\n overflow: hidden;\n}\n</style>\n"],"mappings":""} | ||
| {"version":3,"file":"Authentication.vue.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Authentication.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarToggle } from '@scalar/components'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport type { AuthMeta } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getActiveProxyUrl,\n getSelectedSecurity,\n getServers,\n mergeSecurity,\n} from '@scalar/workspace-store/request-example'\nimport { computed, ref, toValue, watchEffect } from 'vue'\n\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { getDefaultOperationSecurityToggle } from '@/v2/features/collection/helpers/get-default-operation-security-toggle'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst {\n document,\n eventBus,\n environment,\n workspaceStore,\n documentSlug,\n path,\n method,\n collectionType,\n layout,\n options,\n} = defineProps<CollectionProps>()\n\n/**\n * Compute the authentication metadata based on the current collection type.\n * If we're working with an operation, include its path and method; otherwise, use the document scope.\n */\nconst authMeta = computed<AuthMeta>(() => {\n if (collectionType === 'operation') {\n return {\n type: 'operation',\n path: path ?? '',\n method: method ?? 'get',\n }\n }\n return { type: 'document' }\n})\n\n/**\n * Compute the operation object based on the current collection type.\n */\nconst operation = computed(() => {\n if (collectionType === 'operation') {\n // Operation not found\n if (!path || !isHttpMethod(method)) {\n return null\n }\n // Operation found, return the servers\n return getResolvedRef(document?.paths?.[path]?.[method])\n }\n return null\n})\n\n/**\n * If enabled we use/set the selected security schemes on the operation level\n */\nconst useOperationSecurity = ref(false)\nwatchEffect(() => {\n useOperationSecurity.value = getDefaultOperationSecurityToggle({\n authStore: workspaceStore.auth,\n documentName: documentSlug,\n ...authMeta.value,\n })\n})\n\nconst securitySchemes = computed(() =>\n mergeSecurity(\n document?.components?.securitySchemes ?? {},\n {},\n workspaceStore.auth,\n documentSlug,\n ),\n)\n\n/** Resolved selected security for the current collection (operation or document), with defaults applied */\nconst selectedSecurity = computed(() => {\n if (collectionType === 'operation') {\n const fromStore = workspaceStore.auth.getAuthSelectedSchemas({\n type: 'operation',\n documentName: documentSlug,\n path: path ?? '',\n method: method ?? 'get',\n })\n return getSelectedSecurity(\n undefined,\n fromStore,\n operation.value?.security ?? [],\n securitySchemes.value,\n )\n }\n const fromStore = workspaceStore.auth.getAuthSelectedSchemas({\n type: 'document',\n documentName: documentSlug,\n })\n return getSelectedSecurity(\n fromStore,\n undefined,\n document?.security ?? [],\n securitySchemes.value,\n )\n})\n\n/** Compute the security requirements for the operation or document based on the current collection type */\nconst securityRequirements = computed(() => {\n if (collectionType === 'operation') {\n return operation.value?.security ?? []\n }\n return document?.security ?? []\n})\n\n/** Compute the proxy URL for the current layout (for the electron we don't want to use the proxy by default) */\nconst proxyUrl = computed(\n () =>\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n ) ?? '',\n)\n\nconst servers = computed(() => {\n return getServers(operation.value?.servers ?? document?.servers, {\n documentUrl: document?.['x-scalar-original-source-url'],\n })\n})\n\n/** Grab the currently selected server for relative auth URIs */\nconst server = computed(() => {\n const documentServer = document?.['x-scalar-selected-server']\n const operationServer = operation.value?.['x-scalar-selected-server']\n const selectedServerUrl = operationServer ?? documentServer\n return (\n servers.value.find(({ url }) => url === selectedServerUrl) ??\n servers.value[0] ??\n null\n )\n})\n\n/** Auth selector only needs OAuth2-specific option overrides. */\nconst authOptions = computed<OAuth2Options | undefined>(() => {\n const routeOptions = toValue(options)\n if (!routeOptions?.oauth2RedirectUri) {\n return undefined\n }\n\n return {\n oauth2RedirectUri: routeOptions.oauth2RedirectUri,\n }\n})\n\n/**\n * Handles toggling operation-level security authentication. (Only for operation collections)\n * When enabled (`value` is true), overrides document-level authentication for the current operation.\n * When disabled (`value` is false), reverts to using document-level authentication instead.\n */\nconst handleToggleOperationSecurity = (value: boolean) => {\n if (authMeta.value.type !== 'operation') {\n return\n }\n\n useOperationSecurity.value = value\n\n if (value) {\n // Use the same resolved selection as the UI; unpack so the event payload is plain objects\n const { selectedSchemes } = selectedSecurity.value\n return eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: unpackProxyObject(selectedSchemes, { depth: 1 }),\n newSchemes: [],\n meta: authMeta.value,\n })\n }\n\n // Clear the operation security so document level authentication is used\n return eventBus.emit('auth:clear:selected-security-schemes', {\n meta: authMeta.value,\n })\n}\n</script>\n\n<template>\n <Section>\n <template #title>Authentication</template>\n <template #description>\n <template v-if=\"collectionType === 'operation'\">\n <span class=\"block\">\n Override authentication for this operation with the toggle.\n </span>\n <span class=\"mt-1 block\">\n <strong>On</strong> — Authentication below applies only to this\n operation.\n </span>\n <span class=\"mt-1 block\">\n <strong>Off</strong> — This operation uses document-level\n authentication from the OpenAPI spec.\n </span>\n </template>\n <template v-else>\n Configure authentication for this document. Selected authentication\n applies to all operations unless overridden at the operation level.\n </template>\n </template>\n <template\n v-if=\"collectionType === 'operation'\"\n #actions>\n <div class=\"flex h-8 items-center\">\n <ScalarToggle\n class=\"w-4\"\n :modelValue=\"useOperationSecurity\"\n @update:modelValue=\"handleToggleOperationSecurity\" />\n </div>\n </template>\n\n <!-- Auth Selector -->\n <div\n :class=\"\n collectionType === 'operation' &&\n !useOperationSecurity &&\n 'cursor-not-allowed'\n \">\n <AuthSelector\n class=\"scalar-collection-auth border-none!\"\n :class=\"\n collectionType === 'operation' &&\n !useOperationSecurity &&\n 'pointer-events-none opacity-50 mix-blend-luminosity'\n \"\n :createAnySecurityScheme=\"true\"\n :environment\n :eventBus=\"eventBus\"\n isStatic\n :meta=\"authMeta\"\n :options=\"authOptions\"\n :proxyUrl=\"proxyUrl\"\n :securityRequirements=\"securityRequirements\"\n :securitySchemes\n :selectedSecurity=\"selectedSecurity\"\n :server\n title=\"Authentication\" />\n </div>\n </Section>\n</template>\n<style scoped>\n.scalar-collection-auth {\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius-lg);\n overflow: hidden;\n}\n</style>\n"],"mappings":""} |
| import AuthSelector_default from "../../../blocks/scalar-auth-selector-block/components/AuthSelector.vue.js"; | ||
| import { getDefaultOperationSecurityToggle } from "../helpers/get-default-operation-security-toggle.js"; | ||
| import Section_default from "../../settings/components/Section.vue.js"; | ||
| import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, unref, watchEffect, withCtx } from "vue"; | ||
| import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, toValue, unref, watchEffect, withCtx } from "vue"; | ||
| import { ScalarToggle } from "@scalar/components"; | ||
@@ -32,2 +32,3 @@ import { getActiveProxyUrl, getSelectedSecurity, getServers, mergeSecurity } from "@scalar/workspace-store/request-example"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -99,2 +100,8 @@ }, | ||
| }); | ||
| /** Auth selector only needs OAuth2-specific option overrides. */ | ||
| const authOptions = computed(() => { | ||
| const routeOptions = toValue(__props.options); | ||
| if (!routeOptions?.oauth2RedirectUri) return; | ||
| return { oauth2RedirectUri: routeOptions.oauth2RedirectUri }; | ||
| }); | ||
| /** | ||
@@ -133,2 +140,3 @@ * Handles toggling operation-level security authentication. (Only for operation collections) | ||
| meta: authMeta.value, | ||
| options: authOptions.value, | ||
| proxyUrl: proxyUrl.value, | ||
@@ -145,2 +153,3 @@ securityRequirements: securityRequirements.value, | ||
| "meta", | ||
| "options", | ||
| "proxyUrl", | ||
@@ -147,0 +156,0 @@ "securityRequirements", |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Authentication.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Authentication.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarToggle } from '@scalar/components'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport type { AuthMeta } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getActiveProxyUrl,\n getSelectedSecurity,\n getServers,\n mergeSecurity,\n} from '@scalar/workspace-store/request-example'\nimport { computed, ref, watchEffect } from 'vue'\n\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { getDefaultOperationSecurityToggle } from '@/v2/features/collection/helpers/get-default-operation-security-toggle'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst {\n document,\n eventBus,\n environment,\n workspaceStore,\n documentSlug,\n path,\n method,\n collectionType,\n layout,\n} = defineProps<CollectionProps>()\n\n/**\n * Compute the authentication metadata based on the current collection type.\n * If we're working with an operation, include its path and method; otherwise, use the document scope.\n */\nconst authMeta = computed<AuthMeta>(() => {\n if (collectionType === 'operation') {\n return {\n type: 'operation',\n path: path ?? '',\n method: method ?? 'get',\n }\n }\n return { type: 'document' }\n})\n\n/**\n * Compute the operation object based on the current collection type.\n */\nconst operation = computed(() => {\n if (collectionType === 'operation') {\n // Operation not found\n if (!path || !isHttpMethod(method)) {\n return null\n }\n // Operation found, return the servers\n return getResolvedRef(document?.paths?.[path]?.[method])\n }\n return null\n})\n\n/**\n * If enabled we use/set the selected security schemes on the operation level\n */\nconst useOperationSecurity = ref(false)\nwatchEffect(() => {\n useOperationSecurity.value = getDefaultOperationSecurityToggle({\n authStore: workspaceStore.auth,\n documentName: documentSlug,\n ...authMeta.value,\n })\n})\n\nconst securitySchemes = computed(() =>\n mergeSecurity(\n document?.components?.securitySchemes ?? {},\n {},\n workspaceStore.auth,\n documentSlug,\n ),\n)\n\n/** Resolved selected security for the current collection (operation or document), with defaults applied */\nconst selectedSecurity = computed(() => {\n if (collectionType === 'operation') {\n const fromStore = workspaceStore.auth.getAuthSelectedSchemas({\n type: 'operation',\n documentName: documentSlug,\n path: path ?? '',\n method: method ?? 'get',\n })\n return getSelectedSecurity(\n undefined,\n fromStore,\n operation.value?.security ?? [],\n securitySchemes.value,\n )\n }\n const fromStore = workspaceStore.auth.getAuthSelectedSchemas({\n type: 'document',\n documentName: documentSlug,\n })\n return getSelectedSecurity(\n fromStore,\n undefined,\n document?.security ?? [],\n securitySchemes.value,\n )\n})\n\n/** Compute the security requirements for the operation or document based on the current collection type */\nconst securityRequirements = computed(() => {\n if (collectionType === 'operation') {\n return operation.value?.security ?? []\n }\n return document?.security ?? []\n})\n\n/** Compute the proxy URL for the current layout (for the electron we don't want to use the proxy by default) */\nconst proxyUrl = computed(\n () =>\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n ) ?? '',\n)\n\nconst servers = computed(() => {\n return getServers(operation.value?.servers ?? document?.servers, {\n documentUrl: document?.['x-scalar-original-source-url'],\n })\n})\n\n/** Grab the currently selected server for relative auth URIs */\nconst server = computed(() => {\n const documentServer = document?.['x-scalar-selected-server']\n const operationServer = operation.value?.['x-scalar-selected-server']\n const selectedServerUrl = operationServer ?? documentServer\n return (\n servers.value.find(({ url }) => url === selectedServerUrl) ??\n servers.value[0] ??\n null\n )\n})\n\n/**\n * Handles toggling operation-level security authentication. (Only for operation collections)\n * When enabled (`value` is true), overrides document-level authentication for the current operation.\n * When disabled (`value` is false), reverts to using document-level authentication instead.\n */\nconst handleToggleOperationSecurity = (value: boolean) => {\n if (authMeta.value.type !== 'operation') {\n return\n }\n\n useOperationSecurity.value = value\n\n if (value) {\n // Use the same resolved selection as the UI; unpack so the event payload is plain objects\n const { selectedSchemes } = selectedSecurity.value\n return eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: unpackProxyObject(selectedSchemes, { depth: 1 }),\n newSchemes: [],\n meta: authMeta.value,\n })\n }\n\n // Clear the operation security so document level authentication is used\n return eventBus.emit('auth:clear:selected-security-schemes', {\n meta: authMeta.value,\n })\n}\n</script>\n\n<template>\n <Section>\n <template #title>Authentication</template>\n <template #description>\n <template v-if=\"collectionType === 'operation'\">\n <span class=\"block\">\n Override authentication for this operation with the toggle.\n </span>\n <span class=\"mt-1 block\">\n <strong>On</strong> — Authentication below applies only to this\n operation.\n </span>\n <span class=\"mt-1 block\">\n <strong>Off</strong> — This operation uses document-level\n authentication from the OpenAPI spec.\n </span>\n </template>\n <template v-else>\n Configure authentication for this document. Selected authentication\n applies to all operations unless overridden at the operation level.\n </template>\n </template>\n <template\n v-if=\"collectionType === 'operation'\"\n #actions>\n <div class=\"flex h-8 items-center\">\n <ScalarToggle\n class=\"w-4\"\n :modelValue=\"useOperationSecurity\"\n @update:modelValue=\"handleToggleOperationSecurity\" />\n </div>\n </template>\n\n <!-- Auth Selector -->\n <div\n :class=\"\n collectionType === 'operation' &&\n !useOperationSecurity &&\n 'cursor-not-allowed'\n \">\n <AuthSelector\n class=\"scalar-collection-auth border-none!\"\n :class=\"\n collectionType === 'operation' &&\n !useOperationSecurity &&\n 'pointer-events-none opacity-50 mix-blend-luminosity'\n \"\n :createAnySecurityScheme=\"true\"\n :environment\n :eventBus=\"eventBus\"\n isStatic\n :meta=\"authMeta\"\n :proxyUrl=\"proxyUrl\"\n :securityRequirements=\"securityRequirements\"\n :securitySchemes\n :selectedSecurity=\"selectedSecurity\"\n :server\n title=\"Authentication\" />\n </div>\n </Section>\n</template>\n<style scoped>\n.scalar-collection-auth {\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius-lg);\n overflow: hidden;\n}\n</style>\n"],"mappings":"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"} | ||
| {"version":3,"file":"Authentication.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Authentication.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarToggle } from '@scalar/components'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport type { AuthMeta } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getActiveProxyUrl,\n getSelectedSecurity,\n getServers,\n mergeSecurity,\n} from '@scalar/workspace-store/request-example'\nimport { computed, ref, toValue, watchEffect } from 'vue'\n\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { getDefaultOperationSecurityToggle } from '@/v2/features/collection/helpers/get-default-operation-security-toggle'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst {\n document,\n eventBus,\n environment,\n workspaceStore,\n documentSlug,\n path,\n method,\n collectionType,\n layout,\n options,\n} = defineProps<CollectionProps>()\n\n/**\n * Compute the authentication metadata based on the current collection type.\n * If we're working with an operation, include its path and method; otherwise, use the document scope.\n */\nconst authMeta = computed<AuthMeta>(() => {\n if (collectionType === 'operation') {\n return {\n type: 'operation',\n path: path ?? '',\n method: method ?? 'get',\n }\n }\n return { type: 'document' }\n})\n\n/**\n * Compute the operation object based on the current collection type.\n */\nconst operation = computed(() => {\n if (collectionType === 'operation') {\n // Operation not found\n if (!path || !isHttpMethod(method)) {\n return null\n }\n // Operation found, return the servers\n return getResolvedRef(document?.paths?.[path]?.[method])\n }\n return null\n})\n\n/**\n * If enabled we use/set the selected security schemes on the operation level\n */\nconst useOperationSecurity = ref(false)\nwatchEffect(() => {\n useOperationSecurity.value = getDefaultOperationSecurityToggle({\n authStore: workspaceStore.auth,\n documentName: documentSlug,\n ...authMeta.value,\n })\n})\n\nconst securitySchemes = computed(() =>\n mergeSecurity(\n document?.components?.securitySchemes ?? {},\n {},\n workspaceStore.auth,\n documentSlug,\n ),\n)\n\n/** Resolved selected security for the current collection (operation or document), with defaults applied */\nconst selectedSecurity = computed(() => {\n if (collectionType === 'operation') {\n const fromStore = workspaceStore.auth.getAuthSelectedSchemas({\n type: 'operation',\n documentName: documentSlug,\n path: path ?? '',\n method: method ?? 'get',\n })\n return getSelectedSecurity(\n undefined,\n fromStore,\n operation.value?.security ?? [],\n securitySchemes.value,\n )\n }\n const fromStore = workspaceStore.auth.getAuthSelectedSchemas({\n type: 'document',\n documentName: documentSlug,\n })\n return getSelectedSecurity(\n fromStore,\n undefined,\n document?.security ?? [],\n securitySchemes.value,\n )\n})\n\n/** Compute the security requirements for the operation or document based on the current collection type */\nconst securityRequirements = computed(() => {\n if (collectionType === 'operation') {\n return operation.value?.security ?? []\n }\n return document?.security ?? []\n})\n\n/** Compute the proxy URL for the current layout (for the electron we don't want to use the proxy by default) */\nconst proxyUrl = computed(\n () =>\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n ) ?? '',\n)\n\nconst servers = computed(() => {\n return getServers(operation.value?.servers ?? document?.servers, {\n documentUrl: document?.['x-scalar-original-source-url'],\n })\n})\n\n/** Grab the currently selected server for relative auth URIs */\nconst server = computed(() => {\n const documentServer = document?.['x-scalar-selected-server']\n const operationServer = operation.value?.['x-scalar-selected-server']\n const selectedServerUrl = operationServer ?? documentServer\n return (\n servers.value.find(({ url }) => url === selectedServerUrl) ??\n servers.value[0] ??\n null\n )\n})\n\n/** Auth selector only needs OAuth2-specific option overrides. */\nconst authOptions = computed<OAuth2Options | undefined>(() => {\n const routeOptions = toValue(options)\n if (!routeOptions?.oauth2RedirectUri) {\n return undefined\n }\n\n return {\n oauth2RedirectUri: routeOptions.oauth2RedirectUri,\n }\n})\n\n/**\n * Handles toggling operation-level security authentication. (Only for operation collections)\n * When enabled (`value` is true), overrides document-level authentication for the current operation.\n * When disabled (`value` is false), reverts to using document-level authentication instead.\n */\nconst handleToggleOperationSecurity = (value: boolean) => {\n if (authMeta.value.type !== 'operation') {\n return\n }\n\n useOperationSecurity.value = value\n\n if (value) {\n // Use the same resolved selection as the UI; unpack so the event payload is plain objects\n const { selectedSchemes } = selectedSecurity.value\n return eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: unpackProxyObject(selectedSchemes, { depth: 1 }),\n newSchemes: [],\n meta: authMeta.value,\n })\n }\n\n // Clear the operation security so document level authentication is used\n return eventBus.emit('auth:clear:selected-security-schemes', {\n meta: authMeta.value,\n })\n}\n</script>\n\n<template>\n <Section>\n <template #title>Authentication</template>\n <template #description>\n <template v-if=\"collectionType === 'operation'\">\n <span class=\"block\">\n Override authentication for this operation with the toggle.\n </span>\n <span class=\"mt-1 block\">\n <strong>On</strong> — Authentication below applies only to this\n operation.\n </span>\n <span class=\"mt-1 block\">\n <strong>Off</strong> — This operation uses document-level\n authentication from the OpenAPI spec.\n </span>\n </template>\n <template v-else>\n Configure authentication for this document. Selected authentication\n applies to all operations unless overridden at the operation level.\n </template>\n </template>\n <template\n v-if=\"collectionType === 'operation'\"\n #actions>\n <div class=\"flex h-8 items-center\">\n <ScalarToggle\n class=\"w-4\"\n :modelValue=\"useOperationSecurity\"\n @update:modelValue=\"handleToggleOperationSecurity\" />\n </div>\n </template>\n\n <!-- Auth Selector -->\n <div\n :class=\"\n collectionType === 'operation' &&\n !useOperationSecurity &&\n 'cursor-not-allowed'\n \">\n <AuthSelector\n class=\"scalar-collection-auth border-none!\"\n :class=\"\n collectionType === 'operation' &&\n !useOperationSecurity &&\n 'pointer-events-none opacity-50 mix-blend-luminosity'\n \"\n :createAnySecurityScheme=\"true\"\n :environment\n :eventBus=\"eventBus\"\n isStatic\n :meta=\"authMeta\"\n :options=\"authOptions\"\n :proxyUrl=\"proxyUrl\"\n :securityRequirements=\"securityRequirements\"\n :securitySchemes\n :selectedSecurity=\"selectedSecurity\"\n :server\n title=\"Authentication\" />\n </div>\n </Section>\n</template>\n<style scoped>\n.scalar-collection-auth {\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius-lg);\n overflow: hidden;\n}\n</style>\n"],"mappings":"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"} |
@@ -24,2 +24,3 @@ import Section_default from "../../settings/components/Section.vue.js"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -26,0 +27,0 @@ }, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Cookies.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Cookies.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Cookies section for the collection.\n * Renders document or workspace cookies and lets users manage key-value data\n * sent with API requests (e.g. session tokens, auth, preferences).\n */\nexport default {\n name: 'Cookies',\n}\n</script>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { CookiesTable } from '@/v2/features/global-cookies'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst { collectionType, eventBus, document, workspaceStore } =\n defineProps<CollectionProps>()\n\nconst cookies = computed(() => {\n return (\n (collectionType === 'document'\n ? document['x-scalar-cookies']\n : workspaceStore.workspace['x-scalar-cookies']) ?? []\n )\n})\n</script>\n\n<template>\n <Section v-if=\"collectionType !== 'operation'\">\n <template #title>Cookies</template>\n <template #description>\n Manage your collection's cookies here.<br />Cookies allow you to store and\n send key-value data with your API requests—often used for things like\n session tokens, authentication, and saving user preferences.<br />\n </template>\n <CookiesTable\n :collectionType=\"collectionType\"\n :cookies=\"cookies\"\n :eventBus=\"eventBus\" />\n </Section>\n</template>\n"],"mappings":";;;;CAOE,MAAM;;;;;;;;;;;;;;;;;;;;;;EAaR,MAAM,UAAU,eAAe;AAC7B,WACG,QAAA,mBAAmB,aAChB,QAAA,SAAS,sBACT,QAAA,eAAe,UAAU,wBAAwB,EAAC;IAEzD;;UAIgB,QAAA,mBAAc,eAAA,WAAA,EAA7B,YAWU,iBAAA,EAAA,KAAA,GAAA,EAAA;IAVG,OAAK,cAAQ,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAP,WAAO,GAAA,CAAA,EAAA,CAAA;IACb,aAAW,cACkB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA;qBADjB,2CACiB,GAAA;KAAA,mBAAM,MAAA,MAAA,MAAA,GAAA;qBAAA,qKAEgB,GAAA;KAAA,mBAAM,MAAA,MAAA,MAAA,GAAA;;2BAK3C,CAHzB,YAGyB,MAAA,qBAAA,EAAA;KAFtB,gBAAgB,QAAA;KAChB,SAAS,QAAA;KACT,UAAU,QAAA"} | ||
| {"version":3,"file":"Cookies.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Cookies.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Cookies section for the collection.\n * Renders document or workspace cookies and lets users manage key-value data\n * sent with API requests (e.g. session tokens, auth, preferences).\n */\nexport default {\n name: 'Cookies',\n}\n</script>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { CookiesTable } from '@/v2/features/global-cookies'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst { collectionType, eventBus, document, workspaceStore } =\n defineProps<CollectionProps>()\n\nconst cookies = computed(() => {\n return (\n (collectionType === 'document'\n ? document['x-scalar-cookies']\n : workspaceStore.workspace['x-scalar-cookies']) ?? []\n )\n})\n</script>\n\n<template>\n <Section v-if=\"collectionType !== 'operation'\">\n <template #title>Cookies</template>\n <template #description>\n Manage your collection's cookies here.<br />Cookies allow you to store and\n send key-value data with your API requests—often used for things like\n session tokens, authentication, and saving user preferences.<br />\n </template>\n <CookiesTable\n :collectionType=\"collectionType\"\n :cookies=\"cookies\"\n :eventBus=\"eventBus\" />\n </Section>\n</template>\n"],"mappings":";;;;CAOE,MAAM;;;;;;;;;;;;;;;;;;;;;;;EAaR,MAAM,UAAU,eAAe;AAC7B,WACG,QAAA,mBAAmB,aAChB,QAAA,SAAS,sBACT,QAAA,eAAe,UAAU,wBAAwB,EAAC;IAEzD;;UAIgB,QAAA,mBAAc,eAAA,WAAA,EAA7B,YAWU,iBAAA,EAAA,KAAA,GAAA,EAAA;IAVG,OAAK,cAAQ,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAP,WAAO,GAAA,CAAA,EAAA,CAAA;IACb,aAAW,cACkB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA;qBADjB,2CACiB,GAAA;KAAA,mBAAM,MAAA,MAAA,MAAA,GAAA;qBAAA,qKAEgB,GAAA;KAAA,mBAAM,MAAA,MAAA,MAAA,GAAA;;2BAK3C,CAHzB,YAGyB,MAAA,qBAAA,EAAA;KAFtB,gBAAgB,QAAA;KAChB,SAAS,QAAA;KACT,UAAU,QAAA"} |
@@ -58,2 +58,3 @@ import { useEditor } from "../../../editor/hooks/use-editor.js"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -60,0 +61,0 @@ }, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Editor.vue.script.js","names":[],"sources":["../../../../../../src/v2/features/collection/components/Editor/Editor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarHotkey, useLoadingState } from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { ScalarIconArrowsIn, ScalarIconArrowsOut } from '@scalar/icons'\nimport * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n watch,\n} from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { useEditor, useJsonPointerLinkSupport } from '@/v2/features/editor'\nimport { createJsonModel } from '@/v2/features/editor/helpers/json/create-json-model'\nimport { createYamlModel } from '@/v2/features/editor/helpers/yaml/create-yaml-model'\nimport { useEditorMarkers } from '@/v2/features/editor/hooks/use-editor-markers'\n\nimport EditorDiagnosticsPanel from './components/EditorDiagnosticsPanel.vue'\nimport EditorSavePanel from './components/EditorSavePanel.vue'\nimport { getDiagnosticCounts } from './helpers/get-diagnostic-counts'\nimport { getOperationContext } from './helpers/get-operation-context'\nimport { getVisibleDiagnostics } from './helpers/get-visible-diagnostics'\nimport { parseEditorObject } from './helpers/parse-editor-object'\nimport { stringifyDocument } from './helpers/stringify-document'\nimport { useEditorState } from './hooks/use-editor-state'\n\nconst { collectionType, documentSlug, method, path, workspaceStore } =\n defineProps<CollectionProps>()\n\nconst MAX_VISIBLE_DIAGNOSTICS = 6\nconst EDITOR_PERSIST_DEBOUNCE_KEY = 'editor:replace-document'\n\nconst monacoEditorRef = ref<HTMLElement>()\nconst editorApi = shallowRef<ReturnType<typeof useEditor>>()\n\nconst saveLoader = useLoadingState()\nconst {\n isAutoSaveEnabled,\n isDirty,\n editorLanguage,\n isDiagnosticsPaneExpanded,\n isEditorMaximized,\n isYamlMode,\n editorBottomPadding,\n editorRootClass,\n getLanguageToggleClass,\n toggleEditorMaximized,\n} = useEditorState()\n\nconst jsonModel = createJsonModel()\nconst yamlModel = createYamlModel()\n\nconst selectedLanguage = ref<'json' | 'yaml'>('json')\n\nconst currentModel = computed(() => {\n return selectedLanguage.value === 'json' ? jsonModel : yamlModel\n})\n\nconst monacoEditorInstance = computed(() => editorApi.value?.editor)\nconst { markers: diagnostics } = useEditorMarkers(monacoEditorInstance)\n\nconst syncEditorBottomPadding = () => {\n editorApi.value?.editor.updateOptions({\n padding: {\n top: 0,\n bottom: editorBottomPadding.value,\n },\n })\n}\n\nconst diagnosticCounts = computed(() => getDiagnosticCounts(diagnostics.value))\nconst visibleDiagnostics = computed(() =>\n getVisibleDiagnostics(diagnostics.value, MAX_VISIBLE_DIAGNOSTICS),\n)\n\nconst focusDiagnostic = (marker: monaco.editor.IMarker) => {\n const editor = editorApi.value?.editor\n if (!editor) {\n return\n }\n editor.setSelection({\n startLineNumber: marker.startLineNumber,\n startColumn: marker.startColumn,\n endLineNumber: marker.endLineNumber,\n endColumn: marker.endColumn,\n })\n editor.revealPositionInCenter({\n lineNumber: marker.startLineNumber,\n column: marker.startColumn,\n })\n}\n\nconst getEditorValue = (): string | null => currentModel.value.model.getValue()\n\n/** Value from the editor for a specific language (use when switching to avoid reading the wrong model). */\nconst getEditorValueForLanguage = (language: 'json' | 'yaml'): string | null =>\n (language === 'json' ? jsonModel : yamlModel).model.getValue()\n\nconst getDocumentValue = async (\n language?: 'json' | 'yaml',\n): Promise<string> => {\n const document = await workspaceStore.getEditableDocument(documentSlug)\n return stringifyDocument(document, language ?? selectedLanguage.value)\n}\n\nconst debouncedPersist = debounce({ delay: 1500 })\n\nconst applyProgrammaticEditorValue = (value: string): void => {\n // Cancel pending auto-save work so synthetic model updates do not persist stale data.\n debouncedPersist.cleanup()\n editorApi.value?.setValue(value, true)\n}\n\nconst loadDocumentIntoEditor = async () => {\n applyProgrammaticEditorValue(await getDocumentValue())\n isDirty.value = false\n await focusOperation()\n}\n\nconst formatDocument = async () => {\n await editorApi.value?.formatDocument()\n}\n\nconst focusOperation = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n ])\n}\n\nconst persistEditorToWorkspace = async (value: string) => {\n const parsed = parseEditorObject(value, editorLanguage.value)\n if (!parsed) {\n const firstError = diagnostics.value.find(\n (m) => m.severity === monaco.MarkerSeverity.Error,\n )\n if (firstError) {\n focusDiagnostic(firstError)\n }\n await saveLoader.invalidate()\n return\n }\n\n saveLoader.start()\n await workspaceStore.replaceDocument(documentSlug, parsed)\n isDirty.value = false\n await saveLoader.validate({ duration: 900 })\n}\n\nconst saveNow = async () => {\n const value = getEditorValue()\n if (!value) {\n return\n }\n await persistEditorToWorkspace(value)\n}\n\nconst handleEditorChange = (value: string) => {\n isDirty.value = true\n\n if (!isAutoSaveEnabled.value) {\n return\n }\n\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n}\n\nconst focusOperationServers = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n const value = getEditorValue()\n if (!value) {\n return\n }\n\n const parsed = parseEditorObject(value, editorLanguage.value)\n\n if (!parsed || !isObject(parsed.paths)) {\n return\n }\n\n const pathsObject = parsed.paths as Record<string, unknown>\n const operationPathItem = pathsObject[operationContext.path]\n if (!isObject(operationPathItem)) {\n return\n }\n\n const operation = operationPathItem[operationContext.method]\n if (!isObject(operation)) {\n return\n }\n\n // Add default servers if not present\n operation.servers ??= []\n\n // Update the editor value\n editorApi.value?.setValue(stringifyDocument(parsed, editorLanguage.value))\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n 'servers',\n ])\n}\n\nuseJsonPointerLinkSupport(editorApi, currentModel)\n\nonMounted(() => {\n editorApi.value = useEditor({\n element: monacoEditorRef.value ?? document.createElement('div'),\n onChange: handleEditorChange,\n model: currentModel,\n actions: [\n {\n id: 'scalar.editor.focusOperation',\n label: 'Focus Operation',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyO],\n run: async () => {\n await focusOperation()\n },\n },\n {\n id: 'scalar.editor.focusOperationServers',\n label: 'Focus Operation Servers',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyS],\n run: async () => {\n await focusOperationServers()\n },\n },\n {\n id: 'scalar.editor.formatDocument',\n label: 'Format Document',\n keybindings: [\n monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF,\n ],\n run: async () => {\n await formatDocument()\n },\n },\n ],\n })\n\n syncEditorBottomPadding()\n void loadDocumentIntoEditor()\n})\n\nonBeforeUnmount(() => {\n debouncedPersist.cleanup()\n\n // Persist if there is a pending save\n if (isDirty.value && isAutoSaveEnabled.value) {\n void saveNow()\n }\n editorApi.value?.dispose?.()\n // Dispose models created at setup; useEditor only disposes the editor widget, not external models.\n jsonModel.model.dispose()\n yamlModel.model.dispose()\n})\n\nwatch(() => documentSlug, loadDocumentIntoEditor)\n\nwatch(\n () => [path, method] as const,\n async () => {\n await focusOperation()\n },\n)\n\nwatch(isDiagnosticsPaneExpanded, () => {\n syncEditorBottomPadding()\n})\n\nwatch(editorLanguage, async (nextLanguage, previousLanguage) => {\n const wasDirty = isDirty.value\n // Read from the previous model before switching; getEditorValue() would use currentModel\n // which changes with selectedLanguage, so we would read the (empty) new model otherwise.\n const value = getEditorValueForLanguage(previousLanguage ?? 'json')\n if (!value) {\n selectedLanguage.value = nextLanguage\n await nextTick()\n await focusOperation()\n return\n }\n\n const parsed = parseEditorObject(value, previousLanguage ?? 'json')\n selectedLanguage.value = nextLanguage\n await nextTick()\n if (parsed) {\n applyProgrammaticEditorValue(stringifyDocument(parsed, nextLanguage))\n isDirty.value = wasDirty\n }\n await focusOperation()\n})\n\nwatch(\n isAutoSaveEnabled,\n (isEnabled) => {\n if (!isEnabled) {\n debouncedPersist.cleanup()\n return\n }\n\n if (isDirty.value) {\n const value = getEditorValue()\n if (!value) {\n return\n }\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n }\n },\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n v-if=\"\n collectionType === 'operation' &&\n getOperationContext(path, method) !== null\n \"\n class=\"flex w-full min-w-0 flex-1 flex-col gap-2\"\n :class=\"editorRootClass\">\n <div\n class=\"grid grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-3\">\n <div\n class=\"flex min-w-0 items-center gap-1 overflow-x-auto whitespace-nowrap\">\n <span class=\"text-c-2 text-xs font-medium whitespace-nowrap\">\n Shortcuts\n </span>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperation\">\n <span>Operation</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"O\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperationServers\">\n <span>Servers</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"S\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n </div>\n\n <div\n aria-label=\"Editor language\"\n class=\"bg-b-1 shadow-border flex items-center justify-self-center overflow-hidden rounded-lg p-0.5\"\n role=\"tablist\">\n <ScalarButton\n :aria-selected=\"!isYamlMode\"\n :class=\"getLanguageToggleClass(!isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'json'\">\n JSON\n </ScalarButton>\n <ScalarButton\n :aria-selected=\"isYamlMode\"\n :class=\"getLanguageToggleClass(isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'yaml'\">\n YAML\n </ScalarButton>\n </div>\n\n <div class=\"flex min-w-0 shrink-0 items-center gap-2 justify-self-end\">\n <ScalarButton\n size=\"xs\"\n variant=\"ghost\"\n @click=\"formatDocument\">\n <span>Format {{ isYamlMode ? 'YAML' : 'JSON' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"F\"\n :modifier=\"['Alt', 'Shift']\" />\n </span>\n </ScalarButton>\n <ScalarButton\n :aria-label=\"\n isEditorMaximized ? 'Restore editor size' : 'Maximize editor'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"toggleEditorMaximized\">\n <span>{{ isEditorMaximized ? 'Restore' : 'Maximize' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarIconArrowsIn\n v-if=\"isEditorMaximized\"\n class=\"size-3.5\" />\n <ScalarIconArrowsOut\n v-else\n class=\"size-3.5\" />\n </span>\n </ScalarButton>\n </div>\n </div>\n\n <div class=\"flex min-h-0 w-full min-w-0 flex-1 rounded-lg border\">\n <div\n class=\"relative w-full min-w-0 flex-1\"\n :class=\"isEditorMaximized ? 'h-full min-h-0' : 'h-125'\">\n <div class=\"pointer-events-none absolute top-2 right-2 z-10\">\n <EditorSavePanel\n :isAutoSaveEnabled=\"isAutoSaveEnabled\"\n :isDirty=\"isDirty\"\n :saveLoader=\"saveLoader\"\n @saveNow=\"saveNow\"\n @update:isAutoSaveEnabled=\"isAutoSaveEnabled = $event\" />\n </div>\n\n <EditorDiagnosticsPanel\n :diagnosticCounts=\"diagnosticCounts\"\n :expanded=\"isDiagnosticsPaneExpanded\"\n :visibleDiagnostics=\"visibleDiagnostics\"\n @focusDiagnostic=\"focusDiagnostic\"\n @toggle=\"isDiagnosticsPaneExpanded = !isDiagnosticsPaneExpanded\" />\n\n <div\n ref=\"monacoEditorRef\"\n class=\"h-full w-full min-w-0 flex-1 [&_.monaco-editor]:rounded-lg [&_.overflow-guard]:rounded-lg\" />\n </div>\n </div>\n </div>\n <div v-else>No operation context found</div>\n</template>\n<style scoped>\n.editor-container {\n width: 100%;\n height: 100%;\n}\n\n:deep(.json-path-highlight) {\n background-color: rgba(255, 200, 0, 0.35);\n border-radius: 4px;\n}\n\n:deep(.json-focus-highlight) {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-accent, #24b47e) 18%,\n transparent\n );\n border-radius: 4px;\n}\n</style>\n"],"mappings":"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"} | ||
| {"version":3,"file":"Editor.vue.script.js","names":[],"sources":["../../../../../../src/v2/features/collection/components/Editor/Editor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarHotkey, useLoadingState } from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { ScalarIconArrowsIn, ScalarIconArrowsOut } from '@scalar/icons'\nimport * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n shallowRef,\n watch,\n} from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { useEditor, useJsonPointerLinkSupport } from '@/v2/features/editor'\nimport { createJsonModel } from '@/v2/features/editor/helpers/json/create-json-model'\nimport { createYamlModel } from '@/v2/features/editor/helpers/yaml/create-yaml-model'\nimport { useEditorMarkers } from '@/v2/features/editor/hooks/use-editor-markers'\n\nimport EditorDiagnosticsPanel from './components/EditorDiagnosticsPanel.vue'\nimport EditorSavePanel from './components/EditorSavePanel.vue'\nimport { getDiagnosticCounts } from './helpers/get-diagnostic-counts'\nimport { getOperationContext } from './helpers/get-operation-context'\nimport { getVisibleDiagnostics } from './helpers/get-visible-diagnostics'\nimport { parseEditorObject } from './helpers/parse-editor-object'\nimport { stringifyDocument } from './helpers/stringify-document'\nimport { useEditorState } from './hooks/use-editor-state'\n\nconst { collectionType, documentSlug, method, path, workspaceStore } =\n defineProps<CollectionProps>()\n\nconst MAX_VISIBLE_DIAGNOSTICS = 6\nconst EDITOR_PERSIST_DEBOUNCE_KEY = 'editor:replace-document'\n\nconst monacoEditorRef = ref<HTMLElement>()\nconst editorApi = shallowRef<ReturnType<typeof useEditor>>()\n\nconst saveLoader = useLoadingState()\nconst {\n isAutoSaveEnabled,\n isDirty,\n editorLanguage,\n isDiagnosticsPaneExpanded,\n isEditorMaximized,\n isYamlMode,\n editorBottomPadding,\n editorRootClass,\n getLanguageToggleClass,\n toggleEditorMaximized,\n} = useEditorState()\n\nconst jsonModel = createJsonModel()\nconst yamlModel = createYamlModel()\n\nconst selectedLanguage = ref<'json' | 'yaml'>('json')\n\nconst currentModel = computed(() => {\n return selectedLanguage.value === 'json' ? jsonModel : yamlModel\n})\n\nconst monacoEditorInstance = computed(() => editorApi.value?.editor)\nconst { markers: diagnostics } = useEditorMarkers(monacoEditorInstance)\n\nconst syncEditorBottomPadding = () => {\n editorApi.value?.editor.updateOptions({\n padding: {\n top: 0,\n bottom: editorBottomPadding.value,\n },\n })\n}\n\nconst diagnosticCounts = computed(() => getDiagnosticCounts(diagnostics.value))\nconst visibleDiagnostics = computed(() =>\n getVisibleDiagnostics(diagnostics.value, MAX_VISIBLE_DIAGNOSTICS),\n)\n\nconst focusDiagnostic = (marker: monaco.editor.IMarker) => {\n const editor = editorApi.value?.editor\n if (!editor) {\n return\n }\n editor.setSelection({\n startLineNumber: marker.startLineNumber,\n startColumn: marker.startColumn,\n endLineNumber: marker.endLineNumber,\n endColumn: marker.endColumn,\n })\n editor.revealPositionInCenter({\n lineNumber: marker.startLineNumber,\n column: marker.startColumn,\n })\n}\n\nconst getEditorValue = (): string | null => currentModel.value.model.getValue()\n\n/** Value from the editor for a specific language (use when switching to avoid reading the wrong model). */\nconst getEditorValueForLanguage = (language: 'json' | 'yaml'): string | null =>\n (language === 'json' ? jsonModel : yamlModel).model.getValue()\n\nconst getDocumentValue = async (\n language?: 'json' | 'yaml',\n): Promise<string> => {\n const document = await workspaceStore.getEditableDocument(documentSlug)\n return stringifyDocument(document, language ?? selectedLanguage.value)\n}\n\nconst debouncedPersist = debounce({ delay: 1500 })\n\nconst applyProgrammaticEditorValue = (value: string): void => {\n // Cancel pending auto-save work so synthetic model updates do not persist stale data.\n debouncedPersist.cleanup()\n editorApi.value?.setValue(value, true)\n}\n\nconst loadDocumentIntoEditor = async () => {\n applyProgrammaticEditorValue(await getDocumentValue())\n isDirty.value = false\n await focusOperation()\n}\n\nconst formatDocument = async () => {\n await editorApi.value?.formatDocument()\n}\n\nconst focusOperation = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n ])\n}\n\nconst persistEditorToWorkspace = async (value: string) => {\n const parsed = parseEditorObject(value, editorLanguage.value)\n if (!parsed) {\n const firstError = diagnostics.value.find(\n (m) => m.severity === monaco.MarkerSeverity.Error,\n )\n if (firstError) {\n focusDiagnostic(firstError)\n }\n await saveLoader.invalidate()\n return\n }\n\n saveLoader.start()\n await workspaceStore.replaceDocument(documentSlug, parsed)\n isDirty.value = false\n await saveLoader.validate({ duration: 900 })\n}\n\nconst saveNow = async () => {\n const value = getEditorValue()\n if (!value) {\n return\n }\n await persistEditorToWorkspace(value)\n}\n\nconst handleEditorChange = (value: string) => {\n isDirty.value = true\n\n if (!isAutoSaveEnabled.value) {\n return\n }\n\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n}\n\nconst focusOperationServers = async () => {\n const operationContext = getOperationContext(path, method)\n if (!operationContext) {\n return\n }\n\n const value = getEditorValue()\n if (!value) {\n return\n }\n\n const parsed = parseEditorObject(value, editorLanguage.value)\n\n if (!parsed || !isObject(parsed.paths)) {\n return\n }\n\n const pathsObject = parsed.paths as Record<string, unknown>\n const operationPathItem = pathsObject[operationContext.path]\n if (!isObject(operationPathItem)) {\n return\n }\n\n const operation = operationPathItem[operationContext.method]\n if (!isObject(operation)) {\n return\n }\n\n // Add default servers if not present\n operation.servers ??= []\n\n // Update the editor value\n editorApi.value?.setValue(stringifyDocument(parsed, editorLanguage.value))\n await editorApi.value?.focusPath([\n 'paths',\n operationContext.path,\n operationContext.method,\n 'servers',\n ])\n}\n\nuseJsonPointerLinkSupport(editorApi, currentModel)\n\nonMounted(() => {\n editorApi.value = useEditor({\n element: monacoEditorRef.value ?? document.createElement('div'),\n onChange: handleEditorChange,\n model: currentModel,\n actions: [\n {\n id: 'scalar.editor.focusOperation',\n label: 'Focus Operation',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyO],\n run: async () => {\n await focusOperation()\n },\n },\n {\n id: 'scalar.editor.focusOperationServers',\n label: 'Focus Operation Servers',\n keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.KeyS],\n run: async () => {\n await focusOperationServers()\n },\n },\n {\n id: 'scalar.editor.formatDocument',\n label: 'Format Document',\n keybindings: [\n monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF,\n ],\n run: async () => {\n await formatDocument()\n },\n },\n ],\n })\n\n syncEditorBottomPadding()\n void loadDocumentIntoEditor()\n})\n\nonBeforeUnmount(() => {\n debouncedPersist.cleanup()\n\n // Persist if there is a pending save\n if (isDirty.value && isAutoSaveEnabled.value) {\n void saveNow()\n }\n editorApi.value?.dispose?.()\n // Dispose models created at setup; useEditor only disposes the editor widget, not external models.\n jsonModel.model.dispose()\n yamlModel.model.dispose()\n})\n\nwatch(() => documentSlug, loadDocumentIntoEditor)\n\nwatch(\n () => [path, method] as const,\n async () => {\n await focusOperation()\n },\n)\n\nwatch(isDiagnosticsPaneExpanded, () => {\n syncEditorBottomPadding()\n})\n\nwatch(editorLanguage, async (nextLanguage, previousLanguage) => {\n const wasDirty = isDirty.value\n // Read from the previous model before switching; getEditorValue() would use currentModel\n // which changes with selectedLanguage, so we would read the (empty) new model otherwise.\n const value = getEditorValueForLanguage(previousLanguage ?? 'json')\n if (!value) {\n selectedLanguage.value = nextLanguage\n await nextTick()\n await focusOperation()\n return\n }\n\n const parsed = parseEditorObject(value, previousLanguage ?? 'json')\n selectedLanguage.value = nextLanguage\n await nextTick()\n if (parsed) {\n applyProgrammaticEditorValue(stringifyDocument(parsed, nextLanguage))\n isDirty.value = wasDirty\n }\n await focusOperation()\n})\n\nwatch(\n isAutoSaveEnabled,\n (isEnabled) => {\n if (!isEnabled) {\n debouncedPersist.cleanup()\n return\n }\n\n if (isDirty.value) {\n const value = getEditorValue()\n if (!value) {\n return\n }\n debouncedPersist.execute(EDITOR_PERSIST_DEBOUNCE_KEY, () =>\n persistEditorToWorkspace(value),\n )\n }\n },\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n v-if=\"\n collectionType === 'operation' &&\n getOperationContext(path, method) !== null\n \"\n class=\"flex w-full min-w-0 flex-1 flex-col gap-2\"\n :class=\"editorRootClass\">\n <div\n class=\"grid grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-3\">\n <div\n class=\"flex min-w-0 items-center gap-1 overflow-x-auto whitespace-nowrap\">\n <span class=\"text-c-2 text-xs font-medium whitespace-nowrap\">\n Shortcuts\n </span>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperation\">\n <span>Operation</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"O\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n\n <ScalarButton\n class=\"whitespace-nowrap\"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"focusOperationServers\">\n <span>Servers</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"S\"\n :modifier=\"['Alt']\" />\n </span>\n </ScalarButton>\n </div>\n\n <div\n aria-label=\"Editor language\"\n class=\"bg-b-1 shadow-border flex items-center justify-self-center overflow-hidden rounded-lg p-0.5\"\n role=\"tablist\">\n <ScalarButton\n :aria-selected=\"!isYamlMode\"\n :class=\"getLanguageToggleClass(!isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'json'\">\n JSON\n </ScalarButton>\n <ScalarButton\n :aria-selected=\"isYamlMode\"\n :class=\"getLanguageToggleClass(isYamlMode)\"\n role=\"tab\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"editorLanguage = 'yaml'\">\n YAML\n </ScalarButton>\n </div>\n\n <div class=\"flex min-w-0 shrink-0 items-center gap-2 justify-self-end\">\n <ScalarButton\n size=\"xs\"\n variant=\"ghost\"\n @click=\"formatDocument\">\n <span>Format {{ isYamlMode ? 'YAML' : 'JSON' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarHotkey\n hotkey=\"F\"\n :modifier=\"['Alt', 'Shift']\" />\n </span>\n </ScalarButton>\n <ScalarButton\n :aria-label=\"\n isEditorMaximized ? 'Restore editor size' : 'Maximize editor'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"toggleEditorMaximized\">\n <span>{{ isEditorMaximized ? 'Restore' : 'Maximize' }}</span>\n <span class=\"text-c-3 ml-2 text-[11px]\">\n <ScalarIconArrowsIn\n v-if=\"isEditorMaximized\"\n class=\"size-3.5\" />\n <ScalarIconArrowsOut\n v-else\n class=\"size-3.5\" />\n </span>\n </ScalarButton>\n </div>\n </div>\n\n <div class=\"flex min-h-0 w-full min-w-0 flex-1 rounded-lg border\">\n <div\n class=\"relative w-full min-w-0 flex-1\"\n :class=\"isEditorMaximized ? 'h-full min-h-0' : 'h-125'\">\n <div class=\"pointer-events-none absolute top-2 right-2 z-10\">\n <EditorSavePanel\n :isAutoSaveEnabled=\"isAutoSaveEnabled\"\n :isDirty=\"isDirty\"\n :saveLoader=\"saveLoader\"\n @saveNow=\"saveNow\"\n @update:isAutoSaveEnabled=\"isAutoSaveEnabled = $event\" />\n </div>\n\n <EditorDiagnosticsPanel\n :diagnosticCounts=\"diagnosticCounts\"\n :expanded=\"isDiagnosticsPaneExpanded\"\n :visibleDiagnostics=\"visibleDiagnostics\"\n @focusDiagnostic=\"focusDiagnostic\"\n @toggle=\"isDiagnosticsPaneExpanded = !isDiagnosticsPaneExpanded\" />\n\n <div\n ref=\"monacoEditorRef\"\n class=\"h-full w-full min-w-0 flex-1 [&_.monaco-editor]:rounded-lg [&_.overflow-guard]:rounded-lg\" />\n </div>\n </div>\n </div>\n <div v-else>No operation context found</div>\n</template>\n<style scoped>\n.editor-container {\n width: 100%;\n height: 100%;\n}\n\n:deep(.json-path-highlight) {\n background-color: rgba(255, 200, 0, 0.35);\n border-radius: 4px;\n}\n\n:deep(.json-focus-highlight) {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-accent, #24b47e) 18%,\n transparent\n );\n border-radius: 4px;\n}\n</style>\n"],"mappings":"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"} |
@@ -24,2 +24,3 @@ import Section_default from "../../settings/components/Section.vue.js"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -26,0 +27,0 @@ }, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Environment.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Environment.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Environment variables section for the collection.\n * Renders document or workspace environments and lets users set variables\n * that can be referenced in request inputs via {{ variable }}.\n */\nexport default {\n name: 'Environment',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { EnvironmentsList } from '@/v2/features/environments'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst { document, eventBus, collectionType, workspaceStore } =\n defineProps<CollectionProps>()\n\n/** Document or workspace environments */\nconst environments = computed(\n () =>\n (collectionType === 'document'\n ? document['x-scalar-environments']\n : workspaceStore.workspace['x-scalar-environments']) ?? {},\n)\n\nconst activeEnvironment = computed(() => {\n return workspaceStore.workspace['x-scalar-active-environment']\n})\n</script>\n\n<template>\n <Section v-if=\"collectionType !== 'operation'\">\n <template #title>Environment Variables</template>\n <template #description>\n Set environment variables at your collection level. Use\n <code\n v-pre\n class=\"font-code text-c-2\">\n {{ variable }}\n </code>\n to add / search among the selected environment's variables in your request\n inputs.\n </template>\n <EnvironmentsList\n :activeEnvironment\n :collectionType\n :environments\n :eventBus />\n </Section>\n</template>\n"],"mappings":";;;;CAOE,MAAM;;;;;;;;;;;;;;;;;;;;;;;EAeR,MAAM,eAAe,gBAEhB,QAAA,mBAAmB,aAChB,QAAA,SAAS,2BACT,QAAA,eAAe,UAAU,6BAA6B,EAAE,CAChE;EAEA,MAAM,oBAAoB,eAAe;AACvC,UAAO,QAAA,eAAe,UAAU;IACjC;;UAIgB,QAAA,mBAAc,eAAA,WAAA,EAA7B,YAiBU,iBAAA,EAAA,KAAA,GAAA,EAAA;IAhBG,OAAK,cAAsB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAArB,yBAAqB,GAAA,CAAA,EAAA,CAAA;IAC3B,aAAW,cAEpB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA;qBAFqB,6DAErB,GAAA;KAAA,mBAIO,QAAA,EAFL,OAAM,sBAAoB,EAAC,oBAE7B,GAAA;qBAAO,wFAGT,GAAA;;2BAKc,CAJd,YAIc,MAAA,yBAAA,EAAA;KAHX,mBAAA,kBAAA;KACA,gBAAA,QAAA;KACA,cAAA,aAAA;KACA,UAAA,QAAA"} | ||
| {"version":3,"file":"Environment.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Environment.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Environment variables section for the collection.\n * Renders document or workspace environments and lets users set variables\n * that can be referenced in request inputs via {{ variable }}.\n */\nexport default {\n name: 'Environment',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { EnvironmentsList } from '@/v2/features/environments'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst { document, eventBus, collectionType, workspaceStore } =\n defineProps<CollectionProps>()\n\n/** Document or workspace environments */\nconst environments = computed(\n () =>\n (collectionType === 'document'\n ? document['x-scalar-environments']\n : workspaceStore.workspace['x-scalar-environments']) ?? {},\n)\n\nconst activeEnvironment = computed(() => {\n return workspaceStore.workspace['x-scalar-active-environment']\n})\n</script>\n\n<template>\n <Section v-if=\"collectionType !== 'operation'\">\n <template #title>Environment Variables</template>\n <template #description>\n Set environment variables at your collection level. Use\n <code\n v-pre\n class=\"font-code text-c-2\">\n {{ variable }}\n </code>\n to add / search among the selected environment's variables in your request\n inputs.\n </template>\n <EnvironmentsList\n :activeEnvironment\n :collectionType\n :environments\n :eventBus />\n </Section>\n</template>\n"],"mappings":";;;;CAOE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;EAeR,MAAM,eAAe,gBAEhB,QAAA,mBAAmB,aAChB,QAAA,SAAS,2BACT,QAAA,eAAe,UAAU,6BAA6B,EAAE,CAChE;EAEA,MAAM,oBAAoB,eAAe;AACvC,UAAO,QAAA,eAAe,UAAU;IACjC;;UAIgB,QAAA,mBAAc,eAAA,WAAA,EAA7B,YAiBU,iBAAA,EAAA,KAAA,GAAA,EAAA;IAhBG,OAAK,cAAsB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAArB,yBAAqB,GAAA,CAAA,EAAA,CAAA;IAC3B,aAAW,cAEpB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA;qBAFqB,6DAErB,GAAA;KAAA,mBAIO,QAAA,EAFL,OAAM,sBAAoB,EAAC,oBAE7B,GAAA;qBAAO,wFAGT,GAAA;;2BAKc,CAJd,YAIc,MAAA,yBAAA,EAAA;KAHX,mBAAA,kBAAA;KACA,gBAAA,QAAA;KACA,cAAA,aAAA;KACA,UAAA,QAAA"} |
@@ -13,2 +13,4 @@ import type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'; | ||
| environment: XScalarEnvironment; | ||
| /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */ | ||
| withFakeData?: boolean; | ||
| }; | ||
@@ -15,0 +17,0 @@ declare var __VLS_9: {}; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Form.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/collection/components/Form.vue"],"names":[],"mappings":"AA4EA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAQnH,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,EAAE,MAAM,CAAA;QACnB,YAAY,CAAC,EAAE,OAAO,CAAA;KACvB,EAAE,CAAA;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACzB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAA;IACvD,WAAW,EAAE,kBAAkB,CAAA;CAChC,CAAC;AAyKF,QAAA,IAAI,OAAO,IAAW,CAAE;AACxB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAK7C,QAAA,MAAM,UAAU,kSAEd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"} | ||
| {"version":3,"file":"Form.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/collection/components/Form.vue"],"names":[],"mappings":"AA+EA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAQnH,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,EAAE,MAAM,CAAA;QACnB,YAAY,CAAC,EAAE,OAAO,CAAA;KACvB,EAAE,CAAA;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACzB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAA;IACvD,WAAW,EAAE,kBAAkB,CAAA;IAC/B,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAC;AA2KF,QAAA,IAAI,OAAO,IAAW,CAAE;AACxB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAK7C,QAAA,MAAM,UAAU,kSAEd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Form.vue.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Form.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { useId } from 'vue'\n\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport DataTable from '@/v2/components/data-table/DataTable.vue'\nimport DataTableInput from '@/v2/components/data-table/DataTableInput.vue'\nimport DataTableRow from '@/v2/components/data-table/DataTableRow.vue'\n\ndefineProps<{\n title?: string\n options: {\n key: string\n label: string\n placeholder: string\n lineWrapping?: boolean\n }[]\n data: Record<string, any>\n onUpdate: (key: string, value: string | number) => void\n environment: XScalarEnvironment\n}>()\n\nconst id = useId()\n</script>\n<template>\n <ViewLayoutSection class=\"last:rounded-b-lg\">\n <template\n v-if=\"title || $slots.title\"\n #title>\n <span v-if=\"title\">{{ title }}</span>\n <slot\n v-else\n name=\"title\" />\n </template>\n <div class=\"flex flex-1 flex-col gap-1.5\">\n <DataTable\n v-if=\"Object.keys(data).length > 0\"\n class=\"rounded-b-lg\"\n :columns=\"['']\">\n <DataTableRow\n v-for=\"(option, index) in options\"\n :key=\"index\">\n <DataTableInput\n :id=\"id\"\n class=\"pr-9\"\n :environment=\"environment\"\n :lineWrapping=\"option.lineWrapping ?? false\"\n :modelValue=\"data[option.key] ?? ''\"\n :placeholder=\"option.placeholder\"\n @update:modelValue=\"onUpdate(option.key, $event)\">\n <template #default>\n <label :for=\"id\">\n {{ option.label }}\n </label>\n </template>\n <template\n v-if=\"option.key === 'description'\"\n #icon>\n <div\n class=\"centered-y bg-b-2 flex-center absolute right-1 z-1 rounded px-1 py-0.5\">\n <ScalarIcon\n icon=\"Markdown\"\n size=\"lg\" />\n </div>\n </template>\n </DataTableInput>\n </DataTableRow>\n </DataTable>\n </div>\n </ViewLayoutSection>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"Form.vue.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Form.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { useId } from 'vue'\n\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport DataTable from '@/v2/components/data-table/DataTable.vue'\nimport DataTableInput from '@/v2/components/data-table/DataTableInput.vue'\nimport DataTableRow from '@/v2/components/data-table/DataTableRow.vue'\n\ndefineProps<{\n title?: string\n options: {\n key: string\n label: string\n placeholder: string\n lineWrapping?: boolean\n }[]\n data: Record<string, any>\n onUpdate: (key: string, value: string | number) => void\n environment: XScalarEnvironment\n /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */\n withFakeData?: boolean\n}>()\n\nconst id = useId()\n</script>\n<template>\n <ViewLayoutSection class=\"last:rounded-b-lg\">\n <template\n v-if=\"title || $slots.title\"\n #title>\n <span v-if=\"title\">{{ title }}</span>\n <slot\n v-else\n name=\"title\" />\n </template>\n <div class=\"flex flex-1 flex-col gap-1.5\">\n <DataTable\n v-if=\"Object.keys(data).length > 0\"\n class=\"rounded-b-lg\"\n :columns=\"['']\">\n <DataTableRow\n v-for=\"(option, index) in options\"\n :key=\"index\">\n <DataTableInput\n :id=\"id\"\n class=\"pr-9\"\n :environment=\"environment\"\n :lineWrapping=\"option.lineWrapping ?? false\"\n :modelValue=\"data[option.key] ?? ''\"\n :placeholder=\"option.placeholder\"\n :withFakeData=\"withFakeData ?? true\"\n @update:modelValue=\"onUpdate(option.key, $event)\">\n <template #default>\n <label :for=\"id\">\n {{ option.label }}\n </label>\n </template>\n <template\n v-if=\"option.key === 'description'\"\n #icon>\n <div\n class=\"centered-y bg-b-2 flex-center absolute right-1 z-1 rounded px-1 py-0.5\">\n <ScalarIcon\n icon=\"Markdown\"\n size=\"lg\" />\n </div>\n </template>\n </DataTableInput>\n </DataTableRow>\n </DataTable>\n </div>\n </ViewLayoutSection>\n</template>\n"],"mappings":""} |
@@ -19,3 +19,4 @@ import ViewLayoutSection_default from "../../../../components/ViewLayout/ViewLayoutSection.vue.js"; | ||
| onUpdate: { type: Function }, | ||
| environment: {} | ||
| environment: {}, | ||
| withFakeData: { type: Boolean } | ||
| }, | ||
@@ -40,2 +41,3 @@ setup(__props) { | ||
| placeholder: option.placeholder, | ||
| withFakeData: __props.withFakeData ?? true, | ||
| "onUpdate:modelValue": ($event) => __props.onUpdate(option.key, $event) | ||
@@ -58,2 +60,3 @@ }, createSlots({ | ||
| "placeholder", | ||
| "withFakeData", | ||
| "onUpdate:modelValue" | ||
@@ -60,0 +63,0 @@ ])]), |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Form.vue.script.js","names":["$slots"],"sources":["../../../../../src/v2/features/collection/components/Form.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { useId } from 'vue'\n\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport DataTable from '@/v2/components/data-table/DataTable.vue'\nimport DataTableInput from '@/v2/components/data-table/DataTableInput.vue'\nimport DataTableRow from '@/v2/components/data-table/DataTableRow.vue'\n\ndefineProps<{\n title?: string\n options: {\n key: string\n label: string\n placeholder: string\n lineWrapping?: boolean\n }[]\n data: Record<string, any>\n onUpdate: (key: string, value: string | number) => void\n environment: XScalarEnvironment\n}>()\n\nconst id = useId()\n</script>\n<template>\n <ViewLayoutSection class=\"last:rounded-b-lg\">\n <template\n v-if=\"title || $slots.title\"\n #title>\n <span v-if=\"title\">{{ title }}</span>\n <slot\n v-else\n name=\"title\" />\n </template>\n <div class=\"flex flex-1 flex-col gap-1.5\">\n <DataTable\n v-if=\"Object.keys(data).length > 0\"\n class=\"rounded-b-lg\"\n :columns=\"['']\">\n <DataTableRow\n v-for=\"(option, index) in options\"\n :key=\"index\">\n <DataTableInput\n :id=\"id\"\n class=\"pr-9\"\n :environment=\"environment\"\n :lineWrapping=\"option.lineWrapping ?? false\"\n :modelValue=\"data[option.key] ?? ''\"\n :placeholder=\"option.placeholder\"\n @update:modelValue=\"onUpdate(option.key, $event)\">\n <template #default>\n <label :for=\"id\">\n {{ option.label }}\n </label>\n </template>\n <template\n v-if=\"option.key === 'description'\"\n #icon>\n <div\n class=\"centered-y bg-b-2 flex-center absolute right-1 z-1 rounded px-1 py-0.5\">\n <ScalarIcon\n icon=\"Markdown\"\n size=\"lg\" />\n </div>\n </template>\n </DataTableInput>\n </DataTableRow>\n </DataTable>\n </div>\n </ViewLayoutSection>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAuBA,MAAM,KAAK,OAAM;;uBAGf,YA4CoB,2BAAA,EA5CD,OAAM,qBAAmB,EAAA,YAAA;2BA2CpC,CAlCN,mBAkCM,OAlCN,YAkCM,CAhCI,OAAO,KAAK,QAAA,KAAI,CAAE,SAAM,KAAA,WAAA,EADhC,YAgCY,mBAAA;;KA9BV,OAAM;KACL,SAAS,CAAA,GAAI;;4BAEsB,EAAA,UAAA,KAAA,EADpC,mBA2Be,UAAA,MAAA,WA1Ba,QAAA,UAAlB,QAAQ,UAAK;0BADvB,YA2Be,sBAAA,EAzBZ,KAAK,OAAK,EAAA;8BAwBM,CAvBjB,YAuBiB,wBAAA;QAtBd,IAAI,MAAA,GAAE;QACP,OAAM;QACL,aAAa,QAAA;QACb,cAAc,OAAO,gBAAY;QACjC,YAAY,QAAA,KAAK,OAAO,QAAG;QAC3B,aAAa,OAAO;QACpB,wBAAiB,WAAE,QAAA,SAAS,OAAO,KAAK,OAAM;;QACpC,SAAO,cAGR,CAFR,mBAEQ,SAAA,EAFA,KAAK,MAAA,GAAE,EAAA,EAAA,gBACV,OAAO,MAAK,EAAA,GAAA,WAAA,CAAA,CAAA;;WAIX,OAAO,QAAG,gBAAA;cACf;0BAMK,CALN,mBAKM,OALN,YAKM,CAHJ,YAEc,MAAA,WAAA,EAAA;SADZ,MAAK;SACL,MAAK;;;;;;;;;;;;;;;;;OAnCX,QAAA,SAASA,KAAAA,OAAO,QAAA;UACrB;sBACoC,CAAzB,QAAA,SAAA,WAAA,EAAZ,mBAAqC,QAAA,YAAA,gBAAf,QAAA,MAAK,EAAA,EAAA,IAC3B,WAEiB,KAAA,QAAA,SAAA,EAAA,KAAA,GAAA,CAAA,CAAA,CAAA"} | ||
| {"version":3,"file":"Form.vue.script.js","names":["$slots"],"sources":["../../../../../src/v2/features/collection/components/Form.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { useId } from 'vue'\n\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport DataTable from '@/v2/components/data-table/DataTable.vue'\nimport DataTableInput from '@/v2/components/data-table/DataTableInput.vue'\nimport DataTableRow from '@/v2/components/data-table/DataTableRow.vue'\n\ndefineProps<{\n title?: string\n options: {\n key: string\n label: string\n placeholder: string\n lineWrapping?: boolean\n }[]\n data: Record<string, any>\n onUpdate: (key: string, value: string | number) => void\n environment: XScalarEnvironment\n /** Whether to show context function suggestions like $guid, $timestamp. Defaults to true */\n withFakeData?: boolean\n}>()\n\nconst id = useId()\n</script>\n<template>\n <ViewLayoutSection class=\"last:rounded-b-lg\">\n <template\n v-if=\"title || $slots.title\"\n #title>\n <span v-if=\"title\">{{ title }}</span>\n <slot\n v-else\n name=\"title\" />\n </template>\n <div class=\"flex flex-1 flex-col gap-1.5\">\n <DataTable\n v-if=\"Object.keys(data).length > 0\"\n class=\"rounded-b-lg\"\n :columns=\"['']\">\n <DataTableRow\n v-for=\"(option, index) in options\"\n :key=\"index\">\n <DataTableInput\n :id=\"id\"\n class=\"pr-9\"\n :environment=\"environment\"\n :lineWrapping=\"option.lineWrapping ?? false\"\n :modelValue=\"data[option.key] ?? ''\"\n :placeholder=\"option.placeholder\"\n :withFakeData=\"withFakeData ?? true\"\n @update:modelValue=\"onUpdate(option.key, $event)\">\n <template #default>\n <label :for=\"id\">\n {{ option.label }}\n </label>\n </template>\n <template\n v-if=\"option.key === 'description'\"\n #icon>\n <div\n class=\"centered-y bg-b-2 flex-center absolute right-1 z-1 rounded px-1 py-0.5\">\n <ScalarIcon\n icon=\"Markdown\"\n size=\"lg\" />\n </div>\n </template>\n </DataTableInput>\n </DataTableRow>\n </DataTable>\n </div>\n </ViewLayoutSection>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAyBA,MAAM,KAAK,OAAM;;uBAGf,YA6CoB,2BAAA,EA7CD,OAAM,qBAAmB,EAAA,YAAA;2BA4CpC,CAnCN,mBAmCM,OAnCN,YAmCM,CAjCI,OAAO,KAAK,QAAA,KAAI,CAAE,SAAM,KAAA,WAAA,EADhC,YAiCY,mBAAA;;KA/BV,OAAM;KACL,SAAS,CAAA,GAAI;;4BAEsB,EAAA,UAAA,KAAA,EADpC,mBA4Be,UAAA,MAAA,WA3Ba,QAAA,UAAlB,QAAQ,UAAK;0BADvB,YA4Be,sBAAA,EA1BZ,KAAK,OAAK,EAAA;8BAyBM,CAxBjB,YAwBiB,wBAAA;QAvBd,IAAI,MAAA,GAAE;QACP,OAAM;QACL,aAAa,QAAA;QACb,cAAc,OAAO,gBAAY;QACjC,YAAY,QAAA,KAAK,OAAO,QAAG;QAC3B,aAAa,OAAO;QACpB,cAAc,QAAA,gBAAY;QAC1B,wBAAiB,WAAE,QAAA,SAAS,OAAO,KAAK,OAAM;;QACpC,SAAO,cAGR,CAFR,mBAEQ,SAAA,EAFA,KAAK,MAAA,GAAE,EAAA,EAAA,gBACV,OAAO,MAAK,EAAA,GAAA,WAAA,CAAA,CAAA;;WAIX,OAAO,QAAG,gBAAA;cACf;0BAMK,CALN,mBAKM,OALN,YAKM,CAHJ,YAEc,MAAA,WAAA,EAAA;SADZ,MAAK;SACL,MAAK;;;;;;;;;;;;;;;;;;OApCX,QAAA,SAASA,KAAAA,OAAO,QAAA;UACrB;sBACoC,CAAzB,QAAA,SAAA,WAAA,EAAZ,mBAAqC,QAAA,YAAA,gBAAf,QAAA,MAAK,EAAA,EAAA,IAC3B,WAEiB,KAAA,QAAA,SAAA,EAAA,KAAA,GAAA,CAAA,CAAA,CAAA"} |
@@ -13,4 +13,4 @@ type __VLS_Props = { | ||
| }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{ | ||
| onBlur?: ((value: string) => any) | undefined; | ||
| "onUpdate:modelValue"?: ((value: string) => any) | undefined; | ||
| onBlur?: ((value: string) => any) | undefined; | ||
| }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; | ||
@@ -17,0 +17,0 @@ declare const _default: typeof __VLS_export; |
@@ -38,2 +38,3 @@ import CodeInput_default from "../../../components/code-input/CodeInput.vue.js"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -40,0 +41,0 @@ }, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Overview.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Overview.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarMarkdown,\n ScalarModal,\n ScalarToggle,\n useModal,\n} from '@scalar/components'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport { ScalarIconPencil } from '@scalar/icons'\nimport {\n computed,\n nextTick,\n ref,\n useTemplateRef,\n type ComputedRef,\n type Ref,\n} from 'vue'\n\nimport DeleteSidebarListElement from '@/components/Sidebar/Actions/DeleteSidebarListElement.vue'\nimport { CodeInput } from '@/v2/components/code-input'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst {\n document,\n eventBus,\n layout,\n collectionType,\n path,\n method,\n documentSlug,\n} = defineProps<CollectionProps>()\n\nconst operationLabel = computed(() => {\n if (!method || !path) {\n return 'this operation'\n }\n const upperMethod = typeof method === 'string' ? method.toUpperCase() : method\n return `${upperMethod} ${path}`\n})\n\nconst description: ComputedRef<string> = computed(() => {\n if (collectionType === 'operation') {\n if (!path || !method || !isHttpMethod(method)) {\n return ''\n }\n\n return document?.paths?.[path]?.[method]?.description ?? ''\n }\n\n return document?.info?.description ?? ''\n})\n\nconst deprecated: ComputedRef<boolean> = computed(() => {\n if (collectionType !== 'operation' || !path || !isHttpMethod(method)) {\n return false\n }\n\n const operation = document?.paths?.[path]?.[method] as\n | { deprecated?: boolean }\n | undefined\n return operation?.deprecated ?? false\n})\n\nconst mode: Ref<'edit' | 'preview'> = ref('preview')\n\nconst codeInputRef = useTemplateRef('codeInputRef')\n\n/**\n * Switch between edit and preview modes.\n * When switching to edit mode, focus the input after the DOM updates.\n */\nconst switchMode = async (newMode: 'edit' | 'preview'): Promise<void> => {\n mode.value = newMode\n\n if (newMode === 'edit') {\n await nextTick()\n codeInputRef.value?.focus()\n }\n}\n\n/**\n * Updates the description of the collection\n * @param payload - The new description\n * @returns void\n */\nconst handleDescriptionUpdate = async (payload: string) => {\n await switchMode('preview')\n\n /** If the collection type is a document, update the description of the document */\n if (collectionType === 'document') {\n return eventBus.emit('document:update:info', { description: payload })\n }\n\n /** If the collection type is an operation, update the description of the operation */\n if (collectionType === 'operation') {\n if (!path || !method) {\n console.error('Invalid path or method', { path, method })\n return\n }\n\n return eventBus.emit('operation:update:meta', {\n meta: { path, method },\n payload: {\n description: payload,\n },\n })\n }\n\n console.error('Invalid collection type', { collectionType })\n}\n\nconst handleDeprecatedChange = (value: boolean) => {\n if (collectionType !== 'operation' || !path || !method) {\n return\n }\n\n eventBus.emit('operation:update:meta', {\n meta: { path, method },\n payload: { deprecated: value },\n })\n}\n\nconst deleteOperationModal = useModal()\n\nconst handleDeleteOperation = () => {\n if (collectionType !== 'operation' || !path || !method || !documentSlug) {\n return\n }\n\n eventBus.emit('operation:delete:operation', {\n documentName: documentSlug,\n meta: { path, method },\n })\n deleteOperationModal.hide()\n}\n</script>\n\n<template>\n <div class=\"flex flex-col gap-8\">\n <Section>\n <template #title>Description</template>\n <template #actions>\n <ScalarButton\n v-if=\"mode === 'preview'\"\n class=\"text-c-2 hover:text-c-1 flex items-center gap-2\"\n size=\"sm\"\n type=\"button\"\n variant=\"outlined\"\n @click=\"switchMode('edit')\">\n <ScalarIconPencil\n size=\"sm\"\n thickness=\"1.5\" />\n <span>Edit</span>\n </ScalarButton>\n </template>\n <div class=\"has-focus-visible:bg-b-1 group rounded-lg\">\n <!-- Preview -->\n <template v-if=\"mode === 'preview'\">\n <template v-if=\"description.trim().length\">\n <ScalarMarkdown\n class=\"flex-1 rounded border border-transparent p-1.5 hover:border-(--scalar-background-3)\"\n :value=\"description\"\n withImages\n @dblclick=\"switchMode('edit')\" />\n <div\n class=\"brightness-lifted bg-b-1 absolute inset-0 -z-1 hidden rounded group-hover:block group-has-focus-visible:hidden\" />\n </template>\n\n <div\n v-else\n class=\"text-c-3 flex items-center justify-center rounded-lg border p-4\">\n <ScalarButton\n class=\"hover:bg-b-2 hover:text-c-1 text-c-2 flex items-center gap-2\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"switchMode('edit')\">\n <ScalarIconPencil\n size=\"sm\"\n thickness=\"1.5\" />\n <span>Write a description</span>\n </ScalarButton>\n </div>\n </template>\n\n <!-- Edit -->\n <template v-else>\n <CodeInput\n ref=\"codeInputRef\"\n class=\"border px-0.5 py-0\"\n :environment=\"undefined\"\n :layout=\"layout\"\n :modelValue=\"description\"\n @blur=\"handleDescriptionUpdate\" />\n </template>\n </div>\n </Section>\n\n <!-- Operation-only: Status and Danger Zone -->\n <template v-if=\"collectionType === 'operation'\">\n <Section>\n <template #title>Status</template>\n <div\n class=\"rounded-lg border text-sm transition-colors\"\n :class=\"\n deprecated\n ? 'border-(--scalar-color-alert) bg-(--scalar-background-alert)'\n : 'bg-b-2 border-(--scalar-background-3)'\n \">\n <div class=\"flex items-center justify-between gap-4 rounded-lg p-4\">\n <div class=\"min-w-0 flex-1\">\n <h4\n class=\"font-medium\"\n :class=\"\n deprecated ? 'text-(--scalar-color-alert)' : 'text-c-1'\n \">\n Deprecated\n </h4>\n <p class=\"text-c-2 mt-1.5\">\n Mark this operation as deprecated. Consumers SHOULD refrain from\n using it.\n </p>\n </div>\n <ScalarToggle\n class=\"shrink-0\"\n :modelValue=\"deprecated\"\n @update:modelValue=\"handleDeprecatedChange\" />\n </div>\n </div>\n </Section>\n\n <Section>\n <template #title>Danger Zone</template>\n <div\n class=\"bg-b-2 flex items-center justify-between gap-4 rounded-lg border border-(--scalar-background-3) p-4 text-sm\">\n <div class=\"min-w-0 flex-1\">\n <h4 class=\"text-c-1 font-medium\">Delete Operation</h4>\n <p class=\"text-c-2 mt-1.5\">\n Be careful, my friend. Once deleted, there is no way to recover\n the operation.\n </p>\n </div>\n <ScalarButton\n class=\"shrink-0\"\n size=\"sm\"\n variant=\"danger\"\n @click=\"deleteOperationModal.show()\">\n Delete Operation\n </ScalarButton>\n </div>\n </Section>\n </template>\n </div>\n\n <!-- Delete Operation Modal -->\n <ScalarModal\n :size=\"'xxs'\"\n :state=\"deleteOperationModal\"\n :title=\"`Delete ${operationLabel}`\">\n <DeleteSidebarListElement\n :variableName=\"operationLabel\"\n warningMessage=\"This action cannot be undone.\"\n @close=\"deleteOperationModal.hide()\"\n @delete=\"handleDeleteOperation\" />\n </ScalarModal>\n</template>\n\n<style scoped>\n:deep(.cm-content) {\n min-height: fit-content;\n}\n:deep(.cm-scroller) {\n max-width: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n}\n</style>\n"],"mappings":"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"} | ||
| {"version":3,"file":"Overview.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Overview.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarMarkdown,\n ScalarModal,\n ScalarToggle,\n useModal,\n} from '@scalar/components'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport { ScalarIconPencil } from '@scalar/icons'\nimport {\n computed,\n nextTick,\n ref,\n useTemplateRef,\n type ComputedRef,\n type Ref,\n} from 'vue'\n\nimport DeleteSidebarListElement from '@/components/Sidebar/Actions/DeleteSidebarListElement.vue'\nimport { CodeInput } from '@/v2/components/code-input'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst {\n document,\n eventBus,\n layout,\n collectionType,\n path,\n method,\n documentSlug,\n} = defineProps<CollectionProps>()\n\nconst operationLabel = computed(() => {\n if (!method || !path) {\n return 'this operation'\n }\n const upperMethod = typeof method === 'string' ? method.toUpperCase() : method\n return `${upperMethod} ${path}`\n})\n\nconst description: ComputedRef<string> = computed(() => {\n if (collectionType === 'operation') {\n if (!path || !method || !isHttpMethod(method)) {\n return ''\n }\n\n return document?.paths?.[path]?.[method]?.description ?? ''\n }\n\n return document?.info?.description ?? ''\n})\n\nconst deprecated: ComputedRef<boolean> = computed(() => {\n if (collectionType !== 'operation' || !path || !isHttpMethod(method)) {\n return false\n }\n\n const operation = document?.paths?.[path]?.[method] as\n | { deprecated?: boolean }\n | undefined\n return operation?.deprecated ?? false\n})\n\nconst mode: Ref<'edit' | 'preview'> = ref('preview')\n\nconst codeInputRef = useTemplateRef('codeInputRef')\n\n/**\n * Switch between edit and preview modes.\n * When switching to edit mode, focus the input after the DOM updates.\n */\nconst switchMode = async (newMode: 'edit' | 'preview'): Promise<void> => {\n mode.value = newMode\n\n if (newMode === 'edit') {\n await nextTick()\n codeInputRef.value?.focus()\n }\n}\n\n/**\n * Updates the description of the collection\n * @param payload - The new description\n * @returns void\n */\nconst handleDescriptionUpdate = async (payload: string) => {\n await switchMode('preview')\n\n /** If the collection type is a document, update the description of the document */\n if (collectionType === 'document') {\n return eventBus.emit('document:update:info', { description: payload })\n }\n\n /** If the collection type is an operation, update the description of the operation */\n if (collectionType === 'operation') {\n if (!path || !method) {\n console.error('Invalid path or method', { path, method })\n return\n }\n\n return eventBus.emit('operation:update:meta', {\n meta: { path, method },\n payload: {\n description: payload,\n },\n })\n }\n\n console.error('Invalid collection type', { collectionType })\n}\n\nconst handleDeprecatedChange = (value: boolean) => {\n if (collectionType !== 'operation' || !path || !method) {\n return\n }\n\n eventBus.emit('operation:update:meta', {\n meta: { path, method },\n payload: { deprecated: value },\n })\n}\n\nconst deleteOperationModal = useModal()\n\nconst handleDeleteOperation = () => {\n if (collectionType !== 'operation' || !path || !method || !documentSlug) {\n return\n }\n\n eventBus.emit('operation:delete:operation', {\n documentName: documentSlug,\n meta: { path, method },\n })\n deleteOperationModal.hide()\n}\n</script>\n\n<template>\n <div class=\"flex flex-col gap-8\">\n <Section>\n <template #title>Description</template>\n <template #actions>\n <ScalarButton\n v-if=\"mode === 'preview'\"\n class=\"text-c-2 hover:text-c-1 flex items-center gap-2\"\n size=\"sm\"\n type=\"button\"\n variant=\"outlined\"\n @click=\"switchMode('edit')\">\n <ScalarIconPencil\n size=\"sm\"\n thickness=\"1.5\" />\n <span>Edit</span>\n </ScalarButton>\n </template>\n <div class=\"has-focus-visible:bg-b-1 group rounded-lg\">\n <!-- Preview -->\n <template v-if=\"mode === 'preview'\">\n <template v-if=\"description.trim().length\">\n <ScalarMarkdown\n class=\"flex-1 rounded border border-transparent p-1.5 hover:border-(--scalar-background-3)\"\n :value=\"description\"\n withImages\n @dblclick=\"switchMode('edit')\" />\n <div\n class=\"brightness-lifted bg-b-1 absolute inset-0 -z-1 hidden rounded group-hover:block group-has-focus-visible:hidden\" />\n </template>\n\n <div\n v-else\n class=\"text-c-3 flex items-center justify-center rounded-lg border p-4\">\n <ScalarButton\n class=\"hover:bg-b-2 hover:text-c-1 text-c-2 flex items-center gap-2\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"switchMode('edit')\">\n <ScalarIconPencil\n size=\"sm\"\n thickness=\"1.5\" />\n <span>Write a description</span>\n </ScalarButton>\n </div>\n </template>\n\n <!-- Edit -->\n <template v-else>\n <CodeInput\n ref=\"codeInputRef\"\n class=\"border px-0.5 py-0\"\n :environment=\"undefined\"\n :layout=\"layout\"\n :modelValue=\"description\"\n @blur=\"handleDescriptionUpdate\" />\n </template>\n </div>\n </Section>\n\n <!-- Operation-only: Status and Danger Zone -->\n <template v-if=\"collectionType === 'operation'\">\n <Section>\n <template #title>Status</template>\n <div\n class=\"rounded-lg border text-sm transition-colors\"\n :class=\"\n deprecated\n ? 'border-(--scalar-color-alert) bg-(--scalar-background-alert)'\n : 'bg-b-2 border-(--scalar-background-3)'\n \">\n <div class=\"flex items-center justify-between gap-4 rounded-lg p-4\">\n <div class=\"min-w-0 flex-1\">\n <h4\n class=\"font-medium\"\n :class=\"\n deprecated ? 'text-(--scalar-color-alert)' : 'text-c-1'\n \">\n Deprecated\n </h4>\n <p class=\"text-c-2 mt-1.5\">\n Mark this operation as deprecated. Consumers SHOULD refrain from\n using it.\n </p>\n </div>\n <ScalarToggle\n class=\"shrink-0\"\n :modelValue=\"deprecated\"\n @update:modelValue=\"handleDeprecatedChange\" />\n </div>\n </div>\n </Section>\n\n <Section>\n <template #title>Danger Zone</template>\n <div\n class=\"bg-b-2 flex items-center justify-between gap-4 rounded-lg border border-(--scalar-background-3) p-4 text-sm\">\n <div class=\"min-w-0 flex-1\">\n <h4 class=\"text-c-1 font-medium\">Delete Operation</h4>\n <p class=\"text-c-2 mt-1.5\">\n Be careful, my friend. Once deleted, there is no way to recover\n the operation.\n </p>\n </div>\n <ScalarButton\n class=\"shrink-0\"\n size=\"sm\"\n variant=\"danger\"\n @click=\"deleteOperationModal.show()\">\n Delete Operation\n </ScalarButton>\n </div>\n </Section>\n </template>\n </div>\n\n <!-- Delete Operation Modal -->\n <ScalarModal\n :size=\"'xxs'\"\n :state=\"deleteOperationModal\"\n :title=\"`Delete ${operationLabel}`\">\n <DeleteSidebarListElement\n :variableName=\"operationLabel\"\n warningMessage=\"This action cannot be undone.\"\n @close=\"deleteOperationModal.hide()\"\n @delete=\"handleDeleteOperation\" />\n </ScalarModal>\n</template>\n\n<style scoped>\n:deep(.cm-content) {\n min-height: fit-content;\n}\n:deep(.cm-scroller) {\n max-width: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n}\n</style>\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Runner.vue.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/features/collection/components/Runner/components/Runner.vue"],"names":[],"mappings":"AA4xBA,QAAA,MAAM,YAAY;;;;;;;;;;;;kGAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} | ||
| {"version":3,"file":"Runner.vue.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/features/collection/components/Runner/components/Runner.vue"],"names":[],"mappings":"AA0yBA,QAAA,MAAM,YAAY;;;;;;;;;;;;kGAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Runner.vue.js","names":[],"sources":["../../../../../../../src/v2/features/collection/components/Runner/components/Runner.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { ScalarIconArrowCounterClockwise, ScalarIconPlay } from '@scalar/icons'\nimport { computed } from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nimport { useRunnerExecution, useRunnerSelection } from '../hooks'\nimport RunnerCard from './RunnerCard.vue'\nimport RunnerOrderItem from './RunnerOrderItem.vue'\nimport RunnerResults from './RunnerResults.vue'\nimport RunnerTree from './RunnerTree.vue'\n\nconst { document, collectionType, workspaceStore, documentSlug, layout } =\n defineProps<CollectionProps>()\n\nconst {\n selectedOrder,\n hasSelection,\n isSelected,\n toggle,\n clearAll,\n removeFromOrder,\n dragState,\n handleDragStart,\n handleDragOver,\n handleDragLeave,\n handleDrop,\n handleDragEnd,\n} = useRunnerSelection({\n isLocked: () => isLocked.value,\n})\n\nconst {\n isRunning,\n hasRunCompleted,\n currentRunIndex,\n runLoader,\n runSummary,\n run,\n rerun,\n clearResults,\n getResultAtIndex,\n isResultPassed,\n isResultSkipped,\n getFailedTests,\n} = useRunnerExecution({\n workspaceStore,\n document,\n documentName: documentSlug,\n isWeb: layout === 'web',\n selectedOrder: computed(() => selectedOrder.value),\n})\n\nconst isLocked = computed(() => isRunning.value || hasRunCompleted.value)\n\nconst { draggedIndex, dragOverIndex, dragOffset } = dragState\n\nconst navigationChildren = computed(() => {\n return document?.['x-scalar-navigation']?.children ?? []\n})\n\nconst hasOperations = computed(() => navigationChildren.value.length > 0)\n</script>\n\n<template>\n <Section v-if=\"collectionType === 'document'\">\n <template #title>Runner</template>\n <template #description>\n Select operation examples, set the run order, then run them in sequence.\n Variables set by pre-request or post-response scripts are shared between\n runs.\n </template>\n\n <div class=\"flex flex-col gap-8 lg:flex-row lg:items-start\">\n <!-- Left: Document operations tree -->\n <RunnerCard\n class=\"min-w-0 flex-1\"\n subtitle=\"Check the examples you want to run. They will be added to the run order.\"\n title=\"Select operations\">\n <div\n v-if=\"hasOperations\"\n class=\"max-h-[28rem] overflow-y-auto\"\n :class=\"{ 'opacity-60': isLocked }\">\n <RunnerTree\n :disabled=\"isLocked\"\n :entries=\"navigationChildren\"\n :isSelected=\"isSelected\"\n :selectedOrder=\"selectedOrder\"\n @toggle=\"toggle\" />\n </div>\n <div\n v-else\n class=\"py-6 text-center\">\n <p class=\"text-c-3 text-sm\">No operations in this document.</p>\n <p class=\"text-c-3 mt-1 text-xs\">\n Add paths and methods to your API description to see them here.\n </p>\n </div>\n </RunnerCard>\n\n <!-- Right: Run order + actions + results -->\n <div class=\"flex w-full shrink-0 flex-col gap-4 lg:w-96\">\n <!-- Run order card -->\n <RunnerCard title=\"Run order\">\n <template #header>\n <ScalarButton\n class=\"transition-opacity duration-100\"\n :class=\"\n hasSelection && !isLocked\n ? 'opacity-100'\n : 'pointer-events-none opacity-0'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"clearAll\">\n <span class=\"hover:underline\">Clear all</span>\n </ScalarButton>\n </template>\n <template #subtitle>\n {{ selectedOrder.length }}\n {{ selectedOrder.length === 1 ? 'item' : 'items' }} selected.\n <template v-if=\"!isLocked\">Drag to reorder.</template>\n <template v-else-if=\"hasRunCompleted\">\n Clear results to modify.\n </template>\n </template>\n <template #default>\n <div\n v-if=\"selectedOrder.length > 0\"\n class=\"flex flex-col gap-0.5\"\n :class=\"{ 'opacity-60': isLocked }\">\n <RunnerOrderItem\n v-for=\"(item, index) in selectedOrder\"\n :key=\"item.id\"\n :draggable=\"!isLocked\"\n :exampleKey=\"item.exampleKey\"\n :index=\"index\"\n :isDragAfter=\"dragOverIndex === index && dragOffset === 'after'\"\n :isDragBefore=\"\n dragOverIndex === index && dragOffset === 'before'\n \"\n :isDragging=\"draggedIndex === index\"\n :isLocked=\"isLocked\"\n :method=\"item.method\"\n :path=\"item.path\"\n @dragend=\"handleDragEnd\"\n @dragleave=\"handleDragLeave\"\n @dragover=\"handleDragOver(index, $event)\"\n @dragstart=\"handleDragStart(index, $event)\"\n @drop=\"handleDrop\"\n @remove=\"removeFromOrder(item)\" />\n </div>\n <div\n v-else\n class=\"py-4 text-center\">\n <p class=\"text-c-3 text-sm\">No items yet.</p>\n <p class=\"text-c-3 mt-0.5 text-xs\">\n Select operations from the list on the left.\n </p>\n </div>\n </template>\n </RunnerCard>\n\n <!-- Run button -->\n <div class=\"flex justify-end pt-1\">\n <ScalarButton\n v-if=\"!hasRunCompleted\"\n class=\"min-w-40\"\n :disabled=\"!hasSelection || isRunning\"\n :icon=\"ScalarIconPlay\"\n :loader=\"runLoader\"\n size=\"md\"\n variant=\"gradient\"\n @click=\"run\">\n Run sequence\n </ScalarButton>\n <ScalarButton\n v-else\n class=\"min-w-40\"\n :disabled=\"!hasSelection || isRunning\"\n :icon=\"ScalarIconArrowCounterClockwise\"\n :loader=\"runLoader\"\n size=\"md\"\n variant=\"gradient\"\n @click=\"rerun\">\n Re-run sequence\n </ScalarButton>\n </div>\n\n <!-- Running progress -->\n <RunnerCard\n v-if=\"\n isRunning && currentRunIndex != null && selectedOrder.length > 0\n \"\n compact>\n <p class=\"text-c-2 text-sm\">\n Running step\n <span class=\"text-c-1 font-medium\">\n {{ currentRunIndex }} / {{ selectedOrder.length }}\n </span>\n </p>\n <div\n :aria-valuemax=\"selectedOrder.length\"\n :aria-valuemin=\"0\"\n :aria-valuenow=\"currentRunIndex\"\n class=\"bg-b-3 mt-2 h-1.5 overflow-hidden rounded-full\"\n role=\"progressbar\">\n <div\n class=\"bg-accent-color h-full rounded-full transition-[width] duration-200 ease-out\"\n :style=\"{\n width: `${(currentRunIndex / selectedOrder.length) * 100}%`,\n }\" />\n </div>\n </RunnerCard>\n\n <!-- Results -->\n <RunnerResults\n v-if=\"runSummary && hasRunCompleted\"\n :getFailedTests=\"getFailedTests\"\n :getResultAtIndex=\"getResultAtIndex\"\n :isResultPassed=\"isResultPassed\"\n :isResultSkipped=\"isResultSkipped\"\n :selectedOrder=\"selectedOrder\"\n :summary=\"runSummary\"\n @clear=\"clearResults\" />\n </div>\n </div>\n </Section>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"Runner.vue.js","names":[],"sources":["../../../../../../../src/v2/features/collection/components/Runner/components/Runner.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { ScalarIconArrowCounterClockwise, ScalarIconPlay } from '@scalar/icons'\nimport { computed, toValue } from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nimport { useRunnerExecution, useRunnerSelection } from '../hooks'\nimport RunnerCard from './RunnerCard.vue'\nimport RunnerOrderItem from './RunnerOrderItem.vue'\nimport RunnerResults from './RunnerResults.vue'\nimport RunnerTree from './RunnerTree.vue'\n\nconst {\n document,\n collectionType,\n workspaceStore,\n documentSlug,\n layout,\n options,\n} = defineProps<CollectionProps>()\n\nconst {\n selectedOrder,\n hasSelection,\n isSelected,\n toggle,\n clearAll,\n removeFromOrder,\n dragState,\n handleDragStart,\n handleDragOver,\n handleDragLeave,\n handleDrop,\n handleDragEnd,\n} = useRunnerSelection({\n isLocked: () => isLocked.value,\n})\n\nconst {\n isRunning,\n hasRunCompleted,\n currentRunIndex,\n runLoader,\n runSummary,\n run,\n rerun,\n clearResults,\n getResultAtIndex,\n isResultPassed,\n isResultSkipped,\n getFailedTests,\n} = useRunnerExecution({\n workspaceStore,\n document,\n documentName: documentSlug,\n isWeb: layout === 'web',\n selectedOrder: computed(() => selectedOrder.value),\n customFetch: toValue(options)?.customFetch,\n})\n\nconst isLocked = computed(() => isRunning.value || hasRunCompleted.value)\n\nconst { draggedIndex, dragOverIndex, dragOffset } = dragState\n\nconst navigationChildren = computed(() => {\n return document?.['x-scalar-navigation']?.children ?? []\n})\n\nconst hasOperations = computed(() => navigationChildren.value.length > 0)\n</script>\n\n<template>\n <Section v-if=\"collectionType === 'document'\">\n <template #title>Runner</template>\n <template #description>\n Select operation examples, set the run order, then run them in sequence.\n Variables set by pre-request or post-response scripts are shared between\n runs.\n </template>\n\n <div class=\"flex flex-col gap-8 lg:flex-row lg:items-start\">\n <!-- Left: Document operations tree -->\n <RunnerCard\n class=\"min-w-0 flex-1\"\n subtitle=\"Check the examples you want to run. They will be added to the run order.\"\n title=\"Select operations\">\n <div\n v-if=\"hasOperations\"\n class=\"max-h-[28rem] overflow-y-auto\"\n :class=\"{ 'opacity-60': isLocked }\">\n <RunnerTree\n :disabled=\"isLocked\"\n :entries=\"navigationChildren\"\n :isSelected=\"isSelected\"\n :selectedOrder=\"selectedOrder\"\n @toggle=\"toggle\" />\n </div>\n <div\n v-else\n class=\"py-6 text-center\">\n <p class=\"text-c-3 text-sm\">No operations in this document.</p>\n <p class=\"text-c-3 mt-1 text-xs\">\n Add paths and methods to your API description to see them here.\n </p>\n </div>\n </RunnerCard>\n\n <!-- Right: Run order + actions + results -->\n <div class=\"flex w-full shrink-0 flex-col gap-4 lg:w-96\">\n <!-- Run order card -->\n <RunnerCard title=\"Run order\">\n <template #header>\n <ScalarButton\n class=\"transition-opacity duration-100\"\n :class=\"\n hasSelection && !isLocked\n ? 'opacity-100'\n : 'pointer-events-none opacity-0'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"clearAll\">\n <span class=\"hover:underline\">Clear all</span>\n </ScalarButton>\n </template>\n <template #subtitle>\n {{ selectedOrder.length }}\n {{ selectedOrder.length === 1 ? 'item' : 'items' }} selected.\n <template v-if=\"!isLocked\">Drag to reorder.</template>\n <template v-else-if=\"hasRunCompleted\">\n Clear results to modify.\n </template>\n </template>\n <template #default>\n <div\n v-if=\"selectedOrder.length > 0\"\n class=\"flex flex-col gap-0.5\"\n :class=\"{ 'opacity-60': isLocked }\">\n <RunnerOrderItem\n v-for=\"(item, index) in selectedOrder\"\n :key=\"item.id\"\n :draggable=\"!isLocked\"\n :exampleKey=\"item.exampleKey\"\n :index=\"index\"\n :isDragAfter=\"dragOverIndex === index && dragOffset === 'after'\"\n :isDragBefore=\"\n dragOverIndex === index && dragOffset === 'before'\n \"\n :isDragging=\"draggedIndex === index\"\n :isLocked=\"isLocked\"\n :method=\"item.method\"\n :path=\"item.path\"\n @dragend=\"handleDragEnd\"\n @dragleave=\"handleDragLeave\"\n @dragover=\"handleDragOver(index, $event)\"\n @dragstart=\"handleDragStart(index, $event)\"\n @drop=\"handleDrop\"\n @remove=\"removeFromOrder(item)\" />\n </div>\n <div\n v-else\n class=\"py-4 text-center\">\n <p class=\"text-c-3 text-sm\">No items yet.</p>\n <p class=\"text-c-3 mt-0.5 text-xs\">\n Select operations from the list on the left.\n </p>\n </div>\n </template>\n </RunnerCard>\n\n <!-- Run button -->\n <div class=\"flex justify-end pt-1\">\n <ScalarButton\n v-if=\"!hasRunCompleted\"\n class=\"min-w-40\"\n :disabled=\"!hasSelection || isRunning\"\n :icon=\"ScalarIconPlay\"\n :loader=\"runLoader\"\n size=\"md\"\n variant=\"gradient\"\n @click=\"run\">\n Run sequence\n </ScalarButton>\n <ScalarButton\n v-else\n class=\"min-w-40\"\n :disabled=\"!hasSelection || isRunning\"\n :icon=\"ScalarIconArrowCounterClockwise\"\n :loader=\"runLoader\"\n size=\"md\"\n variant=\"gradient\"\n @click=\"rerun\">\n Re-run sequence\n </ScalarButton>\n </div>\n\n <!-- Running progress -->\n <RunnerCard\n v-if=\"\n isRunning && currentRunIndex != null && selectedOrder.length > 0\n \"\n compact>\n <p class=\"text-c-2 text-sm\">\n Running step\n <span class=\"text-c-1 font-medium\">\n {{ currentRunIndex }} / {{ selectedOrder.length }}\n </span>\n </p>\n <div\n :aria-valuemax=\"selectedOrder.length\"\n :aria-valuemin=\"0\"\n :aria-valuenow=\"currentRunIndex\"\n class=\"bg-b-3 mt-2 h-1.5 overflow-hidden rounded-full\"\n role=\"progressbar\">\n <div\n class=\"bg-accent-color h-full rounded-full transition-[width] duration-200 ease-out\"\n :style=\"{\n width: `${(currentRunIndex / selectedOrder.length) * 100}%`,\n }\" />\n </div>\n </RunnerCard>\n\n <!-- Results -->\n <RunnerResults\n v-if=\"runSummary && hasRunCompleted\"\n :getFailedTests=\"getFailedTests\"\n :getResultAtIndex=\"getResultAtIndex\"\n :isResultPassed=\"isResultPassed\"\n :isResultSkipped=\"isResultSkipped\"\n :selectedOrder=\"selectedOrder\"\n :summary=\"runSummary\"\n @clear=\"clearResults\" />\n </div>\n </div>\n </Section>\n</template>\n"],"mappings":""} |
@@ -8,3 +8,3 @@ import Section_default from "../../../../settings/components/Section.vue.js"; | ||
| import RunnerTree_default from "./RunnerTree.vue.js"; | ||
| import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, renderList, toDisplayString, unref, withCtx } from "vue"; | ||
| import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, renderList, toDisplayString, toValue, unref, withCtx } from "vue"; | ||
| import { ScalarButton } from "@scalar/components"; | ||
@@ -47,2 +47,3 @@ import { ScalarIconArrowCounterClockwise, ScalarIconPlay } from "@scalar/icons"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -57,3 +58,4 @@ }, | ||
| isWeb: __props.layout === "web", | ||
| selectedOrder: computed(() => selectedOrder.value) | ||
| selectedOrder: computed(() => selectedOrder.value), | ||
| customFetch: toValue(__props.options)?.customFetch | ||
| }); | ||
@@ -60,0 +62,0 @@ const isLocked = computed(() => isRunning.value || hasRunCompleted.value); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Runner.vue.script.js","names":[],"sources":["../../../../../../../src/v2/features/collection/components/Runner/components/Runner.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { ScalarIconArrowCounterClockwise, ScalarIconPlay } from '@scalar/icons'\nimport { computed } from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nimport { useRunnerExecution, useRunnerSelection } from '../hooks'\nimport RunnerCard from './RunnerCard.vue'\nimport RunnerOrderItem from './RunnerOrderItem.vue'\nimport RunnerResults from './RunnerResults.vue'\nimport RunnerTree from './RunnerTree.vue'\n\nconst { document, collectionType, workspaceStore, documentSlug, layout } =\n defineProps<CollectionProps>()\n\nconst {\n selectedOrder,\n hasSelection,\n isSelected,\n toggle,\n clearAll,\n removeFromOrder,\n dragState,\n handleDragStart,\n handleDragOver,\n handleDragLeave,\n handleDrop,\n handleDragEnd,\n} = useRunnerSelection({\n isLocked: () => isLocked.value,\n})\n\nconst {\n isRunning,\n hasRunCompleted,\n currentRunIndex,\n runLoader,\n runSummary,\n run,\n rerun,\n clearResults,\n getResultAtIndex,\n isResultPassed,\n isResultSkipped,\n getFailedTests,\n} = useRunnerExecution({\n workspaceStore,\n document,\n documentName: documentSlug,\n isWeb: layout === 'web',\n selectedOrder: computed(() => selectedOrder.value),\n})\n\nconst isLocked = computed(() => isRunning.value || hasRunCompleted.value)\n\nconst { draggedIndex, dragOverIndex, dragOffset } = dragState\n\nconst navigationChildren = computed(() => {\n return document?.['x-scalar-navigation']?.children ?? []\n})\n\nconst hasOperations = computed(() => navigationChildren.value.length > 0)\n</script>\n\n<template>\n <Section v-if=\"collectionType === 'document'\">\n <template #title>Runner</template>\n <template #description>\n Select operation examples, set the run order, then run them in sequence.\n Variables set by pre-request or post-response scripts are shared between\n runs.\n </template>\n\n <div class=\"flex flex-col gap-8 lg:flex-row lg:items-start\">\n <!-- Left: Document operations tree -->\n <RunnerCard\n class=\"min-w-0 flex-1\"\n subtitle=\"Check the examples you want to run. They will be added to the run order.\"\n title=\"Select operations\">\n <div\n v-if=\"hasOperations\"\n class=\"max-h-[28rem] overflow-y-auto\"\n :class=\"{ 'opacity-60': isLocked }\">\n <RunnerTree\n :disabled=\"isLocked\"\n :entries=\"navigationChildren\"\n :isSelected=\"isSelected\"\n :selectedOrder=\"selectedOrder\"\n @toggle=\"toggle\" />\n </div>\n <div\n v-else\n class=\"py-6 text-center\">\n <p class=\"text-c-3 text-sm\">No operations in this document.</p>\n <p class=\"text-c-3 mt-1 text-xs\">\n Add paths and methods to your API description to see them here.\n </p>\n </div>\n </RunnerCard>\n\n <!-- Right: Run order + actions + results -->\n <div class=\"flex w-full shrink-0 flex-col gap-4 lg:w-96\">\n <!-- Run order card -->\n <RunnerCard title=\"Run order\">\n <template #header>\n <ScalarButton\n class=\"transition-opacity duration-100\"\n :class=\"\n hasSelection && !isLocked\n ? 'opacity-100'\n : 'pointer-events-none opacity-0'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"clearAll\">\n <span class=\"hover:underline\">Clear all</span>\n </ScalarButton>\n </template>\n <template #subtitle>\n {{ selectedOrder.length }}\n {{ selectedOrder.length === 1 ? 'item' : 'items' }} selected.\n <template v-if=\"!isLocked\">Drag to reorder.</template>\n <template v-else-if=\"hasRunCompleted\">\n Clear results to modify.\n </template>\n </template>\n <template #default>\n <div\n v-if=\"selectedOrder.length > 0\"\n class=\"flex flex-col gap-0.5\"\n :class=\"{ 'opacity-60': isLocked }\">\n <RunnerOrderItem\n v-for=\"(item, index) in selectedOrder\"\n :key=\"item.id\"\n :draggable=\"!isLocked\"\n :exampleKey=\"item.exampleKey\"\n :index=\"index\"\n :isDragAfter=\"dragOverIndex === index && dragOffset === 'after'\"\n :isDragBefore=\"\n dragOverIndex === index && dragOffset === 'before'\n \"\n :isDragging=\"draggedIndex === index\"\n :isLocked=\"isLocked\"\n :method=\"item.method\"\n :path=\"item.path\"\n @dragend=\"handleDragEnd\"\n @dragleave=\"handleDragLeave\"\n @dragover=\"handleDragOver(index, $event)\"\n @dragstart=\"handleDragStart(index, $event)\"\n @drop=\"handleDrop\"\n @remove=\"removeFromOrder(item)\" />\n </div>\n <div\n v-else\n class=\"py-4 text-center\">\n <p class=\"text-c-3 text-sm\">No items yet.</p>\n <p class=\"text-c-3 mt-0.5 text-xs\">\n Select operations from the list on the left.\n </p>\n </div>\n </template>\n </RunnerCard>\n\n <!-- Run button -->\n <div class=\"flex justify-end pt-1\">\n <ScalarButton\n v-if=\"!hasRunCompleted\"\n class=\"min-w-40\"\n :disabled=\"!hasSelection || isRunning\"\n :icon=\"ScalarIconPlay\"\n :loader=\"runLoader\"\n size=\"md\"\n variant=\"gradient\"\n @click=\"run\">\n Run sequence\n </ScalarButton>\n <ScalarButton\n v-else\n class=\"min-w-40\"\n :disabled=\"!hasSelection || isRunning\"\n :icon=\"ScalarIconArrowCounterClockwise\"\n :loader=\"runLoader\"\n size=\"md\"\n variant=\"gradient\"\n @click=\"rerun\">\n Re-run sequence\n </ScalarButton>\n </div>\n\n <!-- Running progress -->\n <RunnerCard\n v-if=\"\n isRunning && currentRunIndex != null && selectedOrder.length > 0\n \"\n compact>\n <p class=\"text-c-2 text-sm\">\n Running step\n <span class=\"text-c-1 font-medium\">\n {{ currentRunIndex }} / {{ selectedOrder.length }}\n </span>\n </p>\n <div\n :aria-valuemax=\"selectedOrder.length\"\n :aria-valuemin=\"0\"\n :aria-valuenow=\"currentRunIndex\"\n class=\"bg-b-3 mt-2 h-1.5 overflow-hidden rounded-full\"\n role=\"progressbar\">\n <div\n class=\"bg-accent-color h-full rounded-full transition-[width] duration-200 ease-out\"\n :style=\"{\n width: `${(currentRunIndex / selectedOrder.length) * 100}%`,\n }\" />\n </div>\n </RunnerCard>\n\n <!-- Results -->\n <RunnerResults\n v-if=\"runSummary && hasRunCompleted\"\n :getFailedTests=\"getFailedTests\"\n :getResultAtIndex=\"getResultAtIndex\"\n :isResultPassed=\"isResultPassed\"\n :isResultSkipped=\"isResultSkipped\"\n :selectedOrder=\"selectedOrder\"\n :summary=\"runSummary\"\n @clear=\"clearResults\" />\n </div>\n </div>\n </Section>\n</template>\n"],"mappings":"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"} | ||
| {"version":3,"file":"Runner.vue.script.js","names":[],"sources":["../../../../../../../src/v2/features/collection/components/Runner/components/Runner.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { ScalarIconArrowCounterClockwise, ScalarIconPlay } from '@scalar/icons'\nimport { computed, toValue } from 'vue'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nimport { useRunnerExecution, useRunnerSelection } from '../hooks'\nimport RunnerCard from './RunnerCard.vue'\nimport RunnerOrderItem from './RunnerOrderItem.vue'\nimport RunnerResults from './RunnerResults.vue'\nimport RunnerTree from './RunnerTree.vue'\n\nconst {\n document,\n collectionType,\n workspaceStore,\n documentSlug,\n layout,\n options,\n} = defineProps<CollectionProps>()\n\nconst {\n selectedOrder,\n hasSelection,\n isSelected,\n toggle,\n clearAll,\n removeFromOrder,\n dragState,\n handleDragStart,\n handleDragOver,\n handleDragLeave,\n handleDrop,\n handleDragEnd,\n} = useRunnerSelection({\n isLocked: () => isLocked.value,\n})\n\nconst {\n isRunning,\n hasRunCompleted,\n currentRunIndex,\n runLoader,\n runSummary,\n run,\n rerun,\n clearResults,\n getResultAtIndex,\n isResultPassed,\n isResultSkipped,\n getFailedTests,\n} = useRunnerExecution({\n workspaceStore,\n document,\n documentName: documentSlug,\n isWeb: layout === 'web',\n selectedOrder: computed(() => selectedOrder.value),\n customFetch: toValue(options)?.customFetch,\n})\n\nconst isLocked = computed(() => isRunning.value || hasRunCompleted.value)\n\nconst { draggedIndex, dragOverIndex, dragOffset } = dragState\n\nconst navigationChildren = computed(() => {\n return document?.['x-scalar-navigation']?.children ?? []\n})\n\nconst hasOperations = computed(() => navigationChildren.value.length > 0)\n</script>\n\n<template>\n <Section v-if=\"collectionType === 'document'\">\n <template #title>Runner</template>\n <template #description>\n Select operation examples, set the run order, then run them in sequence.\n Variables set by pre-request or post-response scripts are shared between\n runs.\n </template>\n\n <div class=\"flex flex-col gap-8 lg:flex-row lg:items-start\">\n <!-- Left: Document operations tree -->\n <RunnerCard\n class=\"min-w-0 flex-1\"\n subtitle=\"Check the examples you want to run. They will be added to the run order.\"\n title=\"Select operations\">\n <div\n v-if=\"hasOperations\"\n class=\"max-h-[28rem] overflow-y-auto\"\n :class=\"{ 'opacity-60': isLocked }\">\n <RunnerTree\n :disabled=\"isLocked\"\n :entries=\"navigationChildren\"\n :isSelected=\"isSelected\"\n :selectedOrder=\"selectedOrder\"\n @toggle=\"toggle\" />\n </div>\n <div\n v-else\n class=\"py-6 text-center\">\n <p class=\"text-c-3 text-sm\">No operations in this document.</p>\n <p class=\"text-c-3 mt-1 text-xs\">\n Add paths and methods to your API description to see them here.\n </p>\n </div>\n </RunnerCard>\n\n <!-- Right: Run order + actions + results -->\n <div class=\"flex w-full shrink-0 flex-col gap-4 lg:w-96\">\n <!-- Run order card -->\n <RunnerCard title=\"Run order\">\n <template #header>\n <ScalarButton\n class=\"transition-opacity duration-100\"\n :class=\"\n hasSelection && !isLocked\n ? 'opacity-100'\n : 'pointer-events-none opacity-0'\n \"\n size=\"xs\"\n variant=\"ghost\"\n @click=\"clearAll\">\n <span class=\"hover:underline\">Clear all</span>\n </ScalarButton>\n </template>\n <template #subtitle>\n {{ selectedOrder.length }}\n {{ selectedOrder.length === 1 ? 'item' : 'items' }} selected.\n <template v-if=\"!isLocked\">Drag to reorder.</template>\n <template v-else-if=\"hasRunCompleted\">\n Clear results to modify.\n </template>\n </template>\n <template #default>\n <div\n v-if=\"selectedOrder.length > 0\"\n class=\"flex flex-col gap-0.5\"\n :class=\"{ 'opacity-60': isLocked }\">\n <RunnerOrderItem\n v-for=\"(item, index) in selectedOrder\"\n :key=\"item.id\"\n :draggable=\"!isLocked\"\n :exampleKey=\"item.exampleKey\"\n :index=\"index\"\n :isDragAfter=\"dragOverIndex === index && dragOffset === 'after'\"\n :isDragBefore=\"\n dragOverIndex === index && dragOffset === 'before'\n \"\n :isDragging=\"draggedIndex === index\"\n :isLocked=\"isLocked\"\n :method=\"item.method\"\n :path=\"item.path\"\n @dragend=\"handleDragEnd\"\n @dragleave=\"handleDragLeave\"\n @dragover=\"handleDragOver(index, $event)\"\n @dragstart=\"handleDragStart(index, $event)\"\n @drop=\"handleDrop\"\n @remove=\"removeFromOrder(item)\" />\n </div>\n <div\n v-else\n class=\"py-4 text-center\">\n <p class=\"text-c-3 text-sm\">No items yet.</p>\n <p class=\"text-c-3 mt-0.5 text-xs\">\n Select operations from the list on the left.\n </p>\n </div>\n </template>\n </RunnerCard>\n\n <!-- Run button -->\n <div class=\"flex justify-end pt-1\">\n <ScalarButton\n v-if=\"!hasRunCompleted\"\n class=\"min-w-40\"\n :disabled=\"!hasSelection || isRunning\"\n :icon=\"ScalarIconPlay\"\n :loader=\"runLoader\"\n size=\"md\"\n variant=\"gradient\"\n @click=\"run\">\n Run sequence\n </ScalarButton>\n <ScalarButton\n v-else\n class=\"min-w-40\"\n :disabled=\"!hasSelection || isRunning\"\n :icon=\"ScalarIconArrowCounterClockwise\"\n :loader=\"runLoader\"\n size=\"md\"\n variant=\"gradient\"\n @click=\"rerun\">\n Re-run sequence\n </ScalarButton>\n </div>\n\n <!-- Running progress -->\n <RunnerCard\n v-if=\"\n isRunning && currentRunIndex != null && selectedOrder.length > 0\n \"\n compact>\n <p class=\"text-c-2 text-sm\">\n Running step\n <span class=\"text-c-1 font-medium\">\n {{ currentRunIndex }} / {{ selectedOrder.length }}\n </span>\n </p>\n <div\n :aria-valuemax=\"selectedOrder.length\"\n :aria-valuemin=\"0\"\n :aria-valuenow=\"currentRunIndex\"\n class=\"bg-b-3 mt-2 h-1.5 overflow-hidden rounded-full\"\n role=\"progressbar\">\n <div\n class=\"bg-accent-color h-full rounded-full transition-[width] duration-200 ease-out\"\n :style=\"{\n width: `${(currentRunIndex / selectedOrder.length) * 100}%`,\n }\" />\n </div>\n </RunnerCard>\n\n <!-- Results -->\n <RunnerResults\n v-if=\"runSummary && hasRunCompleted\"\n :getFailedTests=\"getFailedTests\"\n :getResultAtIndex=\"getResultAtIndex\"\n :isResultPassed=\"isResultPassed\"\n :isResultSkipped=\"isResultSkipped\"\n :selectedOrder=\"selectedOrder\"\n :summary=\"runSummary\"\n @clear=\"clearResults\" />\n </div>\n </div>\n </Section>\n</template>\n"],"mappings":"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"} |
@@ -12,5 +12,5 @@ import type { HttpMethod } from '@scalar/helpers/http/http-methods'; | ||
| declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { | ||
| toggle: (path: string, method: "delete" | "head" | "get" | "options" | "put" | "post" | "patch" | "trace", exampleKey: string, label: string) => any; | ||
| toggle: (path: string, method: "head" | "delete" | "get" | "options" | "patch" | "post" | "put" | "trace", exampleKey: string, label: string) => any; | ||
| }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{ | ||
| onToggle?: ((path: string, method: "delete" | "head" | "get" | "options" | "put" | "post" | "patch" | "trace", exampleKey: string, label: string) => any) | undefined; | ||
| onToggle?: ((path: string, method: "head" | "delete" | "get" | "options" | "patch" | "post" | "put" | "trace", exampleKey: string, label: string) => any) | undefined; | ||
| }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; | ||
@@ -17,0 +17,0 @@ declare const _default: typeof __VLS_export; |
@@ -5,3 +5,3 @@ import { useLoadingState } from '@scalar/components'; | ||
| import { type ComputedRef, type Ref } from 'vue'; | ||
| import { type ResponseInstance } from '../../../../../../v2/blocks/operation-block/helpers/send-request.js'; | ||
| import { type CustomFetch, type ResponseInstance } from '../../../../../../v2/blocks/operation-block/helpers/send-request.js'; | ||
| import type { SelectedItem } from './use-runner-selection.js'; | ||
@@ -40,2 +40,4 @@ export type TestResult = { | ||
| selectedOrder: ComputedRef<SelectedItem[]>; | ||
| /** Optional custom fetch implementation, overrides the global fetch for request execution */ | ||
| customFetch?: CustomFetch; | ||
| }; | ||
@@ -73,4 +75,4 @@ type UseRunnerExecutionReturn = { | ||
| */ | ||
| export declare function useRunnerExecution({ workspaceStore, document, documentName, isWeb, selectedOrder, }: UseRunnerExecutionOptions): UseRunnerExecutionReturn; | ||
| export declare function useRunnerExecution({ workspaceStore, document, documentName, isWeb, selectedOrder, customFetch, }: UseRunnerExecutionOptions): UseRunnerExecutionReturn; | ||
| export {}; | ||
| //# sourceMappingURL=use-runner-execution.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"use-runner-execution.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/features/collection/components/Runner/hooks/use-runner-execution.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"use-runner-execution.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/features/collection/components/Runner/hooks/use-runner-execution.ts"],"names":[],"mappings":"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"} |
@@ -13,3 +13,3 @@ import { sendRequest } from "../../../../../blocks/operation-block/helpers/send-request.js"; | ||
| */ | ||
| function useRunnerExecution({ workspaceStore, document, documentName, isWeb, selectedOrder }) { | ||
| function useRunnerExecution({ workspaceStore, document, documentName, isWeb, selectedOrder, customFetch }) { | ||
| const isRunning = ref(false); | ||
@@ -140,3 +140,4 @@ const hasRunCompleted = ref(false); | ||
| isUsingProxy: requestResult.data.isUsingProxy, | ||
| requestPayload: requestResult.data.requestPayload | ||
| requestPayload: requestResult.data.requestPayload, | ||
| customFetch | ||
| }); | ||
@@ -143,0 +144,0 @@ if (sendError) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"use-runner-execution.js","names":[],"sources":["../../../../../../../src/v2/features/collection/components/Runner/hooks/use-runner-execution.ts"],"sourcesContent":["import { useLoadingState } from '@scalar/components'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { executePostResponseScript, executePreRequestScript, getScript } from '@scalar/pre-post-request-scripts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport {\n type BuildRequestExampleContext,\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n getRequestExampleContext,\n requestFactory,\n} from '@scalar/workspace-store/request-example'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { type ComputedRef, type Ref, computed, ref } from 'vue'\n\nimport { type ResponseInstance, sendRequest } from '@/v2/blocks/operation-block/helpers/send-request'\nimport { APP_VERSION } from '@/v2/constants'\nimport { tryCatch } from '@/v2/helpers/safe-run'\n\nimport type { SelectedItem } from './use-runner-selection'\n\nexport type TestResult = {\n title: string\n passed: boolean\n duration: number\n error?: string\n status: 'pending' | 'passed' | 'failed'\n}\n\nexport type RunResult = {\n item: SelectedItem\n result: ResponseInstance | null\n error: Error | null\n testResults: TestResult[]\n}\n\nexport type RunSummary = {\n total: number\n passed: number\n failed: number\n skipped: number\n duration: number | null\n allPassed: boolean\n}\n\ntype UseRunnerExecutionOptions = {\n /** Workspace store */\n workspaceStore: WorkspaceStore\n /** Document */\n document: OpenApiDocument | null\n /** Document name */\n documentName: string\n /** Whether the layout is web */\n isWeb: boolean\n /** Ordered list of selected items to run */\n selectedOrder: ComputedRef<SelectedItem[]>\n}\n\ntype UseRunnerExecutionReturn = {\n /** Whether a run is currently in progress */\n isRunning: Ref<boolean>\n /** Whether a run has completed */\n hasRunCompleted: Ref<boolean>\n /** Current index being run (1-based) */\n currentRunIndex: Ref<number | null>\n /** Loading state for the run button */\n runLoader: ReturnType<typeof useLoadingState>\n /** Results from the run */\n runResults: Ref<RunResult[]>\n /** Summary of the run results */\n runSummary: ComputedRef<RunSummary | null>\n /** Start running the selected items */\n run: () => Promise<void>\n /** Clear results and run again */\n rerun: () => void\n /** Clear all results */\n clearResults: () => void\n /** Get the result at a specific index */\n getResultAtIndex: (index: number) => RunResult | null\n /** Check if a result passed */\n isResultPassed: (result: RunResult | null) => boolean\n /** Check if a result was skipped */\n isResultSkipped: (index: number) => boolean\n /** Get failed tests from a result */\n getFailedTests: (result: RunResult | null) => TestResult[]\n}\n\n/**\n * Composable for managing runner execution state and logic.\n */\nexport function useRunnerExecution({\n workspaceStore,\n document,\n documentName,\n isWeb,\n selectedOrder,\n}: UseRunnerExecutionOptions): UseRunnerExecutionReturn {\n const isRunning = ref(false)\n const hasRunCompleted = ref(false)\n const currentRunIndex = ref<number | null>(null)\n const runLoader = useLoadingState()\n const runResults = ref<RunResult[]>([])\n const runStartTime = ref<number | null>(null)\n const runEndTime = ref<number | null>(null)\n\n const runSummary = computed<RunSummary | null>(() => {\n if (runResults.value.length === 0 && !hasRunCompleted.value) {\n return null\n }\n const ran = runResults.value.length\n const total = selectedOrder.value.length\n const passed = runResults.value.filter((r) => !r.error && r.testResults.every((t) => t.passed)).length\n const failed = ran - passed\n const skipped = total - ran\n const duration = runStartTime.value && runEndTime.value ? runEndTime.value - runStartTime.value : null\n const allPassed = failed === 0 && skipped === 0\n return { total, passed, failed, skipped, duration, allPassed }\n })\n\n const clearResults = () => {\n runResults.value = []\n hasRunCompleted.value = false\n runStartTime.value = null\n runEndTime.value = null\n }\n\n const rerun = () => {\n clearResults()\n void run()\n }\n\n const getResultAtIndex = (index: number): RunResult | null => {\n return runResults.value[index] ?? null\n }\n\n const isResultPassed = (result: RunResult | null): boolean => {\n if (!result) {\n return false\n }\n if (result.error) {\n return false\n }\n if (result.testResults.some((t) => !t.passed)) {\n return false\n }\n return true\n }\n\n const isResultSkipped = (index: number): boolean => {\n return hasRunCompleted.value && getResultAtIndex(index) === null\n }\n\n const getFailedTests = (result: RunResult | null): TestResult[] => {\n if (!result) {\n return []\n }\n return result.testResults.filter((t) => !t.passed)\n }\n\n const getContext = (item: SelectedItem) => {\n const contextResult = getRequestExampleContext(\n workspaceStore,\n documentName,\n { path: item.path, method: item.method, exampleName: item.exampleKey },\n {\n fallbackDocument: document,\n isElectron: isElectron(),\n layout: isWeb ? 'web' : 'other',\n appVersion: APP_VERSION,\n },\n )\n\n return contextResult\n }\n\n const getRequestFactory = (ctx: BuildRequestExampleContext, item: SelectedItem) => {\n const globalCookies = [...ctx.cookies.workspace, ...ctx.cookies.document]\n return requestFactory({\n defaultHeaders: ctx.headers.default,\n environment: ctx.environment.environment,\n exampleName: item.exampleKey,\n globalCookies,\n method: item.method,\n operation: ctx.operation,\n path: item.path,\n proxyUrl: ctx.proxy.url ?? '',\n server: ctx.servers.selected,\n selectedSecuritySchemes: ctx.security.selectedSchemes,\n isElectron: isElectron(),\n })\n }\n\n const run = async () => {\n if (isRunning.value || !document || selectedOrder.value.length === 0) {\n return\n }\n\n isRunning.value = true\n hasRunCompleted.value = false\n runLoader.start()\n runResults.value = []\n currentRunIndex.value = 0\n runStartTime.value = performance.now()\n runEndTime.value = null\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Run each item in the selected order\n for (let i = 0; i < selectedOrder.value.length; i++) {\n currentRunIndex.value = i + 1\n const item = selectedOrder.value[i]!\n\n // Create a run result for the current item\n const runResult: RunResult = {\n item,\n result: null,\n error: null,\n testResults: [],\n }\n\n try {\n const contextResult = getContext(item)\n\n if (!contextResult.ok) {\n runResult.error = new Error(contextResult.error)\n runResults.value = [...runResults.value, runResult]\n continue\n }\n\n const { request: requestBuilder } = getRequestFactory(contextResult.data, item)\n\n const preRequestScript = getScript(document['x-pre-request'], contextResult.data.operation['x-pre-request'])\n await executePreRequestScript(preRequestScript, {\n requestBuilder,\n variablesStore,\n onTestResultsUpdate: (newResults) => {\n runResult.testResults = [...newResults]\n },\n })\n\n const envVariables = {\n ...getEnvironmentVariables(contextResult.data.environment.environment),\n ...variablesStore.getVariables(),\n }\n\n const requestResult = await tryCatch(() => {\n return buildRequest(requestBuilder, { envVariables })\n })\n\n if (!requestResult.ok) {\n runResult.error = new Error(requestResult.error)\n runResults.value = [...runResults.value, runResult]\n continue\n }\n\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: requestResult.data.isUsingProxy,\n requestPayload: requestResult.data.requestPayload,\n })\n\n if (sendError) {\n runResult.error = sendError\n runResults.value = [...runResults.value, runResult]\n continue\n }\n\n runResult.result = sendResult.response\n\n const postResponseScript = getScript(\n document['x-post-response'],\n contextResult.data.operation['x-post-response'],\n )\n\n const preRequestResults = [...runResult.testResults]\n await executePostResponseScript(postResponseScript, {\n requestBuilder,\n response: sendResult.originalResponse.clone(),\n variablesStore,\n onTestResultsUpdate: (postResponseResults) => {\n runResult.testResults = [...preRequestResults, ...postResponseResults]\n },\n })\n\n runResults.value = [...runResults.value, runResult]\n\n const hasTestFailure = runResult.testResults.some((t) => !t.passed)\n if (hasTestFailure) {\n break\n }\n } catch (error) {\n runResult.error = error instanceof Error ? error : new Error(String(error))\n runResults.value = [...runResults.value, runResult]\n break\n }\n }\n\n isRunning.value = false\n hasRunCompleted.value = true\n runEndTime.value = performance.now()\n void runLoader.clear()\n currentRunIndex.value = null\n }\n\n return {\n isRunning,\n hasRunCompleted,\n currentRunIndex,\n runLoader,\n runResults,\n runSummary,\n run,\n rerun,\n clearResults,\n getResultAtIndex,\n isResultPassed,\n isResultSkipped,\n getFailedTests,\n }\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"use-runner-execution.js","names":[],"sources":["../../../../../../../src/v2/features/collection/components/Runner/hooks/use-runner-execution.ts"],"sourcesContent":["import { useLoadingState } from '@scalar/components'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { executePostResponseScript, executePreRequestScript, getScript } from '@scalar/pre-post-request-scripts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport {\n type BuildRequestExampleContext,\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n getRequestExampleContext,\n requestFactory,\n} from '@scalar/workspace-store/request-example'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { type ComputedRef, type Ref, computed, ref } from 'vue'\n\nimport { type CustomFetch, type ResponseInstance, sendRequest } from '@/v2/blocks/operation-block/helpers/send-request'\nimport { APP_VERSION } from '@/v2/constants'\nimport { tryCatch } from '@/v2/helpers/safe-run'\n\nimport type { SelectedItem } from './use-runner-selection'\n\nexport type TestResult = {\n title: string\n passed: boolean\n duration: number\n error?: string\n status: 'pending' | 'passed' | 'failed'\n}\n\nexport type RunResult = {\n item: SelectedItem\n result: ResponseInstance | null\n error: Error | null\n testResults: TestResult[]\n}\n\nexport type RunSummary = {\n total: number\n passed: number\n failed: number\n skipped: number\n duration: number | null\n allPassed: boolean\n}\n\ntype UseRunnerExecutionOptions = {\n /** Workspace store */\n workspaceStore: WorkspaceStore\n /** Document */\n document: OpenApiDocument | null\n /** Document name */\n documentName: string\n /** Whether the layout is web */\n isWeb: boolean\n /** Ordered list of selected items to run */\n selectedOrder: ComputedRef<SelectedItem[]>\n /** Optional custom fetch implementation, overrides the global fetch for request execution */\n customFetch?: CustomFetch\n}\n\ntype UseRunnerExecutionReturn = {\n /** Whether a run is currently in progress */\n isRunning: Ref<boolean>\n /** Whether a run has completed */\n hasRunCompleted: Ref<boolean>\n /** Current index being run (1-based) */\n currentRunIndex: Ref<number | null>\n /** Loading state for the run button */\n runLoader: ReturnType<typeof useLoadingState>\n /** Results from the run */\n runResults: Ref<RunResult[]>\n /** Summary of the run results */\n runSummary: ComputedRef<RunSummary | null>\n /** Start running the selected items */\n run: () => Promise<void>\n /** Clear results and run again */\n rerun: () => void\n /** Clear all results */\n clearResults: () => void\n /** Get the result at a specific index */\n getResultAtIndex: (index: number) => RunResult | null\n /** Check if a result passed */\n isResultPassed: (result: RunResult | null) => boolean\n /** Check if a result was skipped */\n isResultSkipped: (index: number) => boolean\n /** Get failed tests from a result */\n getFailedTests: (result: RunResult | null) => TestResult[]\n}\n\n/**\n * Composable for managing runner execution state and logic.\n */\nexport function useRunnerExecution({\n workspaceStore,\n document,\n documentName,\n isWeb,\n selectedOrder,\n customFetch,\n}: UseRunnerExecutionOptions): UseRunnerExecutionReturn {\n const isRunning = ref(false)\n const hasRunCompleted = ref(false)\n const currentRunIndex = ref<number | null>(null)\n const runLoader = useLoadingState()\n const runResults = ref<RunResult[]>([])\n const runStartTime = ref<number | null>(null)\n const runEndTime = ref<number | null>(null)\n\n const runSummary = computed<RunSummary | null>(() => {\n if (runResults.value.length === 0 && !hasRunCompleted.value) {\n return null\n }\n const ran = runResults.value.length\n const total = selectedOrder.value.length\n const passed = runResults.value.filter((r) => !r.error && r.testResults.every((t) => t.passed)).length\n const failed = ran - passed\n const skipped = total - ran\n const duration = runStartTime.value && runEndTime.value ? runEndTime.value - runStartTime.value : null\n const allPassed = failed === 0 && skipped === 0\n return { total, passed, failed, skipped, duration, allPassed }\n })\n\n const clearResults = () => {\n runResults.value = []\n hasRunCompleted.value = false\n runStartTime.value = null\n runEndTime.value = null\n }\n\n const rerun = () => {\n clearResults()\n void run()\n }\n\n const getResultAtIndex = (index: number): RunResult | null => {\n return runResults.value[index] ?? null\n }\n\n const isResultPassed = (result: RunResult | null): boolean => {\n if (!result) {\n return false\n }\n if (result.error) {\n return false\n }\n if (result.testResults.some((t) => !t.passed)) {\n return false\n }\n return true\n }\n\n const isResultSkipped = (index: number): boolean => {\n return hasRunCompleted.value && getResultAtIndex(index) === null\n }\n\n const getFailedTests = (result: RunResult | null): TestResult[] => {\n if (!result) {\n return []\n }\n return result.testResults.filter((t) => !t.passed)\n }\n\n const getContext = (item: SelectedItem) => {\n const contextResult = getRequestExampleContext(\n workspaceStore,\n documentName,\n { path: item.path, method: item.method, exampleName: item.exampleKey },\n {\n fallbackDocument: document,\n isElectron: isElectron(),\n layout: isWeb ? 'web' : 'other',\n appVersion: APP_VERSION,\n },\n )\n\n return contextResult\n }\n\n const getRequestFactory = (ctx: BuildRequestExampleContext, item: SelectedItem) => {\n const globalCookies = [...ctx.cookies.workspace, ...ctx.cookies.document]\n return requestFactory({\n defaultHeaders: ctx.headers.default,\n environment: ctx.environment.environment,\n exampleName: item.exampleKey,\n globalCookies,\n method: item.method,\n operation: ctx.operation,\n path: item.path,\n proxyUrl: ctx.proxy.url ?? '',\n server: ctx.servers.selected,\n selectedSecuritySchemes: ctx.security.selectedSchemes,\n isElectron: isElectron(),\n })\n }\n\n const run = async () => {\n if (isRunning.value || !document || selectedOrder.value.length === 0) {\n return\n }\n\n isRunning.value = true\n hasRunCompleted.value = false\n runLoader.start()\n runResults.value = []\n currentRunIndex.value = 0\n runStartTime.value = performance.now()\n runEndTime.value = null\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Run each item in the selected order\n for (let i = 0; i < selectedOrder.value.length; i++) {\n currentRunIndex.value = i + 1\n const item = selectedOrder.value[i]!\n\n // Create a run result for the current item\n const runResult: RunResult = {\n item,\n result: null,\n error: null,\n testResults: [],\n }\n\n try {\n const contextResult = getContext(item)\n\n if (!contextResult.ok) {\n runResult.error = new Error(contextResult.error)\n runResults.value = [...runResults.value, runResult]\n continue\n }\n\n const { request: requestBuilder } = getRequestFactory(contextResult.data, item)\n\n const preRequestScript = getScript(document['x-pre-request'], contextResult.data.operation['x-pre-request'])\n await executePreRequestScript(preRequestScript, {\n requestBuilder,\n variablesStore,\n onTestResultsUpdate: (newResults) => {\n runResult.testResults = [...newResults]\n },\n })\n\n const envVariables = {\n ...getEnvironmentVariables(contextResult.data.environment.environment),\n ...variablesStore.getVariables(),\n }\n\n const requestResult = await tryCatch(() => {\n return buildRequest(requestBuilder, { envVariables })\n })\n\n if (!requestResult.ok) {\n runResult.error = new Error(requestResult.error)\n runResults.value = [...runResults.value, runResult]\n continue\n }\n\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: requestResult.data.isUsingProxy,\n requestPayload: requestResult.data.requestPayload,\n customFetch,\n })\n\n if (sendError) {\n runResult.error = sendError\n runResults.value = [...runResults.value, runResult]\n continue\n }\n\n runResult.result = sendResult.response\n\n const postResponseScript = getScript(\n document['x-post-response'],\n contextResult.data.operation['x-post-response'],\n )\n\n const preRequestResults = [...runResult.testResults]\n await executePostResponseScript(postResponseScript, {\n requestBuilder,\n response: sendResult.originalResponse.clone(),\n variablesStore,\n onTestResultsUpdate: (postResponseResults) => {\n runResult.testResults = [...preRequestResults, ...postResponseResults]\n },\n })\n\n runResults.value = [...runResults.value, runResult]\n\n const hasTestFailure = runResult.testResults.some((t) => !t.passed)\n if (hasTestFailure) {\n break\n }\n } catch (error) {\n runResult.error = error instanceof Error ? error : new Error(String(error))\n runResults.value = [...runResults.value, runResult]\n break\n }\n }\n\n isRunning.value = false\n hasRunCompleted.value = true\n runEndTime.value = performance.now()\n void runLoader.clear()\n currentRunIndex.value = null\n }\n\n return {\n isRunning,\n hasRunCompleted,\n currentRunIndex,\n runLoader,\n runResults,\n runSummary,\n run,\n rerun,\n clearResults,\n getResultAtIndex,\n isResultPassed,\n isResultSkipped,\n getFailedTests,\n }\n}\n"],"mappings":";;;;;;;;;;;;AA4FA,SAAgB,mBAAmB,EACjC,gBACA,UACA,cACA,OACA,eACA,eACsD;CACtD,MAAM,YAAY,IAAI,MAAM;CAC5B,MAAM,kBAAkB,IAAI,MAAM;CAClC,MAAM,kBAAkB,IAAmB,KAAK;CAChD,MAAM,YAAY,iBAAiB;CACnC,MAAM,aAAa,IAAiB,EAAE,CAAC;CACvC,MAAM,eAAe,IAAmB,KAAK;CAC7C,MAAM,aAAa,IAAmB,KAAK;CAE3C,MAAM,aAAa,eAAkC;AACnD,MAAI,WAAW,MAAM,WAAW,KAAK,CAAC,gBAAgB,MACpD,QAAO;EAET,MAAM,MAAM,WAAW,MAAM;EAC7B,MAAM,QAAQ,cAAc,MAAM;EAClC,MAAM,SAAS,WAAW,MAAM,QAAQ,MAAM,CAAC,EAAE,SAAS,EAAE,YAAY,OAAO,MAAM,EAAE,OAAO,CAAC,CAAC;EAChG,MAAM,SAAS,MAAM;EACrB,MAAM,UAAU,QAAQ;AAGxB,SAAO;GAAE;GAAO;GAAQ;GAAQ;GAAS,UAFxB,aAAa,SAAS,WAAW,QAAQ,WAAW,QAAQ,aAAa,QAAQ;GAE/C,WADjC,WAAW,KAAK,YAAY;GACgB;GAC9D;CAEF,MAAM,qBAAqB;AACzB,aAAW,QAAQ,EAAE;AACrB,kBAAgB,QAAQ;AACxB,eAAa,QAAQ;AACrB,aAAW,QAAQ;;CAGrB,MAAM,cAAc;AAClB,gBAAc;AACT,OAAK;;CAGZ,MAAM,oBAAoB,UAAoC;AAC5D,SAAO,WAAW,MAAM,UAAU;;CAGpC,MAAM,kBAAkB,WAAsC;AAC5D,MAAI,CAAC,OACH,QAAO;AAET,MAAI,OAAO,MACT,QAAO;AAET,MAAI,OAAO,YAAY,MAAM,MAAM,CAAC,EAAE,OAAO,CAC3C,QAAO;AAET,SAAO;;CAGT,MAAM,mBAAmB,UAA2B;AAClD,SAAO,gBAAgB,SAAS,iBAAiB,MAAM,KAAK;;CAG9D,MAAM,kBAAkB,WAA2C;AACjE,MAAI,CAAC,OACH,QAAO,EAAE;AAEX,SAAO,OAAO,YAAY,QAAQ,MAAM,CAAC,EAAE,OAAO;;CAGpD,MAAM,cAAc,SAAuB;AAazC,SAZsB,yBACpB,gBACA,cACA;GAAE,MAAM,KAAK;GAAM,QAAQ,KAAK;GAAQ,aAAa,KAAK;GAAY,EACtE;GACE,kBAAkB;GAClB,YAAY,YAAY;GACxB,QAAQ,QAAQ,QAAQ;GACxB,YAAY;GACb,CACF;;CAKH,MAAM,qBAAqB,KAAiC,SAAuB;EACjF,MAAM,gBAAgB,CAAC,GAAG,IAAI,QAAQ,WAAW,GAAG,IAAI,QAAQ,SAAS;AACzE,SAAO,eAAe;GACpB,gBAAgB,IAAI,QAAQ;GAC5B,aAAa,IAAI,YAAY;GAC7B,aAAa,KAAK;GAClB;GACA,QAAQ,KAAK;GACb,WAAW,IAAI;GACf,MAAM,KAAK;GACX,UAAU,IAAI,MAAM,OAAO;GAC3B,QAAQ,IAAI,QAAQ;GACpB,yBAAyB,IAAI,SAAS;GACtC,YAAY,YAAY;GACzB,CAAC;;CAGJ,MAAM,MAAM,YAAY;AACtB,MAAI,UAAU,SAAS,CAAC,YAAY,cAAc,MAAM,WAAW,EACjE;AAGF,YAAU,QAAQ;AAClB,kBAAgB,QAAQ;AACxB,YAAU,OAAO;AACjB,aAAW,QAAQ,EAAE;AACrB,kBAAgB,QAAQ;AACxB,eAAa,QAAQ,YAAY,KAAK;AACtC,aAAW,QAAQ;EAEnB,MAAM,iBAAiB,gCAAgC;AAGvD,OAAK,IAAI,IAAI,GAAG,IAAI,cAAc,MAAM,QAAQ,KAAK;AACnD,mBAAgB,QAAQ,IAAI;GAC5B,MAAM,OAAO,cAAc,MAAM;GAGjC,MAAM,YAAuB;IAC3B;IACA,QAAQ;IACR,OAAO;IACP,aAAa,EAAE;IAChB;AAED,OAAI;IACF,MAAM,gBAAgB,WAAW,KAAK;AAEtC,QAAI,CAAC,cAAc,IAAI;AACrB,eAAU,QAAQ,IAAI,MAAM,cAAc,MAAM;AAChD,gBAAW,QAAQ,CAAC,GAAG,WAAW,OAAO,UAAU;AACnD;;IAGF,MAAM,EAAE,SAAS,mBAAmB,kBAAkB,cAAc,MAAM,KAAK;AAG/E,UAAM,wBADmB,UAAU,SAAS,kBAAkB,cAAc,KAAK,UAAU,iBAAiB,EAC5D;KAC9C;KACA;KACA,sBAAsB,eAAe;AACnC,gBAAU,cAAc,CAAC,GAAG,WAAW;;KAE1C,CAAC;IAEF,MAAM,eAAe;KACnB,GAAG,wBAAwB,cAAc,KAAK,YAAY,YAAY;KACtE,GAAG,eAAe,cAAc;KACjC;IAED,MAAM,gBAAgB,MAAM,eAAe;AACzC,YAAO,aAAa,gBAAgB,EAAE,cAAc,CAAC;MACrD;AAEF,QAAI,CAAC,cAAc,IAAI;AACrB,eAAU,QAAQ,IAAI,MAAM,cAAc,MAAM;AAChD,gBAAW,QAAQ,CAAC,GAAG,WAAW,OAAO,UAAU;AACnD;;IAGF,MAAM,CAAC,WAAW,cAAc,MAAM,YAAY;KAChD,cAAc,cAAc,KAAK;KACjC,gBAAgB,cAAc,KAAK;KACnC;KACD,CAAC;AAEF,QAAI,WAAW;AACb,eAAU,QAAQ;AAClB,gBAAW,QAAQ,CAAC,GAAG,WAAW,OAAO,UAAU;AACnD;;AAGF,cAAU,SAAS,WAAW;IAE9B,MAAM,qBAAqB,UACzB,SAAS,oBACT,cAAc,KAAK,UAAU,mBAC9B;IAED,MAAM,oBAAoB,CAAC,GAAG,UAAU,YAAY;AACpD,UAAM,0BAA0B,oBAAoB;KAClD;KACA,UAAU,WAAW,iBAAiB,OAAO;KAC7C;KACA,sBAAsB,wBAAwB;AAC5C,gBAAU,cAAc,CAAC,GAAG,mBAAmB,GAAG,oBAAoB;;KAEzE,CAAC;AAEF,eAAW,QAAQ,CAAC,GAAG,WAAW,OAAO,UAAU;AAGnD,QADuB,UAAU,YAAY,MAAM,MAAM,CAAC,EAAE,OAAO,CAEjE;YAEK,OAAO;AACd,cAAU,QAAQ,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;AAC3E,eAAW,QAAQ,CAAC,GAAG,WAAW,OAAO,UAAU;AACnD;;;AAIJ,YAAU,QAAQ;AAClB,kBAAgB,QAAQ;AACxB,aAAW,QAAQ,YAAY,KAAK;AAC/B,YAAU,OAAO;AACtB,kBAAgB,QAAQ;;AAG1B,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD"} |
@@ -25,2 +25,3 @@ import Section_default from "../../settings/components/Section.vue.js"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -27,0 +28,0 @@ }, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Scripts.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Scripts.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport DocumentScriptsEditors from '@/v2/features/collection/components/DocumentScriptsEditors.vue'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst { document, eventBus, collectionType } = defineProps<CollectionProps>()\n\nconst handleUpdateExtension = (payload: Record<string, unknown>) => {\n eventBus.emit('document:update:extension', payload)\n}\n</script>\n\n<template>\n <Section v-if=\"collectionType === 'document'\">\n <template #title>Pre-request & Post-response Scripts</template>\n <template #description>\n Scripts at the document level run for every request in this document.\n Operation-level scripts (in the request editor) run in addition to these.\n </template>\n <DocumentScriptsEditors\n :document=\"document\"\n @update:extension=\"handleUpdateExtension\" />\n </Section>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;EAOA,MAAM,yBAAyB,YAAqC;AAClE,WAAA,SAAS,KAAK,6BAA6B,QAAO;;;UAKnC,QAAA,mBAAc,cAAA,WAAA,EAA7B,YASU,iBAAA,EAAA,KAAA,GAAA,EAAA;IARG,OAAK,cAAwC,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAvC,uCAAuC,GAAA,CAAA,EAAA,CAAA;IAC7C,aAAW,cAGtB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAHuB,qJAGvB,GAAA,CAAA,EAAA,CAAA;2BAG8C,CAF9C,YAE8C,gCAAA;KAD3C,UAAU,QAAA;KACV,sBAAkB"} | ||
| {"version":3,"file":"Scripts.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Scripts.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport DocumentScriptsEditors from '@/v2/features/collection/components/DocumentScriptsEditors.vue'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nconst { document, eventBus, collectionType } = defineProps<CollectionProps>()\n\nconst handleUpdateExtension = (payload: Record<string, unknown>) => {\n eventBus.emit('document:update:extension', payload)\n}\n</script>\n\n<template>\n <Section v-if=\"collectionType === 'document'\">\n <template #title>Pre-request & Post-response Scripts</template>\n <template #description>\n Scripts at the document level run for every request in this document.\n Operation-level scripts (in the request editor) run in addition to these.\n </template>\n <DocumentScriptsEditors\n :document=\"document\"\n @update:extension=\"handleUpdateExtension\" />\n </Section>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOA,MAAM,yBAAyB,YAAqC;AAClE,WAAA,SAAS,KAAK,6BAA6B,QAAO;;;UAKnC,QAAA,mBAAc,cAAA,WAAA,EAA7B,YASU,iBAAA,EAAA,KAAA,GAAA,EAAA;IARG,OAAK,cAAwC,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAvC,uCAAuC,GAAA,CAAA,EAAA,CAAA;IAC7C,aAAW,cAGtB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAHuB,qJAGvB,GAAA,CAAA,EAAA,CAAA;2BAG8C,CAF9C,YAE8C,gCAAA;KAD3C,UAAU,QAAA;KACV,sBAAkB"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Servers.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/collection/components/Servers.vue"],"names":[],"mappings":"AAg0BA,QAAA,MAAM,YAAY;;;;;;;;;;;;kGAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} | ||
| {"version":3,"file":"Servers.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/collection/components/Servers.vue"],"names":[],"mappings":"AAm0BA,QAAA,MAAM,YAAY;;;;;;;;;;;;kGAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Servers.vue.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Servers.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarMarkdown,\n ScalarModal,\n ScalarToggle,\n useModal,\n} from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport { ScalarIconPlus, ScalarIconTrash } from '@scalar/icons'\nimport type { ServerMeta } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { ServerObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watchEffect } from 'vue'\n\nimport { ServerVariablesForm } from '@/components/Server'\nimport DeleteSidebarListElement from '@/components/Sidebar/Actions/DeleteSidebarListElement.vue'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nimport Form from './Form.vue'\n\nconst { document, eventBus, collectionType, path, method } =\n defineProps<CollectionProps>()\n\nconst deleteModal = useModal()\nconst selectedServerIndex = ref<number>(-1)\n\nconst isOperation = computed(() => collectionType === 'operation')\n\nconst operation = computed(() => {\n if (!isOperation.value) {\n return null\n }\n // Operation not found\n if (!path || !isHttpMethod(method)) {\n return null\n }\n // Operation found, return the servers\n return getResolvedRef(document?.paths?.[path]?.[method])\n})\n\nconst useOperationServers = ref(false)\nwatchEffect(() => {\n useOperationServers.value = operation.value?.servers !== undefined\n})\n\n/** Grab the servers for the collection */\nconst servers = computed(() => {\n if (collectionType === 'operation' && operation.value) {\n return operation.value.servers ?? []\n }\n return document?.servers ?? []\n})\n\n/** Grab whichever server we are working on */\nconst selectedServer = computed(() => servers.value[selectedServerIndex.value])\n\n/** Meta for server events: document-level or operation-level based on collection type */\nconst serverMeta = computed<ServerMeta>(() => {\n if (collectionType === 'operation' && path && isHttpMethod(method)) {\n return { type: 'operation', path, method }\n }\n return { type: 'document' }\n})\n\n// Form field configuration\nconst FORM_OPTIONS = [\n {\n label: 'URL',\n key: 'url',\n placeholder: 'https://void.scalar.com',\n },\n {\n label: 'Description',\n key: 'description',\n placeholder: 'Production',\n lineWrapping: true,\n },\n]\n\n/** Opens the delete confirmation modal for a server */\nconst openDeleteModal = (index: number) => {\n selectedServerIndex.value = index\n deleteModal.show()\n}\n\n/** Closes the delete modal and resets the selected server */\nconst resetState = () => {\n deleteModal.hide()\n selectedServerIndex.value = -1\n}\n\n/** Handles server deletion */\nconst handleDeleteServer = () => {\n if (selectedServerIndex.value < 0) {\n return\n }\n\n eventBus.emit('server:delete:server', {\n index: selectedServerIndex.value,\n meta: serverMeta.value,\n })\n resetState()\n}\n\n/** Debounced execute function for server updates, keyed so we only debounce by server + key */\nconst { execute } = debounce({ delay: 328, maxWait: 1000 })\n\n/** Handles server property updates with debouncing */\nconst handleServerUpdate = (\n index: number,\n key: string,\n value: string | number,\n) =>\n execute(`${index}-${key}-${serverMeta.value.type}`, () =>\n eventBus.emit('server:update:server', {\n index,\n server: { [key]: value },\n meta: serverMeta.value,\n }),\n )\n\n/** Handles server variable updates with debouncing */\nconst handleVariableUpdate = (index: number, key: string, value: string) =>\n execute(`${index}-${key}-${serverMeta.value.type}`, () =>\n eventBus.emit('server:update:variables', {\n index,\n key,\n value,\n meta: serverMeta.value,\n }),\n )\n\n/** Handles adding a new server */\nconst handleAddServer = () =>\n eventBus.emit('server:add:server', { meta: serverMeta.value })\n\n/**\n * Gets the display name for a server\n */\nconst getServerDisplayName = (server?: ServerObject, index = 0): string =>\n server?.description || `Server ${index + 1}`\n\n/** Handles toggling the operation servers */\nconst handleToggleOperationServers = (value: boolean) => {\n // Only toggle for operation collections\n if (serverMeta.value.type !== 'operation') {\n return\n }\n\n // update the operation servers\n useOperationServers.value = value\n\n if (value) {\n // Initialize the servers with an empty array so we will infer the servers from the operation\n return eventBus.emit('server:initialize:servers', {\n meta: serverMeta.value,\n })\n }\n return eventBus.emit('server:clear:servers', { meta: serverMeta.value })\n}\n</script>\n\n<template>\n <Section>\n <template #title>Servers</template>\n <template #description>\n <template v-if=\"isOperation\">\n <span class=\"block\">\n Override servers for this operation with the toggle.\n </span>\n <span class=\"mt-1 block\">\n <strong>On</strong> — Servers below apply only to this operation.\n </span>\n <span class=\"mt-1 block\">\n <strong>Off</strong> — Removes operation servers; this operation uses\n document or path servers from the OpenAPI spec.\n </span>\n <span class=\"text-c-3 mt-1 block\">\n Use <code class=\"font-code text-c-2\">{variables}</code> for dynamic\n URL parts.\n </span>\n </template>\n <template v-else>\n Add different base URLs for your API. Use\n <code class=\"font-code text-c-2\">{variables}</code> for dynamic parts.\n </template>\n </template>\n <!-- Operation Servers Toggle to use the operation servers instead of the document servers -->\n <template\n v-if=\"isOperation\"\n #actions>\n <div class=\"flex h-8 items-center\">\n <ScalarToggle\n class=\"w-4\"\n :modelValue=\"useOperationServers\"\n @update:modelValue=\"handleToggleOperationServers\" />\n </div>\n </template>\n\n <div :class=\"isOperation && !useOperationServers && 'cursor-not-allowed'\">\n <div\n class=\"flex flex-col gap-4\"\n :class=\"\n isOperation &&\n !useOperationServers &&\n 'pointer-events-none cursor-not-allowed opacity-50 mix-blend-luminosity'\n \">\n <!-- Server List -->\n <div class=\"flex flex-col gap-4\">\n <div\n v-for=\"(server, index) in servers\"\n :key=\"index\"\n class=\"rounded-lg border\">\n <!-- Server Header -->\n <div\n class=\"bg-b-2 flex items-center justify-between rounded-t-lg px-3 py-1 text-sm\">\n <ScalarMarkdown\n v-if=\"server.description\"\n class=\"self-center\"\n :value=\"server.description\" />\n <span\n v-else\n class=\"self-center\">\n {{ getServerDisplayName(server, index) }}\n </span>\n <ScalarButton\n class=\"hover:bg-b-3 hover:text-c-1 h-fit p-1.25\"\n data-testid=\"delete-server-button\"\n variant=\"ghost\"\n @click=\"openDeleteModal(index)\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n </div>\n\n <!-- Server Variables Form -->\n <div\n class=\"divide-0 flex w-full flex-col divide-y rounded-b-lg text-sm\">\n <Form\n :data=\"server\"\n :environment=\"environment\"\n :onUpdate=\"\n (key, value) => handleServerUpdate(index, key, value)\n \"\n :options=\"FORM_OPTIONS\" />\n <ServerVariablesForm\n v-if=\"server.variables\"\n :variables=\"server.variables\"\n @update:variable=\"\n (name, value) => handleVariableUpdate(index, name, value)\n \" />\n </div>\n </div>\n </div>\n\n <!-- Add Server Button -->\n <div\n class=\"text-c-3 flex h-full items-center justify-center rounded-lg border p-4\">\n <ScalarButton\n class=\"hover:bg-b-2 hover:text-c-1 flex items-center gap-2\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"handleAddServer\">\n <ScalarIconPlus />\n <span>Add Server</span>\n </ScalarButton>\n </div>\n </div>\n </div>\n </Section>\n\n <!-- Delete Confirmation Modal -->\n <ScalarModal\n size=\"xxs\"\n :state=\"deleteModal\"\n :title=\"`Delete ${getServerDisplayName(selectedServer, selectedServerIndex)}`\">\n <DeleteSidebarListElement\n variableName=\"Server\"\n warningMessage=\"Are you sure you want to delete this server? This action cannot be undone.\"\n @close=\"resetState\"\n @delete=\"handleDeleteServer\" />\n </ScalarModal>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"Servers.vue.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Servers.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarMarkdown,\n ScalarModal,\n ScalarToggle,\n useModal,\n} from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport { ScalarIconPlus, ScalarIconTrash } from '@scalar/icons'\nimport type { ServerMeta } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { ServerObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watchEffect } from 'vue'\n\nimport { ServerVariablesForm } from '@/components/Server'\nimport DeleteSidebarListElement from '@/components/Sidebar/Actions/DeleteSidebarListElement.vue'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nimport Form from './Form.vue'\n\nconst { document, eventBus, collectionType, path, method } =\n defineProps<CollectionProps>()\n\nconst deleteModal = useModal()\nconst selectedServerIndex = ref<number>(-1)\n\nconst isOperation = computed(() => collectionType === 'operation')\n\nconst operation = computed(() => {\n if (!isOperation.value) {\n return null\n }\n // Operation not found\n if (!path || !isHttpMethod(method)) {\n return null\n }\n // Operation found, return the servers\n return getResolvedRef(document?.paths?.[path]?.[method])\n})\n\nconst useOperationServers = ref(false)\nwatchEffect(() => {\n useOperationServers.value = operation.value?.servers !== undefined\n})\n\n/** Grab the servers for the collection */\nconst servers = computed(() => {\n if (collectionType === 'operation' && operation.value) {\n return operation.value.servers ?? []\n }\n return document?.servers ?? []\n})\n\n/** Grab whichever server we are working on */\nconst selectedServer = computed(() => servers.value[selectedServerIndex.value])\n\n/** Meta for server events: document-level or operation-level based on collection type */\nconst serverMeta = computed<ServerMeta>(() => {\n if (collectionType === 'operation' && path && isHttpMethod(method)) {\n return { type: 'operation', path, method }\n }\n return { type: 'document' }\n})\n\n// Form field configuration\nconst FORM_OPTIONS = [\n {\n label: 'URL',\n key: 'url',\n placeholder: 'https://void.scalar.com',\n },\n {\n label: 'Description',\n key: 'description',\n placeholder: 'Production',\n lineWrapping: true,\n },\n]\n\n/** Opens the delete confirmation modal for a server */\nconst openDeleteModal = (index: number) => {\n selectedServerIndex.value = index\n deleteModal.show()\n}\n\n/** Closes the delete modal and resets the selected server */\nconst resetState = () => {\n deleteModal.hide()\n selectedServerIndex.value = -1\n}\n\n/** Handles server deletion */\nconst handleDeleteServer = () => {\n if (selectedServerIndex.value < 0) {\n return\n }\n\n eventBus.emit('server:delete:server', {\n index: selectedServerIndex.value,\n meta: serverMeta.value,\n })\n resetState()\n}\n\n/** Debounced execute function for server updates, keyed so we only debounce by server + key */\nconst { execute } = debounce({ delay: 328, maxWait: 1000 })\n\n/** Handles server property updates with debouncing */\nconst handleServerUpdate = (\n index: number,\n key: string,\n value: string | number,\n) =>\n execute(`${index}-${key}-${serverMeta.value.type}`, () =>\n eventBus.emit('server:update:server', {\n index,\n server: { [key]: value },\n meta: serverMeta.value,\n }),\n )\n\n/** Handles server variable updates with debouncing */\nconst handleVariableUpdate = (index: number, key: string, value: string) =>\n execute(`${index}-${key}-${serverMeta.value.type}`, () =>\n eventBus.emit('server:update:variables', {\n index,\n key,\n value,\n meta: serverMeta.value,\n }),\n )\n\n/** Handles adding a new server */\nconst handleAddServer = () =>\n eventBus.emit('server:add:server', { meta: serverMeta.value })\n\n/**\n * Gets the display name for a server\n */\nconst getServerDisplayName = (server?: ServerObject, index = 0): string =>\n server?.description || `Server ${index + 1}`\n\n/** Handles toggling the operation servers */\nconst handleToggleOperationServers = (value: boolean) => {\n // Only toggle for operation collections\n if (serverMeta.value.type !== 'operation') {\n return\n }\n\n // update the operation servers\n useOperationServers.value = value\n\n if (value) {\n // Initialize the servers with an empty array so we will infer the servers from the operation\n return eventBus.emit('server:initialize:servers', {\n meta: serverMeta.value,\n })\n }\n return eventBus.emit('server:clear:servers', { meta: serverMeta.value })\n}\n</script>\n\n<template>\n <Section>\n <template #title>Servers</template>\n <template #description>\n <template v-if=\"isOperation\">\n <span class=\"block\">\n Override servers for this operation with the toggle.\n </span>\n <span class=\"mt-1 block\">\n <strong>On</strong> — Servers below apply only to this operation.\n </span>\n <span class=\"mt-1 block\">\n <strong>Off</strong> — Removes operation servers; this operation uses\n document or path servers from the OpenAPI spec.\n </span>\n <span class=\"text-c-3 mt-1 block\">\n Use <code class=\"font-code text-c-2\">{variables}</code> for dynamic\n URL parts.\n </span>\n </template>\n <template v-else>\n Add different base URLs for your API. Use\n <code class=\"font-code text-c-2\">{variables}</code> for dynamic parts.\n </template>\n </template>\n <!-- Operation Servers Toggle to use the operation servers instead of the document servers -->\n <template\n v-if=\"isOperation\"\n #actions>\n <div class=\"flex h-8 items-center\">\n <ScalarToggle\n class=\"w-4\"\n :modelValue=\"useOperationServers\"\n @update:modelValue=\"handleToggleOperationServers\" />\n </div>\n </template>\n\n <div :class=\"isOperation && !useOperationServers && 'cursor-not-allowed'\">\n <div\n class=\"flex flex-col gap-4\"\n :class=\"\n isOperation &&\n !useOperationServers &&\n 'pointer-events-none cursor-not-allowed opacity-50 mix-blend-luminosity'\n \">\n <!-- Server List -->\n <div class=\"flex flex-col gap-4\">\n <div\n v-for=\"(server, index) in servers\"\n :key=\"index\"\n class=\"rounded-lg border\">\n <!-- Server Header -->\n <div\n class=\"bg-b-2 flex items-center justify-between rounded-t-lg px-3 py-1 text-sm\">\n <ScalarMarkdown\n v-if=\"server.description\"\n class=\"self-center\"\n :value=\"server.description\" />\n <span\n v-else\n class=\"self-center\">\n {{ getServerDisplayName(server, index) }}\n </span>\n <ScalarButton\n class=\"hover:bg-b-3 hover:text-c-1 h-fit p-1.25\"\n data-testid=\"delete-server-button\"\n variant=\"ghost\"\n @click=\"openDeleteModal(index)\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n </div>\n\n <!-- Server Variables Form -->\n <div\n class=\"divide-0 flex w-full flex-col divide-y rounded-b-lg text-sm\">\n <Form\n :data=\"server\"\n :environment=\"environment\"\n :onUpdate=\"\n (key, value) => handleServerUpdate(index, key, value)\n \"\n :options=\"FORM_OPTIONS\"\n :withFakeData=\"false\" />\n <ServerVariablesForm\n v-if=\"server.variables\"\n :variables=\"server.variables\"\n @update:variable=\"\n (name, value) => handleVariableUpdate(index, name, value)\n \" />\n </div>\n </div>\n </div>\n\n <!-- Add Server Button -->\n <div\n class=\"text-c-3 flex h-full items-center justify-center rounded-lg border p-4\">\n <ScalarButton\n class=\"hover:bg-b-2 hover:text-c-1 flex items-center gap-2\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"handleAddServer\">\n <ScalarIconPlus />\n <span>Add Server</span>\n </ScalarButton>\n </div>\n </div>\n </div>\n </Section>\n\n <!-- Delete Confirmation Modal -->\n <ScalarModal\n size=\"xxs\"\n :state=\"deleteModal\"\n :title=\"`Delete ${getServerDisplayName(selectedServer, selectedServerIndex)}`\">\n <DeleteSidebarListElement\n variableName=\"Server\"\n warningMessage=\"Are you sure you want to delete this server? This action cannot be undone.\"\n @close=\"resetState\"\n @delete=\"handleDeleteServer\" />\n </ScalarModal>\n</template>\n"],"mappings":""} |
@@ -41,2 +41,3 @@ import ServerVariablesForm_default from "../../../../components/Server/ServerVariablesForm.vue.js"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -170,3 +171,4 @@ }, | ||
| onUpdate: (key, value) => handleServerUpdate(index, key, value), | ||
| options: FORM_OPTIONS | ||
| options: FORM_OPTIONS, | ||
| withFakeData: false | ||
| }, null, 8, [ | ||
@@ -173,0 +175,0 @@ "data", |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Servers.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Servers.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarMarkdown,\n ScalarModal,\n ScalarToggle,\n useModal,\n} from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport { ScalarIconPlus, ScalarIconTrash } from '@scalar/icons'\nimport type { ServerMeta } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { ServerObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watchEffect } from 'vue'\n\nimport { ServerVariablesForm } from '@/components/Server'\nimport DeleteSidebarListElement from '@/components/Sidebar/Actions/DeleteSidebarListElement.vue'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nimport Form from './Form.vue'\n\nconst { document, eventBus, collectionType, path, method } =\n defineProps<CollectionProps>()\n\nconst deleteModal = useModal()\nconst selectedServerIndex = ref<number>(-1)\n\nconst isOperation = computed(() => collectionType === 'operation')\n\nconst operation = computed(() => {\n if (!isOperation.value) {\n return null\n }\n // Operation not found\n if (!path || !isHttpMethod(method)) {\n return null\n }\n // Operation found, return the servers\n return getResolvedRef(document?.paths?.[path]?.[method])\n})\n\nconst useOperationServers = ref(false)\nwatchEffect(() => {\n useOperationServers.value = operation.value?.servers !== undefined\n})\n\n/** Grab the servers for the collection */\nconst servers = computed(() => {\n if (collectionType === 'operation' && operation.value) {\n return operation.value.servers ?? []\n }\n return document?.servers ?? []\n})\n\n/** Grab whichever server we are working on */\nconst selectedServer = computed(() => servers.value[selectedServerIndex.value])\n\n/** Meta for server events: document-level or operation-level based on collection type */\nconst serverMeta = computed<ServerMeta>(() => {\n if (collectionType === 'operation' && path && isHttpMethod(method)) {\n return { type: 'operation', path, method }\n }\n return { type: 'document' }\n})\n\n// Form field configuration\nconst FORM_OPTIONS = [\n {\n label: 'URL',\n key: 'url',\n placeholder: 'https://void.scalar.com',\n },\n {\n label: 'Description',\n key: 'description',\n placeholder: 'Production',\n lineWrapping: true,\n },\n]\n\n/** Opens the delete confirmation modal for a server */\nconst openDeleteModal = (index: number) => {\n selectedServerIndex.value = index\n deleteModal.show()\n}\n\n/** Closes the delete modal and resets the selected server */\nconst resetState = () => {\n deleteModal.hide()\n selectedServerIndex.value = -1\n}\n\n/** Handles server deletion */\nconst handleDeleteServer = () => {\n if (selectedServerIndex.value < 0) {\n return\n }\n\n eventBus.emit('server:delete:server', {\n index: selectedServerIndex.value,\n meta: serverMeta.value,\n })\n resetState()\n}\n\n/** Debounced execute function for server updates, keyed so we only debounce by server + key */\nconst { execute } = debounce({ delay: 328, maxWait: 1000 })\n\n/** Handles server property updates with debouncing */\nconst handleServerUpdate = (\n index: number,\n key: string,\n value: string | number,\n) =>\n execute(`${index}-${key}-${serverMeta.value.type}`, () =>\n eventBus.emit('server:update:server', {\n index,\n server: { [key]: value },\n meta: serverMeta.value,\n }),\n )\n\n/** Handles server variable updates with debouncing */\nconst handleVariableUpdate = (index: number, key: string, value: string) =>\n execute(`${index}-${key}-${serverMeta.value.type}`, () =>\n eventBus.emit('server:update:variables', {\n index,\n key,\n value,\n meta: serverMeta.value,\n }),\n )\n\n/** Handles adding a new server */\nconst handleAddServer = () =>\n eventBus.emit('server:add:server', { meta: serverMeta.value })\n\n/**\n * Gets the display name for a server\n */\nconst getServerDisplayName = (server?: ServerObject, index = 0): string =>\n server?.description || `Server ${index + 1}`\n\n/** Handles toggling the operation servers */\nconst handleToggleOperationServers = (value: boolean) => {\n // Only toggle for operation collections\n if (serverMeta.value.type !== 'operation') {\n return\n }\n\n // update the operation servers\n useOperationServers.value = value\n\n if (value) {\n // Initialize the servers with an empty array so we will infer the servers from the operation\n return eventBus.emit('server:initialize:servers', {\n meta: serverMeta.value,\n })\n }\n return eventBus.emit('server:clear:servers', { meta: serverMeta.value })\n}\n</script>\n\n<template>\n <Section>\n <template #title>Servers</template>\n <template #description>\n <template v-if=\"isOperation\">\n <span class=\"block\">\n Override servers for this operation with the toggle.\n </span>\n <span class=\"mt-1 block\">\n <strong>On</strong> — Servers below apply only to this operation.\n </span>\n <span class=\"mt-1 block\">\n <strong>Off</strong> — Removes operation servers; this operation uses\n document or path servers from the OpenAPI spec.\n </span>\n <span class=\"text-c-3 mt-1 block\">\n Use <code class=\"font-code text-c-2\">{variables}</code> for dynamic\n URL parts.\n </span>\n </template>\n <template v-else>\n Add different base URLs for your API. Use\n <code class=\"font-code text-c-2\">{variables}</code> for dynamic parts.\n </template>\n </template>\n <!-- Operation Servers Toggle to use the operation servers instead of the document servers -->\n <template\n v-if=\"isOperation\"\n #actions>\n <div class=\"flex h-8 items-center\">\n <ScalarToggle\n class=\"w-4\"\n :modelValue=\"useOperationServers\"\n @update:modelValue=\"handleToggleOperationServers\" />\n </div>\n </template>\n\n <div :class=\"isOperation && !useOperationServers && 'cursor-not-allowed'\">\n <div\n class=\"flex flex-col gap-4\"\n :class=\"\n isOperation &&\n !useOperationServers &&\n 'pointer-events-none cursor-not-allowed opacity-50 mix-blend-luminosity'\n \">\n <!-- Server List -->\n <div class=\"flex flex-col gap-4\">\n <div\n v-for=\"(server, index) in servers\"\n :key=\"index\"\n class=\"rounded-lg border\">\n <!-- Server Header -->\n <div\n class=\"bg-b-2 flex items-center justify-between rounded-t-lg px-3 py-1 text-sm\">\n <ScalarMarkdown\n v-if=\"server.description\"\n class=\"self-center\"\n :value=\"server.description\" />\n <span\n v-else\n class=\"self-center\">\n {{ getServerDisplayName(server, index) }}\n </span>\n <ScalarButton\n class=\"hover:bg-b-3 hover:text-c-1 h-fit p-1.25\"\n data-testid=\"delete-server-button\"\n variant=\"ghost\"\n @click=\"openDeleteModal(index)\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n </div>\n\n <!-- Server Variables Form -->\n <div\n class=\"divide-0 flex w-full flex-col divide-y rounded-b-lg text-sm\">\n <Form\n :data=\"server\"\n :environment=\"environment\"\n :onUpdate=\"\n (key, value) => handleServerUpdate(index, key, value)\n \"\n :options=\"FORM_OPTIONS\" />\n <ServerVariablesForm\n v-if=\"server.variables\"\n :variables=\"server.variables\"\n @update:variable=\"\n (name, value) => handleVariableUpdate(index, name, value)\n \" />\n </div>\n </div>\n </div>\n\n <!-- Add Server Button -->\n <div\n class=\"text-c-3 flex h-full items-center justify-center rounded-lg border p-4\">\n <ScalarButton\n class=\"hover:bg-b-2 hover:text-c-1 flex items-center gap-2\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"handleAddServer\">\n <ScalarIconPlus />\n <span>Add Server</span>\n </ScalarButton>\n </div>\n </div>\n </div>\n </Section>\n\n <!-- Delete Confirmation Modal -->\n <ScalarModal\n size=\"xxs\"\n :state=\"deleteModal\"\n :title=\"`Delete ${getServerDisplayName(selectedServer, selectedServerIndex)}`\">\n <DeleteSidebarListElement\n variableName=\"Server\"\n warningMessage=\"Are you sure you want to delete this server? This action cannot be undone.\"\n @close=\"resetState\"\n @delete=\"handleDeleteServer\" />\n </ScalarModal>\n</template>\n"],"mappings":"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"} | ||
| {"version":3,"file":"Servers.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Servers.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarMarkdown,\n ScalarModal,\n ScalarToggle,\n useModal,\n} from '@scalar/components'\nimport { debounce } from '@scalar/helpers/general/debounce'\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport { ScalarIconPlus, ScalarIconTrash } from '@scalar/icons'\nimport type { ServerMeta } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { ServerObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watchEffect } from 'vue'\n\nimport { ServerVariablesForm } from '@/components/Server'\nimport DeleteSidebarListElement from '@/components/Sidebar/Actions/DeleteSidebarListElement.vue'\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport Section from '@/v2/features/settings/components/Section.vue'\n\nimport Form from './Form.vue'\n\nconst { document, eventBus, collectionType, path, method } =\n defineProps<CollectionProps>()\n\nconst deleteModal = useModal()\nconst selectedServerIndex = ref<number>(-1)\n\nconst isOperation = computed(() => collectionType === 'operation')\n\nconst operation = computed(() => {\n if (!isOperation.value) {\n return null\n }\n // Operation not found\n if (!path || !isHttpMethod(method)) {\n return null\n }\n // Operation found, return the servers\n return getResolvedRef(document?.paths?.[path]?.[method])\n})\n\nconst useOperationServers = ref(false)\nwatchEffect(() => {\n useOperationServers.value = operation.value?.servers !== undefined\n})\n\n/** Grab the servers for the collection */\nconst servers = computed(() => {\n if (collectionType === 'operation' && operation.value) {\n return operation.value.servers ?? []\n }\n return document?.servers ?? []\n})\n\n/** Grab whichever server we are working on */\nconst selectedServer = computed(() => servers.value[selectedServerIndex.value])\n\n/** Meta for server events: document-level or operation-level based on collection type */\nconst serverMeta = computed<ServerMeta>(() => {\n if (collectionType === 'operation' && path && isHttpMethod(method)) {\n return { type: 'operation', path, method }\n }\n return { type: 'document' }\n})\n\n// Form field configuration\nconst FORM_OPTIONS = [\n {\n label: 'URL',\n key: 'url',\n placeholder: 'https://void.scalar.com',\n },\n {\n label: 'Description',\n key: 'description',\n placeholder: 'Production',\n lineWrapping: true,\n },\n]\n\n/** Opens the delete confirmation modal for a server */\nconst openDeleteModal = (index: number) => {\n selectedServerIndex.value = index\n deleteModal.show()\n}\n\n/** Closes the delete modal and resets the selected server */\nconst resetState = () => {\n deleteModal.hide()\n selectedServerIndex.value = -1\n}\n\n/** Handles server deletion */\nconst handleDeleteServer = () => {\n if (selectedServerIndex.value < 0) {\n return\n }\n\n eventBus.emit('server:delete:server', {\n index: selectedServerIndex.value,\n meta: serverMeta.value,\n })\n resetState()\n}\n\n/** Debounced execute function for server updates, keyed so we only debounce by server + key */\nconst { execute } = debounce({ delay: 328, maxWait: 1000 })\n\n/** Handles server property updates with debouncing */\nconst handleServerUpdate = (\n index: number,\n key: string,\n value: string | number,\n) =>\n execute(`${index}-${key}-${serverMeta.value.type}`, () =>\n eventBus.emit('server:update:server', {\n index,\n server: { [key]: value },\n meta: serverMeta.value,\n }),\n )\n\n/** Handles server variable updates with debouncing */\nconst handleVariableUpdate = (index: number, key: string, value: string) =>\n execute(`${index}-${key}-${serverMeta.value.type}`, () =>\n eventBus.emit('server:update:variables', {\n index,\n key,\n value,\n meta: serverMeta.value,\n }),\n )\n\n/** Handles adding a new server */\nconst handleAddServer = () =>\n eventBus.emit('server:add:server', { meta: serverMeta.value })\n\n/**\n * Gets the display name for a server\n */\nconst getServerDisplayName = (server?: ServerObject, index = 0): string =>\n server?.description || `Server ${index + 1}`\n\n/** Handles toggling the operation servers */\nconst handleToggleOperationServers = (value: boolean) => {\n // Only toggle for operation collections\n if (serverMeta.value.type !== 'operation') {\n return\n }\n\n // update the operation servers\n useOperationServers.value = value\n\n if (value) {\n // Initialize the servers with an empty array so we will infer the servers from the operation\n return eventBus.emit('server:initialize:servers', {\n meta: serverMeta.value,\n })\n }\n return eventBus.emit('server:clear:servers', { meta: serverMeta.value })\n}\n</script>\n\n<template>\n <Section>\n <template #title>Servers</template>\n <template #description>\n <template v-if=\"isOperation\">\n <span class=\"block\">\n Override servers for this operation with the toggle.\n </span>\n <span class=\"mt-1 block\">\n <strong>On</strong> — Servers below apply only to this operation.\n </span>\n <span class=\"mt-1 block\">\n <strong>Off</strong> — Removes operation servers; this operation uses\n document or path servers from the OpenAPI spec.\n </span>\n <span class=\"text-c-3 mt-1 block\">\n Use <code class=\"font-code text-c-2\">{variables}</code> for dynamic\n URL parts.\n </span>\n </template>\n <template v-else>\n Add different base URLs for your API. Use\n <code class=\"font-code text-c-2\">{variables}</code> for dynamic parts.\n </template>\n </template>\n <!-- Operation Servers Toggle to use the operation servers instead of the document servers -->\n <template\n v-if=\"isOperation\"\n #actions>\n <div class=\"flex h-8 items-center\">\n <ScalarToggle\n class=\"w-4\"\n :modelValue=\"useOperationServers\"\n @update:modelValue=\"handleToggleOperationServers\" />\n </div>\n </template>\n\n <div :class=\"isOperation && !useOperationServers && 'cursor-not-allowed'\">\n <div\n class=\"flex flex-col gap-4\"\n :class=\"\n isOperation &&\n !useOperationServers &&\n 'pointer-events-none cursor-not-allowed opacity-50 mix-blend-luminosity'\n \">\n <!-- Server List -->\n <div class=\"flex flex-col gap-4\">\n <div\n v-for=\"(server, index) in servers\"\n :key=\"index\"\n class=\"rounded-lg border\">\n <!-- Server Header -->\n <div\n class=\"bg-b-2 flex items-center justify-between rounded-t-lg px-3 py-1 text-sm\">\n <ScalarMarkdown\n v-if=\"server.description\"\n class=\"self-center\"\n :value=\"server.description\" />\n <span\n v-else\n class=\"self-center\">\n {{ getServerDisplayName(server, index) }}\n </span>\n <ScalarButton\n class=\"hover:bg-b-3 hover:text-c-1 h-fit p-1.25\"\n data-testid=\"delete-server-button\"\n variant=\"ghost\"\n @click=\"openDeleteModal(index)\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n </div>\n\n <!-- Server Variables Form -->\n <div\n class=\"divide-0 flex w-full flex-col divide-y rounded-b-lg text-sm\">\n <Form\n :data=\"server\"\n :environment=\"environment\"\n :onUpdate=\"\n (key, value) => handleServerUpdate(index, key, value)\n \"\n :options=\"FORM_OPTIONS\"\n :withFakeData=\"false\" />\n <ServerVariablesForm\n v-if=\"server.variables\"\n :variables=\"server.variables\"\n @update:variable=\"\n (name, value) => handleVariableUpdate(index, name, value)\n \" />\n </div>\n </div>\n </div>\n\n <!-- Add Server Button -->\n <div\n class=\"text-c-3 flex h-full items-center justify-center rounded-lg border p-4\">\n <ScalarButton\n class=\"hover:bg-b-2 hover:text-c-1 flex items-center gap-2\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"handleAddServer\">\n <ScalarIconPlus />\n <span>Add Server</span>\n </ScalarButton>\n </div>\n </div>\n </div>\n </Section>\n\n <!-- Delete Confirmation Modal -->\n <ScalarModal\n size=\"xxs\"\n :state=\"deleteModal\"\n :title=\"`Delete ${getServerDisplayName(selectedServer, selectedServerIndex)}`\">\n <DeleteSidebarListElement\n variableName=\"Server\"\n warningMessage=\"Are you sure you want to delete this server? This action cannot be undone.\"\n @close=\"resetState\"\n @delete=\"handleDeleteServer\" />\n </ScalarModal>\n</template>\n"],"mappings":"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"} |
@@ -26,2 +26,3 @@ import CollectionSettings_default from "../../settings/CollectionSettings.vue.js"; | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {}, | ||
| collectionType: {} | ||
@@ -28,0 +29,0 @@ }, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Settings.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { getActiveProxyUrl } from '@scalar/workspace-store/request-example'\nimport type { ColorMode } from '@scalar/workspace-store/schemas/workspace'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { CollectionSettings, DocumentSettings } from '@/v2/features/settings'\n\nconst {\n eventBus,\n documentSlug,\n document,\n workspaceStore,\n collectionType,\n layout,\n telemetry,\n onUpdateTelemetry,\n} = defineProps<CollectionProps>()\n\nconst handleUpdateWatchMode = (watchMode: boolean) => {\n eventBus.emit('document:update:watch-mode', watchMode)\n}\n\nconst handleUpdateThemeSlug = (themeSlug?: string) => {\n eventBus.emit('workspace:update:theme', themeSlug)\n}\nconst handleUpdateActiveProxy = (proxy: string | null) => {\n eventBus.emit('workspace:update:active-proxy', proxy)\n}\n\nconst handleUpdateColorMode = (colorMode: ColorMode) => {\n eventBus.emit('workspace:update:color-mode', colorMode)\n}\n</script>\n<template>\n <DocumentSettings\n v-if=\"collectionType === 'document'\"\n :documentUrl=\"document?.['x-scalar-original-source-url']\"\n :isDraftDocument=\"documentSlug === 'drafts'\"\n :title=\"document?.info.title ?? ''\"\n :watchMode=\"document?.['x-scalar-watch-mode']\"\n @delete:document=\"\n eventBus.emit('document:delete:document', { name: documentSlug })\n \"\n @update:watchMode=\"handleUpdateWatchMode\" />\n <CollectionSettings\n v-else\n :activeProxyUrl=\"\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n )\n \"\n :activeThemeSlug=\"workspaceStore.workspace['x-scalar-theme'] ?? 'none'\"\n :colorMode=\"workspaceStore.workspace['x-scalar-color-mode'] ?? 'system'\"\n :customThemes=\"customThemes\"\n :telemetry=\"telemetry\"\n @update:colorMode=\"handleUpdateColorMode\"\n @update:proxyUrl=\"handleUpdateActiveProxy\"\n @update:telemetry=\"(value) => onUpdateTelemetry?.(value)\"\n @update:themeSlug=\"handleUpdateThemeSlug\" />\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBA,MAAM,yBAAyB,cAAuB;AACpD,WAAA,SAAS,KAAK,8BAA8B,UAAS;;EAGvD,MAAM,yBAAyB,cAAuB;AACpD,WAAA,SAAS,KAAK,0BAA0B,UAAS;;EAEnD,MAAM,2BAA2B,UAAyB;AACxD,WAAA,SAAS,KAAK,iCAAiC,MAAK;;EAGtD,MAAM,yBAAyB,cAAyB;AACtD,WAAA,SAAS,KAAK,+BAA+B,UAAS;;;UAK9C,QAAA,mBAAc,cAAA,WAAA,EADtB,YAS8C,MAAA,yBAAA,EAAA;;IAP3C,aAAa,QAAA,WAAQ;IACrB,iBAAiB,QAAA,iBAAY;IAC7B,OAAO,QAAA,UAAU,KAAK,SAAK;IAC3B,WAAW,QAAA,WAAQ;IACnB,qBAAe,OAAA,OAAA,OAAA,MAAA,WAAS,QAAA,SAAS,KAAI,4BAAA,EAAA,MAAqC,QAAA,cAAY,CAAA;IAGtF,sBAAkB;;;;;;uBACrB,YAe8C,MAAA,2BAAA,EAAA;;IAb3C,gBAAuB,MAAA,kBAAiB,CAAU,QAAA,eAAe,UAAS,0BAAmC,QAAA,WAAM,QAAA,QAAA,QAAA;IAMnH,iBAAiB,QAAA,eAAe,UAAS,qBAAA;IACzC,WAAW,QAAA,eAAe,UAAS,0BAAA;IACnC,cAAc,QAAA;IACd,WAAW,QAAA;IACX,sBAAkB;IAClB,qBAAiB;IACjB,sBAAgB,OAAA,OAAA,OAAA,MAAG,UAAU,QAAA,oBAAoB,MAAK;IACtD,sBAAkB"} | ||
| {"version":3,"file":"Settings.vue.script.js","names":[],"sources":["../../../../../src/v2/features/collection/components/Settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { getActiveProxyUrl } from '@scalar/workspace-store/request-example'\nimport type { ColorMode } from '@scalar/workspace-store/schemas/workspace'\n\nimport type { CollectionProps } from '@/v2/features/app/helpers/routes'\nimport { CollectionSettings, DocumentSettings } from '@/v2/features/settings'\n\nconst {\n eventBus,\n documentSlug,\n document,\n workspaceStore,\n collectionType,\n layout,\n telemetry,\n onUpdateTelemetry,\n} = defineProps<CollectionProps>()\n\nconst handleUpdateWatchMode = (watchMode: boolean) => {\n eventBus.emit('document:update:watch-mode', watchMode)\n}\n\nconst handleUpdateThemeSlug = (themeSlug?: string) => {\n eventBus.emit('workspace:update:theme', themeSlug)\n}\nconst handleUpdateActiveProxy = (proxy: string | null) => {\n eventBus.emit('workspace:update:active-proxy', proxy)\n}\n\nconst handleUpdateColorMode = (colorMode: ColorMode) => {\n eventBus.emit('workspace:update:color-mode', colorMode)\n}\n</script>\n<template>\n <DocumentSettings\n v-if=\"collectionType === 'document'\"\n :documentUrl=\"document?.['x-scalar-original-source-url']\"\n :isDraftDocument=\"documentSlug === 'drafts'\"\n :title=\"document?.info.title ?? ''\"\n :watchMode=\"document?.['x-scalar-watch-mode']\"\n @delete:document=\"\n eventBus.emit('document:delete:document', { name: documentSlug })\n \"\n @update:watchMode=\"handleUpdateWatchMode\" />\n <CollectionSettings\n v-else\n :activeProxyUrl=\"\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n )\n \"\n :activeThemeSlug=\"workspaceStore.workspace['x-scalar-theme'] ?? 'none'\"\n :colorMode=\"workspaceStore.workspace['x-scalar-color-mode'] ?? 'system'\"\n :customThemes=\"customThemes\"\n :telemetry=\"telemetry\"\n @update:colorMode=\"handleUpdateColorMode\"\n @update:proxyUrl=\"handleUpdateActiveProxy\"\n @update:telemetry=\"(value) => onUpdateTelemetry?.(value)\"\n @update:themeSlug=\"handleUpdateThemeSlug\" />\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBA,MAAM,yBAAyB,cAAuB;AACpD,WAAA,SAAS,KAAK,8BAA8B,UAAS;;EAGvD,MAAM,yBAAyB,cAAuB;AACpD,WAAA,SAAS,KAAK,0BAA0B,UAAS;;EAEnD,MAAM,2BAA2B,UAAyB;AACxD,WAAA,SAAS,KAAK,iCAAiC,MAAK;;EAGtD,MAAM,yBAAyB,cAAyB;AACtD,WAAA,SAAS,KAAK,+BAA+B,UAAS;;;UAK9C,QAAA,mBAAc,cAAA,WAAA,EADtB,YAS8C,MAAA,yBAAA,EAAA;;IAP3C,aAAa,QAAA,WAAQ;IACrB,iBAAiB,QAAA,iBAAY;IAC7B,OAAO,QAAA,UAAU,KAAK,SAAK;IAC3B,WAAW,QAAA,WAAQ;IACnB,qBAAe,OAAA,OAAA,OAAA,MAAA,WAAS,QAAA,SAAS,KAAI,4BAAA,EAAA,MAAqC,QAAA,cAAY,CAAA;IAGtF,sBAAkB;;;;;;uBACrB,YAe8C,MAAA,2BAAA,EAAA;;IAb3C,gBAAuB,MAAA,kBAAiB,CAAU,QAAA,eAAe,UAAS,0BAAmC,QAAA,WAAM,QAAA,QAAA,QAAA;IAMnH,iBAAiB,QAAA,eAAe,UAAS,qBAAA;IACzC,WAAW,QAAA,eAAe,UAAS,0BAAA;IACnC,cAAc,QAAA;IACd,WAAW,QAAA;IACX,sBAAkB;IAClB,qBAAiB;IACjB,sBAAgB,OAAA,OAAA,OAAA,MAAG,UAAU,QAAA,oBAAoB,MAAK;IACtD,sBAAkB"} |
@@ -56,3 +56,4 @@ import IconSelector_default from "../../../components/IconSelector.vue.js"; | ||
| telemetry: { type: Boolean }, | ||
| onUpdateTelemetry: { type: Function } | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {} | ||
| }, | ||
@@ -59,0 +60,0 @@ setup(__props) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"DocumentCollection.vue.script.js","names":[],"sources":["../../../../src/v2/features/collection/DocumentCollection.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Document Collection Page\n *\n * Displays primary document editing and viewing interface, enabling users to:\n * - Choose a document icon\n * - Edit the document title\n * - Navigate among Overview, Servers, Authentication, Environment, Cookies, and Settings tabs\n */\nexport default {\n name: 'DocumentCollection',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarModal,\n ScalarSavePrompt,\n useLoadingState,\n useModal,\n} from '@scalar/components'\nimport {\n ScalarIconCloudArrowDown,\n ScalarIconDownload,\n ScalarIconFloppyDisk,\n ScalarIconSpinner,\n ScalarIconWarning,\n} from '@scalar/icons'\nimport { LibraryIcon } from '@scalar/icons/library'\nimport { apply, type Difference, type merge } from '@scalar/json-magic/diff'\nimport { useToasts } from '@scalar/use-toasts'\nimport { deepClone } from '@scalar/workspace-store/helpers/deep-clone'\nimport { computed, ref } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport IconSelector from '@/components/IconSelector.vue'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { downloadAsFile } from '@/v2/helpers/download-document'\n\nimport LabelInput from './components/LabelInput.vue'\nimport SyncConflictResolutionEditor from './components/SyncConflictResolutionEditor.vue'\nimport Tabs from './components/Tabs.vue'\n\nconst props = defineProps<RouteProps>()\n\n/** Snag the title from the info object */\nconst title = computed(() => props.document?.info?.title ?? '')\n\n/** Default to the folder icon */\nconst icon = computed(\n () => props.document?.['x-scalar-icon'] || 'interface-content-folder',\n)\n\nconst syncModal = useModal()\nconst dirtyBeforeSyncModal = useModal()\n\nconst isDocumentDirty = computed(\n () => props.document?.['x-scalar-is-dirty'] === true,\n)\n\nconst saveLoader = useLoadingState()\n\nconst documentSourceUrl = computed(\n () => props.document?.['x-scalar-original-source-url'] as string | undefined,\n)\n\nconst documentRegistryMeta = computed(\n () =>\n props.document?.['x-scalar-registry-meta'] as\n | { namespace: string; slug: string }\n | undefined,\n)\n\n/** Show Sync when the document has a source URL or registry meta (registry can be used if fetchRegistryDocument is set). */\nconst canShowSyncButton = computed(\n () =>\n documentSourceUrl.value !== undefined ||\n documentRegistryMeta.value !== undefined,\n)\n\nconst { toast } = useToasts()\n\nconst undoChanges = () => {\n props.workspaceStore.revertDocumentChanges(props.documentSlug)\n}\n\nconst saveChanges = async () => {\n saveLoader.start()\n const res = await props.workspaceStore.saveDocument(props.documentSlug)\n await (res ? saveLoader.validate() : saveLoader.invalidate({ persist: true }))\n}\n\n/** Downloads the document as a JSON file using the last saved state. */\nconst downloadDocument = () => {\n const content = props.workspaceStore.exportDocument(\n props.documentSlug,\n 'json',\n false,\n )\n if (!content) return\n const baseName = title.value.replace(/[^\\w\\s-]/g, '').trim() || 'document'\n downloadAsFile(content, `${baseName}.json`)\n}\n\nconst handleSaveThenCloseDirtyModal = async () => {\n await props.workspaceStore.saveDocument(props.documentSlug)\n dirtyBeforeSyncModal.hide()\n await handleSyncFlow()\n}\n\nconst handleDiscardThenCloseDirtyModal = async () => {\n await props.workspaceStore.revertDocumentChanges(props.documentSlug)\n dirtyBeforeSyncModal.hide()\n await handleSyncFlow()\n}\n\nconst isSyncInProgress = ref(false)\n\nconst rebaseResult = ref<{\n originalDocument: Record<string, unknown>\n resolvedDocument: Record<string, unknown>\n conflicts: ReturnType<typeof merge>['conflicts']\n applyChanges: (\n applyChangesInput:\n | {\n resolvedConflicts: Difference<unknown>[]\n }\n | {\n resolvedDocument: Record<string, unknown>\n },\n ) => Promise<void>\n} | null>(null)\n\n/**\n * Resolves the source for syncing. Registry meta has priority over x-scalar-original-source-url\n * when fetchRegistryDocument is provided. Returns either a URL or the full document object.\n */\nconst resolveSyncInput = async (): Promise<\n { url: string } | { document: Record<string, unknown> } | null\n> => {\n const registryMeta = documentRegistryMeta.value\n if (registryMeta && props.fetchRegistryDocument) {\n try {\n const result = await props.fetchRegistryDocument(registryMeta)\n if (!result.ok) {\n toast(result.error, 'error')\n return null\n }\n return { document: result.data }\n } catch (err) {\n toast('Failed to resolve document from registry', 'error')\n return null\n }\n }\n const url = documentSourceUrl.value\n if (url) {\n return { url }\n }\n return null\n}\n\n/**\n * Handles actions to perform when synchronization is complete.\n * Hides the sync modal, resets the sync progress flag, and emits the\n * 'hooks:on:rebase:document:complete' event with document metadata.\n */\nconst onSyncComplete = () => {\n syncModal.hide()\n isSyncInProgress.value = false\n // Display the toast to show that the sync is complete\n toast(\n 'Your document has been rebased with the latest version from the source.',\n 'info',\n )\n // Emit the event to notify other components that the sync is complete\n props.eventBus.emit('hooks:on:rebase:document:complete', {\n meta: {\n documentName: props.documentSlug,\n },\n })\n}\n\n/**\n * Handles errors that occur during synchronization.\n * If an error string is provided, it displays the error via toast.\n * Always resets the sync progress flag.\n */\nconst onSyncError = (error: string | null) => {\n if (error !== null) {\n toast(error, 'error')\n }\n isSyncInProgress.value = false\n}\n\n/**\n * Handles the synchronization flow for a document.\n * Checks for unsaved changes, resolves source (registry over URL),\n * initiates rebasing, handles conflicts, and emits completion events.\n * If conflicts are detected, a modal dialog is shown for user resolution.\n */\nconst handleSyncFlow = async () => {\n if (isDocumentDirty.value) {\n dirtyBeforeSyncModal.show()\n return\n }\n\n if (isSyncInProgress.value) {\n return\n }\n\n isSyncInProgress.value = true\n\n const input = await resolveSyncInput()\n if (!input) {\n onSyncError(null)\n return\n }\n\n const result = await props.workspaceStore.rebaseDocument({\n name: props.documentSlug,\n ...input,\n })\n\n if (result?.ok) {\n const originalDocument =\n props.workspaceStore.getOriginalDocument(props.documentSlug) ?? {}\n rebaseResult.value = {\n conflicts: result.conflicts,\n applyChanges: result.applyChanges,\n resolvedDocument: apply(deepClone(originalDocument), result.changes),\n originalDocument,\n }\n\n if (rebaseResult.value.conflicts.length > 0) {\n syncModal.show()\n } else {\n // If there is no conflict just rebase immediately\n await rebaseResult.value?.applyChanges({\n resolvedDocument: rebaseResult.value.resolvedDocument,\n })\n onSyncComplete()\n }\n } else if (result?.ok === false && result.type === 'NO_CHANGES_DETECTED') {\n // Emit the event either way even if there was no need to rebase the document\n onSyncComplete()\n } else {\n onSyncError('Failed to sync document')\n }\n}\n\n/*\n * Handles applying changes to the current document after conflict resolution.\n * Emits a completion event and hides the sync modal dialog.\n */\nconst handleApplyChanges = async ({\n resolvedDocument,\n}: {\n resolvedDocument: Record<string, unknown>\n}) => {\n await rebaseResult.value?.applyChanges({ resolvedDocument })\n props.eventBus.emit('hooks:on:rebase:document:complete', {\n meta: {\n documentName: props.documentSlug,\n },\n })\n syncModal.hide()\n}\n\n/**\n * Resets sync state when the sync conflict modal is closed (dismissed or after\n * applying changes). Ensures the Sync button is re-enabled and conflict state\n * is cleared.\n */\nconst onSyncModalClose = () => {\n isSyncInProgress.value = false\n rebaseResult.value = null\n}\n</script>\n\n<template>\n <div class=\"custom-scroll h-full\">\n <div\n v-if=\"document\"\n class=\"md:max-w-content w-full px-3 md:mx-auto\">\n <!-- Header -->\n <div\n :aria-label=\"`title: ${title}`\"\n class=\"md:max-w-content mx-auto flex h-fit w-full flex-col gap-2 pt-14 pb-3 md:pt-6\">\n <ScalarSavePrompt\n v-model=\"isDocumentDirty\"\n class=\"w-content-padded-4 max-w-full-padded-4 absolute\"\n :loader=\"saveLoader\"\n @discard=\"undoChanges\"\n @save=\"saveChanges\" />\n <div class=\"flex flex-row items-center justify-between gap-2\">\n <div class=\"flex min-w-0 items-center gap-2\">\n <IconSelector\n :modelValue=\"icon\"\n placement=\"bottom-start\"\n @update:modelValue=\"\n (icon) => eventBus.emit('document:update:icon', icon)\n \">\n <ScalarButton\n class=\"hover:bg-b-2 aspect-square h-7 w-7 cursor-pointer rounded border border-transparent p-0 hover:border-inherit\"\n variant=\"ghost\">\n <LibraryIcon\n class=\"text-c-2 size-5\"\n :src=\"icon\"\n stroke-width=\"2\" />\n </ScalarButton>\n </IconSelector>\n\n <div class=\"group relative ml-1.25 min-w-0\">\n <LabelInput\n class=\"text-xl font-bold\"\n inputId=\"documentName\"\n :modelValue=\"title\"\n @update:modelValue=\"\n (title) => eventBus.emit('document:update:info', { title })\n \" />\n </div>\n </div>\n\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex shrink-0 items-center gap-2\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"downloadDocument\">\n <ScalarIconDownload\n size=\"sm\"\n thickness=\"1.5\" />\n <span>Download document</span>\n </ScalarButton>\n\n <ScalarButton\n v-if=\"canShowSyncButton\"\n class=\"text-c-2 hover:text-c-1 shrink-0 gap-1.5\"\n data-testid=\"document-sync-button\"\n :disabled=\"isSyncInProgress\"\n size=\"xs\"\n :title=\"'Pull the latest version from the document source and merge with your local copy. Save your changes first if you have unsaved edits.'\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"handleSyncFlow\">\n <ScalarIconSpinner\n v-if=\"isSyncInProgress\"\n class=\"size-3.5 animate-spin\"\n size=\"sm\" />\n <ScalarIconCloudArrowDown\n v-else\n class=\"size-3.5\"\n size=\"sm\"\n thickness=\"1.5\" />\n <span>Sync from source</span>\n </ScalarButton>\n </div>\n </div>\n\n <!-- Tabs -->\n <Tabs type=\"document\" />\n\n <!-- Router views -->\n <div class=\"px-1.5 pt-8 pb-20\">\n <RouterView v-slot=\"{ Component }\">\n <component\n :is=\"Component\"\n v-bind=\"props\"\n collectionType=\"document\" />\n </RouterView>\n </div>\n </div>\n\n <!-- Document not found -->\n <div\n v-else\n class=\"flex w-full flex-1 items-center justify-center\">\n <div class=\"flex h-full flex-col items-center justify-center\">\n <h1 class=\"text-2xl font-bold\">Document not found</h1>\n <p class=\"text-gray-500\">\n The document you are looking for does not exist.\n </p>\n </div>\n </div>\n </div>\n <ScalarModal\n bodyClass=\"border-t-0 rounded-t-lg flex flex-col gap-5\"\n size=\"xs\"\n :state=\"dirtyBeforeSyncModal\"\n title=\"Sync requires saved document\"\n @close=\"dirtyBeforeSyncModal.hide()\">\n <div class=\"flex flex-col gap-5\">\n <div class=\"flex gap-3\">\n <div\n aria-hidden=\"true\"\n class=\"bg-b-3 text-c-2 flex size-10 shrink-0 items-center justify-center rounded-lg\">\n <ScalarIconWarning class=\"text-yellow size-5\" />\n </div>\n <div class=\"min-w-0 flex-1 space-y-1\">\n <p class=\"text-c-1 text-sm leading-snug font-medium\">\n You have unsaved changes\n </p>\n <p class=\"text-c-2 text-sm leading-relaxed\">\n Save your work to keep changes, or discard to revert to the last\n saved version. Then you can sync with the source.\n </p>\n </div>\n </div>\n <div class=\"flex flex-wrap items-center justify-end gap-2 border-t pt-4\">\n <ScalarButton\n size=\"sm\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"dirtyBeforeSyncModal.hide()\">\n Cancel\n </ScalarButton>\n <ScalarButton\n size=\"sm\"\n type=\"button\"\n variant=\"outlined\"\n @click=\"handleDiscardThenCloseDirtyModal\">\n Discard changes\n </ScalarButton>\n <ScalarButton\n class=\"flex items-center gap-2\"\n size=\"sm\"\n type=\"button\"\n variant=\"solid\"\n @click=\"handleSaveThenCloseDirtyModal\">\n <ScalarIconFloppyDisk\n size=\"sm\"\n thickness=\"1.5\" />\n Save and continue\n </ScalarButton>\n </div>\n </div>\n </ScalarModal>\n <ScalarModal\n v-if=\"rebaseResult\"\n bodyClass=\"sync-conflict-modal-root flex h-dvh flex-col p-4\"\n maxWidth=\"calc(100dvw - 32px)\"\n size=\"full\"\n :state=\"syncModal\"\n @close=\"onSyncModalClose\">\n <div class=\"flex h-full w-full flex-col gap-4 overflow-hidden\">\n <SyncConflictResolutionEditor\n :baseDocument=\"rebaseResult.originalDocument\"\n :conflicts=\"rebaseResult.conflicts\"\n :resolvedDocument=\"rebaseResult.resolvedDocument\"\n @applyChanges=\"(payload) => handleApplyChanges(payload)\" />\n </div>\n </ScalarModal>\n</template>\n\n<style>\n.full-size-styles:has(.sync-conflict-modal-root) {\n width: 100dvw !important;\n max-width: 100dvw !important;\n border-right: none !important;\n}\n\n.full-size-styles:has(.sync-conflict-modal-root)::after {\n display: none;\n}\n</style>\n"],"mappings":"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"} | ||
| {"version":3,"file":"DocumentCollection.vue.script.js","names":[],"sources":["../../../../src/v2/features/collection/DocumentCollection.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Document Collection Page\n *\n * Displays primary document editing and viewing interface, enabling users to:\n * - Choose a document icon\n * - Edit the document title\n * - Navigate among Overview, Servers, Authentication, Environment, Cookies, and Settings tabs\n */\nexport default {\n name: 'DocumentCollection',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarModal,\n ScalarSavePrompt,\n useLoadingState,\n useModal,\n} from '@scalar/components'\nimport {\n ScalarIconCloudArrowDown,\n ScalarIconDownload,\n ScalarIconFloppyDisk,\n ScalarIconSpinner,\n ScalarIconWarning,\n} from '@scalar/icons'\nimport { LibraryIcon } from '@scalar/icons/library'\nimport { apply, type Difference, type merge } from '@scalar/json-magic/diff'\nimport { useToasts } from '@scalar/use-toasts'\nimport { deepClone } from '@scalar/workspace-store/helpers/deep-clone'\nimport { computed, ref } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport IconSelector from '@/components/IconSelector.vue'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { downloadAsFile } from '@/v2/helpers/download-document'\n\nimport LabelInput from './components/LabelInput.vue'\nimport SyncConflictResolutionEditor from './components/SyncConflictResolutionEditor.vue'\nimport Tabs from './components/Tabs.vue'\n\nconst props = defineProps<RouteProps>()\n\n/** Snag the title from the info object */\nconst title = computed(() => props.document?.info?.title ?? '')\n\n/** Default to the folder icon */\nconst icon = computed(\n () => props.document?.['x-scalar-icon'] || 'interface-content-folder',\n)\n\nconst syncModal = useModal()\nconst dirtyBeforeSyncModal = useModal()\n\nconst isDocumentDirty = computed(\n () => props.document?.['x-scalar-is-dirty'] === true,\n)\n\nconst saveLoader = useLoadingState()\n\nconst documentSourceUrl = computed(\n () => props.document?.['x-scalar-original-source-url'] as string | undefined,\n)\n\nconst documentRegistryMeta = computed(\n () =>\n props.document?.['x-scalar-registry-meta'] as\n | { namespace: string; slug: string }\n | undefined,\n)\n\n/** Show Sync when the document has a source URL or registry meta (registry can be used if fetchRegistryDocument is set). */\nconst canShowSyncButton = computed(\n () =>\n documentSourceUrl.value !== undefined ||\n documentRegistryMeta.value !== undefined,\n)\n\nconst { toast } = useToasts()\n\nconst undoChanges = () => {\n props.workspaceStore.revertDocumentChanges(props.documentSlug)\n}\n\nconst saveChanges = async () => {\n saveLoader.start()\n const res = await props.workspaceStore.saveDocument(props.documentSlug)\n await (res ? saveLoader.validate() : saveLoader.invalidate({ persist: true }))\n}\n\n/** Downloads the document as a JSON file using the last saved state. */\nconst downloadDocument = () => {\n const content = props.workspaceStore.exportDocument(\n props.documentSlug,\n 'json',\n false,\n )\n if (!content) return\n const baseName = title.value.replace(/[^\\w\\s-]/g, '').trim() || 'document'\n downloadAsFile(content, `${baseName}.json`)\n}\n\nconst handleSaveThenCloseDirtyModal = async () => {\n await props.workspaceStore.saveDocument(props.documentSlug)\n dirtyBeforeSyncModal.hide()\n await handleSyncFlow()\n}\n\nconst handleDiscardThenCloseDirtyModal = async () => {\n await props.workspaceStore.revertDocumentChanges(props.documentSlug)\n dirtyBeforeSyncModal.hide()\n await handleSyncFlow()\n}\n\nconst isSyncInProgress = ref(false)\n\nconst rebaseResult = ref<{\n originalDocument: Record<string, unknown>\n resolvedDocument: Record<string, unknown>\n conflicts: ReturnType<typeof merge>['conflicts']\n applyChanges: (\n applyChangesInput:\n | {\n resolvedConflicts: Difference<unknown>[]\n }\n | {\n resolvedDocument: Record<string, unknown>\n },\n ) => Promise<void>\n} | null>(null)\n\n/**\n * Resolves the source for syncing. Registry meta has priority over x-scalar-original-source-url\n * when fetchRegistryDocument is provided. Returns either a URL or the full document object.\n */\nconst resolveSyncInput = async (): Promise<\n { url: string } | { document: Record<string, unknown> } | null\n> => {\n const registryMeta = documentRegistryMeta.value\n if (registryMeta && props.fetchRegistryDocument) {\n try {\n const result = await props.fetchRegistryDocument(registryMeta)\n if (!result.ok) {\n toast(result.error, 'error')\n return null\n }\n return { document: result.data }\n } catch (err) {\n toast('Failed to resolve document from registry', 'error')\n return null\n }\n }\n const url = documentSourceUrl.value\n if (url) {\n return { url }\n }\n return null\n}\n\n/**\n * Handles actions to perform when synchronization is complete.\n * Hides the sync modal, resets the sync progress flag, and emits the\n * 'hooks:on:rebase:document:complete' event with document metadata.\n */\nconst onSyncComplete = () => {\n syncModal.hide()\n isSyncInProgress.value = false\n // Display the toast to show that the sync is complete\n toast(\n 'Your document has been rebased with the latest version from the source.',\n 'info',\n )\n // Emit the event to notify other components that the sync is complete\n props.eventBus.emit('hooks:on:rebase:document:complete', {\n meta: {\n documentName: props.documentSlug,\n },\n })\n}\n\n/**\n * Handles errors that occur during synchronization.\n * If an error string is provided, it displays the error via toast.\n * Always resets the sync progress flag.\n */\nconst onSyncError = (error: string | null) => {\n if (error !== null) {\n toast(error, 'error')\n }\n isSyncInProgress.value = false\n}\n\n/**\n * Handles the synchronization flow for a document.\n * Checks for unsaved changes, resolves source (registry over URL),\n * initiates rebasing, handles conflicts, and emits completion events.\n * If conflicts are detected, a modal dialog is shown for user resolution.\n */\nconst handleSyncFlow = async () => {\n if (isDocumentDirty.value) {\n dirtyBeforeSyncModal.show()\n return\n }\n\n if (isSyncInProgress.value) {\n return\n }\n\n isSyncInProgress.value = true\n\n const input = await resolveSyncInput()\n if (!input) {\n onSyncError(null)\n return\n }\n\n const result = await props.workspaceStore.rebaseDocument({\n name: props.documentSlug,\n ...input,\n })\n\n if (result?.ok) {\n const originalDocument =\n props.workspaceStore.getOriginalDocument(props.documentSlug) ?? {}\n rebaseResult.value = {\n conflicts: result.conflicts,\n applyChanges: result.applyChanges,\n resolvedDocument: apply(deepClone(originalDocument), result.changes),\n originalDocument,\n }\n\n if (rebaseResult.value.conflicts.length > 0) {\n syncModal.show()\n } else {\n // If there is no conflict just rebase immediately\n await rebaseResult.value?.applyChanges({\n resolvedDocument: rebaseResult.value.resolvedDocument,\n })\n onSyncComplete()\n }\n } else if (result?.ok === false && result.type === 'NO_CHANGES_DETECTED') {\n // Emit the event either way even if there was no need to rebase the document\n onSyncComplete()\n } else {\n onSyncError('Failed to sync document')\n }\n}\n\n/*\n * Handles applying changes to the current document after conflict resolution.\n * Emits a completion event and hides the sync modal dialog.\n */\nconst handleApplyChanges = async ({\n resolvedDocument,\n}: {\n resolvedDocument: Record<string, unknown>\n}) => {\n await rebaseResult.value?.applyChanges({ resolvedDocument })\n props.eventBus.emit('hooks:on:rebase:document:complete', {\n meta: {\n documentName: props.documentSlug,\n },\n })\n syncModal.hide()\n}\n\n/**\n * Resets sync state when the sync conflict modal is closed (dismissed or after\n * applying changes). Ensures the Sync button is re-enabled and conflict state\n * is cleared.\n */\nconst onSyncModalClose = () => {\n isSyncInProgress.value = false\n rebaseResult.value = null\n}\n</script>\n\n<template>\n <div class=\"custom-scroll h-full\">\n <div\n v-if=\"document\"\n class=\"md:max-w-content w-full px-3 md:mx-auto\">\n <!-- Header -->\n <div\n :aria-label=\"`title: ${title}`\"\n class=\"md:max-w-content mx-auto flex h-fit w-full flex-col gap-2 pt-14 pb-3 md:pt-6\">\n <ScalarSavePrompt\n v-model=\"isDocumentDirty\"\n class=\"w-content-padded-4 max-w-full-padded-4 absolute\"\n :loader=\"saveLoader\"\n @discard=\"undoChanges\"\n @save=\"saveChanges\" />\n <div class=\"flex flex-row items-center justify-between gap-2\">\n <div class=\"flex min-w-0 items-center gap-2\">\n <IconSelector\n :modelValue=\"icon\"\n placement=\"bottom-start\"\n @update:modelValue=\"\n (icon) => eventBus.emit('document:update:icon', icon)\n \">\n <ScalarButton\n class=\"hover:bg-b-2 aspect-square h-7 w-7 cursor-pointer rounded border border-transparent p-0 hover:border-inherit\"\n variant=\"ghost\">\n <LibraryIcon\n class=\"text-c-2 size-5\"\n :src=\"icon\"\n stroke-width=\"2\" />\n </ScalarButton>\n </IconSelector>\n\n <div class=\"group relative ml-1.25 min-w-0\">\n <LabelInput\n class=\"text-xl font-bold\"\n inputId=\"documentName\"\n :modelValue=\"title\"\n @update:modelValue=\"\n (title) => eventBus.emit('document:update:info', { title })\n \" />\n </div>\n </div>\n\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex shrink-0 items-center gap-2\"\n size=\"xs\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"downloadDocument\">\n <ScalarIconDownload\n size=\"sm\"\n thickness=\"1.5\" />\n <span>Download document</span>\n </ScalarButton>\n\n <ScalarButton\n v-if=\"canShowSyncButton\"\n class=\"text-c-2 hover:text-c-1 shrink-0 gap-1.5\"\n data-testid=\"document-sync-button\"\n :disabled=\"isSyncInProgress\"\n size=\"xs\"\n :title=\"'Pull the latest version from the document source and merge with your local copy. Save your changes first if you have unsaved edits.'\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"handleSyncFlow\">\n <ScalarIconSpinner\n v-if=\"isSyncInProgress\"\n class=\"size-3.5 animate-spin\"\n size=\"sm\" />\n <ScalarIconCloudArrowDown\n v-else\n class=\"size-3.5\"\n size=\"sm\"\n thickness=\"1.5\" />\n <span>Sync from source</span>\n </ScalarButton>\n </div>\n </div>\n\n <!-- Tabs -->\n <Tabs type=\"document\" />\n\n <!-- Router views -->\n <div class=\"px-1.5 pt-8 pb-20\">\n <RouterView v-slot=\"{ Component }\">\n <component\n :is=\"Component\"\n v-bind=\"props\"\n collectionType=\"document\" />\n </RouterView>\n </div>\n </div>\n\n <!-- Document not found -->\n <div\n v-else\n class=\"flex w-full flex-1 items-center justify-center\">\n <div class=\"flex h-full flex-col items-center justify-center\">\n <h1 class=\"text-2xl font-bold\">Document not found</h1>\n <p class=\"text-gray-500\">\n The document you are looking for does not exist.\n </p>\n </div>\n </div>\n </div>\n <ScalarModal\n bodyClass=\"border-t-0 rounded-t-lg flex flex-col gap-5\"\n size=\"xs\"\n :state=\"dirtyBeforeSyncModal\"\n title=\"Sync requires saved document\"\n @close=\"dirtyBeforeSyncModal.hide()\">\n <div class=\"flex flex-col gap-5\">\n <div class=\"flex gap-3\">\n <div\n aria-hidden=\"true\"\n class=\"bg-b-3 text-c-2 flex size-10 shrink-0 items-center justify-center rounded-lg\">\n <ScalarIconWarning class=\"text-yellow size-5\" />\n </div>\n <div class=\"min-w-0 flex-1 space-y-1\">\n <p class=\"text-c-1 text-sm leading-snug font-medium\">\n You have unsaved changes\n </p>\n <p class=\"text-c-2 text-sm leading-relaxed\">\n Save your work to keep changes, or discard to revert to the last\n saved version. Then you can sync with the source.\n </p>\n </div>\n </div>\n <div class=\"flex flex-wrap items-center justify-end gap-2 border-t pt-4\">\n <ScalarButton\n size=\"sm\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"dirtyBeforeSyncModal.hide()\">\n Cancel\n </ScalarButton>\n <ScalarButton\n size=\"sm\"\n type=\"button\"\n variant=\"outlined\"\n @click=\"handleDiscardThenCloseDirtyModal\">\n Discard changes\n </ScalarButton>\n <ScalarButton\n class=\"flex items-center gap-2\"\n size=\"sm\"\n type=\"button\"\n variant=\"solid\"\n @click=\"handleSaveThenCloseDirtyModal\">\n <ScalarIconFloppyDisk\n size=\"sm\"\n thickness=\"1.5\" />\n Save and continue\n </ScalarButton>\n </div>\n </div>\n </ScalarModal>\n <ScalarModal\n v-if=\"rebaseResult\"\n bodyClass=\"sync-conflict-modal-root flex h-dvh flex-col p-4\"\n maxWidth=\"calc(100dvw - 32px)\"\n size=\"full\"\n :state=\"syncModal\"\n @close=\"onSyncModalClose\">\n <div class=\"flex h-full w-full flex-col gap-4 overflow-hidden\">\n <SyncConflictResolutionEditor\n :baseDocument=\"rebaseResult.originalDocument\"\n :conflicts=\"rebaseResult.conflicts\"\n :resolvedDocument=\"rebaseResult.resolvedDocument\"\n @applyChanges=\"(payload) => handleApplyChanges(payload)\" />\n </div>\n </ScalarModal>\n</template>\n\n<style>\n.full-size-styles:has(.sync-conflict-modal-root) {\n width: 100dvw !important;\n max-width: 100dvw !important;\n border-right: none !important;\n}\n\n.full-size-styles:has(.sync-conflict-modal-root)::after {\n display: none;\n}\n</style>\n"],"mappings":"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"} |
@@ -39,3 +39,4 @@ import LabelInput_default from "./components/LabelInput.vue.js"; | ||
| telemetry: { type: Boolean }, | ||
| onUpdateTelemetry: { type: Function } | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {} | ||
| }, | ||
@@ -42,0 +43,0 @@ setup(__props) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"OperationCollection.vue.script.js","names":[],"sources":["../../../../src/v2/features/collection/OperationCollection.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Document collection page — tabs for Overview, Servers, Auth, Environment, Cookies, and Settings. */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { computed, ref, watch } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport LabelInput from '@/v2/features/collection/components/LabelInput.vue'\n\nimport Tabs from './components/Tabs.vue'\n\nconst props = defineProps<RouteProps>()\n\nconst operation = computed(() => {\n if (!props.path || !props.method) {\n return undefined\n }\n\n return getResolvedRef(props.document?.paths?.[props.path]?.[props.method])\n})\n\n/**\n * Local copy of the label so we can reset on empty-blur rejection and stay in\n * sync when Vue Router reuses this component across workspace navigations.\n */\nconst operationSummary = ref(operation.value?.summary ?? '')\n\nwatch(\n () => operation.value?.summary,\n (newSummary) => {\n operationSummary.value = newSummary ?? ''\n },\n)\n\n/** Emits the rename event on blur, or resets the input if the title is blank. */\nconst handleSummaryUpdate = (payload: string) => {\n const { path, method } = props\n\n if (!path || !method || !isHttpMethod(method)) {\n return\n }\n\n props.eventBus.emit('operation:update:meta', {\n meta: { path, method },\n payload: {\n summary: payload.trim(),\n },\n })\n}\n\nconst operationPlaceholder = computed(() => {\n if (!props.path || !props.method) {\n return 'Untitled Operation'\n }\n return `${props.method.toUpperCase()} ${props.path}`\n})\n</script>\n\n<template>\n <div\n v-if=\"operation !== undefined\"\n class=\"custom-scroll h-full\">\n <div class=\"w-full px-3 md:mx-auto md:max-w-180\">\n <!-- Header -->\n <div\n :aria-label=\"`title: ${operationSummary}`\"\n class=\"mx-auto flex h-fit w-full flex-row items-center gap-2 pt-14 pb-3 md:max-w-180 md:pt-8\">\n <div class=\"group relative ml-1.25\">\n <LabelInput\n v-model=\"operationSummary\"\n class=\"text-xl font-bold\"\n inputId=\"operationSummary\"\n :placeholder=\"operationPlaceholder\"\n @blur=\"handleSummaryUpdate\" />\n </div>\n </div>\n\n <!-- Tabs -->\n <Tabs type=\"operation\" />\n\n <!-- Router views -->\n <div class=\"px-1.5 py-8\">\n <RouterView\n v-bind=\"props\"\n collectionType=\"operation\" />\n </div>\n </div>\n </div>\n\n <!-- Operation not found -->\n <div\n v-else\n class=\"flex w-full flex-1 items-center justify-center\">\n <div class=\"flex h-full flex-col items-center justify-center\">\n <h1 class=\"text-2xl font-bold\">Operation not found</h1>\n <p class=\"text-gray-500\">\n The operation you are looking for does not exist.\n </p>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBA,MAAM,QAAQ;EAEd,MAAM,YAAY,eAAe;AAC/B,OAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OACxB;AAGF,UAAO,eAAe,MAAM,UAAU,QAAQ,MAAM,QAAQ,MAAM,QAAO;IAC1E;;;;;EAMD,MAAM,mBAAmB,IAAI,UAAU,OAAO,WAAW,GAAE;AAE3D,cACQ,UAAU,OAAO,UACtB,eAAe;AACd,oBAAiB,QAAQ,cAAc;IAE3C;;EAGA,MAAM,uBAAuB,YAAoB;GAC/C,MAAM,EAAE,MAAM,WAAW;AAEzB,OAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,OAAO,CAC3C;AAGF,SAAM,SAAS,KAAK,yBAAyB;IAC3C,MAAM;KAAE;KAAM;KAAQ;IACtB,SAAS,EACP,SAAS,QAAQ,MAAM,EACxB;IACF,CAAA;;EAGH,MAAM,uBAAuB,eAAe;AAC1C,OAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OACxB,QAAO;AAET,UAAO,GAAG,MAAM,OAAO,aAAa,CAAC,GAAG,MAAM;IAC/C;;UAKS,UAAA,UAAc,KAAA,KAAA,WAAA,EADtB,mBA4BM,OA5BN,YA4BM,CAzBJ,mBAwBM,OAxBN,YAwBM;IAtBJ,mBAWM,OAAA;KAVH,cAAU,UAAY,iBAAA;KACvB,OAAM;QACN,mBAOM,OAPN,YAOM,CANJ,YAKgC,oBAAA;iBAJrB,iBAAA;mFAAgB,QAAA;KACzB,OAAM;KACN,SAAQ;KACP,aAAa,qBAAA;KACb,QAAM;;IAKb,YAAyB,cAAA,EAAnB,MAAK,aAAW,CAAA;IAGtB,mBAIM,OAJN,YAIM,CAHJ,YAE+B,MAAA,WAAA,EAF/B,WACU,OAAK,EACb,gBAAe,aAAW,CAAA,EAAA,MAAA,GAAA,CAAA,CAAA;yBAMlC,mBASM,OATN,YASM,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CANJ,mBAKM,OAAA,EALD,OAAM,oDAAkD,EAAA,CAC3D,mBAAuD,MAAA,EAAnD,OAAM,sBAAoB,EAAC,sBAAmB,EAClD,mBAEI,KAAA,EAFD,OAAM,iBAAe,EAAC,sDAEzB,CAAA,EAAA,GAAA,CAAA,EAAA,CAAA"} | ||
| {"version":3,"file":"OperationCollection.vue.script.js","names":[],"sources":["../../../../src/v2/features/collection/OperationCollection.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Document collection page — tabs for Overview, Servers, Auth, Environment, Cookies, and Settings. */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { isHttpMethod } from '@scalar/helpers/http/is-http-method'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { computed, ref, watch } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport LabelInput from '@/v2/features/collection/components/LabelInput.vue'\n\nimport Tabs from './components/Tabs.vue'\n\nconst props = defineProps<RouteProps>()\n\nconst operation = computed(() => {\n if (!props.path || !props.method) {\n return undefined\n }\n\n return getResolvedRef(props.document?.paths?.[props.path]?.[props.method])\n})\n\n/**\n * Local copy of the label so we can reset on empty-blur rejection and stay in\n * sync when Vue Router reuses this component across workspace navigations.\n */\nconst operationSummary = ref(operation.value?.summary ?? '')\n\nwatch(\n () => operation.value?.summary,\n (newSummary) => {\n operationSummary.value = newSummary ?? ''\n },\n)\n\n/** Emits the rename event on blur, or resets the input if the title is blank. */\nconst handleSummaryUpdate = (payload: string) => {\n const { path, method } = props\n\n if (!path || !method || !isHttpMethod(method)) {\n return\n }\n\n props.eventBus.emit('operation:update:meta', {\n meta: { path, method },\n payload: {\n summary: payload.trim(),\n },\n })\n}\n\nconst operationPlaceholder = computed(() => {\n if (!props.path || !props.method) {\n return 'Untitled Operation'\n }\n return `${props.method.toUpperCase()} ${props.path}`\n})\n</script>\n\n<template>\n <div\n v-if=\"operation !== undefined\"\n class=\"custom-scroll h-full\">\n <div class=\"w-full px-3 md:mx-auto md:max-w-180\">\n <!-- Header -->\n <div\n :aria-label=\"`title: ${operationSummary}`\"\n class=\"mx-auto flex h-fit w-full flex-row items-center gap-2 pt-14 pb-3 md:max-w-180 md:pt-8\">\n <div class=\"group relative ml-1.25\">\n <LabelInput\n v-model=\"operationSummary\"\n class=\"text-xl font-bold\"\n inputId=\"operationSummary\"\n :placeholder=\"operationPlaceholder\"\n @blur=\"handleSummaryUpdate\" />\n </div>\n </div>\n\n <!-- Tabs -->\n <Tabs type=\"operation\" />\n\n <!-- Router views -->\n <div class=\"px-1.5 py-8\">\n <RouterView\n v-bind=\"props\"\n collectionType=\"operation\" />\n </div>\n </div>\n </div>\n\n <!-- Operation not found -->\n <div\n v-else\n class=\"flex w-full flex-1 items-center justify-center\">\n <div class=\"flex h-full flex-col items-center justify-center\">\n <h1 class=\"text-2xl font-bold\">Operation not found</h1>\n <p class=\"text-gray-500\">\n The operation you are looking for does not exist.\n </p>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBA,MAAM,QAAQ;EAEd,MAAM,YAAY,eAAe;AAC/B,OAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OACxB;AAGF,UAAO,eAAe,MAAM,UAAU,QAAQ,MAAM,QAAQ,MAAM,QAAO;IAC1E;;;;;EAMD,MAAM,mBAAmB,IAAI,UAAU,OAAO,WAAW,GAAE;AAE3D,cACQ,UAAU,OAAO,UACtB,eAAe;AACd,oBAAiB,QAAQ,cAAc;IAE3C;;EAGA,MAAM,uBAAuB,YAAoB;GAC/C,MAAM,EAAE,MAAM,WAAW;AAEzB,OAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,OAAO,CAC3C;AAGF,SAAM,SAAS,KAAK,yBAAyB;IAC3C,MAAM;KAAE;KAAM;KAAQ;IACtB,SAAS,EACP,SAAS,QAAQ,MAAM,EACxB;IACF,CAAA;;EAGH,MAAM,uBAAuB,eAAe;AAC1C,OAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OACxB,QAAO;AAET,UAAO,GAAG,MAAM,OAAO,aAAa,CAAC,GAAG,MAAM;IAC/C;;UAKS,UAAA,UAAc,KAAA,KAAA,WAAA,EADtB,mBA4BM,OA5BN,YA4BM,CAzBJ,mBAwBM,OAxBN,YAwBM;IAtBJ,mBAWM,OAAA;KAVH,cAAU,UAAY,iBAAA;KACvB,OAAM;QACN,mBAOM,OAPN,YAOM,CANJ,YAKgC,oBAAA;iBAJrB,iBAAA;mFAAgB,QAAA;KACzB,OAAM;KACN,SAAQ;KACP,aAAa,qBAAA;KACb,QAAM;;IAKb,YAAyB,cAAA,EAAnB,MAAK,aAAW,CAAA;IAGtB,mBAIM,OAJN,YAIM,CAHJ,YAE+B,MAAA,WAAA,EAF/B,WACU,OAAK,EACb,gBAAe,aAAW,CAAA,EAAA,MAAA,GAAA,CAAA,CAAA;yBAMlC,mBASM,OATN,YASM,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CANJ,mBAKM,OAAA,EALD,OAAM,oDAAkD,EAAA,CAC3D,mBAAuD,MAAA,EAAnD,OAAM,sBAAoB,EAAC,sBAAmB,EAClD,mBAEI,KAAA,EAFD,OAAM,iBAAe,EAAC,sDAEzB,CAAA,EAAA,GAAA,CAAA,EAAA,CAAA"} |
@@ -30,3 +30,4 @@ import LabelInput_default from "./components/LabelInput.vue.js"; | ||
| telemetry: { type: Boolean }, | ||
| onUpdateTelemetry: { type: Function } | ||
| onUpdateTelemetry: { type: Function }, | ||
| options: {} | ||
| }, | ||
@@ -33,0 +34,0 @@ setup(__props) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"WorkspaceCollection.vue.script.js","names":[],"sources":["../../../../src/v2/features/collection/WorkspaceCollection.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Document collection page — tabs for Overview, Servers, Auth, Environment, Cookies, and Settings. */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport LabelInput from '@/v2/features/collection/components/LabelInput.vue'\n\nimport Tabs from './components/Tabs.vue'\n\nconst props = defineProps<RouteProps>()\n\n/**\n * Local copy of the label so we can reset on empty-blur rejection and stay in\n * sync when Vue Router reuses this component across workspace navigations.\n */\nconst workspaceTitle = ref(props.activeWorkspace.label)\n\nwatch(\n () => props.activeWorkspace.label,\n (newLabel) => {\n workspaceTitle.value = newLabel\n },\n)\n\n/** Emits the rename event on blur, or resets the input if the title is blank. */\nconst handleUpdateWorkspaceTitle = (title: string) => {\n if (title.trim() === '') {\n // Force defineModel inside LabelInput to re-sync to the original value.\n workspaceTitle.value = props.activeWorkspace.label\n return\n }\n props.eventBus.emit('workspace:update:name', title)\n}\n</script>\n\n<template>\n <div class=\"custom-scroll h-full\">\n <div class=\"w-full px-3 md:mx-auto md:max-w-180\">\n <!-- Header -->\n <div\n :aria-label=\"`title: ${activeWorkspace.label}`\"\n class=\"mx-auto flex h-fit w-full flex-row items-center gap-2 pt-14 pb-3 md:max-w-180 md:pt-6\">\n <div class=\"group relative ml-1.25\">\n <LabelInput\n v-model=\"workspaceTitle\"\n class=\"text-xl font-bold\"\n inputId=\"workspaceName\"\n placeholder=\"Untitled Workspace\"\n @blur=\"handleUpdateWorkspaceTitle\" />\n </div>\n </div>\n\n <!-- Tabs -->\n <Tabs type=\"workspace\" />\n\n <!-- Router views -->\n <div class=\"px-1.5 py-8\">\n <RouterView\n v-bind=\"props\"\n collectionType=\"workspace\" />\n </div>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcA,MAAM,QAAQ;;;;;EAMd,MAAM,iBAAiB,IAAI,MAAM,gBAAgB,MAAK;AAEtD,cACQ,MAAM,gBAAgB,QAC3B,aAAa;AACZ,kBAAe,QAAQ;IAE3B;;EAGA,MAAM,8BAA8B,UAAkB;AACpD,OAAI,MAAM,MAAM,KAAK,IAAI;AAEvB,mBAAe,QAAQ,MAAM,gBAAgB;AAC7C;;AAEF,SAAM,SAAS,KAAK,yBAAyB,MAAK;;;uBAKlD,mBA0BM,OA1BN,YA0BM,CAzBJ,mBAwBM,OAxBN,YAwBM;IAtBJ,mBAWM,OAAA;KAVH,cAAU,UAAY,QAAA,gBAAgB;KACvC,OAAM;QACN,mBAOM,OAPN,YAOM,CANJ,YAKuC,oBAAA;iBAJ5B,eAAA;iFAAc,QAAA;KACvB,OAAM;KACN,SAAQ;KACR,aAAY;KACX,QAAM;;IAKb,YAAyB,cAAA,EAAnB,MAAK,aAAW,CAAA;IAGtB,mBAIM,OAJN,YAIM,CAHJ,YAE+B,MAAA,WAAA,EAF/B,WACU,OAAK,EACb,gBAAe,aAAW,CAAA,EAAA,MAAA,GAAA,CAAA,CAAA"} | ||
| {"version":3,"file":"WorkspaceCollection.vue.script.js","names":[],"sources":["../../../../src/v2/features/collection/WorkspaceCollection.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Document collection page — tabs for Overview, Servers, Auth, Environment, Cookies, and Settings. */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\nimport { RouterView } from 'vue-router'\n\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport LabelInput from '@/v2/features/collection/components/LabelInput.vue'\n\nimport Tabs from './components/Tabs.vue'\n\nconst props = defineProps<RouteProps>()\n\n/**\n * Local copy of the label so we can reset on empty-blur rejection and stay in\n * sync when Vue Router reuses this component across workspace navigations.\n */\nconst workspaceTitle = ref(props.activeWorkspace.label)\n\nwatch(\n () => props.activeWorkspace.label,\n (newLabel) => {\n workspaceTitle.value = newLabel\n },\n)\n\n/** Emits the rename event on blur, or resets the input if the title is blank. */\nconst handleUpdateWorkspaceTitle = (title: string) => {\n if (title.trim() === '') {\n // Force defineModel inside LabelInput to re-sync to the original value.\n workspaceTitle.value = props.activeWorkspace.label\n return\n }\n props.eventBus.emit('workspace:update:name', title)\n}\n</script>\n\n<template>\n <div class=\"custom-scroll h-full\">\n <div class=\"w-full px-3 md:mx-auto md:max-w-180\">\n <!-- Header -->\n <div\n :aria-label=\"`title: ${activeWorkspace.label}`\"\n class=\"mx-auto flex h-fit w-full flex-row items-center gap-2 pt-14 pb-3 md:max-w-180 md:pt-6\">\n <div class=\"group relative ml-1.25\">\n <LabelInput\n v-model=\"workspaceTitle\"\n class=\"text-xl font-bold\"\n inputId=\"workspaceName\"\n placeholder=\"Untitled Workspace\"\n @blur=\"handleUpdateWorkspaceTitle\" />\n </div>\n </div>\n\n <!-- Tabs -->\n <Tabs type=\"workspace\" />\n\n <!-- Router views -->\n <div class=\"px-1.5 py-8\">\n <RouterView\n v-bind=\"props\"\n collectionType=\"workspace\" />\n </div>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcA,MAAM,QAAQ;;;;;EAMd,MAAM,iBAAiB,IAAI,MAAM,gBAAgB,MAAK;AAEtD,cACQ,MAAM,gBAAgB,QAC3B,aAAa;AACZ,kBAAe,QAAQ;IAE3B;;EAGA,MAAM,8BAA8B,UAAkB;AACpD,OAAI,MAAM,MAAM,KAAK,IAAI;AAEvB,mBAAe,QAAQ,MAAM,gBAAgB;AAC7C;;AAEF,SAAM,SAAS,KAAK,yBAAyB,MAAK;;;uBAKlD,mBA0BM,OA1BN,YA0BM,CAzBJ,mBAwBM,OAxBN,YAwBM;IAtBJ,mBAWM,OAAA;KAVH,cAAU,UAAY,QAAA,gBAAgB;KACvC,OAAM;QACN,mBAOM,OAPN,YAOM,CANJ,YAKuC,oBAAA;iBAJ5B,eAAA;iFAAc,QAAA;KACvB,OAAM;KACN,SAAQ;KACR,aAAY;KACX,QAAM;;IAKb,YAAyB,cAAA,EAAnB,MAAK,aAAW,CAAA;IAGtB,mBAIM,OAJN,YAIM,CAHJ,YAE+B,MAAA,WAAA,EAF/B,WACU,OAAK,EACb,gBAAe,aAAW,CAAA,EAAA,MAAA,GAAA,CAAA,CAAA"} |
@@ -37,4 +37,4 @@ import { type LoadingState } from '@scalar/components'; | ||
| }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { | ||
| cancel: () => any; | ||
| submit: () => any; | ||
| cancel: () => any; | ||
| back: (e: KeyboardEvent) => any; | ||
@@ -47,4 +47,4 @@ }, string, import("vue").PublicProps, Readonly<{ | ||
| }> & Readonly<{ | ||
| onCancel?: (() => any) | undefined; | ||
| onSubmit?: (() => any) | undefined; | ||
| onCancel?: (() => any) | undefined; | ||
| onBack?: ((e: KeyboardEvent) => any) | undefined; | ||
@@ -51,0 +51,0 @@ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, { |
@@ -7,7 +7,7 @@ import { type ModalState } from '@scalar/components'; | ||
| declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { | ||
| cancel: () => any; | ||
| submit: () => any; | ||
| cancel: () => any; | ||
| }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{ | ||
| onCancel?: (() => any) | undefined; | ||
| onSubmit?: (() => any) | undefined; | ||
| onCancel?: (() => any) | undefined; | ||
| }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; | ||
@@ -14,0 +14,0 @@ declare const _default: typeof __VLS_export; |
| import type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'; | ||
| type __VLS_Props = { | ||
| query: string; | ||
| environment: XScalarEnvironment; | ||
| environment?: XScalarEnvironment; | ||
| dropdownPosition?: { | ||
@@ -6,0 +6,0 @@ left: number; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"EnvironmentVariablesDropdown.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/environments/components/EnvironmentVariablesDropdown.vue"],"names":[],"mappings":"AA6PA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AASnH,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,kBAAkB,CAAA;IAC/B,gBAAgB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IAChD,iFAAiF;IACjF,oBAAoB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC9D,CAAC;AAqYF,QAAA,MAAM,YAAY;gCAnQiB,IAAI,GAAG,MAAM;;;;;;;;kFAuQ9C,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} | ||
| {"version":3,"file":"EnvironmentVariablesDropdown.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/environments/components/EnvironmentVariablesDropdown.vue"],"names":[],"mappings":"AA6PA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AASnH,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,kBAAkB,CAAA;IAChC,gBAAgB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IAChD,iFAAiF;IACjF,oBAAoB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC9D,CAAC;AAqYF,QAAA,MAAM,YAAY;gCAnQiB,IAAI,GAAG,MAAM;;;;;;;;kFAuQ9C,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"EnvironmentVariablesDropdown.vue.js","names":[],"sources":["../../../../../src/v2/features/environments/components/EnvironmentVariablesDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarTeleport } from '@scalar/components'\nimport { ScalarIconPlus } from '@scalar/icons'\nimport { POPULAR_CONTEXT_FUNCTION_KEYS } from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { onClickOutside } from '@vueuse/core'\nimport Fuse from 'fuse.js'\nimport { computed, onMounted, ref, type CSSProperties } from 'vue'\n\ntype DropdownRow =\n | { kind: 'env'; key: string; secondary: string }\n | { kind: 'context'; key: string; secondary: string }\n\nconst {\n query,\n environment,\n dropdownPosition,\n contextFunctionItems = [],\n} = defineProps<{\n query: string\n environment: XScalarEnvironment\n dropdownPosition?: { left: number; top: number }\n /** Runtime placeholders such as `{{$guid}}`, shown with environment variables */\n contextFunctionItems?: { key: string; description: string }[]\n}>()\n\nconst emit = defineEmits<{\n (e: 'select', variable: string): void\n (e: 'redirect'): void\n}>()\n\nconst isOpen = ref(true)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst selectedVariableIndex = ref(0)\n\nconst redirectToEnvironment = () => {\n emit('redirect')\n isOpen.value = false\n}\n\n/** Normalize the variables to have a name and value */\nconst normalizedVariables = computed(() =>\n environment.variables.map((v) => ({\n key: v.name,\n value: typeof v.value === 'string' ? v.value : v.value.default,\n })),\n)\n\nconst contextRows = computed((): DropdownRow[] =>\n contextFunctionItems.map((item) => ({\n kind: 'context',\n key: item.key,\n secondary: item.description,\n })),\n)\n\nconst envRows = computed((): DropdownRow[] =>\n normalizedVariables.value\n .filter(({ key, value }) => key !== '' || value !== '')\n .map(({ key, value }) => ({\n kind: 'env' as const,\n key,\n secondary: value,\n })),\n)\n\ntype FuseRow = DropdownRow & { fuseText: string }\n\nconst envFuseSource = computed((): FuseRow[] =>\n envRows.value.map((row) => ({\n ...row,\n fuseText: `${row.key} ${row.secondary}`,\n })),\n)\n\nconst contextFuseSource = computed((): FuseRow[] =>\n contextRows.value.map((row) => ({\n ...row,\n fuseText: `${row.key} ${row.secondary}`,\n })),\n)\n\nconst fuseEnv = computed(\n () =>\n new Fuse(envFuseSource.value, {\n keys: ['fuseText'],\n threshold: 0.35,\n }),\n)\n\nconst fuseContext = computed(\n () =>\n new Fuse(contextFuseSource.value, {\n keys: ['fuseText'],\n threshold: 0.35,\n }),\n)\n\nconst popularContextRows = computed((): DropdownRow[] => {\n const byKey = new Map(contextFunctionItems.map((c) => [c.key, c]))\n return POPULAR_CONTEXT_FUNCTION_KEYS.flatMap((key) => {\n const item = byKey.get(key)\n return item\n ? [\n {\n kind: 'context' as const,\n key: item.key,\n secondary: item.description,\n },\n ]\n : []\n })\n})\n\nconst DROPDOWN_LIMIT = 12\n\nconst filteredVariables = computed((): DropdownRow[] => {\n if (!query.trim()) {\n const envSlice = envRows.value.slice(-4)\n return [...envSlice, ...popularContextRows.value]\n }\n\n const q = query.trim()\n const envMatches = fuseEnv.value\n .search(q, { limit: DROPDOWN_LIMIT })\n .map((res) => {\n const { kind, key, secondary } = res.item\n return { kind, key, secondary }\n })\n\n const remaining = DROPDOWN_LIMIT - envMatches.length\n const contextMatches =\n remaining > 0\n ? fuseContext.value.search(q, { limit: remaining }).map((res) => {\n const { kind, key, secondary } = res.item\n return { kind, key, secondary }\n })\n : []\n\n return [...envMatches, ...contextMatches]\n})\n\nconst selectVariable = (variableKey: string): void => {\n emit('select', variableKey)\n}\n\nconst handleArrowKey = (direction: 'up' | 'down') => {\n const offset = direction === 'up' ? -1 : 1\n const length = filteredVariables.value.length\n\n if (length === 0) {\n return\n }\n\n selectedVariableIndex.value =\n (selectedVariableIndex.value + offset + length) % length\n}\n\nconst handleSelect = () => {\n if (selectedVariableIndex.value >= 0) {\n const selectedVariable =\n filteredVariables.value[selectedVariableIndex.value]\n if (selectedVariable) {\n selectVariable(selectedVariable.key)\n }\n }\n}\n\ndefineExpose({\n handleArrowKey,\n handleSelect,\n})\n\nonMounted(() => {\n // Reset selected index to the first item when dropdown opens\n selectedVariableIndex.value = 0\n})\n\nconst dropdownStyle = computed<CSSProperties>(() => {\n return {\n left: (dropdownPosition?.left ?? 0) + 'px',\n // Add a 5px offset from the editor\n top: (dropdownPosition?.top ?? 0) + 5 + 'px',\n }\n})\n\nonClickOutside(\n dropdownRef,\n () => {\n isOpen.value = false\n },\n { ignore: [dropdownRef] },\n)\n</script>\n<template>\n <ScalarTeleport\n v-if=\"isOpen\"\n class=\"scalar-client\">\n <div\n ref=\"dropdownRef\"\n class=\"custom-scroll z-context fixed top-0 left-0 flex max-h-[60svh] w-56 flex-col rounded border p-0.75\"\n :style=\"dropdownStyle\">\n <ul\n v-if=\"filteredVariables.length\"\n class=\"gap-1/2 flex flex-col\">\n <template\n v-for=\"(item, index) in filteredVariables\"\n :key=\"`${item.kind}-${item.key}`\">\n <li\n class=\"font-code text-xxs hover:bg-b-2 flex h-8 cursor-pointer items-center justify-between gap-1.5 rounded p-1.5 transition-colors duration-150\"\n :class=\"{ 'bg-b-2': index === selectedVariableIndex }\"\n @click=\"selectVariable(item.key)\">\n <div class=\"flex items-center gap-2 whitespace-nowrap\">\n <span\n v-if=\"item.kind === 'env'\"\n class=\"h-2.25 w-2.25 min-w-2.25 rounded-full\"\n :style=\"{\n backgroundColor: environment.color,\n }\" />\n <span\n v-else\n class=\"text-c-3 bg-b-3 flex h-4.5 min-w-4.5 items-center justify-center rounded px-0.5 font-sans text-[9px] font-semibold\">\n fn\n </span>\n {{ item.key }}\n </div>\n <span\n class=\"max-w-[9rem] overflow-hidden text-right text-ellipsis whitespace-nowrap\">\n {{ item.secondary }}\n </span>\n </li>\n </template>\n </ul>\n <ScalarButton\n v-else\n class=\"font-code text-xxs bg-b-inherit hover:bg-b-2 flex h-8 w-full justify-start gap-2 px-1.5 transition-colors duration-150\"\n variant=\"outlined\"\n @click=\"redirectToEnvironment\">\n <ScalarIconPlus class=\"size-3\" />\n Add Variable\n </ScalarButton>\n <!-- Backdrop for the dropdown -->\n <div\n class=\"bg-b-1 brightness-lifted absolute inset-0 -z-1 rounded shadow-lg\" />\n </div>\n </ScalarTeleport>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"EnvironmentVariablesDropdown.vue.js","names":[],"sources":["../../../../../src/v2/features/environments/components/EnvironmentVariablesDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarTeleport } from '@scalar/components'\nimport { ScalarIconPlus } from '@scalar/icons'\nimport { POPULAR_CONTEXT_FUNCTION_KEYS } from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { onClickOutside } from '@vueuse/core'\nimport Fuse from 'fuse.js'\nimport { computed, onMounted, ref, type CSSProperties } from 'vue'\n\ntype DropdownRow =\n | { kind: 'env'; key: string; secondary: string }\n | { kind: 'context'; key: string; secondary: string }\n\nconst {\n query,\n environment,\n dropdownPosition,\n contextFunctionItems = [],\n} = defineProps<{\n query: string\n environment?: XScalarEnvironment\n dropdownPosition?: { left: number; top: number }\n /** Runtime placeholders such as `{{$guid}}`, shown with environment variables */\n contextFunctionItems?: { key: string; description: string }[]\n}>()\n\nconst emit = defineEmits<{\n (e: 'select', variable: string): void\n (e: 'redirect'): void\n}>()\n\nconst isOpen = ref(true)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst selectedVariableIndex = ref(0)\n\nconst redirectToEnvironment = () => {\n emit('redirect')\n isOpen.value = false\n}\n\n/** Normalize the variables to have a name and value */\nconst normalizedVariables = computed(() =>\n (environment?.variables ?? []).map((v) => ({\n key: v.name,\n value: typeof v.value === 'string' ? v.value : v.value.default,\n })),\n)\n\nconst contextRows = computed((): DropdownRow[] =>\n contextFunctionItems.map((item) => ({\n kind: 'context',\n key: item.key,\n secondary: item.description,\n })),\n)\n\nconst envRows = computed((): DropdownRow[] =>\n normalizedVariables.value\n .filter(({ key, value }) => key !== '' || value !== '')\n .map(({ key, value }) => ({\n kind: 'env' as const,\n key,\n secondary: value,\n })),\n)\n\ntype FuseRow = DropdownRow & { fuseText: string }\n\nconst envFuseSource = computed((): FuseRow[] =>\n envRows.value.map((row) => ({\n ...row,\n fuseText: `${row.key} ${row.secondary}`,\n })),\n)\n\nconst contextFuseSource = computed((): FuseRow[] =>\n contextRows.value.map((row) => ({\n ...row,\n fuseText: `${row.key} ${row.secondary}`,\n })),\n)\n\nconst fuseEnv = computed(\n () =>\n new Fuse(envFuseSource.value, {\n keys: ['fuseText'],\n threshold: 0.35,\n }),\n)\n\nconst fuseContext = computed(\n () =>\n new Fuse(contextFuseSource.value, {\n keys: ['fuseText'],\n threshold: 0.35,\n }),\n)\n\nconst popularContextRows = computed((): DropdownRow[] => {\n const byKey = new Map(contextFunctionItems.map((c) => [c.key, c]))\n return POPULAR_CONTEXT_FUNCTION_KEYS.flatMap((key) => {\n const item = byKey.get(key)\n return item\n ? [\n {\n kind: 'context' as const,\n key: item.key,\n secondary: item.description,\n },\n ]\n : []\n })\n})\n\nconst DROPDOWN_LIMIT = 12\n\nconst filteredVariables = computed((): DropdownRow[] => {\n if (!query.trim()) {\n const envSlice = envRows.value.slice(-4)\n return [...envSlice, ...popularContextRows.value]\n }\n\n const q = query.trim()\n const envMatches = fuseEnv.value\n .search(q, { limit: DROPDOWN_LIMIT })\n .map((res) => {\n const { kind, key, secondary } = res.item\n return { kind, key, secondary }\n })\n\n const remaining = DROPDOWN_LIMIT - envMatches.length\n const contextMatches =\n remaining > 0\n ? fuseContext.value.search(q, { limit: remaining }).map((res) => {\n const { kind, key, secondary } = res.item\n return { kind, key, secondary }\n })\n : []\n\n return [...envMatches, ...contextMatches]\n})\n\nconst selectVariable = (variableKey: string): void => {\n emit('select', variableKey)\n}\n\nconst handleArrowKey = (direction: 'up' | 'down') => {\n const offset = direction === 'up' ? -1 : 1\n const length = filteredVariables.value.length\n\n if (length === 0) {\n return\n }\n\n selectedVariableIndex.value =\n (selectedVariableIndex.value + offset + length) % length\n}\n\nconst handleSelect = () => {\n if (selectedVariableIndex.value >= 0) {\n const selectedVariable =\n filteredVariables.value[selectedVariableIndex.value]\n if (selectedVariable) {\n selectVariable(selectedVariable.key)\n }\n }\n}\n\ndefineExpose({\n handleArrowKey,\n handleSelect,\n})\n\nonMounted(() => {\n // Reset selected index to the first item when dropdown opens\n selectedVariableIndex.value = 0\n})\n\nconst dropdownStyle = computed<CSSProperties>(() => {\n return {\n left: (dropdownPosition?.left ?? 0) + 'px',\n // Add a 5px offset from the editor\n top: (dropdownPosition?.top ?? 0) + 5 + 'px',\n }\n})\n\nonClickOutside(\n dropdownRef,\n () => {\n isOpen.value = false\n },\n { ignore: [dropdownRef] },\n)\n</script>\n<template>\n <ScalarTeleport\n v-if=\"isOpen\"\n class=\"scalar-client\">\n <div\n ref=\"dropdownRef\"\n class=\"custom-scroll z-context fixed top-0 left-0 flex max-h-[60svh] w-56 flex-col rounded border p-0.75\"\n :style=\"dropdownStyle\">\n <ul\n v-if=\"filteredVariables.length\"\n class=\"gap-1/2 flex flex-col\">\n <template\n v-for=\"(item, index) in filteredVariables\"\n :key=\"`${item.kind}-${item.key}`\">\n <li\n class=\"font-code text-xxs hover:bg-b-2 flex h-8 cursor-pointer items-center justify-between gap-1.5 rounded p-1.5 transition-colors duration-150\"\n :class=\"{ 'bg-b-2': index === selectedVariableIndex }\"\n @click=\"selectVariable(item.key)\">\n <div class=\"flex items-center gap-2 whitespace-nowrap\">\n <span\n v-if=\"item.kind === 'env'\"\n class=\"h-2.25 w-2.25 min-w-2.25 rounded-full\"\n :style=\"{\n backgroundColor: environment?.color,\n }\" />\n <span\n v-else\n class=\"text-c-3 bg-b-3 flex h-4.5 min-w-4.5 items-center justify-center rounded px-0.5 font-sans text-[9px] font-semibold\">\n fn\n </span>\n {{ item.key }}\n </div>\n <span\n class=\"max-w-[9rem] overflow-hidden text-right text-ellipsis whitespace-nowrap\">\n {{ item.secondary }}\n </span>\n </li>\n </template>\n </ul>\n <ScalarButton\n v-else\n class=\"font-code text-xxs bg-b-inherit hover:bg-b-2 flex h-8 w-full justify-start gap-2 px-1.5 transition-colors duration-150\"\n variant=\"outlined\"\n @click=\"redirectToEnvironment\">\n <ScalarIconPlus class=\"size-3\" />\n Add Variable\n </ScalarButton>\n <!-- Backdrop for the dropdown -->\n <div\n class=\"bg-b-1 brightness-lifted absolute inset-0 -z-1 rounded shadow-lg\" />\n </div>\n </ScalarTeleport>\n</template>\n"],"mappings":""} |
@@ -39,3 +39,3 @@ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, onMounted, openBlock, ref, renderList, toDisplayString, unref, withCtx } from "vue"; | ||
| /** Normalize the variables to have a name and value */ | ||
| const normalizedVariables = computed(() => __props.environment.variables.map((v) => ({ | ||
| const normalizedVariables = computed(() => (__props.environment?.variables ?? []).map((v) => ({ | ||
| key: v.name, | ||
@@ -152,3 +152,3 @@ value: typeof v.value === "string" ? v.value : v.value.default | ||
| class: "h-2.25 w-2.25 min-w-2.25 rounded-full", | ||
| style: normalizeStyle({ backgroundColor: __props.environment.color }) | ||
| style: normalizeStyle({ backgroundColor: __props.environment?.color }) | ||
| }, null, 4)) : (openBlock(), createElementBlock("span", _hoisted_4, " fn ")), createTextVNode(" " + toDisplayString(item.key), 1)]), createElementVNode("span", _hoisted_5, toDisplayString(item.secondary), 1)], 10, _hoisted_2); | ||
@@ -155,0 +155,0 @@ }), 128))])) : (openBlock(), createBlock(unref(ScalarButton), { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"EnvironmentVariablesDropdown.vue.script.js","names":[],"sources":["../../../../../src/v2/features/environments/components/EnvironmentVariablesDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarTeleport } from '@scalar/components'\nimport { ScalarIconPlus } from '@scalar/icons'\nimport { POPULAR_CONTEXT_FUNCTION_KEYS } from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { onClickOutside } from '@vueuse/core'\nimport Fuse from 'fuse.js'\nimport { computed, onMounted, ref, type CSSProperties } from 'vue'\n\ntype DropdownRow =\n | { kind: 'env'; key: string; secondary: string }\n | { kind: 'context'; key: string; secondary: string }\n\nconst {\n query,\n environment,\n dropdownPosition,\n contextFunctionItems = [],\n} = defineProps<{\n query: string\n environment: XScalarEnvironment\n dropdownPosition?: { left: number; top: number }\n /** Runtime placeholders such as `{{$guid}}`, shown with environment variables */\n contextFunctionItems?: { key: string; description: string }[]\n}>()\n\nconst emit = defineEmits<{\n (e: 'select', variable: string): void\n (e: 'redirect'): void\n}>()\n\nconst isOpen = ref(true)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst selectedVariableIndex = ref(0)\n\nconst redirectToEnvironment = () => {\n emit('redirect')\n isOpen.value = false\n}\n\n/** Normalize the variables to have a name and value */\nconst normalizedVariables = computed(() =>\n environment.variables.map((v) => ({\n key: v.name,\n value: typeof v.value === 'string' ? v.value : v.value.default,\n })),\n)\n\nconst contextRows = computed((): DropdownRow[] =>\n contextFunctionItems.map((item) => ({\n kind: 'context',\n key: item.key,\n secondary: item.description,\n })),\n)\n\nconst envRows = computed((): DropdownRow[] =>\n normalizedVariables.value\n .filter(({ key, value }) => key !== '' || value !== '')\n .map(({ key, value }) => ({\n kind: 'env' as const,\n key,\n secondary: value,\n })),\n)\n\ntype FuseRow = DropdownRow & { fuseText: string }\n\nconst envFuseSource = computed((): FuseRow[] =>\n envRows.value.map((row) => ({\n ...row,\n fuseText: `${row.key} ${row.secondary}`,\n })),\n)\n\nconst contextFuseSource = computed((): FuseRow[] =>\n contextRows.value.map((row) => ({\n ...row,\n fuseText: `${row.key} ${row.secondary}`,\n })),\n)\n\nconst fuseEnv = computed(\n () =>\n new Fuse(envFuseSource.value, {\n keys: ['fuseText'],\n threshold: 0.35,\n }),\n)\n\nconst fuseContext = computed(\n () =>\n new Fuse(contextFuseSource.value, {\n keys: ['fuseText'],\n threshold: 0.35,\n }),\n)\n\nconst popularContextRows = computed((): DropdownRow[] => {\n const byKey = new Map(contextFunctionItems.map((c) => [c.key, c]))\n return POPULAR_CONTEXT_FUNCTION_KEYS.flatMap((key) => {\n const item = byKey.get(key)\n return item\n ? [\n {\n kind: 'context' as const,\n key: item.key,\n secondary: item.description,\n },\n ]\n : []\n })\n})\n\nconst DROPDOWN_LIMIT = 12\n\nconst filteredVariables = computed((): DropdownRow[] => {\n if (!query.trim()) {\n const envSlice = envRows.value.slice(-4)\n return [...envSlice, ...popularContextRows.value]\n }\n\n const q = query.trim()\n const envMatches = fuseEnv.value\n .search(q, { limit: DROPDOWN_LIMIT })\n .map((res) => {\n const { kind, key, secondary } = res.item\n return { kind, key, secondary }\n })\n\n const remaining = DROPDOWN_LIMIT - envMatches.length\n const contextMatches =\n remaining > 0\n ? fuseContext.value.search(q, { limit: remaining }).map((res) => {\n const { kind, key, secondary } = res.item\n return { kind, key, secondary }\n })\n : []\n\n return [...envMatches, ...contextMatches]\n})\n\nconst selectVariable = (variableKey: string): void => {\n emit('select', variableKey)\n}\n\nconst handleArrowKey = (direction: 'up' | 'down') => {\n const offset = direction === 'up' ? -1 : 1\n const length = filteredVariables.value.length\n\n if (length === 0) {\n return\n }\n\n selectedVariableIndex.value =\n (selectedVariableIndex.value + offset + length) % length\n}\n\nconst handleSelect = () => {\n if (selectedVariableIndex.value >= 0) {\n const selectedVariable =\n filteredVariables.value[selectedVariableIndex.value]\n if (selectedVariable) {\n selectVariable(selectedVariable.key)\n }\n }\n}\n\ndefineExpose({\n handleArrowKey,\n handleSelect,\n})\n\nonMounted(() => {\n // Reset selected index to the first item when dropdown opens\n selectedVariableIndex.value = 0\n})\n\nconst dropdownStyle = computed<CSSProperties>(() => {\n return {\n left: (dropdownPosition?.left ?? 0) + 'px',\n // Add a 5px offset from the editor\n top: (dropdownPosition?.top ?? 0) + 5 + 'px',\n }\n})\n\nonClickOutside(\n dropdownRef,\n () => {\n isOpen.value = false\n },\n { ignore: [dropdownRef] },\n)\n</script>\n<template>\n <ScalarTeleport\n v-if=\"isOpen\"\n class=\"scalar-client\">\n <div\n ref=\"dropdownRef\"\n class=\"custom-scroll z-context fixed top-0 left-0 flex max-h-[60svh] w-56 flex-col rounded border p-0.75\"\n :style=\"dropdownStyle\">\n <ul\n v-if=\"filteredVariables.length\"\n class=\"gap-1/2 flex flex-col\">\n <template\n v-for=\"(item, index) in filteredVariables\"\n :key=\"`${item.kind}-${item.key}`\">\n <li\n class=\"font-code text-xxs hover:bg-b-2 flex h-8 cursor-pointer items-center justify-between gap-1.5 rounded p-1.5 transition-colors duration-150\"\n :class=\"{ 'bg-b-2': index === selectedVariableIndex }\"\n @click=\"selectVariable(item.key)\">\n <div class=\"flex items-center gap-2 whitespace-nowrap\">\n <span\n v-if=\"item.kind === 'env'\"\n class=\"h-2.25 w-2.25 min-w-2.25 rounded-full\"\n :style=\"{\n backgroundColor: environment.color,\n }\" />\n <span\n v-else\n class=\"text-c-3 bg-b-3 flex h-4.5 min-w-4.5 items-center justify-center rounded px-0.5 font-sans text-[9px] font-semibold\">\n fn\n </span>\n {{ item.key }}\n </div>\n <span\n class=\"max-w-[9rem] overflow-hidden text-right text-ellipsis whitespace-nowrap\">\n {{ item.secondary }}\n </span>\n </li>\n </template>\n </ul>\n <ScalarButton\n v-else\n class=\"font-code text-xxs bg-b-inherit hover:bg-b-2 flex h-8 w-full justify-start gap-2 px-1.5 transition-colors duration-150\"\n variant=\"outlined\"\n @click=\"redirectToEnvironment\">\n <ScalarIconPlus class=\"size-3\" />\n Add Variable\n </ScalarButton>\n <!-- Backdrop for the dropdown -->\n <div\n class=\"bg-b-1 brightness-lifted absolute inset-0 -z-1 rounded shadow-lg\" />\n </div>\n </ScalarTeleport>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkHA,IAAM,iBAAiB;;;;;;;;;;;EAxFvB,MAAM,OAAO;EAKb,MAAM,SAAS,IAAI,KAAI;EACvB,MAAM,cAAc,IAAwB,KAAI;EAChD,MAAM,wBAAwB,IAAI,EAAC;EAEnC,MAAM,8BAA8B;AAClC,QAAK,WAAU;AACf,UAAO,QAAQ;;;EAIjB,MAAM,sBAAsB,eAC1B,QAAA,YAAY,UAAU,KAAK,OAAO;GAChC,KAAK,EAAE;GACP,OAAO,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ,EAAE,MAAM;GACxD,EAAE,CACL;EAEA,MAAM,cAAc,eAClB,QAAA,qBAAqB,KAAK,UAAU;GAClC,MAAM;GACN,KAAK,KAAK;GACV,WAAW,KAAK;GACjB,EAAE,CACL;EAEA,MAAM,UAAU,eACd,oBAAoB,MACjB,QAAQ,EAAE,KAAK,YAAY,QAAQ,MAAM,UAAU,GAAE,CACrD,KAAK,EAAE,KAAK,aAAa;GACxB,MAAM;GACN;GACA,WAAW;GACZ,EAAE,CACP;EAIA,MAAM,gBAAgB,eACpB,QAAQ,MAAM,KAAK,SAAS;GAC1B,GAAG;GACH,UAAU,GAAG,IAAI,IAAI,GAAG,IAAI;GAC7B,EAAE,CACL;EAEA,MAAM,oBAAoB,eACxB,YAAY,MAAM,KAAK,SAAS;GAC9B,GAAG;GACH,UAAU,GAAG,IAAI,IAAI,GAAG,IAAI;GAC7B,EAAE,CACL;EAEA,MAAM,UAAU,eAEZ,IAAI,KAAK,cAAc,OAAO;GAC5B,MAAM,CAAC,WAAW;GAClB,WAAW;GACZ,CAAC,CACN;EAEA,MAAM,cAAc,eAEhB,IAAI,KAAK,kBAAkB,OAAO;GAChC,MAAM,CAAC,WAAW;GAClB,WAAW;GACZ,CAAC,CACN;EAEA,MAAM,qBAAqB,eAA8B;GACvD,MAAM,QAAQ,IAAI,IAAI,QAAA,qBAAqB,KAAK,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AACjE,UAAO,8BAA8B,SAAS,QAAQ;IACpD,MAAM,OAAO,MAAM,IAAI,IAAG;AAC1B,WAAO,OACH,CACE;KACE,MAAM;KACN,KAAK,KAAK;KACV,WAAW,KAAK;KACjB,CACH,GACA,EAAC;KACN;IACF;EAID,MAAM,oBAAoB,eAA8B;AACtD,OAAI,CAAC,QAAA,MAAM,MAAM,CAEf,QAAO,CAAC,GADS,QAAQ,MAAM,MAAM,GAAE,EAClB,GAAG,mBAAmB,MAAK;GAGlD,MAAM,IAAI,QAAA,MAAM,MAAK;GACrB,MAAM,aAAa,QAAQ,MACxB,OAAO,GAAG,EAAE,OAAO,gBAAgB,CAAA,CACnC,KAAK,QAAQ;IACZ,MAAM,EAAE,MAAM,KAAK,cAAc,IAAI;AACrC,WAAO;KAAE;KAAM;KAAK;KAAU;KAC/B;GAEH,MAAM,YAAY,iBAAiB,WAAW;GAC9C,MAAM,iBACJ,YAAY,IACR,YAAY,MAAM,OAAO,GAAG,EAAE,OAAO,WAAW,CAAC,CAAC,KAAK,QAAQ;IAC7D,MAAM,EAAE,MAAM,KAAK,cAAc,IAAI;AACrC,WAAO;KAAE;KAAM;KAAK;KAAU;KAC/B,GACD,EAAC;AAEP,UAAO,CAAC,GAAG,YAAY,GAAG,eAAc;IACzC;EAED,MAAM,kBAAkB,gBAA8B;AACpD,QAAK,UAAU,YAAW;;EAG5B,MAAM,kBAAkB,cAA6B;GACnD,MAAM,SAAS,cAAc,OAAO,KAAK;GACzC,MAAM,SAAS,kBAAkB,MAAM;AAEvC,OAAI,WAAW,EACb;AAGF,yBAAsB,SACnB,sBAAsB,QAAQ,SAAS,UAAU;;EAGtD,MAAM,qBAAqB;AACzB,OAAI,sBAAsB,SAAS,GAAG;IACpC,MAAM,mBACJ,kBAAkB,MAAM,sBAAsB;AAChD,QAAI,iBACF,gBAAe,iBAAiB,IAAG;;;AAKzC,WAAa;GACX;GACA;GACD,CAAA;AAED,kBAAgB;AAEd,yBAAsB,QAAQ;IAC/B;EAED,MAAM,gBAAgB,eAA8B;AAClD,UAAO;IACL,OAAO,QAAA,kBAAkB,QAAQ,KAAK;IAEtC,MAAM,QAAA,kBAAkB,OAAO,KAAK,IAAI;IAC1C;IACD;AAED,iBACE,mBACM;AACJ,UAAO,QAAQ;KAEjB,EAAE,QAAQ,CAAC,YAAY,EAAE,CAC3B;;UAIU,OAAA,SAAA,WAAA,EADR,YAkDiB,MAAA,eAAA,EAAA;;IAhDf,OAAM;;2BA+CA,CA9CN,mBA8CM,OAAA;cA7CA;KAAJ,KAAI;KACJ,OAAM;KACL,OAAK,eAAE,cAAA,MAAa;QAEb,kBAAA,MAAkB,UAAA,WAAA,EAD1B,mBA8BK,MA9BL,YA8BK,EAAA,UAAA,KAAA,EA3BH,mBA0BW,UAAA,MAAA,WAzBe,kBAAA,QAAhB,MAAM,UAAK;yBAEnB,mBAsBK,MAAA;cAvBI,KAAK,KAAI,GAAI,KAAK;MAEzB,OAAK,eAAA,CAAC,6IAA2I,EAAA,UAC7H,UAAU,sBAAA,OAAqB,CAAA,CAAA;MAClD,UAAK,WAAE,eAAe,KAAK,IAAG;SAC/B,mBAaM,OAbN,YAaM,CAXI,KAAK,SAAI,SAAA,WAAA,EADjB,mBAKO,QAAA;;MAHL,OAAM;MACL,OAAK,eAAA,EAAA,iBAAuC,QAAA,YAAY,OAAA,CAAA;kCAG3D,mBAIO,QAJP,YAE6H,OAE7H,GAAA,gBAAO,MACP,gBAAG,KAAK,IAAG,EAAA,EAAA,CAAA,CAAA,EAEb,mBAGO,QAHP,YAGO,gBADF,KAAK,UAAS,EAAA,EAAA,CAAA,EAAA,IAAA,WAAA;iCAKzB,YAOe,MAAA,aAAA,EAAA;;KALb,OAAM;KACN,SAAQ;KACP,SAAO;;4BACyB,CAAjC,YAAiC,MAAA,eAAA,EAAA,EAAjB,OAAM,UAAQ,CAAA,EAAA,OAAA,OAAA,OAAA,KAAA,gBAAG,kBAEnC,GAAA,EAAA,CAAA;;mCAEA,mBAC6E,OAAA,EAA3E,OAAM,oEAAkE,EAAA,MAAA,GAAA,EAAA,EAAA,EAAA,CAAA,CAAA"} | ||
| {"version":3,"file":"EnvironmentVariablesDropdown.vue.script.js","names":[],"sources":["../../../../../src/v2/features/environments/components/EnvironmentVariablesDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton, ScalarTeleport } from '@scalar/components'\nimport { ScalarIconPlus } from '@scalar/icons'\nimport { POPULAR_CONTEXT_FUNCTION_KEYS } from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { onClickOutside } from '@vueuse/core'\nimport Fuse from 'fuse.js'\nimport { computed, onMounted, ref, type CSSProperties } from 'vue'\n\ntype DropdownRow =\n | { kind: 'env'; key: string; secondary: string }\n | { kind: 'context'; key: string; secondary: string }\n\nconst {\n query,\n environment,\n dropdownPosition,\n contextFunctionItems = [],\n} = defineProps<{\n query: string\n environment?: XScalarEnvironment\n dropdownPosition?: { left: number; top: number }\n /** Runtime placeholders such as `{{$guid}}`, shown with environment variables */\n contextFunctionItems?: { key: string; description: string }[]\n}>()\n\nconst emit = defineEmits<{\n (e: 'select', variable: string): void\n (e: 'redirect'): void\n}>()\n\nconst isOpen = ref(true)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst selectedVariableIndex = ref(0)\n\nconst redirectToEnvironment = () => {\n emit('redirect')\n isOpen.value = false\n}\n\n/** Normalize the variables to have a name and value */\nconst normalizedVariables = computed(() =>\n (environment?.variables ?? []).map((v) => ({\n key: v.name,\n value: typeof v.value === 'string' ? v.value : v.value.default,\n })),\n)\n\nconst contextRows = computed((): DropdownRow[] =>\n contextFunctionItems.map((item) => ({\n kind: 'context',\n key: item.key,\n secondary: item.description,\n })),\n)\n\nconst envRows = computed((): DropdownRow[] =>\n normalizedVariables.value\n .filter(({ key, value }) => key !== '' || value !== '')\n .map(({ key, value }) => ({\n kind: 'env' as const,\n key,\n secondary: value,\n })),\n)\n\ntype FuseRow = DropdownRow & { fuseText: string }\n\nconst envFuseSource = computed((): FuseRow[] =>\n envRows.value.map((row) => ({\n ...row,\n fuseText: `${row.key} ${row.secondary}`,\n })),\n)\n\nconst contextFuseSource = computed((): FuseRow[] =>\n contextRows.value.map((row) => ({\n ...row,\n fuseText: `${row.key} ${row.secondary}`,\n })),\n)\n\nconst fuseEnv = computed(\n () =>\n new Fuse(envFuseSource.value, {\n keys: ['fuseText'],\n threshold: 0.35,\n }),\n)\n\nconst fuseContext = computed(\n () =>\n new Fuse(contextFuseSource.value, {\n keys: ['fuseText'],\n threshold: 0.35,\n }),\n)\n\nconst popularContextRows = computed((): DropdownRow[] => {\n const byKey = new Map(contextFunctionItems.map((c) => [c.key, c]))\n return POPULAR_CONTEXT_FUNCTION_KEYS.flatMap((key) => {\n const item = byKey.get(key)\n return item\n ? [\n {\n kind: 'context' as const,\n key: item.key,\n secondary: item.description,\n },\n ]\n : []\n })\n})\n\nconst DROPDOWN_LIMIT = 12\n\nconst filteredVariables = computed((): DropdownRow[] => {\n if (!query.trim()) {\n const envSlice = envRows.value.slice(-4)\n return [...envSlice, ...popularContextRows.value]\n }\n\n const q = query.trim()\n const envMatches = fuseEnv.value\n .search(q, { limit: DROPDOWN_LIMIT })\n .map((res) => {\n const { kind, key, secondary } = res.item\n return { kind, key, secondary }\n })\n\n const remaining = DROPDOWN_LIMIT - envMatches.length\n const contextMatches =\n remaining > 0\n ? fuseContext.value.search(q, { limit: remaining }).map((res) => {\n const { kind, key, secondary } = res.item\n return { kind, key, secondary }\n })\n : []\n\n return [...envMatches, ...contextMatches]\n})\n\nconst selectVariable = (variableKey: string): void => {\n emit('select', variableKey)\n}\n\nconst handleArrowKey = (direction: 'up' | 'down') => {\n const offset = direction === 'up' ? -1 : 1\n const length = filteredVariables.value.length\n\n if (length === 0) {\n return\n }\n\n selectedVariableIndex.value =\n (selectedVariableIndex.value + offset + length) % length\n}\n\nconst handleSelect = () => {\n if (selectedVariableIndex.value >= 0) {\n const selectedVariable =\n filteredVariables.value[selectedVariableIndex.value]\n if (selectedVariable) {\n selectVariable(selectedVariable.key)\n }\n }\n}\n\ndefineExpose({\n handleArrowKey,\n handleSelect,\n})\n\nonMounted(() => {\n // Reset selected index to the first item when dropdown opens\n selectedVariableIndex.value = 0\n})\n\nconst dropdownStyle = computed<CSSProperties>(() => {\n return {\n left: (dropdownPosition?.left ?? 0) + 'px',\n // Add a 5px offset from the editor\n top: (dropdownPosition?.top ?? 0) + 5 + 'px',\n }\n})\n\nonClickOutside(\n dropdownRef,\n () => {\n isOpen.value = false\n },\n { ignore: [dropdownRef] },\n)\n</script>\n<template>\n <ScalarTeleport\n v-if=\"isOpen\"\n class=\"scalar-client\">\n <div\n ref=\"dropdownRef\"\n class=\"custom-scroll z-context fixed top-0 left-0 flex max-h-[60svh] w-56 flex-col rounded border p-0.75\"\n :style=\"dropdownStyle\">\n <ul\n v-if=\"filteredVariables.length\"\n class=\"gap-1/2 flex flex-col\">\n <template\n v-for=\"(item, index) in filteredVariables\"\n :key=\"`${item.kind}-${item.key}`\">\n <li\n class=\"font-code text-xxs hover:bg-b-2 flex h-8 cursor-pointer items-center justify-between gap-1.5 rounded p-1.5 transition-colors duration-150\"\n :class=\"{ 'bg-b-2': index === selectedVariableIndex }\"\n @click=\"selectVariable(item.key)\">\n <div class=\"flex items-center gap-2 whitespace-nowrap\">\n <span\n v-if=\"item.kind === 'env'\"\n class=\"h-2.25 w-2.25 min-w-2.25 rounded-full\"\n :style=\"{\n backgroundColor: environment?.color,\n }\" />\n <span\n v-else\n class=\"text-c-3 bg-b-3 flex h-4.5 min-w-4.5 items-center justify-center rounded px-0.5 font-sans text-[9px] font-semibold\">\n fn\n </span>\n {{ item.key }}\n </div>\n <span\n class=\"max-w-[9rem] overflow-hidden text-right text-ellipsis whitespace-nowrap\">\n {{ item.secondary }}\n </span>\n </li>\n </template>\n </ul>\n <ScalarButton\n v-else\n class=\"font-code text-xxs bg-b-inherit hover:bg-b-2 flex h-8 w-full justify-start gap-2 px-1.5 transition-colors duration-150\"\n variant=\"outlined\"\n @click=\"redirectToEnvironment\">\n <ScalarIconPlus class=\"size-3\" />\n Add Variable\n </ScalarButton>\n <!-- Backdrop for the dropdown -->\n <div\n class=\"bg-b-1 brightness-lifted absolute inset-0 -z-1 rounded shadow-lg\" />\n </div>\n </ScalarTeleport>\n</template>\n"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"CookiesTable.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/global-cookies/components/CookiesTable.vue"],"names":[],"mappings":"AAuPA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AAYxG,KAAK,WAAW,GAAG;IACf,OAAO,EAAE,aAAa,EAAE,CAAA;IACxB,QAAQ,EAAE,iBAAiB,CAAA;CAC5B,GAAG,cAAc,CAAC;AA8erB,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} | ||
| {"version":3,"file":"CookiesTable.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/global-cookies/components/CookiesTable.vue"],"names":[],"mappings":"AAyPA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AAYxG,KAAK,WAAW,GAAG;IACf,OAAO,EAAE,aAAa,EAAE,CAAA;IACxB,QAAQ,EAAE,iBAAiB,CAAA;CAC5B,GAAG,cAAc,CAAC;AAkfrB,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"} |
@@ -5,3 +5,3 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_export-helper.js"; | ||
| //#region src/v2/features/global-cookies/components/CookiesTable.vue | ||
| var CookiesTable_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CookiesTable_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-ddfccc08"]]); | ||
| var CookiesTable_default = /* @__PURE__ */ _plugin_vue_export_helper_default(CookiesTable_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-2f13118d"]]); | ||
| //#endregion | ||
@@ -8,0 +8,0 @@ export { CookiesTable_default as default }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"CookiesTable.vue.js","names":[],"sources":["../../../../../src/v2/features/global-cookies/components/CookiesTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { ScalarIconTrash } from '@scalar/icons'\nimport type {\n CollectionType,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport { computed } from 'vue'\n\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableCell,\n DataTableCheckbox,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nconst { cookies, eventBus, collectionType } = defineProps<\n {\n cookies: XScalarCookie[]\n eventBus: WorkspaceEventBus\n } & CollectionType\n>()\n\n/** Column widths: Enabled checkbox, Name, Value, Domain, Actions (delete button) */\nconst COLUMNS = ['32px', '1fr', '1fr', '1fr', '36px']\n\n/** Adds an empty row at the end for creating new cookies */\nconst displayRows = computed<\n {\n name: string\n value: string\n domain: string\n isDisabled: boolean\n }[]\n>(() => {\n /** Normalize the cookies to have name, value, and domain */\n const cookieRows = cookies.map((cookie) => ({\n name: cookie.name,\n value: cookie.value,\n domain: cookie.domain ?? '',\n isDisabled: cookie.isDisabled ?? false,\n }))\n\n const lastCookie = cookies.at(-1)\n const hasContentInLastRow =\n lastCookie &&\n (lastCookie.name !== '' ||\n lastCookie.value !== '' ||\n lastCookie.domain !== '')\n\n // Add the extra row at the end\n if (!lastCookie || hasContentInLastRow) {\n return [\n ...cookieRows,\n { name: '', value: '', domain: '', isDisabled: true },\n ]\n }\n\n return cookieRows\n})\n\n/** Updates an existing cookie or creates a new one */\nconst handleCookieChange = (\n name: string,\n value: string,\n domain: string,\n isDisabled: boolean,\n index: number,\n): void => {\n const isNewCookie = index >= cookies.length\n\n /**\n * Do not allow adding a new cookie with an empty name on the last row,\n * we allow it on other rows as it will delete the row\n */\n if (!name && isNewCookie) {\n return\n }\n\n // Adding a new cookie\n if (index >= cookies.length) {\n eventBus.emit('cookie:upsert:cookie', {\n payload: { name, value, domain, isDisabled: false },\n collectionType,\n })\n return\n }\n\n // Updating existing cookie\n eventBus.emit('cookie:upsert:cookie', {\n payload: { name, value, domain, isDisabled },\n collectionType,\n index,\n })\n}\n\n/** Deletes a cookie by index */\nconst handleCookieDelete = (index: number): void =>\n eventBus.emit('cookie:delete:cookie', {\n cookieName: cookies[index]?.name ?? '',\n index,\n collectionType,\n })\n</script>\n<template>\n <!-- Cookies table -->\n <DataTable\n class=\"group/table data-table h-min flex-1 rounded border border-t-0\"\n :columns=\"COLUMNS\">\n <!-- Accessibility header row -->\n <DataTableRow class=\"sr-only !block\">\n <DataTableHeader>Enabled</DataTableHeader>\n <DataTableHeader>Name</DataTableHeader>\n <DataTableHeader>Value</DataTableHeader>\n <DataTableHeader>Domain</DataTableHeader>\n <DataTableHeader>Actions</DataTableHeader>\n </DataTableRow>\n\n <!-- Cookie rows -->\n <DataTableRow\n v-for=\"(row, index) in displayRows\"\n :key=\"index\"\n class=\"group/row\">\n <!-- Enabled checkbox -->\n <DataTableCheckbox\n class=\"!border-r\"\n :modelValue=\"!row.isDisabled\"\n @update:modelValue=\"\n (value) =>\n handleCookieChange(row.name, row.value, row.domain, !value, index)\n \" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Name\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.name\"\n placeholder=\"Name\"\n @update:modelValue=\"\n (name) =>\n handleCookieChange(\n name,\n row.value,\n row.domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Value\"\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.value\"\n placeholder=\"Value\"\n @update:modelValue=\"\n (value) =>\n handleCookieChange(\n row.name,\n value,\n row.domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Domain -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Domain\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.domain\"\n placeholder=\"Domain\"\n @update:modelValue=\"\n (domain) =>\n handleCookieChange(\n row.name,\n row.value,\n domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Delete button -->\n <DataTableCell class=\"flex items-center justify-center\">\n <ScalarButton\n v-if=\"index < cookies.length\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 hidden h-fit rounded p-1 group-focus-within:flex group-hover/row:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"handleCookieDelete(index)\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n </DataTableCell>\n </DataTableRow>\n </DataTable>\n</template>\n<style scoped>\n:deep(.cm-editor) {\n padding: 0;\n}\n:deep(.cm-content) {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n width: 100%;\n}\n:deep(.cm-content):has(.cm-pill) {\n padding: 5px 8px;\n}\n:deep(.cm-content .cm-pill:not(:last-of-type)) {\n margin-right: 0.5px;\n}\n:deep(.cm-content .cm-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n:deep(.cm-line) {\n overflow: hidden;\n padding: 0;\n text-overflow: ellipsis;\n}\n</style>\n"],"mappings":""} | ||
| {"version":3,"file":"CookiesTable.vue.js","names":[],"sources":["../../../../../src/v2/features/global-cookies/components/CookiesTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { ScalarIconTrash } from '@scalar/icons'\nimport type {\n CollectionType,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport { computed } from 'vue'\n\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableCell,\n DataTableCheckbox,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nconst { cookies, eventBus, collectionType } = defineProps<\n {\n cookies: XScalarCookie[]\n eventBus: WorkspaceEventBus\n } & CollectionType\n>()\n\n/** Column widths: Enabled checkbox, Name, Value, Domain, Actions (delete button) */\nconst COLUMNS = ['32px', '1fr', '1fr', '1fr', '36px']\n\n/** Adds an empty row at the end for creating new cookies */\nconst displayRows = computed<\n {\n name: string\n value: string\n domain: string\n isDisabled: boolean\n }[]\n>(() => {\n /** Normalize the cookies to have name, value, and domain */\n const cookieRows = cookies.map((cookie) => ({\n name: cookie.name,\n value: cookie.value,\n domain: cookie.domain ?? '',\n isDisabled: cookie.isDisabled ?? false,\n }))\n\n const lastCookie = cookies.at(-1)\n const hasContentInLastRow =\n lastCookie &&\n (lastCookie.name !== '' ||\n lastCookie.value !== '' ||\n lastCookie.domain !== '')\n\n // Add the extra row at the end\n if (!lastCookie || hasContentInLastRow) {\n return [\n ...cookieRows,\n { name: '', value: '', domain: '', isDisabled: true },\n ]\n }\n\n return cookieRows\n})\n\n/** Updates an existing cookie or creates a new one */\nconst handleCookieChange = (\n name: string,\n value: string,\n domain: string,\n isDisabled: boolean,\n index: number,\n): void => {\n const isNewCookie = index >= cookies.length\n\n /**\n * Do not allow adding a new cookie with an empty name on the last row,\n * we allow it on other rows as it will delete the row\n */\n if (!name && isNewCookie) {\n return\n }\n\n // Adding a new cookie\n if (index >= cookies.length) {\n eventBus.emit('cookie:upsert:cookie', {\n payload: { name, value, domain, isDisabled: false },\n collectionType,\n })\n return\n }\n\n // Updating existing cookie\n eventBus.emit('cookie:upsert:cookie', {\n payload: { name, value, domain, isDisabled },\n collectionType,\n index,\n })\n}\n\n/** Deletes a cookie by index */\nconst handleCookieDelete = (index: number): void =>\n eventBus.emit('cookie:delete:cookie', {\n cookieName: cookies[index]?.name ?? '',\n index,\n collectionType,\n })\n</script>\n<template>\n <!-- Cookies table -->\n <DataTable\n class=\"group/table data-table h-min flex-1 rounded border border-t-0\"\n :columns=\"COLUMNS\">\n <!-- Accessibility header row -->\n <DataTableRow class=\"sr-only !block\">\n <DataTableHeader>Enabled</DataTableHeader>\n <DataTableHeader>Name</DataTableHeader>\n <DataTableHeader>Value</DataTableHeader>\n <DataTableHeader>Domain</DataTableHeader>\n <DataTableHeader>Actions</DataTableHeader>\n </DataTableRow>\n\n <!-- Cookie rows -->\n <DataTableRow\n v-for=\"(row, index) in displayRows\"\n :key=\"index\"\n class=\"group/row\">\n <!-- Enabled checkbox -->\n <DataTableCheckbox\n class=\"!border-r\"\n :modelValue=\"!row.isDisabled\"\n @update:modelValue=\"\n (value) =>\n handleCookieChange(row.name, row.value, row.domain, !value, index)\n \" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Name\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.name\"\n placeholder=\"Name\"\n @update:modelValue=\"\n (name) =>\n handleCookieChange(\n name,\n row.value,\n row.domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Value\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.value\"\n placeholder=\"Value\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n handleCookieChange(\n row.name,\n value,\n row.domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Domain -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Domain\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.domain\"\n placeholder=\"Domain\"\n @update:modelValue=\"\n (domain) =>\n handleCookieChange(\n row.name,\n row.value,\n domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Delete button -->\n <DataTableCell class=\"flex items-center justify-center\">\n <ScalarButton\n v-if=\"index < cookies.length\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 hidden h-fit rounded p-1 group-focus-within:flex group-hover/row:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"handleCookieDelete(index)\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n </DataTableCell>\n </DataTableRow>\n </DataTable>\n</template>\n<style scoped>\n:deep(.cm-editor) {\n padding: 0;\n}\n:deep(.cm-content) {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n width: 100%;\n}\n:deep(.cm-content):has(.cm-pill) {\n padding: 5px 8px;\n}\n:deep(.cm-content .cm-pill:not(:last-of-type)) {\n margin-right: 0.5px;\n}\n:deep(.cm-content .cm-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n:deep(.cm-line) {\n overflow: hidden;\n padding: 0;\n text-overflow: ellipsis;\n}\n</style>\n"],"mappings":""} |
@@ -139,2 +139,3 @@ import CodeInput_default from "../../../components/code-input/CodeInput.vue.js"; | ||
| "aria-label": "Cookie Value", | ||
| disableCloseBrackets: "", | ||
| disableTabIndent: "", | ||
@@ -145,2 +146,3 @@ environment: void 0, | ||
| placeholder: "Value", | ||
| withFakeData: "", | ||
| "onUpdate:modelValue": (value) => handleCookieChange(row.name, value, row.domain, row.isDisabled, index) | ||
@@ -147,0 +149,0 @@ }, null, 8, ["modelValue", "onUpdate:modelValue"])]), |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"CookiesTable.vue.script.js","names":[],"sources":["../../../../../src/v2/features/global-cookies/components/CookiesTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { ScalarIconTrash } from '@scalar/icons'\nimport type {\n CollectionType,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport { computed } from 'vue'\n\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableCell,\n DataTableCheckbox,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nconst { cookies, eventBus, collectionType } = defineProps<\n {\n cookies: XScalarCookie[]\n eventBus: WorkspaceEventBus\n } & CollectionType\n>()\n\n/** Column widths: Enabled checkbox, Name, Value, Domain, Actions (delete button) */\nconst COLUMNS = ['32px', '1fr', '1fr', '1fr', '36px']\n\n/** Adds an empty row at the end for creating new cookies */\nconst displayRows = computed<\n {\n name: string\n value: string\n domain: string\n isDisabled: boolean\n }[]\n>(() => {\n /** Normalize the cookies to have name, value, and domain */\n const cookieRows = cookies.map((cookie) => ({\n name: cookie.name,\n value: cookie.value,\n domain: cookie.domain ?? '',\n isDisabled: cookie.isDisabled ?? false,\n }))\n\n const lastCookie = cookies.at(-1)\n const hasContentInLastRow =\n lastCookie &&\n (lastCookie.name !== '' ||\n lastCookie.value !== '' ||\n lastCookie.domain !== '')\n\n // Add the extra row at the end\n if (!lastCookie || hasContentInLastRow) {\n return [\n ...cookieRows,\n { name: '', value: '', domain: '', isDisabled: true },\n ]\n }\n\n return cookieRows\n})\n\n/** Updates an existing cookie or creates a new one */\nconst handleCookieChange = (\n name: string,\n value: string,\n domain: string,\n isDisabled: boolean,\n index: number,\n): void => {\n const isNewCookie = index >= cookies.length\n\n /**\n * Do not allow adding a new cookie with an empty name on the last row,\n * we allow it on other rows as it will delete the row\n */\n if (!name && isNewCookie) {\n return\n }\n\n // Adding a new cookie\n if (index >= cookies.length) {\n eventBus.emit('cookie:upsert:cookie', {\n payload: { name, value, domain, isDisabled: false },\n collectionType,\n })\n return\n }\n\n // Updating existing cookie\n eventBus.emit('cookie:upsert:cookie', {\n payload: { name, value, domain, isDisabled },\n collectionType,\n index,\n })\n}\n\n/** Deletes a cookie by index */\nconst handleCookieDelete = (index: number): void =>\n eventBus.emit('cookie:delete:cookie', {\n cookieName: cookies[index]?.name ?? '',\n index,\n collectionType,\n })\n</script>\n<template>\n <!-- Cookies table -->\n <DataTable\n class=\"group/table data-table h-min flex-1 rounded border border-t-0\"\n :columns=\"COLUMNS\">\n <!-- Accessibility header row -->\n <DataTableRow class=\"sr-only !block\">\n <DataTableHeader>Enabled</DataTableHeader>\n <DataTableHeader>Name</DataTableHeader>\n <DataTableHeader>Value</DataTableHeader>\n <DataTableHeader>Domain</DataTableHeader>\n <DataTableHeader>Actions</DataTableHeader>\n </DataTableRow>\n\n <!-- Cookie rows -->\n <DataTableRow\n v-for=\"(row, index) in displayRows\"\n :key=\"index\"\n class=\"group/row\">\n <!-- Enabled checkbox -->\n <DataTableCheckbox\n class=\"!border-r\"\n :modelValue=\"!row.isDisabled\"\n @update:modelValue=\"\n (value) =>\n handleCookieChange(row.name, row.value, row.domain, !value, index)\n \" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Name\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.name\"\n placeholder=\"Name\"\n @update:modelValue=\"\n (name) =>\n handleCookieChange(\n name,\n row.value,\n row.domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Value\"\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.value\"\n placeholder=\"Value\"\n @update:modelValue=\"\n (value) =>\n handleCookieChange(\n row.name,\n value,\n row.domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Domain -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Domain\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.domain\"\n placeholder=\"Domain\"\n @update:modelValue=\"\n (domain) =>\n handleCookieChange(\n row.name,\n row.value,\n domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Delete button -->\n <DataTableCell class=\"flex items-center justify-center\">\n <ScalarButton\n v-if=\"index < cookies.length\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 hidden h-fit rounded p-1 group-focus-within:flex group-hover/row:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"handleCookieDelete(index)\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n </DataTableCell>\n </DataTableRow>\n </DataTable>\n</template>\n<style scoped>\n:deep(.cm-editor) {\n padding: 0;\n}\n:deep(.cm-content) {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n width: 100%;\n}\n:deep(.cm-content):has(.cm-pill) {\n padding: 5px 8px;\n}\n:deep(.cm-content .cm-pill:not(:last-of-type)) {\n margin-right: 0.5px;\n}\n:deep(.cm-content .cm-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n:deep(.cm-line) {\n overflow: hidden;\n padding: 0;\n text-overflow: ellipsis;\n}\n</style>\n"],"mappings":"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"} | ||
| {"version":3,"file":"CookiesTable.vue.script.js","names":[],"sources":["../../../../../src/v2/features/global-cookies/components/CookiesTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components'\nimport { ScalarIconTrash } from '@scalar/icons'\nimport type {\n CollectionType,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport { computed } from 'vue'\n\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableCell,\n DataTableCheckbox,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\n\nconst { cookies, eventBus, collectionType } = defineProps<\n {\n cookies: XScalarCookie[]\n eventBus: WorkspaceEventBus\n } & CollectionType\n>()\n\n/** Column widths: Enabled checkbox, Name, Value, Domain, Actions (delete button) */\nconst COLUMNS = ['32px', '1fr', '1fr', '1fr', '36px']\n\n/** Adds an empty row at the end for creating new cookies */\nconst displayRows = computed<\n {\n name: string\n value: string\n domain: string\n isDisabled: boolean\n }[]\n>(() => {\n /** Normalize the cookies to have name, value, and domain */\n const cookieRows = cookies.map((cookie) => ({\n name: cookie.name,\n value: cookie.value,\n domain: cookie.domain ?? '',\n isDisabled: cookie.isDisabled ?? false,\n }))\n\n const lastCookie = cookies.at(-1)\n const hasContentInLastRow =\n lastCookie &&\n (lastCookie.name !== '' ||\n lastCookie.value !== '' ||\n lastCookie.domain !== '')\n\n // Add the extra row at the end\n if (!lastCookie || hasContentInLastRow) {\n return [\n ...cookieRows,\n { name: '', value: '', domain: '', isDisabled: true },\n ]\n }\n\n return cookieRows\n})\n\n/** Updates an existing cookie or creates a new one */\nconst handleCookieChange = (\n name: string,\n value: string,\n domain: string,\n isDisabled: boolean,\n index: number,\n): void => {\n const isNewCookie = index >= cookies.length\n\n /**\n * Do not allow adding a new cookie with an empty name on the last row,\n * we allow it on other rows as it will delete the row\n */\n if (!name && isNewCookie) {\n return\n }\n\n // Adding a new cookie\n if (index >= cookies.length) {\n eventBus.emit('cookie:upsert:cookie', {\n payload: { name, value, domain, isDisabled: false },\n collectionType,\n })\n return\n }\n\n // Updating existing cookie\n eventBus.emit('cookie:upsert:cookie', {\n payload: { name, value, domain, isDisabled },\n collectionType,\n index,\n })\n}\n\n/** Deletes a cookie by index */\nconst handleCookieDelete = (index: number): void =>\n eventBus.emit('cookie:delete:cookie', {\n cookieName: cookies[index]?.name ?? '',\n index,\n collectionType,\n })\n</script>\n<template>\n <!-- Cookies table -->\n <DataTable\n class=\"group/table data-table h-min flex-1 rounded border border-t-0\"\n :columns=\"COLUMNS\">\n <!-- Accessibility header row -->\n <DataTableRow class=\"sr-only !block\">\n <DataTableHeader>Enabled</DataTableHeader>\n <DataTableHeader>Name</DataTableHeader>\n <DataTableHeader>Value</DataTableHeader>\n <DataTableHeader>Domain</DataTableHeader>\n <DataTableHeader>Actions</DataTableHeader>\n </DataTableRow>\n\n <!-- Cookie rows -->\n <DataTableRow\n v-for=\"(row, index) in displayRows\"\n :key=\"index\"\n class=\"group/row\">\n <!-- Enabled checkbox -->\n <DataTableCheckbox\n class=\"!border-r\"\n :modelValue=\"!row.isDisabled\"\n @update:modelValue=\"\n (value) =>\n handleCookieChange(row.name, row.value, row.domain, !value, index)\n \" />\n\n <!-- Name -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Name\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.name\"\n placeholder=\"Name\"\n @update:modelValue=\"\n (name) =>\n handleCookieChange(\n name,\n row.value,\n row.domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Value -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Value\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.value\"\n placeholder=\"Value\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n handleCookieChange(\n row.name,\n value,\n row.domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Domain -->\n <DataTableCell>\n <CodeInput\n aria-label=\"Cookie Domain\"\n disableCloseBrackets\n disableTabIndent\n :environment=\"undefined\"\n lineWrapping\n :modelValue=\"row.domain\"\n placeholder=\"Domain\"\n @update:modelValue=\"\n (domain) =>\n handleCookieChange(\n row.name,\n row.value,\n domain,\n row.isDisabled,\n index,\n )\n \" />\n </DataTableCell>\n\n <!-- Delete button -->\n <DataTableCell class=\"flex items-center justify-center\">\n <ScalarButton\n v-if=\"index < cookies.length\"\n class=\"text-c-2 hover:text-c-1 hover:bg-b-2 hidden h-fit rounded p-1 group-focus-within:flex group-hover/row:flex\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"handleCookieDelete(index)\">\n <ScalarIconTrash class=\"size-3.5\" />\n </ScalarButton>\n </DataTableCell>\n </DataTableRow>\n </DataTable>\n</template>\n<style scoped>\n:deep(.cm-editor) {\n padding: 0;\n}\n:deep(.cm-content) {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-family: var(--scalar-font);\n font-size: var(--scalar-small);\n padding: 5px 8px;\n width: 100%;\n}\n:deep(.cm-content):has(.cm-pill) {\n padding: 5px 8px;\n}\n:deep(.cm-content .cm-pill:not(:last-of-type)) {\n margin-right: 0.5px;\n}\n:deep(.cm-content .cm-pill:not(:first-of-type)) {\n margin-left: 0.5px;\n}\n:deep(.cm-line) {\n overflow: hidden;\n padding: 0;\n text-overflow: ellipsis;\n}\n</style>\n"],"mappings":"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"} |
@@ -7,4 +7,4 @@ import { type ModalState } from '@scalar/components'; | ||
| import { type RoutePayload } from '../../../../v2/features/modal/helpers/resolve-route-parameters.js'; | ||
| import type { ApiClientModalOptions } from '../../../../v2/features/modal/helpers/types'; | ||
| type CreateApiClientModalOptions = { | ||
| import type { ApiClientOptions } from '../../../../v2/types/options'; | ||
| type CreateApiClientOptions = { | ||
| /** Element to mount the client modal to. */ | ||
@@ -24,3 +24,3 @@ el: HTMLElement | null; | ||
| /** Subset of the configuration options for the modal, if you want it to be reactive ensure its a ref */ | ||
| options?: MaybeRefOrGetter<ApiClientModalOptions>; | ||
| options?: MaybeRefOrGetter<ApiClientOptions>; | ||
| }; | ||
@@ -32,3 +32,3 @@ export type ApiClientModal = { | ||
| route: (payload: RoutePayload) => void; | ||
| updateOptions: (nextOptions: ApiClientModalOptions, overwrite?: boolean) => void; | ||
| updateOptions: (nextOptions: ApiClientOptions, overwrite?: boolean) => void; | ||
| modalState: ModalState; | ||
@@ -42,4 +42,4 @@ }; | ||
| */ | ||
| export declare const createApiClientModal: ({ el, eventBus, mountOnInitialize, plugins, workspaceStore, options, }: CreateApiClientModalOptions) => ApiClientModal; | ||
| export declare const createApiClientModal: ({ el, eventBus, mountOnInitialize, plugins, workspaceStore, options, }: CreateApiClientOptions) => ApiClientModal; | ||
| export {}; | ||
| //# sourceMappingURL=create-api-client-modal.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create-api-client-modal.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,oBAAoB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,KAAK,iBAAiB,EAA2B,MAAM,gCAAgC,CAAA;AAChG,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAA6D,MAAM,KAAK,CAAA;AAEhH,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,sDAAsD,CAAA;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,mCAAmC,CAAA;AAIxG,KAAK,2BAA2B,GAAG;IACjC,4CAA4C;IAC5C,EAAE,EAAE,WAAW,GAAG,IAAI,CAAA;IACtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,6DAA6D;IAC7D,cAAc,EAAE,cAAc,CAAA;IAC9B,iDAAiD;IACjD,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB,wGAAwG;IACxG,OAAO,CAAC,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;CAClD,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,KAAK,EAAE,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/C,KAAK,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,aAAa,EAAE,CAAC,WAAW,EAAE,qBAAqB,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IAChF,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,wEASlC,2BAA2B,KAAG,cAiJhC,CAAA"} | ||
| {"version":3,"file":"create-api-client-modal.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,oBAAoB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,KAAK,iBAAiB,EAA2B,MAAM,gCAAgC,CAAA;AAChG,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAA6D,MAAM,KAAK,CAAA;AAEhH,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,sDAAsD,CAAA;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAuB,MAAM,oBAAoB,CAAA;AAI/E,KAAK,sBAAsB,GAAG;IAC5B,4CAA4C;IAC5C,EAAE,EAAE,WAAW,GAAG,IAAI,CAAA;IACtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,6DAA6D;IAC7D,cAAc,EAAE,cAAc,CAAA;IAC9B,iDAAiD;IACjD,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB,wGAAwG;IACxG,OAAO,CAAC,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,KAAK,EAAE,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/C,KAAK,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,aAAa,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IAC3E,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,wEASlC,sBAAsB,KAAG,cAiJ3B,CAAA"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create-api-client-modal.js","names":[],"sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"sourcesContent":["import { type ModalState, useModal } from '@scalar/components'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus, createWorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { type App, type MaybeRefOrGetter, computed, createApp, isRef, reactive, ref, toValue, watch } from 'vue'\n\nimport {\n type DefaultEntities,\n type RoutePayload,\n resolveRouteParameters,\n} from '@/v2/features/modal/helpers/resolve-route-parameters'\nimport type { ApiClientModalOptions, ApiClientModalOptionsRef } from '@/v2/features/modal/helpers/types'\nimport { useModalSidebar } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport Modal, { type ModalProps } from '@/v2/features/modal/Modal.vue'\n\ntype CreateApiClientModalOptions = {\n /** Element to mount the client modal to. */\n el: HTMLElement | null\n /**\n * Will attempt to mount the references immediately.\n * For SSR this may need to be disabled and handled manually on the client side.\n */\n mountOnInitialize?: boolean\n /** You can pass in an event bus if you have one already, or we will create one */\n eventBus?: WorkspaceEventBus\n /** The workspace store must be initialized and passed in. */\n workspaceStore: WorkspaceStore\n /** Api client plugins to include in the modal */\n plugins?: ClientPlugin[]\n /** Subset of the configuration options for the modal, if you want it to be reactive ensure its a ref */\n options?: MaybeRefOrGetter<ApiClientModalOptions>\n}\n\nexport type ApiClientModal = {\n app: App\n open: (payload?: RoutePayload) => void\n mount: (mountingEl: HTMLElement | null) => void\n route: (payload: RoutePayload) => void\n updateOptions: (nextOptions: ApiClientModalOptions, overwrite?: boolean) => void\n modalState: ModalState\n}\n\n/**\n * Creates the API Client Modal.\n *\n * The modal does not require a router. Instead, navigation is handled by setting\n * active entities directly through the returned `route` function.\n */\nexport const createApiClientModal = ({\n el,\n eventBus = createWorkspaceEventBus({\n debug: import.meta.env.DEV,\n }),\n mountOnInitialize = true,\n plugins = [],\n workspaceStore,\n options = {},\n}: CreateApiClientModalOptions): ApiClientModal => {\n const requestBodyCompositionSelection = ref<Record<string, number>>({})\n\n /** This is to ensure that the options are a ref if they are not already, useful for react */\n const optionsRef = (isRef(options) ? options : ref(toValue(options))) as ApiClientModalOptionsRef\n\n const defaultEntities: DefaultEntities = {\n path: 'default',\n method: 'default',\n example: 'default',\n documentSlug: workspaceStore.workspace['x-scalar-active-document'] || 'default',\n }\n\n const parameters = reactive<DefaultEntities>({ ...defaultEntities })\n\n /** Navigate to the specified path, method, and example. */\n const route = (payload: RoutePayload): void => {\n Object.assign(parameters, defaultEntities, payload)\n }\n\n /** Resolved parameters from the workspace store. */\n const resolvedParameters = computed(() => resolveRouteParameters(workspaceStore, parameters))\n const documentSlug = computed(() => resolvedParameters.value.documentSlug)\n const path = computed(() => resolvedParameters.value.path)\n const method = computed(() => resolvedParameters.value.method)\n const exampleName = computed(() => resolvedParameters.value.example)\n /** The document from the workspace store. */\n const document = computed(() => workspaceStore.workspace.documents[documentSlug.value ?? ''] ?? null)\n\n /** Sidebar state and selection handling. */\n const sidebarState = useModalSidebar({\n workspaceStore,\n documentSlug: documentSlug,\n path: path,\n method: method,\n exampleName: exampleName,\n route,\n })\n\n const modalState = useModal()\n\n const app = createApp(Modal, {\n document,\n eventBus,\n exampleName,\n method,\n modalState,\n path,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n options: optionsRef,\n } satisfies ModalProps)\n\n /** Restore the workspace store when the modal is closed. */\n const handleModalClose = () => {\n requestBodyCompositionSelection.value = {}\n }\n\n /** Initialize plugins and subscribe to event bus events */\n const pluginUnsubscribes: (() => void)[] = []\n for (const plugin of plugins) {\n plugin.lifecycle?.onInit?.()\n\n if (plugin.on) {\n for (const [event, handler] of Object.entries(plugin.on)) {\n pluginUnsubscribes.push(eventBus.on(event as any, handler as any))\n }\n }\n }\n\n /** Clean up plugin lifecycle and event bus subscriptions when the app is unmounted */\n app.onUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n })\n\n watch(\n () => modalState.open,\n (open) => (open ? null : handleModalClose()),\n )\n\n // Update the active proxy when the proxyUrl changes\n watch(\n () => toValue(optionsRef).proxyUrl,\n (newProxyUrl) => workspaceStore.update('x-scalar-active-proxy', newProxyUrl),\n { immediate: true },\n )\n\n // Use a unique id prefix to prevent collisions with other Vue apps on the page\n app.config.idPrefix = 'scalar-client'\n\n /** Mount the modal to a given element. */\n const mount = (mountingEl: HTMLElement | null = el): void => {\n if (!mountingEl) {\n console.error(\n '[@scalar/api-client] Could not create the API client Modal.',\n 'Invalid HTML element provided.',\n 'Read more: https://github.com/scalar/scalar/tree/main/packages/api-client',\n )\n return\n }\n app.mount(mountingEl)\n }\n\n if (mountOnInitialize) {\n mount()\n }\n\n return {\n /** The Vue app instance for the modal. Use with caution. */\n app,\n /** Open the modal and optionally navigate to a specific route. */\n open: (payload?: RoutePayload): void => {\n modalState.open = true\n if (payload) {\n route(payload)\n }\n },\n /** Mount the modal to a given element. */\n mount,\n /** Navigate to the specified path, method, and example. */\n route,\n /** Controls the visibility of the modal. */\n modalState,\n /**\n * Merge new options into the current modal options.\n *\n * @param newOptions - The new options to merge into the current modal options.\n * @param overwrite - Whether to overwrite the current modal options with the new options. If false, the new options will be merged with the current options.\n */\n updateOptions: (newOptions: ApiClientModalOptions, overwrite = false): void => {\n optionsRef.value = overwrite\n ? newOptions\n : {\n ...optionsRef.value,\n ...newOptions,\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAgDA,IAAa,wBAAwB,EACnC,IACA,WAAW,wBAAwB,EACjC,OAAA,OACD,CAAC,EACF,oBAAoB,MACpB,UAAU,EAAE,EACZ,gBACA,UAAU,EAAE,OACqC;CACjD,MAAM,kCAAkC,IAA4B,EAAE,CAAC;;CAGvE,MAAM,aAAc,MAAM,QAAQ,GAAG,UAAU,IAAI,QAAQ,QAAQ,CAAC;CAEpE,MAAM,kBAAmC;EACvC,MAAM;EACN,QAAQ;EACR,SAAS;EACT,cAAc,eAAe,UAAU,+BAA+B;EACvE;CAED,MAAM,aAAa,SAA0B,EAAE,GAAG,iBAAiB,CAAC;;CAGpE,MAAM,SAAS,YAAgC;AAC7C,SAAO,OAAO,YAAY,iBAAiB,QAAQ;;;CAIrD,MAAM,qBAAqB,eAAe,uBAAuB,gBAAgB,WAAW,CAAC;CAC7F,MAAM,eAAe,eAAe,mBAAmB,MAAM,aAAa;CAC1E,MAAM,OAAO,eAAe,mBAAmB,MAAM,KAAK;CAC1D,MAAM,SAAS,eAAe,mBAAmB,MAAM,OAAO;CAC9D,MAAM,cAAc,eAAe,mBAAmB,MAAM,QAAQ;;CAEpE,MAAM,WAAW,eAAe,eAAe,UAAU,UAAU,aAAa,SAAS,OAAO,KAAK;;CAGrG,MAAM,eAAe,gBAAgB;EACnC;EACc;EACR;EACE;EACK;EACb;EACD,CAAC;CAEF,MAAM,aAAa,UAAU;CAE7B,MAAM,MAAM,UAAU,eAAO;EAC3B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACV,CAAsB;;CAGvB,MAAM,yBAAyB;AAC7B,kCAAgC,QAAQ,EAAE;;;CAI5C,MAAM,qBAAqC,EAAE;AAC7C,MAAK,MAAM,UAAU,SAAS;AAC5B,SAAO,WAAW,UAAU;AAE5B,MAAI,OAAO,GACT,MAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,OAAO,GAAG,CACtD,oBAAmB,KAAK,SAAS,GAAG,OAAc,QAAe,CAAC;;;AAMxE,KAAI,gBAAgB;AAClB,OAAK,MAAM,SAAS,mBAClB,QAAO;AAET,OAAK,MAAM,UAAU,QACnB,QAAO,WAAW,aAAa;GAEjC;AAEF,aACQ,WAAW,OAChB,SAAU,OAAO,OAAO,kBAAkB,CAC5C;AAGD,aACQ,QAAQ,WAAW,CAAC,WACzB,gBAAgB,eAAe,OAAO,yBAAyB,YAAY,EAC5E,EAAE,WAAW,MAAM,CACpB;AAGD,KAAI,OAAO,WAAW;;CAGtB,MAAM,SAAS,aAAiC,OAAa;AAC3D,MAAI,CAAC,YAAY;AACf,WAAQ,MACN,+DACA,kCACA,4EACD;AACD;;AAEF,MAAI,MAAM,WAAW;;AAGvB,KAAI,kBACF,QAAO;AAGT,QAAO;EAEL;EAEA,OAAO,YAAiC;AACtC,cAAW,OAAO;AAClB,OAAI,QACF,OAAM,QAAQ;;EAIlB;EAEA;EAEA;EAOA,gBAAgB,YAAmC,YAAY,UAAgB;AAC7E,cAAW,QAAQ,YACf,aACA;IACE,GAAG,WAAW;IACd,GAAG;IACJ;;EAER"} | ||
| {"version":3,"file":"create-api-client-modal.js","names":[],"sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"sourcesContent":["import { type ModalState, useModal } from '@scalar/components'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus, createWorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { type App, type MaybeRefOrGetter, computed, createApp, isRef, reactive, ref, toValue, watch } from 'vue'\n\nimport {\n type DefaultEntities,\n type RoutePayload,\n resolveRouteParameters,\n} from '@/v2/features/modal/helpers/resolve-route-parameters'\nimport type { ApiClientOptions, ApiClientOptionsRef } from '@/v2/types/options'\nimport { useModalSidebar } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport Modal, { type ModalProps } from '@/v2/features/modal/Modal.vue'\n\ntype CreateApiClientOptions = {\n /** Element to mount the client modal to. */\n el: HTMLElement | null\n /**\n * Will attempt to mount the references immediately.\n * For SSR this may need to be disabled and handled manually on the client side.\n */\n mountOnInitialize?: boolean\n /** You can pass in an event bus if you have one already, or we will create one */\n eventBus?: WorkspaceEventBus\n /** The workspace store must be initialized and passed in. */\n workspaceStore: WorkspaceStore\n /** Api client plugins to include in the modal */\n plugins?: ClientPlugin[]\n /** Subset of the configuration options for the modal, if you want it to be reactive ensure its a ref */\n options?: MaybeRefOrGetter<ApiClientOptions>\n}\n\nexport type ApiClientModal = {\n app: App\n open: (payload?: RoutePayload) => void\n mount: (mountingEl: HTMLElement | null) => void\n route: (payload: RoutePayload) => void\n updateOptions: (nextOptions: ApiClientOptions, overwrite?: boolean) => void\n modalState: ModalState\n}\n\n/**\n * Creates the API Client Modal.\n *\n * The modal does not require a router. Instead, navigation is handled by setting\n * active entities directly through the returned `route` function.\n */\nexport const createApiClientModal = ({\n el,\n eventBus = createWorkspaceEventBus({\n debug: import.meta.env.DEV,\n }),\n mountOnInitialize = true,\n plugins = [],\n workspaceStore,\n options = {},\n}: CreateApiClientOptions): ApiClientModal => {\n const requestBodyCompositionSelection = ref<Record<string, number>>({})\n\n /** This is to ensure that the options are a ref if they are not already, useful for react */\n const optionsRef = (isRef(options) ? options : ref(toValue(options))) as ApiClientOptionsRef\n\n const defaultEntities: DefaultEntities = {\n path: 'default',\n method: 'default',\n example: 'default',\n documentSlug: workspaceStore.workspace['x-scalar-active-document'] || 'default',\n }\n\n const parameters = reactive<DefaultEntities>({ ...defaultEntities })\n\n /** Navigate to the specified path, method, and example. */\n const route = (payload: RoutePayload): void => {\n Object.assign(parameters, defaultEntities, payload)\n }\n\n /** Resolved parameters from the workspace store. */\n const resolvedParameters = computed(() => resolveRouteParameters(workspaceStore, parameters))\n const documentSlug = computed(() => resolvedParameters.value.documentSlug)\n const path = computed(() => resolvedParameters.value.path)\n const method = computed(() => resolvedParameters.value.method)\n const exampleName = computed(() => resolvedParameters.value.example)\n /** The document from the workspace store. */\n const document = computed(() => workspaceStore.workspace.documents[documentSlug.value ?? ''] ?? null)\n\n /** Sidebar state and selection handling. */\n const sidebarState = useModalSidebar({\n workspaceStore,\n documentSlug: documentSlug,\n path: path,\n method: method,\n exampleName: exampleName,\n route,\n })\n\n const modalState = useModal()\n\n const app = createApp(Modal, {\n document,\n eventBus,\n exampleName,\n method,\n modalState,\n path,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n options: optionsRef,\n } satisfies ModalProps)\n\n /** Restore the workspace store when the modal is closed. */\n const handleModalClose = () => {\n requestBodyCompositionSelection.value = {}\n }\n\n /** Initialize plugins and subscribe to event bus events */\n const pluginUnsubscribes: (() => void)[] = []\n for (const plugin of plugins) {\n plugin.lifecycle?.onInit?.()\n\n if (plugin.on) {\n for (const [event, handler] of Object.entries(plugin.on)) {\n pluginUnsubscribes.push(eventBus.on(event as any, handler as any))\n }\n }\n }\n\n /** Clean up plugin lifecycle and event bus subscriptions when the app is unmounted */\n app.onUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n })\n\n watch(\n () => modalState.open,\n (open) => (open ? null : handleModalClose()),\n )\n\n // Update the active proxy when the proxyUrl changes\n watch(\n () => toValue(optionsRef).proxyUrl,\n (newProxyUrl) => workspaceStore.update('x-scalar-active-proxy', newProxyUrl),\n { immediate: true },\n )\n\n // Use a unique id prefix to prevent collisions with other Vue apps on the page\n app.config.idPrefix = 'scalar-client'\n\n /** Mount the modal to a given element. */\n const mount = (mountingEl: HTMLElement | null = el): void => {\n if (!mountingEl) {\n console.error(\n '[@scalar/api-client] Could not create the API client Modal.',\n 'Invalid HTML element provided.',\n 'Read more: https://github.com/scalar/scalar/tree/main/packages/api-client',\n )\n return\n }\n app.mount(mountingEl)\n }\n\n if (mountOnInitialize) {\n mount()\n }\n\n return {\n /** The Vue app instance for the modal. Use with caution. */\n app,\n /** Open the modal and optionally navigate to a specific route. */\n open: (payload?: RoutePayload): void => {\n modalState.open = true\n if (payload) {\n route(payload)\n }\n },\n /** Mount the modal to a given element. */\n mount,\n /** Navigate to the specified path, method, and example. */\n route,\n /** Controls the visibility of the modal. */\n modalState,\n /**\n * Merge new options into the current modal options.\n *\n * @param newOptions - The new options to merge into the current modal options.\n * @param overwrite - Whether to overwrite the current modal options with the new options. If false, the new options will be merged with the current options.\n */\n updateOptions: (newOptions: ApiClientOptions, overwrite = false): void => {\n optionsRef.value = overwrite\n ? newOptions\n : {\n ...optionsRef.value,\n ...newOptions,\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAgDA,IAAa,wBAAwB,EACnC,IACA,WAAW,wBAAwB,EACjC,OAAA,OACD,CAAC,EACF,oBAAoB,MACpB,UAAU,EAAE,EACZ,gBACA,UAAU,EAAE,OACgC;CAC5C,MAAM,kCAAkC,IAA4B,EAAE,CAAC;;CAGvE,MAAM,aAAc,MAAM,QAAQ,GAAG,UAAU,IAAI,QAAQ,QAAQ,CAAC;CAEpE,MAAM,kBAAmC;EACvC,MAAM;EACN,QAAQ;EACR,SAAS;EACT,cAAc,eAAe,UAAU,+BAA+B;EACvE;CAED,MAAM,aAAa,SAA0B,EAAE,GAAG,iBAAiB,CAAC;;CAGpE,MAAM,SAAS,YAAgC;AAC7C,SAAO,OAAO,YAAY,iBAAiB,QAAQ;;;CAIrD,MAAM,qBAAqB,eAAe,uBAAuB,gBAAgB,WAAW,CAAC;CAC7F,MAAM,eAAe,eAAe,mBAAmB,MAAM,aAAa;CAC1E,MAAM,OAAO,eAAe,mBAAmB,MAAM,KAAK;CAC1D,MAAM,SAAS,eAAe,mBAAmB,MAAM,OAAO;CAC9D,MAAM,cAAc,eAAe,mBAAmB,MAAM,QAAQ;;CAEpE,MAAM,WAAW,eAAe,eAAe,UAAU,UAAU,aAAa,SAAS,OAAO,KAAK;;CAGrG,MAAM,eAAe,gBAAgB;EACnC;EACc;EACR;EACE;EACK;EACb;EACD,CAAC;CAEF,MAAM,aAAa,UAAU;CAE7B,MAAM,MAAM,UAAU,eAAO;EAC3B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACV,CAAsB;;CAGvB,MAAM,yBAAyB;AAC7B,kCAAgC,QAAQ,EAAE;;;CAI5C,MAAM,qBAAqC,EAAE;AAC7C,MAAK,MAAM,UAAU,SAAS;AAC5B,SAAO,WAAW,UAAU;AAE5B,MAAI,OAAO,GACT,MAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,OAAO,GAAG,CACtD,oBAAmB,KAAK,SAAS,GAAG,OAAc,QAAe,CAAC;;;AAMxE,KAAI,gBAAgB;AAClB,OAAK,MAAM,SAAS,mBAClB,QAAO;AAET,OAAK,MAAM,UAAU,QACnB,QAAO,WAAW,aAAa;GAEjC;AAEF,aACQ,WAAW,OAChB,SAAU,OAAO,OAAO,kBAAkB,CAC5C;AAGD,aACQ,QAAQ,WAAW,CAAC,WACzB,gBAAgB,eAAe,OAAO,yBAAyB,YAAY,EAC5E,EAAE,WAAW,MAAM,CACpB;AAGD,KAAI,OAAO,WAAW;;CAGtB,MAAM,SAAS,aAAiC,OAAa;AAC3D,MAAI,CAAC,YAAY;AACf,WAAQ,MACN,+DACA,kCACA,4EACD;AACD;;AAEF,MAAI,MAAM,WAAW;;AAGvB,KAAI,kBACF,QAAO;AAGT,QAAO;EAEL;EAEA,OAAO,YAAiC;AACtC,cAAW,OAAO;AAClB,OAAI,QACF,OAAM,QAAQ;;EAIlB;EAEA;EAEA;EAOA,gBAAgB,YAA8B,YAAY,UAAgB;AACxE,cAAW,QAAQ,YACf,aACA;IACE,GAAG,WAAW;IACd,GAAG;IACJ;;EAER"} |
@@ -1,8 +0,2 @@ | ||
| import type { ApiReferenceConfigurationRaw } from '@scalar/types/api-reference'; | ||
| import type { Ref } from 'vue'; | ||
| /** | ||
| * Configuration options supported by the API Client modal constructor. | ||
| */ | ||
| export type ApiClientModalOptions = Partial<Pick<ApiReferenceConfigurationRaw, 'authentication' | 'baseServerURL' | 'hideClientButton' | 'hiddenClients' | 'oauth2RedirectUri' | 'proxyUrl' | 'servers'>>; | ||
| export type ApiClientModalOptionsRef = Ref<ApiClientModalOptions>; | ||
| export type { ApiClientOptions, ApiClientOptionsRef } from '../../../../v2/types/options'; | ||
| //# sourceMappingURL=types.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/modal/helpers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAC/E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAE9B;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,CACzC,IAAI,CACF,4BAA4B,EAC1B,gBAAgB,GAChB,eAAe,GACf,kBAAkB,GAClB,eAAe,GACf,mBAAmB,GACnB,UAAU,GACV,SAAS,CACZ,CACF,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,GAAG,CAAC,qBAAqB,CAAC,CAAA"} | ||
| {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/modal/helpers/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA"} |
| export { type ApiClientModal, createApiClientModal } from './helpers/create-api-client-modal.js'; | ||
| export { mapHiddenClientsConfig } from './helpers/map-hidden-clients-config.js'; | ||
| export type { RoutePayload } from './helpers/resolve-route-parameters.js'; | ||
| export type { ApiClientModalOptions } from './helpers/types'; | ||
| export type { ApiClientOptions } from '../../../v2/types/options'; | ||
| export { initializeModalEvents } from './modal-events.js'; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/modal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AAC7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAA;AAC5E,YAAY,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AACtE,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/modal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AAC7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAA;AAC5E,YAAY,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AACtE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA"} |
| import { type ModalState } from '@scalar/components'; | ||
| import type { HttpMethod } from '@scalar/helpers/http/http-methods'; | ||
| import type { ClientPlugin } from '@scalar/oas-utils/helpers'; | ||
| import type { ApiReferenceConfigurationRaw } from '@scalar/types/api-reference'; | ||
| import type { WorkspaceStore } from '@scalar/workspace-store/client'; | ||
| import { type WorkspaceEventBus } from '@scalar/workspace-store/events'; | ||
| import type { WorkspaceDocument } from '@scalar/workspace-store/schemas'; | ||
| import { type ComputedRef, type MaybeRefOrGetter, type Ref } from 'vue'; | ||
| import type { ApiClientModalOptionsRef } from '../../../v2/features/modal/helpers/types'; | ||
| import { type ComputedRef, type Ref } from 'vue'; | ||
| import { type UseModalSidebarReturn } from '../../../v2/features/modal/hooks/use-modal-sidebar.js'; | ||
| import type { ApiClientOptionsRef } from '../../../v2/types/options'; | ||
| import type { MaybeRefOrGetter } from 'vue'; | ||
| import type { ApiClientOptions } from '../../../v2/types/options'; | ||
| export type ModalProps = { | ||
@@ -33,3 +34,3 @@ /** The workspace store must be initialized and passed in */ | ||
| /** Subset of the configuration options for the modal */ | ||
| options: MaybeRefOrGetter<Partial<Pick<ApiReferenceConfigurationRaw, 'authentication' | 'baseServerURL' | 'hideClientButton' | 'hiddenClients' | 'oauth2RedirectUri' | 'servers'>>>; | ||
| options: MaybeRefOrGetter<ApiClientOptions>; | ||
| }; | ||
@@ -44,3 +45,3 @@ /** | ||
| declare const __VLS_export: import("vue").DefineComponent<Omit<ModalProps, "options"> & { | ||
| options: ApiClientModalOptionsRef; | ||
| options: ApiClientOptionsRef; | ||
| }, { | ||
@@ -50,4 +51,4 @@ sidebarWidth: ComputedRef<number>; | ||
| }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Omit<ModalProps, "options"> & { | ||
| options: ApiClientModalOptionsRef; | ||
| options: ApiClientOptionsRef; | ||
| }> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; | ||
| //# sourceMappingURL=Modal.vue.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Modal.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/modal/Modal.vue"],"names":[],"mappings":"AAyNA,OAAO,EAAE,KAAK,UAAU,EAA4B,MAAM,oBAAoB,CAAA;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAE/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,GAAG,EACT,MAAM,KAAK,CAAA;AAIZ,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAA;AACjF,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,6CAA6C,CAAA;AAOxF,MAAM,MAAM,UAAU,GAAG;IACvB,4DAA4D;IAC5D,cAAc,EAAE,cAAc,CAAA;IAC9B,qDAAqD;IACrD,QAAQ,EAAE,WAAW,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAA;IAC/C,iDAAiD;IACjD,IAAI,EAAE,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACrC,4CAA4C;IAC5C,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,mDAAmD;IACnD,MAAM,EAAE,WAAW,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;IAC3C,yDAAyD;IACzD,WAAW,EAAE,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAC5C,sEAAsE;IACtE,+BAA+B,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC5D,2CAA2C;IAC3C,UAAU,EAAE,UAAU,CAAA;IACtB,0DAA0D;IAC1D,YAAY,EAAE,qBAAqB,CAAA;IACnC,iDAAiD;IACjD,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,wDAAwD;IACxD,OAAO,EAAE,gBAAgB,CACvB,OAAO,CACL,IAAI,CACF,4BAA4B,EAC1B,gBAAgB,GAChB,eAAe,GACf,kBAAkB,GAClB,eAAe,GACf,mBAAmB,GACnB,SAAS,CACZ,CACF,CACF,CAAA;CACF,CAAA;AAED;;;;GAIG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;aAC0C,wBAAwB;;;;;aAAxB,wBAAwB;iGAwQhF,CAAC"} | ||
| {"version":3,"file":"Modal.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/modal/Modal.vue"],"names":[],"mappings":"AA+MA,OAAO,EAAE,KAAK,UAAU,EAA4B,MAAM,oBAAoB,CAAA;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,GAAG,EACT,MAAM,KAAK,CAAA;AAIZ,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,6CAA6C,CAAA;AAKxF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAG7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAA;AAE3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,MAAM,MAAM,UAAU,GAAG;IACvB,4DAA4D;IAC5D,cAAc,EAAE,cAAc,CAAA;IAC9B,qDAAqD;IACrD,QAAQ,EAAE,WAAW,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAA;IAC/C,iDAAiD;IACjD,IAAI,EAAE,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACrC,4CAA4C;IAC5C,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,mDAAmD;IACnD,MAAM,EAAE,WAAW,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;IAC3C,yDAAyD;IACzD,WAAW,EAAE,WAAW,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAC5C,sEAAsE;IACtE,+BAA+B,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC5D,2CAA2C;IAC3C,UAAU,EAAE,UAAU,CAAA;IACtB,0DAA0D;IAC1D,YAAY,EAAE,qBAAqB,CAAA;IACnC,iDAAiD;IACjD,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,wDAAwD;IACxD,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAA;CAC5C,CAAA;AAED;;;;GAIG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;aAC0C,mBAAmB;;;;;aAAnB,mBAAmB;iGAwQ3E,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Modal.vue.js","names":[],"sources":["../../../../src/v2/features/modal/Modal.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type ModalProps = {\n /** The workspace store must be initialized and passed in */\n workspaceStore: WorkspaceStore\n /** The document must be initialized and passed in */\n document: ComputedRef<WorkspaceDocument | null>\n /** The path must be initialized and passed in */\n path: ComputedRef<string | undefined>\n /** The event bus for handling all events */\n eventBus: WorkspaceEventBus\n /** The method must be initialized and passed in */\n method: ComputedRef<HttpMethod | undefined>\n /** The example name must be initialized and passed in */\n exampleName: ComputedRef<string | undefined>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection: Ref<Record<string, number>>\n /** Controls the visibility of the modal */\n modalState: ModalState\n /** The sidebar state must be initialized and passed in */\n sidebarState: UseModalSidebarReturn\n /** Api client plugins to include in the modal */\n plugins: ClientPlugin[]\n /** Subset of the configuration options for the modal */\n options: MaybeRefOrGetter<\n Partial<\n Pick<\n ApiReferenceConfigurationRaw,\n | 'authentication'\n | 'baseServerURL'\n | 'hideClientButton'\n | 'hiddenClients'\n | 'oauth2RedirectUri'\n | 'servers'\n >\n >\n >\n}\n\n/**\n * Scalar Api Client Modal\n *\n * This component is used to render the API Client Modal\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { type ModalState, type ScalarListboxOption } from '@scalar/components'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { ApiReferenceConfigurationRaw } from '@scalar/types/api-reference'\nimport { ScalarToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getActiveEnvironment } from '@scalar/workspace-store/request-example'\nimport type { WorkspaceDocument } from '@scalar/workspace-store/schemas'\nimport {\n computed,\n onBeforeUnmount,\n ref,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\n\nimport ModalClientContainer from '@/v2/components/modals/ModalClientContainer.vue'\nimport { Sidebar, SidebarToggle } from '@/v2/components/sidebar'\nimport type { ApiClientModalOptionsRef } from '@/v2/features/modal/helpers/types'\nimport { type UseModalSidebarReturn } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport { initializeModalEvents } from '@/v2/features/modal/modal-events'\nimport Operation from '@/v2/features/operation/Operation.vue'\nimport { useGlobalHotKeys } from '@/v2/hooks/use-global-hot-keys'\nimport { useScrollLock } from '@/v2/hooks/use-scroll-lock'\n\nconst {\n document,\n eventBus,\n modalState,\n options,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n} = defineProps<\n Omit<ModalProps, 'options'> & { options: ApiClientModalOptionsRef }\n>()\n\nconst activeWorkspace: ScalarListboxOption = {\n label: 'default',\n id: 'default',\n}\n\n/** Controls the visibility of the sidebar. */\nconst isSidebarOpen = ref(false)\n\n/** Initialize modal events */\ninitializeModalEvents({\n eventBus,\n isSidebarOpen,\n requestBodyCompositionSelection,\n sidebarState,\n modalState,\n store: workspaceStore,\n})\n\n/** Register global hotkeys for the app, passing the workspace event bus and layout state */\nuseGlobalHotKeys(eventBus, 'modal', () => !modalState.open)\n\n/** Clean up on close */\nconst cleanUp = () => {\n eventBus.emit('operation:cancel:request')\n}\n\nconst isLocked = useScrollLock(() => {\n if (typeof window !== 'undefined') {\n return window.document.body\n }\n return null\n})\n\nwatch(\n () => modalState.open,\n (open) => {\n // Make sure scrolling is locked or unlocked when the modal is opened or closed\n isLocked.value = open\n\n if (!open) {\n cleanUp()\n }\n },\n)\n\n// Ensure we add our scalar wrapper class to the headless ui root\nonBeforeUnmount(() => cleanUp())\n\n/** Default sidebar width in pixels. */\nconst DEFAULT_SIDEBAR_WIDTH = 288\n\n/** Width of the sidebar, with fallback to default. */\nconst sidebarWidth = computed(\n () =>\n workspaceStore?.workspace?.['x-scalar-sidebar-width'] ??\n DEFAULT_SIDEBAR_WIDTH,\n)\n\n/** Handler for sidebar width changes. */\nconst handleSidebarWidthUpdate = (width: number) =>\n workspaceStore?.update('x-scalar-sidebar-width', width)\n\n/**\n * Merged environment variables from workspace and document levels.\n * Variables from both sources are combined, with document variables\n * taking precedence in case of naming conflicts.\n */\nconst environment = computed(\n () => getActiveEnvironment(workspaceStore, document.value).environment,\n)\n\ndefineExpose({\n sidebarWidth,\n environment,\n})\n</script>\n\n<template>\n <ModalClientContainer :modalState>\n <!-- Toasts -->\n <ScalarToasts />\n\n <!-- If we have a document, path and method, render the operation -->\n <main\n v-if=\"document.value && path?.value && method?.value\"\n class=\"relative flex h-full min-h-0 w-full flex-1\">\n <SidebarToggle\n v-model=\"isSidebarOpen\"\n class=\"absolute top-2 left-3 z-2\" />\n <Sidebar\n v-show=\"isSidebarOpen\"\n v-model:sidebarWidth=\"sidebarWidth\"\n :activeWorkspace=\"activeWorkspace\"\n class=\"h-full max-md:absolute! max-md:w-full!\"\n :documents=\"[document.value]\"\n :eventBus\n :isDroppable=\"() => false\"\n layout=\"modal\"\n :sidebarState=\"sidebarState.state\"\n :workspaces=\"[]\"\n @selectItem=\"sidebarState.handleSelectItem\"\n @update:sidebarWidth=\"handleSidebarWidthUpdate\" />\n <Operation\n :activeWorkspace=\"activeWorkspace\"\n class=\"flex-1\"\n :document=\"document.value\"\n :documentSlug=\"document.value['x-scalar-navigation']?.id ?? ''\"\n :environment\n :eventBus\n :exampleName=\"exampleName?.value\"\n layout=\"modal\"\n :method=\"method?.value\"\n :options\n :path=\"path?.value\"\n :plugins\n :requestBodyCompositionSelection=\"requestBodyCompositionSelection.value\"\n :workspaceStore />\n </main>\n <!-- Empty state -->\n <div\n v-else\n class=\"flex h-full w-full items-center justify-center\">\n <span class=\"text-c-3\">No document selected</span>\n </div>\n </ModalClientContainer>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"Modal.vue.js","names":[],"sources":["../../../../src/v2/features/modal/Modal.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { MaybeRefOrGetter } from 'vue'\n\nimport type { ApiClientOptions } from '@/v2/types/options'\n\nexport type ModalProps = {\n /** The workspace store must be initialized and passed in */\n workspaceStore: WorkspaceStore\n /** The document must be initialized and passed in */\n document: ComputedRef<WorkspaceDocument | null>\n /** The path must be initialized and passed in */\n path: ComputedRef<string | undefined>\n /** The event bus for handling all events */\n eventBus: WorkspaceEventBus\n /** The method must be initialized and passed in */\n method: ComputedRef<HttpMethod | undefined>\n /** The example name must be initialized and passed in */\n exampleName: ComputedRef<string | undefined>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection: Ref<Record<string, number>>\n /** Controls the visibility of the modal */\n modalState: ModalState\n /** The sidebar state must be initialized and passed in */\n sidebarState: UseModalSidebarReturn\n /** Api client plugins to include in the modal */\n plugins: ClientPlugin[]\n /** Subset of the configuration options for the modal */\n options: MaybeRefOrGetter<ApiClientOptions>\n}\n\n/**\n * Scalar Api Client Modal\n *\n * This component is used to render the API Client Modal\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { type ModalState, type ScalarListboxOption } from '@scalar/components'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport { ScalarToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getActiveEnvironment } from '@scalar/workspace-store/request-example'\nimport type { WorkspaceDocument } from '@scalar/workspace-store/schemas'\nimport {\n computed,\n onBeforeUnmount,\n ref,\n watch,\n type ComputedRef,\n type Ref,\n} from 'vue'\n\nimport ModalClientContainer from '@/v2/components/modals/ModalClientContainer.vue'\nimport { Sidebar, SidebarToggle } from '@/v2/components/sidebar'\nimport { type UseModalSidebarReturn } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport { initializeModalEvents } from '@/v2/features/modal/modal-events'\nimport Operation from '@/v2/features/operation/Operation.vue'\nimport { useGlobalHotKeys } from '@/v2/hooks/use-global-hot-keys'\nimport { useScrollLock } from '@/v2/hooks/use-scroll-lock'\nimport type { ApiClientOptionsRef } from '@/v2/types/options'\n\nconst {\n document,\n eventBus,\n modalState,\n options,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n} = defineProps<\n Omit<ModalProps, 'options'> & { options: ApiClientOptionsRef }\n>()\n\nconst activeWorkspace: ScalarListboxOption = {\n label: 'default',\n id: 'default',\n}\n\n/** Controls the visibility of the sidebar. */\nconst isSidebarOpen = ref(false)\n\n/** Initialize modal events */\ninitializeModalEvents({\n eventBus,\n isSidebarOpen,\n requestBodyCompositionSelection,\n sidebarState,\n modalState,\n store: workspaceStore,\n})\n\n/** Register global hotkeys for the app, passing the workspace event bus and layout state */\nuseGlobalHotKeys(eventBus, 'modal', () => !modalState.open)\n\n/** Clean up on close */\nconst cleanUp = () => {\n eventBus.emit('operation:cancel:request')\n}\n\nconst isLocked = useScrollLock(() => {\n if (typeof window !== 'undefined') {\n return window.document.body\n }\n return null\n})\n\nwatch(\n () => modalState.open,\n (open) => {\n // Make sure scrolling is locked or unlocked when the modal is opened or closed\n isLocked.value = open\n\n if (!open) {\n cleanUp()\n }\n },\n)\n\n// Ensure we add our scalar wrapper class to the headless ui root\nonBeforeUnmount(() => cleanUp())\n\n/** Default sidebar width in pixels. */\nconst DEFAULT_SIDEBAR_WIDTH = 288\n\n/** Width of the sidebar, with fallback to default. */\nconst sidebarWidth = computed(\n () =>\n workspaceStore?.workspace?.['x-scalar-sidebar-width'] ??\n DEFAULT_SIDEBAR_WIDTH,\n)\n\n/** Handler for sidebar width changes. */\nconst handleSidebarWidthUpdate = (width: number) =>\n workspaceStore?.update('x-scalar-sidebar-width', width)\n\n/**\n * Merged environment variables from workspace and document levels.\n * Variables from both sources are combined, with document variables\n * taking precedence in case of naming conflicts.\n */\nconst environment = computed(\n () => getActiveEnvironment(workspaceStore, document.value).environment,\n)\n\ndefineExpose({\n sidebarWidth,\n environment,\n})\n</script>\n\n<template>\n <ModalClientContainer :modalState>\n <!-- Toasts -->\n <ScalarToasts />\n\n <!-- If we have a document, path and method, render the operation -->\n <main\n v-if=\"document.value && path?.value && method?.value\"\n class=\"relative flex h-full min-h-0 w-full flex-1\">\n <SidebarToggle\n v-model=\"isSidebarOpen\"\n class=\"absolute top-2 left-3 z-2\" />\n <Sidebar\n v-show=\"isSidebarOpen\"\n v-model:sidebarWidth=\"sidebarWidth\"\n :activeWorkspace=\"activeWorkspace\"\n class=\"h-full max-md:absolute! max-md:w-full!\"\n :documents=\"[document.value]\"\n :eventBus\n :isDroppable=\"() => false\"\n layout=\"modal\"\n :sidebarState=\"sidebarState.state\"\n :workspaces=\"[]\"\n @selectItem=\"sidebarState.handleSelectItem\"\n @update:sidebarWidth=\"handleSidebarWidthUpdate\" />\n <Operation\n :activeWorkspace=\"activeWorkspace\"\n class=\"flex-1\"\n :document=\"document.value\"\n :documentSlug=\"document.value['x-scalar-navigation']?.id ?? ''\"\n :environment\n :eventBus\n :exampleName=\"exampleName?.value\"\n layout=\"modal\"\n :method=\"method?.value\"\n :options\n :path=\"path?.value\"\n :plugins\n :requestBodyCompositionSelection=\"requestBodyCompositionSelection.value\"\n :workspaceStore />\n </main>\n <!-- Empty state -->\n <div\n v-else\n class=\"flex h-full w-full items-center justify-center\">\n <span class=\"text-c-3\">No document selected</span>\n </div>\n </ModalClientContainer>\n</template>\n"],"mappings":""} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Modal.vue.script.js","names":[],"sources":["../../../../src/v2/features/modal/Modal.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type ModalProps = {\n /** The workspace store must be initialized and passed in */\n workspaceStore: WorkspaceStore\n /** The document must be initialized and passed in */\n document: ComputedRef<WorkspaceDocument | null>\n /** The path must be initialized and passed in */\n path: ComputedRef<string | undefined>\n /** The event bus for handling all events */\n eventBus: WorkspaceEventBus\n /** The method must be initialized and passed in */\n method: ComputedRef<HttpMethod | undefined>\n /** The example name must be initialized and passed in */\n exampleName: ComputedRef<string | undefined>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection: Ref<Record<string, number>>\n /** Controls the visibility of the modal */\n modalState: ModalState\n /** The sidebar state must be initialized and passed in */\n sidebarState: UseModalSidebarReturn\n /** Api client plugins to include in the modal */\n plugins: ClientPlugin[]\n /** Subset of the configuration options for the modal */\n options: MaybeRefOrGetter<\n Partial<\n Pick<\n ApiReferenceConfigurationRaw,\n | 'authentication'\n | 'baseServerURL'\n | 'hideClientButton'\n | 'hiddenClients'\n | 'oauth2RedirectUri'\n | 'servers'\n >\n >\n >\n}\n\n/**\n * Scalar Api Client Modal\n *\n * This component is used to render the API Client Modal\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { type ModalState, type ScalarListboxOption } from '@scalar/components'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { ApiReferenceConfigurationRaw } from '@scalar/types/api-reference'\nimport { ScalarToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getActiveEnvironment } from '@scalar/workspace-store/request-example'\nimport type { WorkspaceDocument } from '@scalar/workspace-store/schemas'\nimport {\n computed,\n onBeforeUnmount,\n ref,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\n\nimport ModalClientContainer from '@/v2/components/modals/ModalClientContainer.vue'\nimport { Sidebar, SidebarToggle } from '@/v2/components/sidebar'\nimport type { ApiClientModalOptionsRef } from '@/v2/features/modal/helpers/types'\nimport { type UseModalSidebarReturn } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport { initializeModalEvents } from '@/v2/features/modal/modal-events'\nimport Operation from '@/v2/features/operation/Operation.vue'\nimport { useGlobalHotKeys } from '@/v2/hooks/use-global-hot-keys'\nimport { useScrollLock } from '@/v2/hooks/use-scroll-lock'\n\nconst {\n document,\n eventBus,\n modalState,\n options,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n} = defineProps<\n Omit<ModalProps, 'options'> & { options: ApiClientModalOptionsRef }\n>()\n\nconst activeWorkspace: ScalarListboxOption = {\n label: 'default',\n id: 'default',\n}\n\n/** Controls the visibility of the sidebar. */\nconst isSidebarOpen = ref(false)\n\n/** Initialize modal events */\ninitializeModalEvents({\n eventBus,\n isSidebarOpen,\n requestBodyCompositionSelection,\n sidebarState,\n modalState,\n store: workspaceStore,\n})\n\n/** Register global hotkeys for the app, passing the workspace event bus and layout state */\nuseGlobalHotKeys(eventBus, 'modal', () => !modalState.open)\n\n/** Clean up on close */\nconst cleanUp = () => {\n eventBus.emit('operation:cancel:request')\n}\n\nconst isLocked = useScrollLock(() => {\n if (typeof window !== 'undefined') {\n return window.document.body\n }\n return null\n})\n\nwatch(\n () => modalState.open,\n (open) => {\n // Make sure scrolling is locked or unlocked when the modal is opened or closed\n isLocked.value = open\n\n if (!open) {\n cleanUp()\n }\n },\n)\n\n// Ensure we add our scalar wrapper class to the headless ui root\nonBeforeUnmount(() => cleanUp())\n\n/** Default sidebar width in pixels. */\nconst DEFAULT_SIDEBAR_WIDTH = 288\n\n/** Width of the sidebar, with fallback to default. */\nconst sidebarWidth = computed(\n () =>\n workspaceStore?.workspace?.['x-scalar-sidebar-width'] ??\n DEFAULT_SIDEBAR_WIDTH,\n)\n\n/** Handler for sidebar width changes. */\nconst handleSidebarWidthUpdate = (width: number) =>\n workspaceStore?.update('x-scalar-sidebar-width', width)\n\n/**\n * Merged environment variables from workspace and document levels.\n * Variables from both sources are combined, with document variables\n * taking precedence in case of naming conflicts.\n */\nconst environment = computed(\n () => getActiveEnvironment(workspaceStore, document.value).environment,\n)\n\ndefineExpose({\n sidebarWidth,\n environment,\n})\n</script>\n\n<template>\n <ModalClientContainer :modalState>\n <!-- Toasts -->\n <ScalarToasts />\n\n <!-- If we have a document, path and method, render the operation -->\n <main\n v-if=\"document.value && path?.value && method?.value\"\n class=\"relative flex h-full min-h-0 w-full flex-1\">\n <SidebarToggle\n v-model=\"isSidebarOpen\"\n class=\"absolute top-2 left-3 z-2\" />\n <Sidebar\n v-show=\"isSidebarOpen\"\n v-model:sidebarWidth=\"sidebarWidth\"\n :activeWorkspace=\"activeWorkspace\"\n class=\"h-full max-md:absolute! max-md:w-full!\"\n :documents=\"[document.value]\"\n :eventBus\n :isDroppable=\"() => false\"\n layout=\"modal\"\n :sidebarState=\"sidebarState.state\"\n :workspaces=\"[]\"\n @selectItem=\"sidebarState.handleSelectItem\"\n @update:sidebarWidth=\"handleSidebarWidthUpdate\" />\n <Operation\n :activeWorkspace=\"activeWorkspace\"\n class=\"flex-1\"\n :document=\"document.value\"\n :documentSlug=\"document.value['x-scalar-navigation']?.id ?? ''\"\n :environment\n :eventBus\n :exampleName=\"exampleName?.value\"\n layout=\"modal\"\n :method=\"method?.value\"\n :options\n :path=\"path?.value\"\n :plugins\n :requestBodyCompositionSelection=\"requestBodyCompositionSelection.value\"\n :workspaceStore />\n </main>\n <!-- Empty state -->\n <div\n v-else\n class=\"flex h-full w-full items-center justify-center\">\n <span class=\"text-c-3\">No document selected</span>\n </div>\n </ModalClientContainer>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwFA,MAAM,kBAAuC;GAC3C,OAAO;GACP,IAAI;GACN;;EAGA,MAAM,gBAAgB,IAAI,MAAK;;AAG/B,wBAAsB;GACpB,UAAO,QAAA;GACP;GACA,iCAA8B,QAAA;GAC9B,cAAW,QAAA;GACX,YAAS,QAAA;GACT,OAAO,QAAA;GACR,CAAA;;AAGD,mBAAiB,QAAA,UAAU,eAAe,CAAC,QAAA,WAAW,KAAI;;EAG1D,MAAM,gBAAgB;AACpB,WAAA,SAAS,KAAK,2BAA0B;;EAG1C,MAAM,WAAW,oBAAoB;AACnC,OAAI,OAAO,WAAW,YACpB,QAAO,OAAO,SAAS;AAEzB,UAAO;IACR;AAED,cACQ,QAAA,WAAW,OAChB,SAAS;AAER,YAAS,QAAQ;AAEjB,OAAI,CAAC,KACH,UAAQ;IAGd;AAGA,wBAAsB,SAAS,CAAA;;EAG/B,MAAM,wBAAwB;;EAG9B,MAAM,eAAe,eAEjB,QAAA,gBAAgB,YAAY,6BAC5B,sBACJ;;EAGA,MAAM,4BAA4B,UAChC,QAAA,gBAAgB,OAAO,0BAA0B,MAAK;;;;;;EAOxD,MAAM,cAAc,eACZ,qBAAqB,QAAA,gBAAgB,QAAA,SAAS,MAAM,CAAC,YAC7D;AAEA,WAAa;GACX;GACA;GACD,CAAA;;uBAIC,YA8CuB,8BAAA,EA9CA,YAAA,QAAA,YAAU,EAAA;2BAEf,CAAhB,YAAgB,MAAA,aAAA,CAAA,EAIR,QAAA,SAAS,SAAS,QAAA,MAAM,SAAS,QAAA,QAAQ,SAAA,WAAA,EADjD,mBAkCO,QAlCP,YAkCO;KA/BL,YAEsC,MAAA,sBAAA,EAAA;kBAD3B,cAAA;iFAAa,QAAA;MACtB,OAAM;;oBACR,YAYoD,MAAA,gBAAA,EAAA;MAV1C,cAAc,aAAA;mFAAY,QAAA,SAUZ,yBAAA;MATJ;MAClB,OAAM;MACL,WAAS,CAAG,QAAA,SAAS,MAAK;MAC1B,UAAA,QAAA;MACA,mBAAa;MACd,QAAO;MACN,cAAc,QAAA,aAAa;MAC3B,YAAY,EAAE;MACd,cAAY,QAAA,aAAa;;;;;;;kBAVlB,cAAA,MAAa,CAAA,CAAA;KAYvB,YAcoB,mBAAA;MAbA;MAClB,OAAM;MACL,UAAU,QAAA,SAAS;MACnB,cAAc,QAAA,SAAS,MAAK,wBAAyB,MAAE;MACvD,aAAA,YAAA;MACA,UAAA,QAAA;MACA,aAAa,QAAA,aAAa;MAC3B,QAAO;MACN,QAAQ,QAAA,QAAQ;MAChB,SAAA,QAAA;MACA,MAAM,QAAA,MAAM;MACZ,SAAA,QAAA;MACA,iCAAiC,QAAA,gCAAgC;MACjE,gBAAA,QAAA;;;;;;;;;;;;;;wBAGL,mBAIM,OAJN,YAIM,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CADJ,mBAAkD,QAAA,EAA5C,OAAM,YAAU,EAAC,wBAAoB,GAAA,CAAA,EAAA,CAAA,EAAA,CAAA"} | ||
| {"version":3,"file":"Modal.vue.script.js","names":[],"sources":["../../../../src/v2/features/modal/Modal.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { MaybeRefOrGetter } from 'vue'\n\nimport type { ApiClientOptions } from '@/v2/types/options'\n\nexport type ModalProps = {\n /** The workspace store must be initialized and passed in */\n workspaceStore: WorkspaceStore\n /** The document must be initialized and passed in */\n document: ComputedRef<WorkspaceDocument | null>\n /** The path must be initialized and passed in */\n path: ComputedRef<string | undefined>\n /** The event bus for handling all events */\n eventBus: WorkspaceEventBus\n /** The method must be initialized and passed in */\n method: ComputedRef<HttpMethod | undefined>\n /** The example name must be initialized and passed in */\n exampleName: ComputedRef<string | undefined>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection: Ref<Record<string, number>>\n /** Controls the visibility of the modal */\n modalState: ModalState\n /** The sidebar state must be initialized and passed in */\n sidebarState: UseModalSidebarReturn\n /** Api client plugins to include in the modal */\n plugins: ClientPlugin[]\n /** Subset of the configuration options for the modal */\n options: MaybeRefOrGetter<ApiClientOptions>\n}\n\n/**\n * Scalar Api Client Modal\n *\n * This component is used to render the API Client Modal\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { type ModalState, type ScalarListboxOption } from '@scalar/components'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport { ScalarToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getActiveEnvironment } from '@scalar/workspace-store/request-example'\nimport type { WorkspaceDocument } from '@scalar/workspace-store/schemas'\nimport {\n computed,\n onBeforeUnmount,\n ref,\n watch,\n type ComputedRef,\n type Ref,\n} from 'vue'\n\nimport ModalClientContainer from '@/v2/components/modals/ModalClientContainer.vue'\nimport { Sidebar, SidebarToggle } from '@/v2/components/sidebar'\nimport { type UseModalSidebarReturn } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport { initializeModalEvents } from '@/v2/features/modal/modal-events'\nimport Operation from '@/v2/features/operation/Operation.vue'\nimport { useGlobalHotKeys } from '@/v2/hooks/use-global-hot-keys'\nimport { useScrollLock } from '@/v2/hooks/use-scroll-lock'\nimport type { ApiClientOptionsRef } from '@/v2/types/options'\n\nconst {\n document,\n eventBus,\n modalState,\n options,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n} = defineProps<\n Omit<ModalProps, 'options'> & { options: ApiClientOptionsRef }\n>()\n\nconst activeWorkspace: ScalarListboxOption = {\n label: 'default',\n id: 'default',\n}\n\n/** Controls the visibility of the sidebar. */\nconst isSidebarOpen = ref(false)\n\n/** Initialize modal events */\ninitializeModalEvents({\n eventBus,\n isSidebarOpen,\n requestBodyCompositionSelection,\n sidebarState,\n modalState,\n store: workspaceStore,\n})\n\n/** Register global hotkeys for the app, passing the workspace event bus and layout state */\nuseGlobalHotKeys(eventBus, 'modal', () => !modalState.open)\n\n/** Clean up on close */\nconst cleanUp = () => {\n eventBus.emit('operation:cancel:request')\n}\n\nconst isLocked = useScrollLock(() => {\n if (typeof window !== 'undefined') {\n return window.document.body\n }\n return null\n})\n\nwatch(\n () => modalState.open,\n (open) => {\n // Make sure scrolling is locked or unlocked when the modal is opened or closed\n isLocked.value = open\n\n if (!open) {\n cleanUp()\n }\n },\n)\n\n// Ensure we add our scalar wrapper class to the headless ui root\nonBeforeUnmount(() => cleanUp())\n\n/** Default sidebar width in pixels. */\nconst DEFAULT_SIDEBAR_WIDTH = 288\n\n/** Width of the sidebar, with fallback to default. */\nconst sidebarWidth = computed(\n () =>\n workspaceStore?.workspace?.['x-scalar-sidebar-width'] ??\n DEFAULT_SIDEBAR_WIDTH,\n)\n\n/** Handler for sidebar width changes. */\nconst handleSidebarWidthUpdate = (width: number) =>\n workspaceStore?.update('x-scalar-sidebar-width', width)\n\n/**\n * Merged environment variables from workspace and document levels.\n * Variables from both sources are combined, with document variables\n * taking precedence in case of naming conflicts.\n */\nconst environment = computed(\n () => getActiveEnvironment(workspaceStore, document.value).environment,\n)\n\ndefineExpose({\n sidebarWidth,\n environment,\n})\n</script>\n\n<template>\n <ModalClientContainer :modalState>\n <!-- Toasts -->\n <ScalarToasts />\n\n <!-- If we have a document, path and method, render the operation -->\n <main\n v-if=\"document.value && path?.value && method?.value\"\n class=\"relative flex h-full min-h-0 w-full flex-1\">\n <SidebarToggle\n v-model=\"isSidebarOpen\"\n class=\"absolute top-2 left-3 z-2\" />\n <Sidebar\n v-show=\"isSidebarOpen\"\n v-model:sidebarWidth=\"sidebarWidth\"\n :activeWorkspace=\"activeWorkspace\"\n class=\"h-full max-md:absolute! max-md:w-full!\"\n :documents=\"[document.value]\"\n :eventBus\n :isDroppable=\"() => false\"\n layout=\"modal\"\n :sidebarState=\"sidebarState.state\"\n :workspaces=\"[]\"\n @selectItem=\"sidebarState.handleSelectItem\"\n @update:sidebarWidth=\"handleSidebarWidthUpdate\" />\n <Operation\n :activeWorkspace=\"activeWorkspace\"\n class=\"flex-1\"\n :document=\"document.value\"\n :documentSlug=\"document.value['x-scalar-navigation']?.id ?? ''\"\n :environment\n :eventBus\n :exampleName=\"exampleName?.value\"\n layout=\"modal\"\n :method=\"method?.value\"\n :options\n :path=\"path?.value\"\n :plugins\n :requestBodyCompositionSelection=\"requestBodyCompositionSelection.value\"\n :workspaceStore />\n </main>\n <!-- Empty state -->\n <div\n v-else\n class=\"flex h-full w-full items-center justify-center\">\n <span class=\"text-c-3\">No document selected</span>\n </div>\n </ModalClientContainer>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8EA,MAAM,kBAAuC;GAC3C,OAAO;GACP,IAAI;GACN;;EAGA,MAAM,gBAAgB,IAAI,MAAK;;AAG/B,wBAAsB;GACpB,UAAO,QAAA;GACP;GACA,iCAA8B,QAAA;GAC9B,cAAW,QAAA;GACX,YAAS,QAAA;GACT,OAAO,QAAA;GACR,CAAA;;AAGD,mBAAiB,QAAA,UAAU,eAAe,CAAC,QAAA,WAAW,KAAI;;EAG1D,MAAM,gBAAgB;AACpB,WAAA,SAAS,KAAK,2BAA0B;;EAG1C,MAAM,WAAW,oBAAoB;AACnC,OAAI,OAAO,WAAW,YACpB,QAAO,OAAO,SAAS;AAEzB,UAAO;IACR;AAED,cACQ,QAAA,WAAW,OAChB,SAAS;AAER,YAAS,QAAQ;AAEjB,OAAI,CAAC,KACH,UAAQ;IAGd;AAGA,wBAAsB,SAAS,CAAA;;EAG/B,MAAM,wBAAwB;;EAG9B,MAAM,eAAe,eAEjB,QAAA,gBAAgB,YAAY,6BAC5B,sBACJ;;EAGA,MAAM,4BAA4B,UAChC,QAAA,gBAAgB,OAAO,0BAA0B,MAAK;;;;;;EAOxD,MAAM,cAAc,eACZ,qBAAqB,QAAA,gBAAgB,QAAA,SAAS,MAAM,CAAC,YAC7D;AAEA,WAAa;GACX;GACA;GACD,CAAA;;uBAIC,YA8CuB,8BAAA,EA9CA,YAAA,QAAA,YAAU,EAAA;2BAEf,CAAhB,YAAgB,MAAA,aAAA,CAAA,EAIR,QAAA,SAAS,SAAS,QAAA,MAAM,SAAS,QAAA,QAAQ,SAAA,WAAA,EADjD,mBAkCO,QAlCP,YAkCO;KA/BL,YAEsC,MAAA,sBAAA,EAAA;kBAD3B,cAAA;iFAAa,QAAA;MACtB,OAAM;;oBACR,YAYoD,MAAA,gBAAA,EAAA;MAV1C,cAAc,aAAA;mFAAY,QAAA,SAUZ,yBAAA;MATJ;MAClB,OAAM;MACL,WAAS,CAAG,QAAA,SAAS,MAAK;MAC1B,UAAA,QAAA;MACA,mBAAa;MACd,QAAO;MACN,cAAc,QAAA,aAAa;MAC3B,YAAY,EAAE;MACd,cAAY,QAAA,aAAa;;;;;;;kBAVlB,cAAA,MAAa,CAAA,CAAA;KAYvB,YAcoB,mBAAA;MAbA;MAClB,OAAM;MACL,UAAU,QAAA,SAAS;MACnB,cAAc,QAAA,SAAS,MAAK,wBAAyB,MAAE;MACvD,aAAA,YAAA;MACA,UAAA,QAAA;MACA,aAAa,QAAA,aAAa;MAC3B,QAAO;MACN,QAAQ,QAAA,QAAQ;MAChB,SAAA,QAAA;MACA,MAAM,QAAA,MAAM;MACZ,SAAA,QAAA;MACA,iCAAiC,QAAA,gCAAgC;MACjE,gBAAA,QAAA;;;;;;;;;;;;;;wBAGL,mBAIM,OAJN,YAIM,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CADJ,mBAAkD,QAAA,EAA5C,OAAM,YAAU,EAAC,wBAAoB,GAAA,CAAA,EAAA,CAAA,EAAA,CAAA"} |
| import type { RouteProps } from '../../../v2/features/app/helpers/routes.js'; | ||
| import type { ApiClientModalOptionsRef } from '../../../v2/features/modal/helpers/types'; | ||
| /** | ||
@@ -14,9 +13,5 @@ * Operation example page | ||
| declare const __VLS_export: import("vue").DefineComponent<RouteProps & { | ||
| /** Subset of config options for the modal */ | ||
| options?: ApiClientModalOptionsRef; | ||
| /** Selected anyOf/oneOf request-body variants keyed by schema path */ | ||
| requestBodyCompositionSelection?: Record<string, number>; | ||
| }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<RouteProps & { | ||
| /** Subset of config options for the modal */ | ||
| options?: ApiClientModalOptionsRef; | ||
| /** Selected anyOf/oneOf request-body variants keyed by schema path */ | ||
@@ -23,0 +18,0 @@ requestBodyCompositionSelection?: Record<string, number>; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Operation.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/operation/Operation.vue"],"names":[],"mappings":"AAoMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAElE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAA;AAGjF;;;;;;;GAOG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IAEd,6CAA6C;cACnC,wBAAwB;IAClC,sEAAsE;sCACpC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;IAHxD,6CAA6C;cACnC,wBAAwB;IAClC,sEAAsE;sCACpC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;iGAyPxD,CAAC"} | ||
| {"version":3,"file":"Operation.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/features/operation/Operation.vue"],"names":[],"mappings":"AAiMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAIlE;;;;;;;GAOG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IAEd,sEAAsE;sCACpC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;IADxD,sEAAsE;sCACpC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;iGAyPxD,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Operation.vue.js","names":[],"sources":["../../../../src/v2/features/operation/Operation.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Operation example page\n *\n * Displays an operation with a specific example selected\n * - View example request data\n * - Modify example request data\n * - Send example request\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport {\n getActiveProxyUrl,\n getRequestExampleContext,\n} from '@scalar/workspace-store/request-example'\nimport { computed, toValue } from 'vue'\n\nimport { OperationBlock } from '@/v2/blocks/operation-block'\nimport { APP_VERSION } from '@/v2/constants'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { mapHiddenClientsConfig } from '@/v2/features/modal/helpers/map-hidden-clients-config'\nimport type { ApiClientModalOptionsRef } from '@/v2/features/modal/helpers/types'\n\nconst {\n document,\n layout,\n eventBus,\n path,\n method,\n environment,\n exampleName,\n options,\n workspaceStore,\n plugins,\n documentSlug,\n} = defineProps<\n RouteProps & {\n /** Subset of config options for the modal */\n options?: ApiClientModalOptionsRef\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n }\n>()\n\n/**\n * Shared request-example context (operation, servers, auth scope, cookies). Recomputed when any\n * underlying workspace or route input changes — same reactivity as the previous local computeds.\n */\nconst requestExample = computed(() => {\n if (!path || !method || !exampleName || !document) {\n return null\n }\n\n const result = getRequestExampleContext(\n workspaceStore,\n documentSlug,\n { path, method, exampleName },\n {\n baseServerUrl: toValue(options)?.baseServerURL,\n fallbackDocument: document,\n isElectron: isElectron(),\n layout: layout === 'web' ? 'web' : 'other',\n servers: toValue(options)?.servers,\n appVersion: APP_VERSION,\n authentication: toValue(options)?.authentication,\n },\n )\n\n return result.ok ? result.data : null\n})\n\nconst operation = computed(() => requestExample.value?.operation ?? null)\nconst workspaceCookies = computed(\n () => requestExample.value?.cookies.workspace ?? [],\n)\nconst documentCookies = computed(\n () => requestExample.value?.cookies.document ?? [],\n)\nconst servers = computed(() => requestExample.value?.servers.list ?? [])\nconst selectedServer = computed(\n () => requestExample.value?.servers.selected ?? null,\n)\nconst serverMeta = computed(\n () => requestExample.value?.servers.meta ?? { type: 'document' as const },\n)\n\nconst securitySchemes = computed(\n () => requestExample.value?.security.schemes ?? {},\n)\n\nconst selectedSecurity = computed(\n () =>\n requestExample.value?.security.selected ?? {\n selectedIndex: -1,\n selectedSchemes: [],\n },\n)\nconst selectedSecuritySchemes = computed(\n () => requestExample.value?.security.selectedSchemes ?? [],\n)\nconst securityRequirements = computed(\n () => requestExample.value?.security.requirements ?? [],\n)\nconst authMeta = computed(\n () => requestExample.value?.security.meta ?? { type: 'document' as const },\n)\n\nconst defaultHeaders = computed(\n () => requestExample.value?.headers.default ?? {},\n)\n\n/** Combine environments from document and workspace into a unique array of environment names */\nconst environments = computed(() => {\n return Array.from(\n new Set(\n Object.keys({\n ...document?.['x-scalar-environments'],\n ...workspaceStore.workspace['x-scalar-environments'],\n }),\n ),\n )\n})\n\n/** Temporarily use the old config.hiddenClients until we migrate to the new httpClients config */\nconst httpClients = computed(() =>\n mapHiddenClientsConfig(toValue(options)?.hiddenClients),\n)\n</script>\n\n<template>\n <!-- Operation exists -->\n <template v-if=\"path && method && exampleName && operation && document\">\n <OperationBlock\n :activeEnvironment=\"\n workspaceStore.workspace['x-scalar-active-environment']\n \"\n :appVersion=\"APP_VERSION\"\n :authMeta\n :defaultHeaders\n :document\n :documentCookies\n :documentSecurity=\"document?.security ?? []\"\n :documentUrl=\"document?.['x-scalar-original-source-url']\"\n :environment\n :environments\n :eventBus\n :exampleKey=\"exampleName\"\n :hideClientButton=\"toValue(options)?.hideClientButton ?? false\"\n :history=\"workspaceStore.history.getHistory(documentSlug, path, method)\"\n :httpClients\n :layout\n :method\n :operation\n :options\n :path\n :plugins=\"plugins\"\n :proxyUrl=\"\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n ) ?? ''\n \"\n :requestBodyCompositionSelection\n :securityRequirements=\"securityRequirements\"\n :securitySchemes\n :selectedClient=\"workspaceStore.workspace['x-scalar-default-client']\"\n :selectedSecurity=\"selectedSecurity\"\n :selectedSecuritySchemes=\"selectedSecuritySchemes\"\n :server=\"selectedServer\"\n :serverMeta\n :servers\n :workspaceCookies />\n </template>\n\n <!-- Empty state -->\n <div\n v-else\n class=\"flex h-full w-full items-center justify-center\">\n <span class=\"text-c-3\">Select an operation to view details</span>\n </div>\n</template>\n"],"mappings":""} | ||
| {"version":3,"file":"Operation.vue.js","names":[],"sources":["../../../../src/v2/features/operation/Operation.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Operation example page\n *\n * Displays an operation with a specific example selected\n * - View example request data\n * - Modify example request data\n * - Send example request\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport {\n getActiveProxyUrl,\n getRequestExampleContext,\n} from '@scalar/workspace-store/request-example'\nimport { computed, toValue } from 'vue'\n\nimport { OperationBlock } from '@/v2/blocks/operation-block'\nimport { APP_VERSION } from '@/v2/constants'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { mapHiddenClientsConfig } from '@/v2/features/modal/helpers/map-hidden-clients-config'\n\nconst {\n document,\n layout,\n eventBus,\n path,\n method,\n environment,\n exampleName,\n options,\n workspaceStore,\n plugins,\n documentSlug,\n} = defineProps<\n RouteProps & {\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n }\n>()\n\n/**\n * Shared request-example context (operation, servers, auth scope, cookies). Recomputed when any\n * underlying workspace or route input changes — same reactivity as the previous local computeds.\n */\nconst requestExample = computed(() => {\n if (!path || !method || !exampleName || !document) {\n return null\n }\n\n const result = getRequestExampleContext(\n workspaceStore,\n documentSlug,\n { path, method, exampleName },\n {\n baseServerUrl: toValue(options)?.baseServerURL,\n fallbackDocument: document,\n isElectron: isElectron(),\n layout: layout === 'web' ? 'web' : 'other',\n servers: toValue(options)?.servers,\n appVersion: APP_VERSION,\n authentication: toValue(options)?.authentication,\n },\n )\n\n return result.ok ? result.data : null\n})\n\nconst operation = computed(() => requestExample.value?.operation ?? null)\nconst workspaceCookies = computed(\n () => requestExample.value?.cookies.workspace ?? [],\n)\nconst documentCookies = computed(\n () => requestExample.value?.cookies.document ?? [],\n)\nconst servers = computed(() => requestExample.value?.servers.list ?? [])\nconst selectedServer = computed(\n () => requestExample.value?.servers.selected ?? null,\n)\nconst serverMeta = computed(\n () => requestExample.value?.servers.meta ?? { type: 'document' as const },\n)\n\nconst securitySchemes = computed(\n () => requestExample.value?.security.schemes ?? {},\n)\n\nconst selectedSecurity = computed(\n () =>\n requestExample.value?.security.selected ?? {\n selectedIndex: -1,\n selectedSchemes: [],\n },\n)\nconst selectedSecuritySchemes = computed(\n () => requestExample.value?.security.selectedSchemes ?? [],\n)\nconst securityRequirements = computed(\n () => requestExample.value?.security.requirements ?? [],\n)\nconst authMeta = computed(\n () => requestExample.value?.security.meta ?? { type: 'document' as const },\n)\n\nconst defaultHeaders = computed(\n () => requestExample.value?.headers.default ?? {},\n)\n\n/** Combine environments from document and workspace into a unique array of environment names */\nconst environments = computed(() => {\n return Array.from(\n new Set(\n Object.keys({\n ...document?.['x-scalar-environments'],\n ...workspaceStore.workspace['x-scalar-environments'],\n }),\n ),\n )\n})\n\n/** Temporarily use the old config.hiddenClients until we migrate to the new httpClients config */\nconst httpClients = computed(() =>\n mapHiddenClientsConfig(toValue(options)?.hiddenClients),\n)\n</script>\n\n<template>\n <!-- Operation exists -->\n <template v-if=\"path && method && exampleName && operation && document\">\n <OperationBlock\n :activeEnvironment=\"\n workspaceStore.workspace['x-scalar-active-environment']\n \"\n :appVersion=\"APP_VERSION\"\n :authMeta\n :defaultHeaders\n :document\n :documentCookies\n :documentSecurity=\"document?.security ?? []\"\n :documentUrl=\"document?.['x-scalar-original-source-url']\"\n :environment\n :environments\n :eventBus\n :exampleKey=\"exampleName\"\n :hideClientButton=\"toValue(options)?.hideClientButton ?? false\"\n :history=\"workspaceStore.history.getHistory(documentSlug, path, method)\"\n :httpClients\n :layout\n :method\n :operation\n :options\n :path\n :plugins=\"plugins\"\n :proxyUrl=\"\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n ) ?? ''\n \"\n :requestBodyCompositionSelection\n :securityRequirements=\"securityRequirements\"\n :securitySchemes\n :selectedClient=\"workspaceStore.workspace['x-scalar-default-client']\"\n :selectedSecurity=\"selectedSecurity\"\n :selectedSecuritySchemes=\"selectedSecuritySchemes\"\n :server=\"selectedServer\"\n :serverMeta\n :servers\n :workspaceCookies />\n </template>\n\n <!-- Empty state -->\n <div\n v-else\n class=\"flex h-full w-full items-center justify-center\">\n <span class=\"text-c-3\">Select an operation to view details</span>\n </div>\n</template>\n"],"mappings":""} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Operation.vue.script.js","names":[],"sources":["../../../../src/v2/features/operation/Operation.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Operation example page\n *\n * Displays an operation with a specific example selected\n * - View example request data\n * - Modify example request data\n * - Send example request\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport {\n getActiveProxyUrl,\n getRequestExampleContext,\n} from '@scalar/workspace-store/request-example'\nimport { computed, toValue } from 'vue'\n\nimport { OperationBlock } from '@/v2/blocks/operation-block'\nimport { APP_VERSION } from '@/v2/constants'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { mapHiddenClientsConfig } from '@/v2/features/modal/helpers/map-hidden-clients-config'\nimport type { ApiClientModalOptionsRef } from '@/v2/features/modal/helpers/types'\n\nconst {\n document,\n layout,\n eventBus,\n path,\n method,\n environment,\n exampleName,\n options,\n workspaceStore,\n plugins,\n documentSlug,\n} = defineProps<\n RouteProps & {\n /** Subset of config options for the modal */\n options?: ApiClientModalOptionsRef\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n }\n>()\n\n/**\n * Shared request-example context (operation, servers, auth scope, cookies). Recomputed when any\n * underlying workspace or route input changes — same reactivity as the previous local computeds.\n */\nconst requestExample = computed(() => {\n if (!path || !method || !exampleName || !document) {\n return null\n }\n\n const result = getRequestExampleContext(\n workspaceStore,\n documentSlug,\n { path, method, exampleName },\n {\n baseServerUrl: toValue(options)?.baseServerURL,\n fallbackDocument: document,\n isElectron: isElectron(),\n layout: layout === 'web' ? 'web' : 'other',\n servers: toValue(options)?.servers,\n appVersion: APP_VERSION,\n authentication: toValue(options)?.authentication,\n },\n )\n\n return result.ok ? result.data : null\n})\n\nconst operation = computed(() => requestExample.value?.operation ?? null)\nconst workspaceCookies = computed(\n () => requestExample.value?.cookies.workspace ?? [],\n)\nconst documentCookies = computed(\n () => requestExample.value?.cookies.document ?? [],\n)\nconst servers = computed(() => requestExample.value?.servers.list ?? [])\nconst selectedServer = computed(\n () => requestExample.value?.servers.selected ?? null,\n)\nconst serverMeta = computed(\n () => requestExample.value?.servers.meta ?? { type: 'document' as const },\n)\n\nconst securitySchemes = computed(\n () => requestExample.value?.security.schemes ?? {},\n)\n\nconst selectedSecurity = computed(\n () =>\n requestExample.value?.security.selected ?? {\n selectedIndex: -1,\n selectedSchemes: [],\n },\n)\nconst selectedSecuritySchemes = computed(\n () => requestExample.value?.security.selectedSchemes ?? [],\n)\nconst securityRequirements = computed(\n () => requestExample.value?.security.requirements ?? [],\n)\nconst authMeta = computed(\n () => requestExample.value?.security.meta ?? { type: 'document' as const },\n)\n\nconst defaultHeaders = computed(\n () => requestExample.value?.headers.default ?? {},\n)\n\n/** Combine environments from document and workspace into a unique array of environment names */\nconst environments = computed(() => {\n return Array.from(\n new Set(\n Object.keys({\n ...document?.['x-scalar-environments'],\n ...workspaceStore.workspace['x-scalar-environments'],\n }),\n ),\n )\n})\n\n/** Temporarily use the old config.hiddenClients until we migrate to the new httpClients config */\nconst httpClients = computed(() =>\n mapHiddenClientsConfig(toValue(options)?.hiddenClients),\n)\n</script>\n\n<template>\n <!-- Operation exists -->\n <template v-if=\"path && method && exampleName && operation && document\">\n <OperationBlock\n :activeEnvironment=\"\n workspaceStore.workspace['x-scalar-active-environment']\n \"\n :appVersion=\"APP_VERSION\"\n :authMeta\n :defaultHeaders\n :document\n :documentCookies\n :documentSecurity=\"document?.security ?? []\"\n :documentUrl=\"document?.['x-scalar-original-source-url']\"\n :environment\n :environments\n :eventBus\n :exampleKey=\"exampleName\"\n :hideClientButton=\"toValue(options)?.hideClientButton ?? false\"\n :history=\"workspaceStore.history.getHistory(documentSlug, path, method)\"\n :httpClients\n :layout\n :method\n :operation\n :options\n :path\n :plugins=\"plugins\"\n :proxyUrl=\"\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n ) ?? ''\n \"\n :requestBodyCompositionSelection\n :securityRequirements=\"securityRequirements\"\n :securitySchemes\n :selectedClient=\"workspaceStore.workspace['x-scalar-default-client']\"\n :selectedSecurity=\"selectedSecurity\"\n :selectedSecuritySchemes=\"selectedSecuritySchemes\"\n :server=\"selectedServer\"\n :serverMeta\n :servers\n :workspaceCookies />\n </template>\n\n <!-- Empty state -->\n <div\n v-else\n class=\"flex h-full w-full items-center justify-center\">\n <span class=\"text-c-3\">Select an operation to view details</span>\n </div>\n</template>\n"],"mappings":"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"} | ||
| {"version":3,"file":"Operation.vue.script.js","names":[],"sources":["../../../../src/v2/features/operation/Operation.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Operation example page\n *\n * Displays an operation with a specific example selected\n * - View example request data\n * - Modify example request data\n * - Send example request\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport {\n getActiveProxyUrl,\n getRequestExampleContext,\n} from '@scalar/workspace-store/request-example'\nimport { computed, toValue } from 'vue'\n\nimport { OperationBlock } from '@/v2/blocks/operation-block'\nimport { APP_VERSION } from '@/v2/constants'\nimport type { RouteProps } from '@/v2/features/app/helpers/routes'\nimport { mapHiddenClientsConfig } from '@/v2/features/modal/helpers/map-hidden-clients-config'\n\nconst {\n document,\n layout,\n eventBus,\n path,\n method,\n environment,\n exampleName,\n options,\n workspaceStore,\n plugins,\n documentSlug,\n} = defineProps<\n RouteProps & {\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n }\n>()\n\n/**\n * Shared request-example context (operation, servers, auth scope, cookies). Recomputed when any\n * underlying workspace or route input changes — same reactivity as the previous local computeds.\n */\nconst requestExample = computed(() => {\n if (!path || !method || !exampleName || !document) {\n return null\n }\n\n const result = getRequestExampleContext(\n workspaceStore,\n documentSlug,\n { path, method, exampleName },\n {\n baseServerUrl: toValue(options)?.baseServerURL,\n fallbackDocument: document,\n isElectron: isElectron(),\n layout: layout === 'web' ? 'web' : 'other',\n servers: toValue(options)?.servers,\n appVersion: APP_VERSION,\n authentication: toValue(options)?.authentication,\n },\n )\n\n return result.ok ? result.data : null\n})\n\nconst operation = computed(() => requestExample.value?.operation ?? null)\nconst workspaceCookies = computed(\n () => requestExample.value?.cookies.workspace ?? [],\n)\nconst documentCookies = computed(\n () => requestExample.value?.cookies.document ?? [],\n)\nconst servers = computed(() => requestExample.value?.servers.list ?? [])\nconst selectedServer = computed(\n () => requestExample.value?.servers.selected ?? null,\n)\nconst serverMeta = computed(\n () => requestExample.value?.servers.meta ?? { type: 'document' as const },\n)\n\nconst securitySchemes = computed(\n () => requestExample.value?.security.schemes ?? {},\n)\n\nconst selectedSecurity = computed(\n () =>\n requestExample.value?.security.selected ?? {\n selectedIndex: -1,\n selectedSchemes: [],\n },\n)\nconst selectedSecuritySchemes = computed(\n () => requestExample.value?.security.selectedSchemes ?? [],\n)\nconst securityRequirements = computed(\n () => requestExample.value?.security.requirements ?? [],\n)\nconst authMeta = computed(\n () => requestExample.value?.security.meta ?? { type: 'document' as const },\n)\n\nconst defaultHeaders = computed(\n () => requestExample.value?.headers.default ?? {},\n)\n\n/** Combine environments from document and workspace into a unique array of environment names */\nconst environments = computed(() => {\n return Array.from(\n new Set(\n Object.keys({\n ...document?.['x-scalar-environments'],\n ...workspaceStore.workspace['x-scalar-environments'],\n }),\n ),\n )\n})\n\n/** Temporarily use the old config.hiddenClients until we migrate to the new httpClients config */\nconst httpClients = computed(() =>\n mapHiddenClientsConfig(toValue(options)?.hiddenClients),\n)\n</script>\n\n<template>\n <!-- Operation exists -->\n <template v-if=\"path && method && exampleName && operation && document\">\n <OperationBlock\n :activeEnvironment=\"\n workspaceStore.workspace['x-scalar-active-environment']\n \"\n :appVersion=\"APP_VERSION\"\n :authMeta\n :defaultHeaders\n :document\n :documentCookies\n :documentSecurity=\"document?.security ?? []\"\n :documentUrl=\"document?.['x-scalar-original-source-url']\"\n :environment\n :environments\n :eventBus\n :exampleKey=\"exampleName\"\n :hideClientButton=\"toValue(options)?.hideClientButton ?? false\"\n :history=\"workspaceStore.history.getHistory(documentSlug, path, method)\"\n :httpClients\n :layout\n :method\n :operation\n :options\n :path\n :plugins=\"plugins\"\n :proxyUrl=\"\n getActiveProxyUrl(\n workspaceStore.workspace['x-scalar-active-proxy'],\n layout === 'web' ? 'web' : 'other',\n ) ?? ''\n \"\n :requestBodyCompositionSelection\n :securityRequirements=\"securityRequirements\"\n :securitySchemes\n :selectedClient=\"workspaceStore.workspace['x-scalar-default-client']\"\n :selectedSecurity=\"selectedSecurity\"\n :selectedSecuritySchemes=\"selectedSecuritySchemes\"\n :server=\"selectedServer\"\n :serverMeta\n :servers\n :workspaceCookies />\n </template>\n\n <!-- Empty state -->\n <div\n v-else\n class=\"flex h-full w-full items-center justify-center\">\n <span class=\"text-c-3\">Select an operation to view details</span>\n </div>\n</template>\n"],"mappings":"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"} |
+12
-12
@@ -21,3 +21,3 @@ { | ||
| ], | ||
| "version": "3.1.0", | ||
| "version": "3.2.0", | ||
| "engines": { | ||
@@ -336,17 +336,17 @@ "node": ">=22" | ||
| "zod": "^4.3.5", | ||
| "@scalar/components": "0.22.1", | ||
| "@scalar/helpers": "0.5.1", | ||
| "@scalar/icons": "0.7.2", | ||
| "@scalar/oas-utils": "0.13.1", | ||
| "@scalar/components": "0.22.2", | ||
| "@scalar/openapi-types": "0.8.0", | ||
| "@scalar/json-magic": "0.12.7", | ||
| "@scalar/oas-utils": "0.13.0", | ||
| "@scalar/icons": "0.7.2", | ||
| "@scalar/openapi-types": "0.7.0", | ||
| "@scalar/postman-to-openapi": "0.6.3", | ||
| "@scalar/sidebar": "0.9.2", | ||
| "@scalar/postman-to-openapi": "0.7.0", | ||
| "@scalar/sidebar": "0.9.3", | ||
| "@scalar/snippetz": "0.9.1", | ||
| "@scalar/themes": "0.15.3", | ||
| "@scalar/types": "0.9.1", | ||
| "@scalar/use-hooks": "0.4.3", | ||
| "@scalar/use-codemirror": "0.14.11", | ||
| "@scalar/use-hooks": "0.4.2", | ||
| "@scalar/use-toasts": "0.10.1", | ||
| "@scalar/workspace-store": "0.46.1", | ||
| "@scalar/helpers": "0.5.1" | ||
| "@scalar/use-toasts": "0.10.2", | ||
| "@scalar/workspace-store": "0.46.2" | ||
| }, | ||
@@ -366,3 +366,3 @@ "devDependencies": { | ||
| "vitest": "4.1.0", | ||
| "@scalar/pre-post-request-scripts": "0.4.3" | ||
| "@scalar/pre-post-request-scripts": "0.4.4" | ||
| }, | ||
@@ -369,0 +369,0 @@ "scripts": { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
7321942
0.41%1447
0.14%114333
0.2%60
22.45%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated
Updated