mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-31 02:25:18 +00:00
refactor(form): rename link fields to external
This commit is contained in:
parent
08ff181df6
commit
ad0227c9dd
10 changed files with 84 additions and 80 deletions
|
|
@ -2510,7 +2510,7 @@ export type FormRequestListOutput = {
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -2593,7 +2593,7 @@ export type FormRequestListOutput = {
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
>,
|
||||
]
|
||||
}>
|
||||
|
|
@ -2689,7 +2689,7 @@ export type FormListOutput = {
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -2772,7 +2772,7 @@ export type FormListOutput = {
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
>,
|
||||
]
|
||||
}>
|
||||
|
|
@ -2874,7 +2874,7 @@ export type FormCreateInput = {
|
|||
readonly custom?: boolean
|
||||
readonly default?: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "link"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
| { readonly type: "external"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -2965,7 +2965,7 @@ export type FormCreateInput = {
|
|||
readonly custom?: boolean
|
||||
readonly default?: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "link"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
| { readonly type: "external"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
>,
|
||||
]
|
||||
}["id"]
|
||||
|
|
@ -3063,7 +3063,7 @@ export type FormCreateInput = {
|
|||
readonly custom?: boolean
|
||||
readonly default?: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "link"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
| { readonly type: "external"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -3154,7 +3154,7 @@ export type FormCreateInput = {
|
|||
readonly custom?: boolean
|
||||
readonly default?: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "link"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
| { readonly type: "external"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
>,
|
||||
]
|
||||
}["title"]
|
||||
|
|
@ -3252,7 +3252,7 @@ export type FormCreateInput = {
|
|||
readonly custom?: boolean
|
||||
readonly default?: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "link"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
| { readonly type: "external"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -3343,7 +3343,7 @@ export type FormCreateInput = {
|
|||
readonly custom?: boolean
|
||||
readonly default?: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "link"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
| { readonly type: "external"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
>,
|
||||
]
|
||||
}["metadata"]
|
||||
|
|
@ -3441,7 +3441,7 @@ export type FormCreateInput = {
|
|||
readonly custom?: boolean
|
||||
readonly default?: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "link"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
| { readonly type: "external"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -3532,7 +3532,7 @@ export type FormCreateInput = {
|
|||
readonly custom?: boolean
|
||||
readonly default?: ReadonlyArray<string>
|
||||
}
|
||||
| { readonly type: "link"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
| { readonly type: "external"; readonly url: string; readonly title?: string; readonly description?: string }
|
||||
>,
|
||||
]
|
||||
}["fields"]
|
||||
|
|
@ -3626,7 +3626,7 @@ export type FormCreateOutput = {
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -3709,7 +3709,7 @@ export type FormCreateOutput = {
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
>,
|
||||
]
|
||||
}
|
||||
|
|
@ -3808,7 +3808,7 @@ export type FormGetOutput = {
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -3891,7 +3891,7 @@ export type FormGetOutput = {
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
>,
|
||||
]
|
||||
}
|
||||
|
|
@ -5429,7 +5429,7 @@ export type EventSubscribeOutput =
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
),
|
||||
...Array<
|
||||
| {
|
||||
|
|
@ -5492,7 +5492,7 @@ export type EventSubscribeOutput =
|
|||
custom?: boolean
|
||||
default?: Array<string>
|
||||
}
|
||||
| { type: "link"; url: string; title?: string; description?: string }
|
||||
| { type: "external"; url: string; title?: string; description?: string }
|
||||
>,
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,12 +224,14 @@ export const locationLayer = layer
|
|||
export const node = makeLocationNode({ service: Service, layer, deps: [EventV2.node] })
|
||||
|
||||
function validateAnswer(form: Info, answer: Answer) {
|
||||
const fields = new Map(form.fields.flatMap((field) => (field.type === "link" ? [] : [[field.key, field] as const])))
|
||||
const fields = new Map(
|
||||
form.fields.flatMap((field) => (field.type === "external" ? [] : [[field.key, field] as const])),
|
||||
)
|
||||
for (const key of Object.keys(answer)) {
|
||||
if (!fields.has(key)) return `Unknown form field: ${key}`
|
||||
}
|
||||
for (const field of form.fields) {
|
||||
if (field.type === "link") continue
|
||||
if (field.type === "external") continue
|
||||
const value = answer[field.key]
|
||||
const active = isActive(field, answer)
|
||||
if (value === undefined) {
|
||||
|
|
@ -242,7 +244,7 @@ function validateAnswer(form: Info, answer: Answer) {
|
|||
}
|
||||
}
|
||||
|
||||
type InputField = Exclude<Form.Field, Form.LinkField>
|
||||
type InputField = Exclude<Form.Field, Form.ExternalField>
|
||||
|
||||
function isActive(field: InputField, answer: Answer) {
|
||||
if (!field.when) return true
|
||||
|
|
@ -265,7 +267,7 @@ function validateFields(fields: ReadonlyArray<Form.Field>) {
|
|||
if (fields.length === 0) return "Form must have at least one field"
|
||||
const earlier = new Map<string, InputField>()
|
||||
for (const field of fields) {
|
||||
if (field.type === "link") continue
|
||||
if (field.type === "external") continue
|
||||
if (earlier.has(field.key)) return `Duplicate form field key: ${field.key}`
|
||||
for (const when of field.when ?? []) {
|
||||
const target = earlier.get(when.key)
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ export const layer = Layer.effect(
|
|||
elicitationID: input.params.elicitationId,
|
||||
message: input.params.message,
|
||||
},
|
||||
fields: [{ type: "link", url: input.params.url }],
|
||||
fields: [{ type: "external", url: input.params.url }],
|
||||
})
|
||||
.pipe(
|
||||
Effect.raceFirst(waitForAbort(input.signal)),
|
||||
|
|
|
|||
|
|
@ -58,13 +58,13 @@ describe("Form", () => {
|
|||
yield* service.reply({ id: created.id, answer: { name: "Ava" } })
|
||||
expect(yield* service.state(created.id)).toEqual({ status: "answered", answer: { name: "Ava" } })
|
||||
|
||||
const linkOnly = yield* service.create({
|
||||
const externalOnly = yield* service.create({
|
||||
sessionID: "global",
|
||||
title: "External setup",
|
||||
fields: [{ type: "link", url: "https://example.com/setup" }],
|
||||
fields: [{ type: "external", url: "https://example.com/setup" }],
|
||||
})
|
||||
yield* service.reply({ id: linkOnly.id, answer: {} })
|
||||
expect(yield* service.state(linkOnly.id)).toEqual({ status: "answered", answer: {} })
|
||||
yield* service.reply({ id: externalOnly.id, answer: {} })
|
||||
expect(yield* service.state(externalOnly.id)).toEqual({ status: "answered", answer: {} })
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -267,14 +267,14 @@ describe("Form", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("treats link fields as non-answerable", () =>
|
||||
it.effect("treats external fields as non-answerable", () =>
|
||||
Effect.gen(function* () {
|
||||
const service = yield* Form.Service
|
||||
const created = yield* service.create({
|
||||
sessionID: "global",
|
||||
title: "External setup",
|
||||
fields: [
|
||||
{ type: "link", url: "https://example.com/setup", title: "Open setup" },
|
||||
{ type: "external", url: "https://example.com/setup", title: "Open setup" },
|
||||
{ key: "name", type: "string", required: true },
|
||||
],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -94,13 +94,13 @@ export const MultiselectField = Schema.Struct({
|
|||
}).annotate({ identifier: "Form.MultiselectField" })
|
||||
export interface MultiselectField extends Schema.Schema.Type<typeof MultiselectField> {}
|
||||
|
||||
export const LinkField = Schema.Struct({
|
||||
type: Schema.Literal("link"),
|
||||
export const ExternalField = Schema.Struct({
|
||||
type: Schema.Literal("external"),
|
||||
url: Schema.String,
|
||||
title: Schema.String.pipe(optional),
|
||||
description: Schema.String.pipe(optional),
|
||||
}).annotate({ identifier: "Form.LinkField" })
|
||||
export interface LinkField extends Schema.Schema.Type<typeof LinkField> {}
|
||||
}).annotate({ identifier: "Form.ExternalField" })
|
||||
export interface ExternalField extends Schema.Schema.Type<typeof ExternalField> {}
|
||||
|
||||
export const Field = Schema.Union([
|
||||
StringField,
|
||||
|
|
@ -108,9 +108,9 @@ export const Field = Schema.Union([
|
|||
IntegerField,
|
||||
BooleanField,
|
||||
MultiselectField,
|
||||
LinkField,
|
||||
ExternalField,
|
||||
]).pipe(Schema.toTaggedUnion("type"), Schema.annotate({ identifier: "Form.Field" }))
|
||||
export type Field = StringField | NumberField | IntegerField | BooleanField | MultiselectField | LinkField
|
||||
export type Field = StringField | NumberField | IntegerField | BooleanField | MultiselectField | ExternalField
|
||||
|
||||
export const Fields = Schema.NonEmptyArray(Field).annotate({ identifier: "Form.Fields" })
|
||||
export type Fields = typeof Fields.Type
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ describe("contract hygiene", () => {
|
|||
Schema.decodeUnknownSync(Form.Info)({
|
||||
id: Form.ID.create(),
|
||||
sessionID: "global",
|
||||
title: "Link form",
|
||||
fields: [{ type: "link", url: "https://example.com" }],
|
||||
title: "External form",
|
||||
fields: [{ type: "external", url: "https://example.com" }],
|
||||
}).fields,
|
||||
).toHaveLength(1)
|
||||
})
|
||||
|
|
@ -92,7 +92,7 @@ describe("contract hygiene", () => {
|
|||
Form.Field,
|
||||
Form.Fields,
|
||||
Form.Info,
|
||||
Form.LinkField,
|
||||
Form.ExternalField,
|
||||
Mcp.Resource,
|
||||
Mcp.ResourceTemplate,
|
||||
Mcp.ResourceCatalog,
|
||||
|
|
|
|||
|
|
@ -3545,8 +3545,8 @@ export type FormMultiselectField = {
|
|||
default?: Array<string>
|
||||
}
|
||||
|
||||
export type FormLinkField = {
|
||||
type: "link"
|
||||
export type FormExternalField = {
|
||||
type: "external"
|
||||
url: string
|
||||
title?: string
|
||||
description?: string
|
||||
|
|
@ -3558,7 +3558,7 @@ export type FormField =
|
|||
| FormIntegerField
|
||||
| FormBooleanField
|
||||
| FormMultiselectField
|
||||
| FormLinkField
|
||||
| FormExternalField
|
||||
|
||||
export type FormFields = Array<FormField>
|
||||
|
||||
|
|
@ -10622,7 +10622,7 @@ export type FormField1 =
|
|||
| FormIntegerField1
|
||||
| FormBooleanField1
|
||||
| FormMultiselectField1
|
||||
| FormLinkField
|
||||
| FormExternalField
|
||||
|
||||
export type FormFields1 = [FormField1, FormField1]
|
||||
|
||||
|
|
|
|||
|
|
@ -15,19 +15,19 @@ import { useBindings, useOpencodeModeStack } from "../../keymap"
|
|||
|
||||
const FORM_MODE = "form"
|
||||
|
||||
type Field = Exclude<FormField, { type: "link" }>
|
||||
type LinkField = Extract<FormField, { type: "link" }>
|
||||
type Field = Exclude<FormField, { type: "external" }>
|
||||
type ExternalField = Extract<FormField, { type: "external" }>
|
||||
|
||||
function isField(field: FormField): field is Field {
|
||||
return field.type !== "link"
|
||||
return field.type !== "external"
|
||||
}
|
||||
|
||||
function isLink(field: FormField): field is LinkField {
|
||||
return field.type === "link"
|
||||
function isExternal(field: FormField): field is ExternalField {
|
||||
return field.type === "external"
|
||||
}
|
||||
|
||||
function fieldLabel(field: FormField) {
|
||||
return field.title ?? (field.type === "link" ? field.url : field.key)
|
||||
return field.title ?? (field.type === "external" ? field.url : field.key)
|
||||
}
|
||||
|
||||
function truncate(label: string, max: number) {
|
||||
|
|
@ -193,7 +193,7 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
const fields = createMemo(() => {
|
||||
const answers: Record<string, FormValue | undefined> = {}
|
||||
return props.form.fields.filter((field) => {
|
||||
if (field.type === "link") return true
|
||||
if (field.type === "external") return true
|
||||
const active = (field.when ?? []).every((when) => {
|
||||
const value = answers[when.key]
|
||||
if (value === undefined) return false
|
||||
|
|
@ -208,7 +208,7 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
const list = fields()
|
||||
if (list.length !== 1) return false
|
||||
const field = list[0]!
|
||||
if (field.type === "link") return false
|
||||
if (field.type === "external") return false
|
||||
return field.type === "boolean" || (field.type === "string" && field.options !== undefined)
|
||||
})
|
||||
const answerable = createMemo(() => fields().filter(isField))
|
||||
|
|
@ -229,9 +229,9 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
const current = field()
|
||||
return current && isField(current) ? current : undefined
|
||||
})
|
||||
const linkField = createMemo(() => {
|
||||
const externalField = createMemo(() => {
|
||||
const current = field()
|
||||
return current && isLink(current) ? current : undefined
|
||||
return current && isExternal(current) ? current : undefined
|
||||
})
|
||||
const confirm = createMemo(() => !single() && store.tab >= fields().length)
|
||||
const rows = createMemo(() => {
|
||||
|
|
@ -263,7 +263,7 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
const multi = createMemo(() => answerField()?.type === "multiselect")
|
||||
const actionLabel = createMemo(() => {
|
||||
if (confirm()) return answerable().length === 0 ? "I finished" : "submit"
|
||||
if (linkField()) return "open link"
|
||||
if (externalField()) return "open link"
|
||||
if (multi()) return "toggle"
|
||||
if (single()) return "submit"
|
||||
return "confirm"
|
||||
|
|
@ -487,8 +487,8 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }, requestOptions(props.form))
|
||||
}
|
||||
|
||||
function openLink() {
|
||||
const current = linkField()
|
||||
function openExternal() {
|
||||
const current = externalField()
|
||||
if (!current) return
|
||||
const index = store.tab
|
||||
setStore("error", "")
|
||||
|
|
@ -497,8 +497,8 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
.catch(() => setStore("error", "Could not open the browser. Copy the URL and continue manually."))
|
||||
}
|
||||
|
||||
function copyLink() {
|
||||
const current = linkField()
|
||||
function copyExternal() {
|
||||
const current = externalField()
|
||||
if (!current || !clipboard.write) return
|
||||
void clipboard
|
||||
.write(current.url)
|
||||
|
|
@ -657,10 +657,10 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
group: "Form",
|
||||
cmd: () => selectTab((store.tab - 1 + tabs()) % tabs()),
|
||||
},
|
||||
...(linkField()
|
||||
...(externalField()
|
||||
? [
|
||||
{ key: "return", desc: "Open link", group: "Form", cmd: openLink },
|
||||
{ key: "c", desc: "Copy link", group: "Form", cmd: copyLink },
|
||||
{ key: "return", desc: "Open link", group: "Form", cmd: openExternal },
|
||||
{ key: "c", desc: "Copy link", group: "Form", cmd: copyExternal },
|
||||
{ key: "escape", desc: "Dismiss form", group: "Form", cmd: cancel },
|
||||
...tuiConfig.keybinds.get("app.exit"),
|
||||
]
|
||||
|
|
@ -764,7 +764,7 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
<For each={fields()}>
|
||||
{(item, index) => {
|
||||
const isTab = () => index() === store.tab
|
||||
const isAnswered = () => item.type !== "link" && store.answers[item.key] !== undefined
|
||||
const isAnswered = () => item.type !== "external" && store.answers[item.key] !== undefined
|
||||
return (
|
||||
<box
|
||||
paddingLeft={1}
|
||||
|
|
@ -808,23 +808,23 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
</box>
|
||||
</Show>
|
||||
|
||||
<Show when={!confirm() && linkField()}>
|
||||
{(link) => (
|
||||
<Show when={!confirm() && externalField()}>
|
||||
{(external) => (
|
||||
<box paddingLeft={1} gap={1}>
|
||||
<Show when={link().title}>
|
||||
<text fg={theme.text}>{link().title}</text>
|
||||
<Show when={external().title}>
|
||||
<text fg={theme.text}>{external().title}</text>
|
||||
</Show>
|
||||
<Show when={link().description}>
|
||||
<text fg={theme.textMuted}>{link().description}</text>
|
||||
<Show when={external().description}>
|
||||
<text fg={theme.textMuted}>{external().description}</text>
|
||||
</Show>
|
||||
<text
|
||||
fg={theme.primary}
|
||||
onMouseUp={() => {
|
||||
if (renderer.getSelection()?.getSelectedText()) return
|
||||
openLink()
|
||||
openExternal()
|
||||
}}
|
||||
>
|
||||
{link().url}
|
||||
{external().url}
|
||||
</text>
|
||||
</box>
|
||||
)}
|
||||
|
|
@ -1025,7 +1025,7 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
{"⇆"} <span style={{ fg: theme.textMuted }}>tab</span>
|
||||
</text>
|
||||
</Show>
|
||||
<Show when={!confirm() && !textual() && !linkField()}>
|
||||
<Show when={!confirm() && !textual() && !externalField()}>
|
||||
<text fg={theme.text}>
|
||||
{"↑↓"} <span style={{ fg: theme.textMuted }}>select</span>
|
||||
</text>
|
||||
|
|
@ -1040,13 +1040,13 @@ function FieldsPrompt(props: { form: FormInfo }) {
|
|||
onMouseUp={() => {
|
||||
if (renderer.getSelection()?.getSelectedText()) return
|
||||
if (confirm()) submit()
|
||||
if (linkField()) openLink()
|
||||
if (externalField()) openExternal()
|
||||
}}
|
||||
>
|
||||
enter <span style={{ fg: theme.textMuted }}>{actionLabel()}</span>
|
||||
</text>
|
||||
<Show when={linkField() && clipboard.write}>
|
||||
<text fg={theme.text} onMouseUp={copyLink}>
|
||||
<Show when={externalField() && clipboard.write}>
|
||||
<text fg={theme.text} onMouseUp={copyExternal}>
|
||||
c <span style={{ fg: theme.textMuted }}>copy</span>
|
||||
</text>
|
||||
</Show>
|
||||
|
|
|
|||
|
|
@ -77,15 +77,12 @@ function question(id: string, sessionID = "session"): QuestionRequest {
|
|||
}
|
||||
}
|
||||
|
||||
function form(
|
||||
id: string,
|
||||
sessionID = "session",
|
||||
): Extract<OpenCodeEvent, { type: "form.created" }>["data"]["form"] {
|
||||
function form(id: string, sessionID = "session"): Extract<OpenCodeEvent, { type: "form.created" }>["data"]["form"] {
|
||||
return {
|
||||
id,
|
||||
sessionID,
|
||||
title: "Input requested",
|
||||
fields: [{ type: "link", url: "https://example.com" }],
|
||||
fields: [{ type: "external", url: "https://example.com" }],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,12 @@ import { createSessionRows, type SessionRow } from "../../../src/routes/session/
|
|||
import { createApi, createClient, createEventStream, createFetch, directory, json } from "../../fixture/tui-sdk"
|
||||
import { TestTuiContexts } from "../../fixture/tui-environment"
|
||||
|
||||
const formFields = [{ type: "link", url: "https://example.com" }] satisfies [{ type: "link"; url: string }]
|
||||
const formFields = [{ type: "external", url: "https://example.com" }] satisfies [
|
||||
{
|
||||
type: "external"
|
||||
url: string
|
||||
},
|
||||
]
|
||||
|
||||
async function wait(fn: () => boolean, timeout = 2000) {
|
||||
const start = Date.now()
|
||||
|
|
@ -1808,7 +1813,7 @@ test("reconciles all pending form requests when the event stream reconnects", as
|
|||
id: "frm_keep",
|
||||
sessionID: "ses_keep",
|
||||
title: "Input requested",
|
||||
fields: [{ type: "link" as const, url: "https://example.com" }],
|
||||
fields: [{ type: "external" as const, url: "https://example.com" }],
|
||||
},
|
||||
]
|
||||
let calls = 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue