fumadocs-openapi 10.3.18 → 10.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/generated/shared.css +64 -17
- package/dist/i18n.d.ts +100 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +113 -0
- package/dist/i18n.js.map +1 -0
- package/dist/playground/client.d.ts +1 -1
- package/dist/playground/client.d.ts.map +1 -1
- package/dist/playground/client.js +40 -30
- package/dist/playground/client.js.map +1 -1
- package/dist/playground/components/inputs.js +16 -12
- package/dist/playground/components/inputs.js.map +1 -1
- package/dist/playground/components/oauth-dialog.js +45 -44
- package/dist/playground/components/oauth-dialog.js.map +1 -1
- package/dist/playground/components/server-select.js +7 -4
- package/dist/playground/components/server-select.js.map +1 -1
- package/dist/playground/status-info.js +18 -11
- package/dist/playground/status-info.js.map +1 -1
- package/dist/requests/generators/index.d.ts +1 -1
- package/dist/requests/generators/index.js +2 -2
- package/dist/requests/generators/index.js.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/base.d.ts +9 -8
- package/dist/ui/base.d.ts.map +1 -1
- package/dist/ui/base.js +13 -7
- package/dist/ui/base.js.map +1 -1
- package/dist/ui/client/i18n.js +19 -0
- package/dist/ui/client/i18n.js.map +1 -0
- package/dist/ui/components/codeblock.d.ts +15 -0
- package/dist/ui/components/codeblock.d.ts.map +1 -0
- package/dist/ui/components/codeblock.js +27 -0
- package/dist/ui/components/codeblock.js.map +1 -0
- package/dist/ui/components/dialog.js +17 -13
- package/dist/ui/components/dialog.js.map +1 -1
- package/dist/ui/full.client.js +6 -7
- package/dist/ui/full.client.js.map +1 -1
- package/dist/ui/full.d.ts.map +1 -1
- package/dist/ui/full.js +8 -4
- package/dist/ui/full.js.map +1 -1
- package/dist/ui/operation/client.js +7 -8
- package/dist/ui/operation/client.js.map +1 -1
- package/dist/ui/operation/index.js +46 -23
- package/dist/ui/operation/index.js.map +1 -1
- package/dist/ui/operation/request-tabs.d.ts.map +1 -1
- package/dist/ui/operation/request-tabs.js +9 -8
- package/dist/ui/operation/request-tabs.js.map +1 -1
- package/dist/ui/operation/response-tabs.d.ts +1 -1
- package/dist/ui/operation/response-tabs.d.ts.map +1 -1
- package/dist/ui/operation/response-tabs.js +13 -12
- package/dist/ui/operation/response-tabs.js.map +1 -1
- package/dist/ui/operation/usage-tabs/client.js +4 -5
- package/dist/ui/operation/usage-tabs/client.js.map +1 -1
- package/dist/ui/schema/client.d.ts.map +1 -1
- package/dist/ui/schema/client.js +32 -21
- package/dist/ui/schema/client.js.map +1 -1
- package/dist/ui/schema/index.d.ts +1 -1
- package/dist/ui/schema/index.d.ts.map +1 -1
- package/dist/ui/schema/index.js +11 -10
- package/dist/ui/schema/index.js.map +1 -1
- package/dist/utils/process-document.d.ts +1 -1
- package/dist/utils/process-document.js +19 -15
- package/dist/utils/process-document.js.map +1 -1
- package/package.json +19 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inputs.js","names":[],"sources":["../../../src/playground/components/inputs.tsx"],"sourcesContent":["'use client';\nimport { type ComponentProps, type HTMLAttributes, type ReactNode, useState } from 'react';\nimport { ChevronRight, Plus, Trash2, X } from 'lucide-react';\nimport { FieldKey, useArray, useDataEngine, useFieldValue, useObject } from '@fumari/stf';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { FormatFlags } from '@/utils/schema-to-string';\nimport {\n anyFields,\n useFieldInfo,\n useSchemaUtils,\n useSchemaScope,\n useResolvedSchema,\n} from '@/playground/schema';\nimport type { ParsedSchema } from '@/utils/schema';\nimport { stringifyFieldKey } from '@fumari/stf/lib/utils';\nimport { cva } from 'class-variance-authority';\n\nconst fieldLabelVariants = cva('w-full inline-flex items-center gap-0.5');\n\nfunction FieldLabelType(props: ComponentProps<'code'>) {\n return (\n <code {...props} className={cn('text-xs text-fd-muted-foreground', props.className)}>\n {props.children}\n </code>\n );\n}\n\nexport function ObjectInput({\n field: _field,\n fieldName,\n ...props\n}: {\n field: Exclude<ParsedSchema, boolean>;\n fieldName: FieldKey;\n} & ComponentProps<'div'>) {\n const { generateDefault } = useSchemaUtils();\n const field = useResolvedSchema(_field);\n const schemaPropKeys = field.properties ? Object.keys(field.properties) : [];\n const {\n patternProperties = {},\n additionalProperties,\n 'x-playground-lazy': isLazy = schemaPropKeys.length > 100,\n } = field;\n const isDynamic = Object.keys(patternProperties).length > 0 || additionalProperties;\n\n const [nextName, setNextName] = useState('');\n const { properties, onAppend, onDelete, _objectKeys } = useObject(fieldName, {\n lazy: isLazy,\n defaultValue: () => generateDefault(field) as object,\n properties: field.properties ?? {},\n fallback: additionalProperties,\n patternProperties: patternProperties,\n });\n\n const hiddenProperties = isLazy ? schemaPropKeys.filter((key) => !_objectKeys.includes(key)) : [];\n\n return (\n <div\n {...props}\n className={cn(\n 'grid grid-cols-1 gap-4 @md:grid-cols-2 *:data-[collapsible=true]:order-last',\n props.className,\n )}\n >\n {isLazy && hiddenProperties.length > 0 && (\n <Select value=\"\" onValueChange={onAppend}>\n <SelectTrigger className=\"col-span-full\">\n <SelectValue placeholder=\"Show Property\" />\n </SelectTrigger>\n <SelectContent>\n {hiddenProperties.map((key) => (\n <SelectItem key={key} value={key}>\n {key}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n\n {properties.map((child) => {\n let toolbar: ReactNode = null;\n if (child.kind === 'pattern' || child.kind === 'fallback') {\n toolbar = (\n <button\n type=\"button\"\n aria-label=\"Remove Item\"\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => {\n onDelete(child.key);\n }}\n >\n <Trash2 />\n </button>\n );\n }\n\n return (\n <FieldSet\n key={child.key}\n name={child.key}\n field={child.info}\n fieldName={child.field}\n isRequired={field.required?.includes(child.key)}\n toolbar={toolbar}\n />\n );\n })}\n {isDynamic && (\n <div className=\"flex gap-2 order-last col-span-full\">\n <Input\n value={nextName}\n placeholder=\"Enter Property Name\"\n onChange={(e) => setNextName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n setNextName('');\n onAppend(nextName);\n e.preventDefault();\n }\n }}\n />\n <button\n type=\"button\"\n className={cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'px-4')}\n onClick={() => {\n onAppend(nextName);\n setNextName('');\n }}\n >\n New\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function JsonInput({ fieldName }: { fieldName: FieldKey }) {\n const engine = useDataEngine();\n const [error, setError] = useState<string | null>(null);\n const [value, setValue] = useState(() => JSON.stringify(engine.init(fieldName, {}), null, 2));\n\n return (\n <div className=\"flex flex-col bg-fd-secondary text-fd-secondary-foreground overflow-hidden border rounded-lg\">\n <textarea\n value={value}\n className=\"p-2 h-[240px] text-sm font-mono resize-none focus-visible:outline-none\"\n onChange={(v) => {\n setValue(v.target.value);\n try {\n engine.update(fieldName, JSON.parse(v.target.value));\n setError(null);\n } catch (e) {\n if (e instanceof Error) setError(e.message);\n }\n }}\n />\n <p className=\"p-2 text-xs font-mono border-t text-red-400 empty:hidden\">{error}</p>\n </div>\n );\n}\n\nexport function FieldInput({\n field,\n fieldName,\n isRequired,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n field: Exclude<ParsedSchema, boolean>;\n isRequired?: boolean;\n fieldName: FieldKey;\n}) {\n const [value, setValue] = useFieldValue(fieldName);\n const id = stringifyFieldKey(fieldName);\n if (field.type === 'null') return;\n\n if (field.type === 'string' && field.format === 'binary') {\n return (\n <>\n <label\n htmlFor={id}\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'w-full h-9 gap-2 truncate',\n }),\n )}\n >\n {value instanceof File ? (\n <>\n <span className=\"text-fd-muted-foreground text-xs\">Selected</span>\n <span className=\"truncate w-0 flex-1 text-end\">{value.name}</span>\n </>\n ) : (\n <span className=\"text-fd-muted-foreground\">Upload</span>\n )}\n </label>\n <input\n id={id}\n type=\"file\"\n multiple={false}\n onChange={(e) => {\n if (!e.target.files || e.target.files.length === 0) return;\n setValue(e.target.files.item(0));\n }}\n hidden\n />\n </>\n );\n }\n\n if (field.enum && field.enum.length > 0) {\n const idx = field.enum.indexOf(value);\n\n return (\n <Select\n value={idx === -1 && isRequired ? '' : String(idx)}\n onValueChange={(v) => setValue(field.enum![Number(v)])}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue placeholder=\"Select\" />\n </SelectTrigger>\n <SelectContent>\n {field.enum.map((item, i) => (\n <SelectItem key={i} value={String(i)}>\n {typeof item === 'string' ? item : JSON.stringify(item, null, 2)}\n </SelectItem>\n ))}\n {!isRequired && <SelectItem value=\"-1\">Unset</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Select\n value={String(value)}\n onValueChange={(value) => setValue(value === 'undefined' ? undefined : value === 'true')}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"true\">True</SelectItem>\n <SelectItem value=\"false\">False</SelectItem>\n {!isRequired && <SelectItem value=\"undefined\">Unset</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n const isNumber = field.type === 'integer' || field.type === 'number';\n return (\n <Input\n id={id}\n placeholder=\"Enter value\"\n type={isNumber ? 'number' : 'text'}\n step={field.type === 'integer' ? 1 : undefined}\n value={String(value ?? '')}\n onChange={(e) => {\n if (isNumber) {\n setValue(Number.isNaN(e.target.valueAsNumber) ? undefined : e.target.valueAsNumber);\n } else if (!isNumber) {\n setValue(e.target.value);\n }\n }}\n />\n );\n}\n\nexport function FieldSet({\n field: _field,\n fieldName,\n toolbar,\n name,\n isRequired,\n depth = 0,\n slotType,\n collapsible = true,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n isRequired?: boolean;\n name?: ReactNode;\n field: ParsedSchema;\n fieldName: FieldKey;\n depth?: number;\n\n slotType?: ReactNode;\n toolbar?: ReactNode;\n collapsible?: boolean;\n}) {\n const { readOnly, writeOnly } = useSchemaScope();\n const { generateDefault, schemaToString } = useSchemaUtils();\n const field = useResolvedSchema(_field);\n const [show, setShow] = useState(!collapsible);\n const { info, updateInfo } = useFieldInfo(fieldName, field, depth);\n const id = stringifyFieldKey(fieldName);\n const dataEngine = useDataEngine();\n const [isDefined] = useFieldValue(fieldName, {\n compute(currentValue) {\n return currentValue !== undefined;\n },\n });\n\n if (_field === false) return;\n if (field.readOnly && !readOnly) return;\n if (field.writeOnly && !writeOnly) return;\n\n if (collapsible && !isDefined && show) setShow(false);\n\n function renderLabelTrigger(schema = field) {\n if (!collapsible) return renderLabelName();\n\n return (\n <button\n type=\"button\"\n className={cn(labelVariants(), 'inline-flex items-center gap-1 font-mono me-auto')}\n onClick={() => {\n dataEngine.init(fieldName, generateDefault(schema));\n setShow((prev) => !prev);\n }}\n >\n <ChevronRight className={cn('size-3.5 text-fd-muted-foreground', show && 'rotate-90')} />\n {name}\n {isRequired && <span className=\"text-red-400/80\">*</span>}\n </button>\n );\n }\n\n function renderLabelName() {\n return (\n <span className={cn(labelVariants(), 'font-mono me-auto')}>\n {name}\n {isRequired && <span className=\"text-red-400/80 mx-1\">*</span>}\n </span>\n );\n }\n\n function renderUnsetButton() {\n return (\n <button\n type=\"button\"\n onClick={() => dataEngine.delete(fieldName)}\n className=\"text-fd-muted-foreground hover:text-fd-accent-foreground\"\n >\n <X className=\"size-3.5\" />\n </button>\n );\n }\n\n if (info.unionField && field[info.unionField] && field[info.unionField]!.length > 0) {\n const union = field[info.unionField]!;\n const showSelect = union.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={union[info.oneOf]}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n collapsible={collapsible}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.oneOf}\n onChange={(e) => {\n updateInfo({\n oneOf: Number(e.target.value),\n });\n }}\n >\n {union.map((item, i) => (\n <option key={i} value={i} className=\"bg-fd-popover text-fd-popover-foreground\">\n {schemaToString(item, FormatFlags.UseAlias)}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (Array.isArray(field.type)) {\n const showSelect = field.type.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={{\n ...field,\n type: info.selectedType,\n }}\n collapsible={collapsible}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.selectedType}\n onChange={(e) => {\n updateInfo({\n selectedType: e.target.value,\n });\n }}\n >\n {field.type.map((item) => (\n <option\n key={item}\n value={item}\n className=\"bg-fd-popover text-fd-popover-foreground\"\n >\n {item}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (field.type === 'object') {\n return (\n <fieldset\n {...props}\n data-collapsible={collapsible}\n className={cn('flex flex-col gap-1.5 col-span-full @container', props.className)}\n >\n <div className={fieldLabelVariants()}>\n {renderLabelTrigger(field)}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </div>\n {show && (\n <ObjectInput\n field={field}\n fieldName={fieldName}\n className=\"rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm\"\n />\n )}\n </fieldset>\n );\n }\n\n if (field.type === 'array') {\n return (\n <fieldset\n {...props}\n data-collapsible={collapsible}\n className={cn('flex flex-col gap-1.5 col-span-full', props.className)}\n >\n <div className={fieldLabelVariants()}>\n {renderLabelTrigger()}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </div>\n {show && (\n <ArrayInput\n fieldName={fieldName}\n items={field.items ?? anyFields}\n className=\"rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm\"\n />\n )}\n </fieldset>\n );\n }\n\n return (\n <fieldset {...props} className={cn('flex flex-col gap-1.5', props.className)}>\n <label className={fieldLabelVariants()} htmlFor={id}>\n {renderLabelName()}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </label>\n <FieldInput field={field} fieldName={fieldName} isRequired={isRequired} />\n </fieldset>\n );\n}\n\nfunction ArrayInput({\n fieldName,\n items: itemSchema,\n ...props\n}: {\n fieldName: FieldKey;\n items: ParsedSchema;\n} & ComponentProps<'div'>) {\n const name = fieldName.at(-1) ?? '';\n const { generateDefault } = useSchemaUtils();\n const { items, insertItem, removeItem } = useArray(fieldName);\n\n return (\n <div {...props} className={cn('flex flex-col gap-2', props.className)}>\n {items.map((item) => (\n <FieldSet\n key={item.index}\n name={\n <span className=\"text-fd-muted-foreground\">\n {name}[{item.index}]\n </span>\n }\n field={itemSchema}\n isRequired\n fieldName={item.field}\n toolbar={\n <button\n type=\"button\"\n aria-label=\"Remove Item\"\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => removeItem(item.index)}\n >\n <Trash2 />\n </button>\n }\n />\n ))}\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'gap-1.5 py-2',\n size: 'sm',\n }),\n )}\n onClick={() => {\n insertItem(generateDefault(itemSchema));\n }}\n >\n <Plus className=\"size-4\" />\n New Item\n </button>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"inputs.js","names":[],"sources":["../../../src/playground/components/inputs.tsx"],"sourcesContent":["'use client';\nimport { type ComponentProps, type HTMLAttributes, type ReactNode, useState } from 'react';\nimport { ChevronRight, Plus, Trash2, X } from 'lucide-react';\nimport { FieldKey, useArray, useDataEngine, useFieldValue, useObject } from '@fumari/stf';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { FormatFlags } from '@/utils/schema-to-string';\nimport {\n anyFields,\n useFieldInfo,\n useSchemaUtils,\n useSchemaScope,\n useResolvedSchema,\n} from '@/playground/schema';\nimport type { ParsedSchema } from '@/utils/schema';\nimport { stringifyFieldKey } from '@fumari/stf/lib/utils';\nimport { cva } from 'class-variance-authority';\nimport { useTranslations } from '@/ui/client/i18n';\n\nconst fieldLabelVariants = cva('w-full inline-flex items-center gap-0.5');\n\nfunction FieldLabelType(props: ComponentProps<'code'>) {\n return (\n <code {...props} className={cn('text-xs text-fd-muted-foreground', props.className)}>\n {props.children}\n </code>\n );\n}\n\nexport function ObjectInput({\n field: _field,\n fieldName,\n ...props\n}: {\n field: Exclude<ParsedSchema, boolean>;\n fieldName: FieldKey;\n} & ComponentProps<'div'>) {\n const { generateDefault } = useSchemaUtils();\n const field = useResolvedSchema(_field);\n const schemaPropKeys = field.properties ? Object.keys(field.properties) : [];\n const {\n patternProperties = {},\n additionalProperties,\n 'x-playground-lazy': isLazy = schemaPropKeys.length > 100,\n } = field;\n const isDynamic = Object.keys(patternProperties).length > 0 || additionalProperties;\n\n const [nextName, setNextName] = useState('');\n const { properties, onAppend, onDelete, _objectKeys } = useObject(fieldName, {\n lazy: isLazy,\n defaultValue: () => generateDefault(field) as object,\n properties: field.properties ?? {},\n fallback: additionalProperties,\n patternProperties: patternProperties,\n });\n\n const hiddenProperties = isLazy ? schemaPropKeys.filter((key) => !_objectKeys.includes(key)) : [];\n const t = useTranslations();\n\n return (\n <div\n {...props}\n className={cn(\n 'grid grid-cols-1 gap-4 @md:grid-cols-2 *:data-[collapsible=true]:order-last',\n props.className,\n )}\n >\n {isLazy && hiddenProperties.length > 0 && (\n <Select value=\"\" onValueChange={onAppend}>\n <SelectTrigger className=\"col-span-full\">\n <SelectValue placeholder={t.playgroundShowProperty} />\n </SelectTrigger>\n <SelectContent>\n {hiddenProperties.map((key) => (\n <SelectItem key={key} value={key}>\n {key}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n\n {properties.map((child) => {\n let toolbar: ReactNode = null;\n if (child.kind === 'pattern' || child.kind === 'fallback') {\n toolbar = (\n <button\n type=\"button\"\n aria-label={t.playgroundRemoveItem}\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => {\n onDelete(child.key);\n }}\n >\n <Trash2 />\n </button>\n );\n }\n\n return (\n <FieldSet\n key={child.key}\n name={child.key}\n field={child.info}\n fieldName={child.field}\n isRequired={field.required?.includes(child.key)}\n toolbar={toolbar}\n />\n );\n })}\n {isDynamic && (\n <div className=\"flex gap-2 order-last col-span-full\">\n <Input\n value={nextName}\n placeholder={t.playgroundPropertyPlaceholder}\n onChange={(e) => setNextName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n setNextName('');\n onAppend(nextName);\n e.preventDefault();\n }\n }}\n />\n <button\n type=\"button\"\n className={cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'px-4')}\n onClick={() => {\n onAppend(nextName);\n setNextName('');\n }}\n >\n {t.playgroundNewProperty}\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function JsonInput({ fieldName }: { fieldName: FieldKey }) {\n const engine = useDataEngine();\n const [error, setError] = useState<string | null>(null);\n const [value, setValue] = useState(() => JSON.stringify(engine.init(fieldName, {}), null, 2));\n\n return (\n <div className=\"flex flex-col bg-fd-secondary text-fd-secondary-foreground overflow-hidden border rounded-lg\">\n <textarea\n value={value}\n className=\"p-2 h-[240px] text-sm font-mono resize-none focus-visible:outline-none\"\n onChange={(v) => {\n setValue(v.target.value);\n try {\n engine.update(fieldName, JSON.parse(v.target.value));\n setError(null);\n } catch (e) {\n if (e instanceof Error) setError(e.message);\n }\n }}\n />\n <p className=\"p-2 text-xs font-mono border-t text-red-400 empty:hidden\">{error}</p>\n </div>\n );\n}\n\nexport function FieldInput({\n field,\n fieldName,\n isRequired,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n field: Exclude<ParsedSchema, boolean>;\n isRequired?: boolean;\n fieldName: FieldKey;\n}) {\n const [value, setValue] = useFieldValue(fieldName);\n const id = stringifyFieldKey(fieldName);\n const t = useTranslations();\n if (field.type === 'null') return;\n\n if (field.type === 'string' && field.format === 'binary') {\n return (\n <>\n <label\n htmlFor={id}\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'w-full h-9 gap-2 truncate',\n }),\n )}\n >\n {value instanceof File ? (\n <>\n <span className=\"text-fd-muted-foreground text-xs\">{t.playgroundSelected}</span>\n <span className=\"truncate w-0 flex-1 text-end\">{value.name}</span>\n </>\n ) : (\n <span className=\"text-fd-muted-foreground\">{t.playgroundInputUpload}</span>\n )}\n </label>\n <input\n id={id}\n type=\"file\"\n multiple={false}\n onChange={(e) => {\n if (!e.target.files || e.target.files.length === 0) return;\n setValue(e.target.files.item(0));\n }}\n hidden\n />\n </>\n );\n }\n\n if (field.enum && field.enum.length > 0) {\n const idx = field.enum.indexOf(value);\n\n return (\n <Select\n value={idx === -1 && isRequired ? '' : String(idx)}\n onValueChange={(v) => setValue(field.enum![Number(v)])}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue placeholder={t.playgroundSelectPlaceholder} />\n </SelectTrigger>\n <SelectContent>\n {field.enum.map((item, i) => (\n <SelectItem key={i} value={String(i)}>\n {typeof item === 'string' ? item : JSON.stringify(item, null, 2)}\n </SelectItem>\n ))}\n {!isRequired && <SelectItem value=\"-1\">{t.playgroundInputUnset}</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Select\n value={String(value)}\n onValueChange={(value) => setValue(value === 'undefined' ? undefined : value === 'true')}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"true\">True</SelectItem>\n <SelectItem value=\"false\">False</SelectItem>\n {!isRequired && <SelectItem value=\"undefined\">{t.playgroundInputUnset}</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n const isNumber = field.type === 'integer' || field.type === 'number';\n return (\n <Input\n id={id}\n placeholder={t.inputPlaceholder}\n type={isNumber ? 'number' : 'text'}\n step={field.type === 'integer' ? 1 : undefined}\n value={String(value ?? '')}\n onChange={(e) => {\n if (isNumber) {\n setValue(Number.isNaN(e.target.valueAsNumber) ? undefined : e.target.valueAsNumber);\n } else if (!isNumber) {\n setValue(e.target.value);\n }\n }}\n />\n );\n}\n\nexport function FieldSet({\n field: _field,\n fieldName,\n toolbar,\n name,\n isRequired,\n depth = 0,\n slotType,\n collapsible = true,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n isRequired?: boolean;\n name?: ReactNode;\n field: ParsedSchema;\n fieldName: FieldKey;\n depth?: number;\n\n slotType?: ReactNode;\n toolbar?: ReactNode;\n collapsible?: boolean;\n}) {\n const { readOnly, writeOnly } = useSchemaScope();\n const { generateDefault, schemaToString } = useSchemaUtils();\n const field = useResolvedSchema(_field);\n const [show, setShow] = useState(!collapsible);\n const { info, updateInfo } = useFieldInfo(fieldName, field, depth);\n const id = stringifyFieldKey(fieldName);\n const dataEngine = useDataEngine();\n const [isDefined] = useFieldValue(fieldName, {\n compute(currentValue) {\n return currentValue !== undefined;\n },\n });\n\n if (_field === false) return;\n if (field.readOnly && !readOnly) return;\n if (field.writeOnly && !writeOnly) return;\n\n if (collapsible && !isDefined && show) setShow(false);\n\n function renderLabelTrigger(schema = field) {\n if (!collapsible) return renderLabelName();\n\n return (\n <button\n type=\"button\"\n className={cn(labelVariants(), 'inline-flex items-center gap-1 font-mono me-auto')}\n onClick={() => {\n dataEngine.init(fieldName, generateDefault(schema));\n setShow((prev) => !prev);\n }}\n >\n <ChevronRight className={cn('size-3.5 text-fd-muted-foreground', show && 'rotate-90')} />\n {name}\n {isRequired && <span className=\"text-red-400/80\">*</span>}\n </button>\n );\n }\n\n function renderLabelName() {\n return (\n <span className={cn(labelVariants(), 'font-mono me-auto')}>\n {name}\n {isRequired && <span className=\"text-red-400/80 mx-1\">*</span>}\n </span>\n );\n }\n\n function renderUnsetButton() {\n return (\n <button\n type=\"button\"\n onClick={() => dataEngine.delete(fieldName)}\n className=\"text-fd-muted-foreground hover:text-fd-accent-foreground\"\n >\n <X className=\"size-3.5\" />\n </button>\n );\n }\n\n if (info.unionField && field[info.unionField] && field[info.unionField]!.length > 0) {\n const union = field[info.unionField]!;\n const showSelect = union.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={union[info.oneOf]}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n collapsible={collapsible}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.oneOf}\n onChange={(e) => {\n updateInfo({\n oneOf: Number(e.target.value),\n });\n }}\n >\n {union.map((item, i) => (\n <option key={i} value={i} className=\"bg-fd-popover text-fd-popover-foreground\">\n {schemaToString(item, FormatFlags.UseAlias)}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (Array.isArray(field.type)) {\n const showSelect = field.type.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={{\n ...field,\n type: info.selectedType,\n }}\n collapsible={collapsible}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.selectedType}\n onChange={(e) => {\n updateInfo({\n selectedType: e.target.value,\n });\n }}\n >\n {field.type.map((item) => (\n <option\n key={item}\n value={item}\n className=\"bg-fd-popover text-fd-popover-foreground\"\n >\n {item}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (field.type === 'object') {\n return (\n <fieldset\n {...props}\n data-collapsible={collapsible}\n className={cn('flex flex-col gap-1.5 col-span-full @container', props.className)}\n >\n <div className={fieldLabelVariants()}>\n {renderLabelTrigger(field)}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </div>\n {show && (\n <ObjectInput\n field={field}\n fieldName={fieldName}\n className=\"rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm\"\n />\n )}\n </fieldset>\n );\n }\n\n if (field.type === 'array') {\n return (\n <fieldset\n {...props}\n data-collapsible={collapsible}\n className={cn('flex flex-col gap-1.5 col-span-full', props.className)}\n >\n <div className={fieldLabelVariants()}>\n {renderLabelTrigger()}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </div>\n {show && (\n <ArrayInput\n fieldName={fieldName}\n items={field.items ?? anyFields}\n className=\"rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm\"\n />\n )}\n </fieldset>\n );\n }\n\n return (\n <fieldset {...props} className={cn('flex flex-col gap-1.5', props.className)}>\n <label className={fieldLabelVariants()} htmlFor={id}>\n {renderLabelName()}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </label>\n <FieldInput field={field} fieldName={fieldName} isRequired={isRequired} />\n </fieldset>\n );\n}\n\nfunction ArrayInput({\n fieldName,\n items: itemSchema,\n ...props\n}: {\n fieldName: FieldKey;\n items: ParsedSchema;\n} & ComponentProps<'div'>) {\n const name = fieldName.at(-1) ?? '';\n const { generateDefault } = useSchemaUtils();\n const { items, insertItem, removeItem } = useArray(fieldName);\n const t = useTranslations();\n\n return (\n <div {...props} className={cn('flex flex-col gap-2', props.className)}>\n {items.map((item) => (\n <FieldSet\n key={item.index}\n name={\n <span className=\"text-fd-muted-foreground\">\n {name}[{item.index}]\n </span>\n }\n field={itemSchema}\n isRequired\n fieldName={item.field}\n toolbar={\n <button\n type=\"button\"\n aria-label={t.playgroundRemoveItem}\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => removeItem(item.index)}\n >\n <Trash2 />\n </button>\n }\n />\n ))}\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'gap-1.5 py-2',\n size: 'sm',\n }),\n )}\n onClick={() => {\n insertItem(generateDefault(itemSchema));\n }}\n >\n <Plus className=\"size-4\" />\n {t.playgroundNewItem}\n </button>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,44 +2,45 @@ import { cn } from "../../utils/cn.js";
|
|
|
2
2
|
import { useQuery } from "../../utils/use-query.js";
|
|
3
3
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
|
|
4
4
|
import { Input, labelVariants } from "../../ui/components/input.js";
|
|
5
|
+
import { useTranslations } from "../../ui/client/i18n.js";
|
|
5
6
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
|
|
6
|
-
import { useEffect, useState } from "react";
|
|
7
|
+
import { useEffect, useMemo, useState } from "react";
|
|
7
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
9
10
|
import { useForm } from "react-hook-form";
|
|
10
11
|
//#region src/playground/components/oauth-dialog.tsx
|
|
11
|
-
const FlowTypes = {
|
|
12
|
-
password: {
|
|
13
|
-
name: "Resource Owner Password Flow",
|
|
14
|
-
description: "Authenticate using username and password.",
|
|
15
|
-
supported: true
|
|
16
|
-
},
|
|
17
|
-
clientCredentials: {
|
|
18
|
-
name: "Client Credentials",
|
|
19
|
-
description: "Intended for the server-to-server authentication.",
|
|
20
|
-
supported: true
|
|
21
|
-
},
|
|
22
|
-
authorizationCode: {
|
|
23
|
-
name: "Authorization code",
|
|
24
|
-
description: "Authenticate with 3rd party services",
|
|
25
|
-
supported: true
|
|
26
|
-
},
|
|
27
|
-
implicit: {
|
|
28
|
-
name: "Implicit",
|
|
29
|
-
description: "Retrieve the access token directly.",
|
|
30
|
-
supported: true
|
|
31
|
-
},
|
|
32
|
-
deviceAuthorization: {
|
|
33
|
-
name: "Device Authorization",
|
|
34
|
-
description: "Authenticate with device.",
|
|
35
|
-
supported: false
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
12
|
function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
39
13
|
const [type, setType] = useState(() => {
|
|
40
14
|
return Object.keys(scheme.flows)[0];
|
|
41
15
|
});
|
|
42
|
-
const
|
|
16
|
+
const t = useTranslations();
|
|
17
|
+
const allFlows = useMemo(() => ({
|
|
18
|
+
password: {
|
|
19
|
+
name: t.resourceOwnerPassword,
|
|
20
|
+
description: t.resourceOwnerPasswordDesc,
|
|
21
|
+
supported: true
|
|
22
|
+
},
|
|
23
|
+
clientCredentials: {
|
|
24
|
+
name: t.clientCredentials,
|
|
25
|
+
description: t.clientCredentialsDesc,
|
|
26
|
+
supported: true
|
|
27
|
+
},
|
|
28
|
+
authorizationCode: {
|
|
29
|
+
name: t.authorizationCode,
|
|
30
|
+
description: t.authorizationCodeDesc,
|
|
31
|
+
supported: true
|
|
32
|
+
},
|
|
33
|
+
implicit: {
|
|
34
|
+
name: t.implicit,
|
|
35
|
+
description: t.implicitDesc,
|
|
36
|
+
supported: true
|
|
37
|
+
},
|
|
38
|
+
deviceAuthorization: {
|
|
39
|
+
name: t.deviceAuthorization,
|
|
40
|
+
description: t.deviceAuthorizationDesc,
|
|
41
|
+
supported: false
|
|
42
|
+
}
|
|
43
|
+
}), [t]);
|
|
43
44
|
const form = useForm({ defaultValues: {
|
|
44
45
|
clientId: "",
|
|
45
46
|
clientSecret: "",
|
|
@@ -164,7 +165,7 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
164
165
|
return /* @__PURE__ */ jsxs(Dialog, {
|
|
165
166
|
open,
|
|
166
167
|
onOpenChange: setOpen,
|
|
167
|
-
children: [children, /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children:
|
|
168
|
+
children: [children, /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t.authorization }), /* @__PURE__ */ jsx(DialogDescription, { children: t.obtainAccessToken })] }), /* @__PURE__ */ jsxs("form", {
|
|
168
169
|
className: "flex flex-col gap-6",
|
|
169
170
|
onSubmit: (e) => {
|
|
170
171
|
onSubmit(e);
|
|
@@ -175,7 +176,7 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
175
176
|
value: type,
|
|
176
177
|
onValueChange: setType,
|
|
177
178
|
children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }), /* @__PURE__ */ jsx(SelectContent, { children: Object.keys(scheme.flows).map((key) => {
|
|
178
|
-
const { name, description } =
|
|
179
|
+
const { name, description } = allFlows[key];
|
|
179
180
|
return /* @__PURE__ */ jsxs(SelectItem, {
|
|
180
181
|
value: key,
|
|
181
182
|
children: [/* @__PURE__ */ jsx("p", {
|
|
@@ -194,15 +195,15 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
194
195
|
/* @__PURE__ */ jsx("label", {
|
|
195
196
|
htmlFor: "client_id",
|
|
196
197
|
className: cn(labelVariants()),
|
|
197
|
-
children:
|
|
198
|
+
children: t.clientId
|
|
198
199
|
}),
|
|
199
200
|
/* @__PURE__ */ jsx("p", {
|
|
200
201
|
className: "text-fd-muted-foreground text-sm",
|
|
201
|
-
children:
|
|
202
|
+
children: t.clientIdHint
|
|
202
203
|
}),
|
|
203
204
|
/* @__PURE__ */ jsx(Input, {
|
|
204
205
|
id: "client_id",
|
|
205
|
-
placeholder:
|
|
206
|
+
placeholder: t.inputPlaceholder,
|
|
206
207
|
type: "text",
|
|
207
208
|
autoComplete: "off",
|
|
208
209
|
disabled: isLoading,
|
|
@@ -216,15 +217,15 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
216
217
|
/* @__PURE__ */ jsx("label", {
|
|
217
218
|
htmlFor: "client_secret",
|
|
218
219
|
className: cn(labelVariants()),
|
|
219
|
-
children:
|
|
220
|
+
children: t.clientSecret
|
|
220
221
|
}),
|
|
221
222
|
/* @__PURE__ */ jsx("p", {
|
|
222
223
|
className: "text-fd-muted-foreground text-sm",
|
|
223
|
-
children:
|
|
224
|
+
children: t.clientSecretHint
|
|
224
225
|
}),
|
|
225
226
|
/* @__PURE__ */ jsx(Input, {
|
|
226
227
|
id: "client_secret",
|
|
227
|
-
placeholder:
|
|
228
|
+
placeholder: t.inputPlaceholder,
|
|
228
229
|
type: "password",
|
|
229
230
|
autoComplete: "off",
|
|
230
231
|
disabled: isLoading,
|
|
@@ -237,10 +238,10 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
237
238
|
children: [/* @__PURE__ */ jsx("label", {
|
|
238
239
|
htmlFor: "username",
|
|
239
240
|
className: cn(labelVariants()),
|
|
240
|
-
children:
|
|
241
|
+
children: t.usernameField
|
|
241
242
|
}), /* @__PURE__ */ jsx(Input, {
|
|
242
243
|
id: "username",
|
|
243
|
-
placeholder:
|
|
244
|
+
placeholder: t.inputPlaceholder,
|
|
244
245
|
type: "text",
|
|
245
246
|
disabled: isLoading,
|
|
246
247
|
autoComplete: "off",
|
|
@@ -251,27 +252,27 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
251
252
|
children: [/* @__PURE__ */ jsx("label", {
|
|
252
253
|
htmlFor: "password",
|
|
253
254
|
className: cn(labelVariants()),
|
|
254
|
-
children:
|
|
255
|
+
children: t.clientSecret
|
|
255
256
|
}), /* @__PURE__ */ jsx(Input, {
|
|
256
257
|
id: "password",
|
|
257
|
-
placeholder:
|
|
258
|
+
placeholder: t.inputPlaceholder,
|
|
258
259
|
type: "password",
|
|
259
260
|
autoComplete: "off",
|
|
260
261
|
disabled: isLoading,
|
|
261
262
|
...form.register("password", { required: true })
|
|
262
263
|
})]
|
|
263
264
|
})] }),
|
|
264
|
-
supported ? /* @__PURE__ */ jsxs(Fragment$1, { children: [error ? /* @__PURE__ */ jsx("p", {
|
|
265
|
+
allFlows[type].supported ? /* @__PURE__ */ jsxs(Fragment$1, { children: [error ? /* @__PURE__ */ jsx("p", {
|
|
265
266
|
className: "text-red-400 font-medium text-sm",
|
|
266
267
|
children: String(error)
|
|
267
268
|
}) : null, /* @__PURE__ */ jsx("button", {
|
|
268
269
|
type: "submit",
|
|
269
270
|
disabled: isLoading,
|
|
270
271
|
className: cn(buttonVariants({ color: "primary" })),
|
|
271
|
-
children: authCodeCallback.isLoading ?
|
|
272
|
+
children: authCodeCallback.isLoading ? t.fetchingToken : t.submit
|
|
272
273
|
})] }) : /* @__PURE__ */ jsx("p", {
|
|
273
274
|
className: "text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border",
|
|
274
|
-
children:
|
|
275
|
+
children: t.unsupported
|
|
275
276
|
})
|
|
276
277
|
]
|
|
277
278
|
})] })]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-dialog.js","names":[],"sources":["../../../src/playground/components/oauth-dialog.tsx"],"sourcesContent":["import {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { useForm } from 'react-hook-form';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useQuery } from '@/utils/use-query';\nimport { type ReactNode, useEffect, useState } from 'react';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport type { OAuth2SecurityScheme } from '@/types';\n\ntype FlowType = keyof NonNullable<OAuth2SecurityScheme['flows']>;\n\nexport interface AuthDialogProps {\n scheme: OAuth2SecurityScheme;\n scopes: string[];\n\n open: boolean;\n setOpen: (v: boolean) => void;\n setToken: (token: string) => void;\n children: ReactNode;\n}\n\ninterface FormValues {\n clientId: string;\n clientSecret: string;\n username: string;\n password: string;\n}\n\ninterface AuthCodeState {\n redirect_uri: string;\n client_id: string;\n client_secret: string;\n}\n\ninterface ImplicitState {\n redirect_uri: string;\n client_id: string;\n}\n\nconst FlowTypes = {\n password: {\n name: 'Resource Owner Password Flow',\n description: 'Authenticate using username and password.',\n supported: true,\n },\n clientCredentials: {\n name: 'Client Credentials',\n description: 'Intended for the server-to-server authentication.',\n supported: true,\n },\n authorizationCode: {\n name: 'Authorization code',\n description: 'Authenticate with 3rd party services',\n supported: true,\n },\n implicit: {\n name: 'Implicit',\n description: 'Retrieve the access token directly.',\n supported: true,\n },\n deviceAuthorization: {\n name: 'Device Authorization',\n description: 'Authenticate with device.',\n supported: false,\n },\n} as const;\n\nexport function OauthDialog({\n scheme,\n scopes,\n setToken,\n children,\n open,\n setOpen,\n}: AuthDialogProps) {\n const [type, setType] = useState(() => {\n return Object.keys(scheme.flows!)[0] as FlowType;\n });\n const { supported } = FlowTypes[type];\n const form = useForm<FormValues>({\n defaultValues: {\n clientId: '',\n clientSecret: '',\n username: '',\n password: '',\n },\n });\n\n const authCodeCallback = useQuery(async (code: string, state: AuthCodeState) => {\n const value = scheme.flows!.authorizationCode!;\n\n const res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n // note: `state` could be invalid, but server will check it\n redirect_uri: state.redirect_uri,\n client_id: state.client_id,\n client_secret: state.client_secret,\n }),\n });\n\n if (!res.ok) throw new Error(await res.text());\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n });\n\n useEffect(() => {\n if (scheme.flows!.authorizationCode) {\n const params = new URLSearchParams(window.location.search);\n const state = params.get('state');\n const code = params.get('code');\n\n if (state && code) {\n const parsedState = JSON.parse(state) as AuthCodeState;\n setOpen(true);\n\n form.setValue('clientId', parsedState.client_id);\n form.setValue('clientSecret', parsedState.client_secret);\n authCodeCallback.start(code, parsedState);\n window.history.replaceState(null, '', window.location.pathname);\n return;\n }\n }\n\n if (scheme.flows!.implicit && window.location.hash.length > 1) {\n const params = new URLSearchParams(window.location.hash.slice(1));\n const state = params.get('state');\n const token = params.get('access_token');\n const type = params.get('token_type') ?? 'Bearer';\n\n if (state && token) {\n const parsedState = JSON.parse(state) as ImplicitState;\n\n form.setValue('clientId', parsedState.client_id);\n setToken(`${type} ${token}`);\n window.history.replaceState(null, '', window.location.pathname);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- first page load only\n }, []);\n\n const authorize = useQuery(async (values: FormValues) => {\n if (type === 'implicit') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'token');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n redirect_uri: window.location.href,\n } satisfies ImplicitState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n if (type === 'authorizationCode') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'code');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n client_secret: values.clientSecret,\n redirect_uri: window.location.href,\n } satisfies AuthCodeState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n\n let res;\n if (type === 'password') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'password',\n username: values.username,\n password: values.password,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (type === 'clientCredentials') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: values.clientId,\n client_secret: values.clientSecret,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (res) {\n if (!res.ok) throw new Error(await res.text());\n\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n }\n });\n\n const onSubmit = form.handleSubmit((values) => {\n return authorize.start(values);\n });\n\n const isLoading = authorize.isLoading || authCodeCallback.isLoading;\n const error = authCodeCallback.error ?? authorize.error;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n {children}\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Authorization</DialogTitle>\n <DialogDescription>Obtain the access token for API.</DialogDescription>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(e) => {\n void onSubmit(e);\n e.stopPropagation();\n }}\n >\n <Select value={type} onValueChange={setType as (s: string) => void}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.keys(scheme.flows!).map((key) => {\n const { name, description } = FlowTypes[key as FlowType];\n\n return (\n <SelectItem key={key} value={key}>\n <p className=\"font-medium\">{name}</p>\n <p className=\"text-fd-muted-foreground\">{description}</p>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n\n {(type === 'authorizationCode' ||\n type === 'clientCredentials' ||\n type === 'implicit') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_id\" className={cn(labelVariants())}>\n Client ID\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">\n The client ID of your OAuth application.\n </p>\n <Input\n id=\"client_id\"\n placeholder=\"Enter value\"\n type=\"text\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientId', { required: true })}\n />\n </fieldset>\n )}\n {(type === 'authorizationCode' || type === 'clientCredentials') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_secret\" className={cn(labelVariants())}>\n Client Secret\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">\n The client secret of your OAuth application.\n </p>\n <Input\n id=\"client_secret\"\n placeholder=\"Enter value\"\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientSecret', { required: true })}\n />\n </fieldset>\n )}\n {type === 'password' && (\n <>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"username\" className={cn(labelVariants())}>\n Username\n </label>\n <Input\n id=\"username\"\n placeholder=\"Enter value\"\n type=\"text\"\n disabled={isLoading}\n autoComplete=\"off\"\n {...form.register('username', { required: true })}\n />\n </fieldset>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"password\" className={cn(labelVariants())}>\n Client Secret\n </label>\n <Input\n id=\"password\"\n placeholder=\"Enter value\"\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('password', { required: true })}\n />\n </fieldset>\n </>\n )}\n {supported ? (\n <>\n {error ? <p className=\"text-red-400 font-medium text-sm\">{String(error)}</p> : null}\n <button\n type=\"submit\"\n disabled={isLoading}\n className={cn(\n buttonVariants({\n color: 'primary',\n }),\n )}\n >\n {authCodeCallback.isLoading ? 'Fetching token...' : 'Submit'}\n </button>\n </>\n ) : (\n <p className=\"text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border\">\n Unsupported\n </p>\n )}\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport const OauthDialogTrigger = DialogTrigger;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"oauth-dialog.js","names":[],"sources":["../../../src/playground/components/oauth-dialog.tsx"],"sourcesContent":["import {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { useForm } from 'react-hook-form';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useQuery } from '@/utils/use-query';\nimport { type ReactNode, useEffect, useMemo, useState } from 'react';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport type { OAuth2SecurityScheme } from '@/types';\nimport { useTranslations } from '@/ui/client/i18n';\n\ntype FlowType = keyof NonNullable<OAuth2SecurityScheme['flows']>;\n\nexport interface AuthDialogProps {\n scheme: OAuth2SecurityScheme;\n scopes: string[];\n\n open: boolean;\n setOpen: (v: boolean) => void;\n setToken: (token: string) => void;\n children: ReactNode;\n}\n\ninterface FormValues {\n clientId: string;\n clientSecret: string;\n username: string;\n password: string;\n}\n\ninterface AuthCodeState {\n redirect_uri: string;\n client_id: string;\n client_secret: string;\n}\n\ninterface ImplicitState {\n redirect_uri: string;\n client_id: string;\n}\n\ninterface FlowInfo {\n name: ReactNode;\n description: ReactNode;\n supported: boolean;\n}\n\nexport function OauthDialog({\n scheme,\n scopes,\n setToken,\n children,\n open,\n setOpen,\n}: AuthDialogProps) {\n const [type, setType] = useState(() => {\n return Object.keys(scheme.flows!)[0] as FlowType;\n });\n const t = useTranslations();\n const allFlows: Record<FlowType, FlowInfo> = useMemo(\n () => ({\n password: {\n name: t.resourceOwnerPassword,\n description: t.resourceOwnerPasswordDesc,\n supported: true,\n },\n clientCredentials: {\n name: t.clientCredentials,\n description: t.clientCredentialsDesc,\n supported: true,\n },\n authorizationCode: {\n name: t.authorizationCode,\n description: t.authorizationCodeDesc,\n supported: true,\n },\n implicit: {\n name: t.implicit,\n description: t.implicitDesc,\n supported: true,\n },\n deviceAuthorization: {\n name: t.deviceAuthorization,\n description: t.deviceAuthorizationDesc,\n supported: false,\n },\n }),\n [t],\n );\n\n const form = useForm<FormValues>({\n defaultValues: {\n clientId: '',\n clientSecret: '',\n username: '',\n password: '',\n },\n });\n\n const authCodeCallback = useQuery(async (code: string, state: AuthCodeState) => {\n const value = scheme.flows!.authorizationCode!;\n\n const res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n // note: `state` could be invalid, but server will check it\n redirect_uri: state.redirect_uri,\n client_id: state.client_id,\n client_secret: state.client_secret,\n }),\n });\n\n if (!res.ok) throw new Error(await res.text());\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n });\n\n useEffect(() => {\n if (scheme.flows!.authorizationCode) {\n const params = new URLSearchParams(window.location.search);\n const state = params.get('state');\n const code = params.get('code');\n\n if (state && code) {\n const parsedState = JSON.parse(state) as AuthCodeState;\n setOpen(true);\n\n form.setValue('clientId', parsedState.client_id);\n form.setValue('clientSecret', parsedState.client_secret);\n authCodeCallback.start(code, parsedState);\n window.history.replaceState(null, '', window.location.pathname);\n return;\n }\n }\n\n if (scheme.flows!.implicit && window.location.hash.length > 1) {\n const params = new URLSearchParams(window.location.hash.slice(1));\n const state = params.get('state');\n const token = params.get('access_token');\n const type = params.get('token_type') ?? 'Bearer';\n\n if (state && token) {\n const parsedState = JSON.parse(state) as ImplicitState;\n\n form.setValue('clientId', parsedState.client_id);\n setToken(`${type} ${token}`);\n window.history.replaceState(null, '', window.location.pathname);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- first page load only\n }, []);\n\n const authorize = useQuery(async (values: FormValues) => {\n if (type === 'implicit') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'token');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n redirect_uri: window.location.href,\n } satisfies ImplicitState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n if (type === 'authorizationCode') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'code');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n client_secret: values.clientSecret,\n redirect_uri: window.location.href,\n } satisfies AuthCodeState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n\n let res;\n if (type === 'password') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'password',\n username: values.username,\n password: values.password,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (type === 'clientCredentials') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: values.clientId,\n client_secret: values.clientSecret,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (res) {\n if (!res.ok) throw new Error(await res.text());\n\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n }\n });\n\n const onSubmit = form.handleSubmit((values) => {\n return authorize.start(values);\n });\n\n const isLoading = authorize.isLoading || authCodeCallback.isLoading;\n const error = authCodeCallback.error ?? authorize.error;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n {children}\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{t.authorization}</DialogTitle>\n <DialogDescription>{t.obtainAccessToken}</DialogDescription>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(e) => {\n void onSubmit(e);\n e.stopPropagation();\n }}\n >\n <Select value={type} onValueChange={setType as (s: string) => void}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.keys(scheme.flows!).map((key) => {\n const { name, description } = allFlows[key as FlowType];\n\n return (\n <SelectItem key={key} value={key}>\n <p className=\"font-medium\">{name}</p>\n <p className=\"text-fd-muted-foreground\">{description}</p>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n\n {(type === 'authorizationCode' ||\n type === 'clientCredentials' ||\n type === 'implicit') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_id\" className={cn(labelVariants())}>\n {t.clientId}\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">{t.clientIdHint}</p>\n <Input\n id=\"client_id\"\n placeholder={t.inputPlaceholder}\n type=\"text\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientId', { required: true })}\n />\n </fieldset>\n )}\n {(type === 'authorizationCode' || type === 'clientCredentials') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_secret\" className={cn(labelVariants())}>\n {t.clientSecret}\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">{t.clientSecretHint}</p>\n <Input\n id=\"client_secret\"\n placeholder={t.inputPlaceholder}\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientSecret', { required: true })}\n />\n </fieldset>\n )}\n {type === 'password' && (\n <>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"username\" className={cn(labelVariants())}>\n {t.usernameField}\n </label>\n <Input\n id=\"username\"\n placeholder={t.inputPlaceholder}\n type=\"text\"\n disabled={isLoading}\n autoComplete=\"off\"\n {...form.register('username', { required: true })}\n />\n </fieldset>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"password\" className={cn(labelVariants())}>\n {t.clientSecret}\n </label>\n <Input\n id=\"password\"\n placeholder={t.inputPlaceholder}\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('password', { required: true })}\n />\n </fieldset>\n </>\n )}\n {allFlows[type].supported ? (\n <>\n {error ? <p className=\"text-red-400 font-medium text-sm\">{String(error)}</p> : null}\n <button\n type=\"submit\"\n disabled={isLoading}\n className={cn(\n buttonVariants({\n color: 'primary',\n }),\n )}\n >\n {authCodeCallback.isLoading ? t.fetchingToken : t.submit}\n </button>\n </>\n ) : (\n <p className=\"text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border\">\n {t.unsupported}\n </p>\n )}\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport const OauthDialogTrigger = DialogTrigger;\n"],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ import { useServerContext, useServerSelectContext } from "../../ui/contexts/api.
|
|
|
4
4
|
import { cn } from "../../utils/cn.js";
|
|
5
5
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
|
|
6
6
|
import { Input, labelVariants } from "../../ui/components/input.js";
|
|
7
|
+
import { useTranslations } from "../../ui/client/i18n.js";
|
|
7
8
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
|
|
8
9
|
import { useEffect, useRef, useState } from "react";
|
|
9
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -15,6 +16,7 @@ function ServerSelect(props) {
|
|
|
15
16
|
const { server, setServer, setServerVariables } = useServerSelectContext();
|
|
16
17
|
const [open, setOpen] = useState(false);
|
|
17
18
|
const [isMounted, setIsMounted] = useState(false);
|
|
19
|
+
const t = useTranslations();
|
|
18
20
|
useEffect(() => {
|
|
19
21
|
setIsMounted(true);
|
|
20
22
|
}, []);
|
|
@@ -29,16 +31,16 @@ function ServerSelect(props) {
|
|
|
29
31
|
children: [
|
|
30
32
|
/* @__PURE__ */ jsx("span", {
|
|
31
33
|
className: "px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm",
|
|
32
|
-
children: server?.name ??
|
|
34
|
+
children: server?.name ?? t.serverUrl
|
|
33
35
|
}),
|
|
34
36
|
/* @__PURE__ */ jsx("code", {
|
|
35
37
|
className: "truncate min-w-0 flex-1",
|
|
36
|
-
children: isMounted ? withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin) :
|
|
38
|
+
children: isMounted ? withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin) : t.loading
|
|
37
39
|
}),
|
|
38
40
|
/* @__PURE__ */ jsx(EditIcon, { className: "size-4" })
|
|
39
41
|
]
|
|
40
42
|
}), /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
41
|
-
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children:
|
|
43
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t.serverUrl }), /* @__PURE__ */ jsx(DialogDescription, { children: t.serverUrlDescription })] }),
|
|
42
44
|
/* @__PURE__ */ jsxs(Select, {
|
|
43
45
|
value: server?.url,
|
|
44
46
|
onValueChange: setServer,
|
|
@@ -99,6 +101,7 @@ function ServerSelectContent({ defaultValues, onChange, schema }) {
|
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
103
|
function Field({ fieldName, variable }) {
|
|
104
|
+
const t = useTranslations();
|
|
102
105
|
const [value, setValue] = useFieldValue([fieldName], { compute(currentValue) {
|
|
103
106
|
return typeof currentValue === "string" ? currentValue : void 0;
|
|
104
107
|
} });
|
|
@@ -117,7 +120,7 @@ function Field({ fieldName, variable }) {
|
|
|
117
120
|
id: fieldName,
|
|
118
121
|
value,
|
|
119
122
|
onChange: (e) => setValue(e.target.value),
|
|
120
|
-
placeholder:
|
|
123
|
+
placeholder: t.serverUrlFieldPlaceholder
|
|
121
124
|
});
|
|
122
125
|
}
|
|
123
126
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-select.js","names":[],"sources":["../../../src/playground/components/server-select.tsx"],"sourcesContent":["'use client';\nimport { useServerContext, useServerSelectContext } from '@/ui/contexts/api';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useEffect, useState, useRef, type ComponentProps } from 'react';\nimport { cn } from '@/utils/cn';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { resolveServerUrl, withBase } from '@/utils/url';\nimport type { ServerVariableObject } from '@/types';\nimport type { NoReference } from '@/utils/schema';\nimport { StfProvider, useFieldValue, useListener, useStf } from '@fumari/stf';\nimport { EditIcon } from 'lucide-react';\n\nexport default function ServerSelect(props: ComponentProps<typeof DialogTrigger>) {\n const { servers } = useServerContext();\n const { server, setServer, setServerVariables } = useServerSelectContext();\n const [open, setOpen] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n if (servers.length <= 0) return;\n const serverSchema = server ? servers.find((obj) => obj.url === server.url) : null;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger\n {...props}\n className={cn(\n 'flex items-center gap-2 text-sm text-start px-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground',\n props.className,\n )}\n >\n <span className=\"px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm\">\n {server?.name ??
|
|
1
|
+
{"version":3,"file":"server-select.js","names":[],"sources":["../../../src/playground/components/server-select.tsx"],"sourcesContent":["'use client';\nimport { useServerContext, useServerSelectContext } from '@/ui/contexts/api';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useEffect, useState, useRef, type ComponentProps } from 'react';\nimport { cn } from '@/utils/cn';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { resolveServerUrl, withBase } from '@/utils/url';\nimport type { ServerVariableObject } from '@/types';\nimport type { NoReference } from '@/utils/schema';\nimport { StfProvider, useFieldValue, useListener, useStf } from '@fumari/stf';\nimport { EditIcon } from 'lucide-react';\nimport { useTranslations } from '@/ui/client/i18n';\n\nexport default function ServerSelect(props: ComponentProps<typeof DialogTrigger>) {\n const { servers } = useServerContext();\n const { server, setServer, setServerVariables } = useServerSelectContext();\n const [open, setOpen] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n const t = useTranslations();\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n if (servers.length <= 0) return;\n const serverSchema = server ? servers.find((obj) => obj.url === server.url) : null;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger\n {...props}\n className={cn(\n 'flex items-center gap-2 text-sm text-start px-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground',\n props.className,\n )}\n >\n <span className=\"px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm\">\n {server?.name ?? t.serverUrl}\n </span>\n <code className=\"truncate min-w-0 flex-1\">\n {isMounted\n ? withBase(\n server ? resolveServerUrl(server.url, server.variables) : '/',\n window.location.origin,\n )\n : t.loading}\n </code>\n <EditIcon className=\"size-4\" />\n </DialogTrigger>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{t.serverUrl}</DialogTitle>\n <DialogDescription>{t.serverUrlDescription}</DialogDescription>\n </DialogHeader>\n <Select value={server?.url} onValueChange={setServer}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {servers.map((item) => (\n <SelectItem key={item.url} value={item.url!}>\n <code className=\"text-[0.8125rem]\">{item.url}</code>\n <p className=\"text-fd-muted-foreground\">{item.description}</p>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {server?.variables && serverSchema?.variables && (\n <ServerSelectContent\n key={server.url}\n defaultValues={server.variables}\n schema={serverSchema.variables}\n onChange={setServerVariables}\n />\n )}\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ServerSelectContent({\n defaultValues,\n onChange,\n schema,\n}: {\n defaultValues: Record<string, string>;\n onChange: (values: Record<string, string>) => void;\n schema: Record<string, NoReference<ServerVariableObject>>;\n}) {\n const stf = useStf({\n defaultValues: () => structuredClone(defaultValues),\n });\n const timerRef = useRef<number | null>(null);\n useListener({\n stf,\n onUpdate() {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n\n timerRef.current = window.setTimeout(\n () => onChange(stf.dataEngine.getData() as Record<string, string>),\n 500,\n );\n },\n });\n\n return (\n <StfProvider value={stf}>\n <div className=\"flex flex-col gap-4\">\n {Object.entries(schema).map(([key, variable]) => {\n return (\n <fieldset key={key} className=\"flex flex-col gap-1\">\n <label className={cn(labelVariants())} htmlFor={key}>\n {key}\n </label>\n <p className=\"text-xs text-fd-muted-foreground empty:hidden\">\n {variable.description}\n </p>\n <Field fieldName={key} variable={variable} />\n </fieldset>\n );\n })}\n </div>\n </StfProvider>\n );\n}\n\nfunction Field({\n fieldName,\n variable,\n}: {\n variable: NoReference<ServerVariableObject>;\n fieldName: string;\n}) {\n const t = useTranslations();\n const [value, setValue] = useFieldValue([fieldName], {\n compute(currentValue) {\n return typeof currentValue === 'string' ? currentValue : undefined;\n },\n });\n\n if (variable.enum) {\n return (\n <Select value={value} onValueChange={setValue}>\n <SelectTrigger id={fieldName}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {variable.enum.map((value) => (\n <SelectItem key={value} value={String(value)}>\n {value}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n }\n\n return (\n <Input\n id={fieldName}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder={t.serverUrlFieldPlaceholder}\n />\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,46 +1,53 @@
|
|
|
1
1
|
import { CircleCheck, CircleX } from "lucide-react";
|
|
2
2
|
//#region src/playground/status-info.tsx
|
|
3
|
-
const
|
|
3
|
+
const statusKeys = {
|
|
4
4
|
400: {
|
|
5
|
-
|
|
5
|
+
key: "statusBadRequest",
|
|
6
6
|
color: "text-red-500",
|
|
7
7
|
icon: CircleX
|
|
8
8
|
},
|
|
9
9
|
401: {
|
|
10
|
-
|
|
10
|
+
key: "statusUnauthorized",
|
|
11
11
|
color: "text-red-500",
|
|
12
12
|
icon: CircleX
|
|
13
13
|
},
|
|
14
14
|
403: {
|
|
15
|
-
|
|
15
|
+
key: "statusForbidden",
|
|
16
16
|
color: "text-red-500",
|
|
17
17
|
icon: CircleX
|
|
18
18
|
},
|
|
19
19
|
404: {
|
|
20
|
-
|
|
20
|
+
key: "statusNotFound",
|
|
21
21
|
color: "text-fd-muted-foreground",
|
|
22
22
|
icon: CircleX
|
|
23
23
|
},
|
|
24
24
|
500: {
|
|
25
|
-
|
|
25
|
+
key: "statusInternalServerError",
|
|
26
26
|
color: "text-red-500",
|
|
27
27
|
icon: CircleX
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
-
function getStatusInfo(status) {
|
|
31
|
-
if (status in
|
|
30
|
+
function getStatusInfo(status, t) {
|
|
31
|
+
if (status in statusKeys) {
|
|
32
|
+
const { key, color, icon } = statusKeys[status];
|
|
33
|
+
return {
|
|
34
|
+
description: t[key],
|
|
35
|
+
color,
|
|
36
|
+
icon
|
|
37
|
+
};
|
|
38
|
+
}
|
|
32
39
|
if (status >= 200 && status < 300) return {
|
|
33
|
-
description:
|
|
40
|
+
description: t.statusSuccessful,
|
|
34
41
|
color: "text-green-500",
|
|
35
42
|
icon: CircleCheck
|
|
36
43
|
};
|
|
37
44
|
if (status >= 400) return {
|
|
38
|
-
description:
|
|
45
|
+
description: t.statusError,
|
|
39
46
|
color: "text-red-500",
|
|
40
47
|
icon: CircleX
|
|
41
48
|
};
|
|
42
49
|
return {
|
|
43
|
-
description:
|
|
50
|
+
description: t.statusNoDescription,
|
|
44
51
|
color: "text-fd-muted-foreground",
|
|
45
52
|
icon: CircleX
|
|
46
53
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-info.js","names":[],"sources":["../../src/playground/status-info.tsx"],"sourcesContent":["import { CircleCheck, CircleX } from 'lucide-react';\n\ninterface StatusInfo {\n description: string;\n color: string;\n icon: React.ElementType;\n}\n\nconst
|
|
1
|
+
{"version":3,"file":"status-info.js","names":[],"sources":["../../src/playground/status-info.tsx"],"sourcesContent":["import { CircleCheck, CircleX } from 'lucide-react';\nimport type { Translations } from '@/i18n';\n\ninterface StatusInfo {\n description: string;\n color: string;\n icon: React.ElementType;\n}\n\nconst statusKeys: Record<\n number,\n { key: keyof Translations; color: string; icon: React.ElementType }\n> = {\n 400: { key: 'statusBadRequest', color: 'text-red-500', icon: CircleX },\n 401: { key: 'statusUnauthorized', color: 'text-red-500', icon: CircleX },\n 403: { key: 'statusForbidden', color: 'text-red-500', icon: CircleX },\n 404: { key: 'statusNotFound', color: 'text-fd-muted-foreground', icon: CircleX },\n 500: { key: 'statusInternalServerError', color: 'text-red-500', icon: CircleX },\n};\n\nexport function getStatusInfo(status: number, t: Translations): StatusInfo {\n if (status in statusKeys) {\n const { key, color, icon } = statusKeys[status];\n return { description: t[key], color, icon };\n }\n\n if (status >= 200 && status < 300) {\n return {\n description: t.statusSuccessful,\n color: 'text-green-500',\n icon: CircleCheck,\n };\n }\n\n if (status >= 400) {\n return { description: t.statusError, color: 'text-red-500', icon: CircleX };\n }\n\n return {\n description: t.statusNoDescription,\n color: 'text-fd-muted-foreground',\n icon: CircleX,\n };\n}\n"],"mappings":";;AASA,MAAM,aAGF;CACF,KAAK;EAAE,KAAK;EAAoB,OAAO;EAAgB,MAAM;EAAS;CACtE,KAAK;EAAE,KAAK;EAAsB,OAAO;EAAgB,MAAM;EAAS;CACxE,KAAK;EAAE,KAAK;EAAmB,OAAO;EAAgB,MAAM;EAAS;CACrE,KAAK;EAAE,KAAK;EAAkB,OAAO;EAA4B,MAAM;EAAS;CAChF,KAAK;EAAE,KAAK;EAA6B,OAAO;EAAgB,MAAM;EAAS;CAChF;AAED,SAAgB,cAAc,QAAgB,GAA6B;AACzE,KAAI,UAAU,YAAY;EACxB,MAAM,EAAE,KAAK,OAAO,SAAS,WAAW;AACxC,SAAO;GAAE,aAAa,EAAE;GAAM;GAAO;GAAM;;AAG7C,KAAI,UAAU,OAAO,SAAS,IAC5B,QAAO;EACL,aAAa,EAAE;EACf,OAAO;EACP,MAAM;EACP;AAGH,KAAI,UAAU,IACZ,QAAO;EAAE,aAAa,EAAE;EAAa,OAAO;EAAgB,MAAM;EAAS;AAG7E,QAAO;EACL,aAAa,EAAE;EACf,OAAO;EACP,MAAM;EACP"}
|
|
@@ -46,7 +46,7 @@ interface InlineCodeUsageGenerator<T = unknown> {
|
|
|
46
46
|
*/
|
|
47
47
|
serverContext?: T;
|
|
48
48
|
}
|
|
49
|
-
declare function createCodeUsageGeneratorRegistry(
|
|
49
|
+
declare function createCodeUsageGeneratorRegistry(inherit?: CodeUsageGeneratorRegistry): CodeUsageGeneratorRegistry;
|
|
50
50
|
type CodeUsageGeneratorFn<ServerContext = unknown> = (url: string, data: RequestData, context: {
|
|
51
51
|
mediaAdapters: Record<string, MediaAdapter>;
|
|
52
52
|
server: ServerContext;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/requests/generators/index.ts
|
|
2
|
-
function createCodeUsageGeneratorRegistry(
|
|
3
|
-
const registry = new Map(
|
|
2
|
+
function createCodeUsageGeneratorRegistry(inherit) {
|
|
3
|
+
const registry = new Map(inherit?.map());
|
|
4
4
|
return {
|
|
5
5
|
add(id, generator) {
|
|
6
6
|
registry.set(id, generator);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/requests/generators/index.ts"],"sourcesContent":["import type { MediaAdapter } from '../media/adapter';\nimport type { RequestData } from '../types';\n\nexport interface CodeUsageGeneratorRegistry {\n add: (id: string, generator: CodeUsageGenerator) => void;\n get: (id: string) => CodeUsageGenerator | undefined;\n addInline: (generator: InlineCodeUsageGenerator) => void;\n /**\n * @returns if the generator is removed\n */\n remove: (id: string) => boolean;\n map: () => Map<string, CodeUsageGenerator>;\n}\n\n/**\n * Generate code example for given programming language\n */\nexport interface CodeUsageGenerator {\n generate: CodeUsageGeneratorFn;\n lang: string;\n label?: string;\n\n /**\n * for inline generators passed from server, this stores info available for client (e.g. forwarded from \"use client\").\n */\n _client?: {\n generate: string | CodeUsageGeneratorFn;\n serverContext?: unknown;\n };\n}\n\n/**\n * Generate code example for given programming language\n */\nexport interface InlineCodeUsageGenerator<T = unknown> {\n id?: string;\n lang: string;\n label?: string;\n /**\n * either:\n * - code\n * - a function imported from a file with \"use client\" directive\n * - false (disabled)\n */\n source?: string | CodeUsageGeneratorFn<T> | false;\n\n /**\n * Pass extra context to client-side source generator\n */\n serverContext?: T;\n}\n\nexport function createCodeUsageGeneratorRegistry(\n
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/requests/generators/index.ts"],"sourcesContent":["import type { MediaAdapter } from '../media/adapter';\nimport type { RequestData } from '../types';\n\nexport interface CodeUsageGeneratorRegistry {\n add: (id: string, generator: CodeUsageGenerator) => void;\n get: (id: string) => CodeUsageGenerator | undefined;\n addInline: (generator: InlineCodeUsageGenerator) => void;\n /**\n * @returns if the generator is removed\n */\n remove: (id: string) => boolean;\n map: () => Map<string, CodeUsageGenerator>;\n}\n\n/**\n * Generate code example for given programming language\n */\nexport interface CodeUsageGenerator {\n generate: CodeUsageGeneratorFn;\n lang: string;\n label?: string;\n\n /**\n * for inline generators passed from server, this stores info available for client (e.g. forwarded from \"use client\").\n */\n _client?: {\n generate: string | CodeUsageGeneratorFn;\n serverContext?: unknown;\n };\n}\n\n/**\n * Generate code example for given programming language\n */\nexport interface InlineCodeUsageGenerator<T = unknown> {\n id?: string;\n lang: string;\n label?: string;\n /**\n * either:\n * - code\n * - a function imported from a file with \"use client\" directive\n * - false (disabled)\n */\n source?: string | CodeUsageGeneratorFn<T> | false;\n\n /**\n * Pass extra context to client-side source generator\n */\n serverContext?: T;\n}\n\nexport function createCodeUsageGeneratorRegistry(\n inherit?: CodeUsageGeneratorRegistry,\n): CodeUsageGeneratorRegistry {\n const registry = new Map<string, CodeUsageGenerator>(inherit?.map());\n\n return {\n add(id, generator) {\n registry.set(id, generator);\n },\n get(id) {\n return registry.get(id);\n },\n addInline(generator) {\n const source = generator.source;\n const id = generator.id ?? generator.lang;\n if (!source) {\n this.remove(id);\n return;\n }\n\n registry.set(id, {\n lang: generator.lang,\n label: generator.label,\n generate() {\n return typeof source === 'string' ? source : '';\n },\n _client: {\n generate: source,\n serverContext: generator.serverContext,\n },\n });\n },\n remove(id) {\n return registry.delete(id);\n },\n map() {\n return registry;\n },\n };\n}\n\nexport type CodeUsageGeneratorFn<ServerContext = unknown> = (\n url: string,\n data: RequestData,\n context: {\n mediaAdapters: Record<string, MediaAdapter>;\n server: ServerContext;\n },\n) => string;\n"],"mappings":";AAoDA,SAAgB,iCACd,SAC4B;CAC5B,MAAM,WAAW,IAAI,IAAgC,SAAS,KAAK,CAAC;AAEpE,QAAO;EACL,IAAI,IAAI,WAAW;AACjB,YAAS,IAAI,IAAI,UAAU;;EAE7B,IAAI,IAAI;AACN,UAAO,SAAS,IAAI,GAAG;;EAEzB,UAAU,WAAW;GACnB,MAAM,SAAS,UAAU;GACzB,MAAM,KAAK,UAAU,MAAM,UAAU;AACrC,OAAI,CAAC,QAAQ;AACX,SAAK,OAAO,GAAG;AACf;;AAGF,YAAS,IAAI,IAAI;IACf,MAAM,UAAU;IAChB,OAAO,UAAU;IACjB,WAAW;AACT,YAAO,OAAO,WAAW,WAAW,SAAS;;IAE/C,SAAS;KACP,UAAU;KACV,eAAe,UAAU;KAC1B;IACF,CAAC;;EAEJ,OAAO,IAAI;AACT,UAAO,SAAS,OAAO,GAAG;;EAE5B,MAAM;AACJ,UAAO;;EAEV"}
|