Skip to content

Commit

Permalink
Merge pull request #775 from interval/ctx-redirect
Browse files Browse the repository at this point in the history
Add `ctx.redirect()` method
  • Loading branch information
jacobmischka authored Aug 26, 2022
2 parents 7aca3da + 3feba30 commit 5ae05ad
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 11 deletions.
14 changes: 14 additions & 0 deletions src/classes/IntervalClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
ActionResultSchema,
IOFunctionReturnType,
IO_RESPONSE,
LinkProps,
T_IO_RESPONSE,
} from '../ioSchema'
import { IOClient } from './IOClient'
Expand Down Expand Up @@ -652,6 +653,8 @@ export default class IntervalClient {
})
},
}),
redirect: (props: LinkProps) =>
this.#sendRedirect(transactionId, props),
}

const { io } = client
Expand Down Expand Up @@ -904,4 +907,15 @@ export default class IntervalClient {
timestamp: new Date().valueOf(),
})
}

async #sendRedirect(transactionId: string, props: LinkProps) {
const response = await this.#send('SEND_REDIRECT', {
transactionId,
...props,
})

if (!response) {
throw new IntervalError('Failed sending redirect')
}
}
}
70 changes: 70 additions & 0 deletions src/examples/basic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,35 @@ const prod = new Interval({
})
return ctx.params
},
perform_redirect_flow: async () => {
let startedWork = false
const { workDone = false } = ctx.params
if (!workDone) {
await ctx.redirect({
action: 'perform_common_work',
})
startedWork = true
}

console.log({ startedWork, workDone })

return {
startedWork,
workDone,
}
},
perform_common_work: async () => {
ctx.loading.start(
'Performing some work, will redirect back when complete'
)
await sleep(2000)
await ctx.redirect({
action: 'perform_redirect_flow',
params: {
workDone: true,
},
})
},
},
})

Expand Down Expand Up @@ -835,6 +864,47 @@ const interval = new Interval({

return { url: url.href }
},
redirect: async () => {
const [url, , action, paramsStr] = await io.group([
io.input.url('Enter a URL').optional(),
io.display.markdown('--- or ---'),
io.input.text('Enter an action slug').optional(),
io.input
.text('With optional params', {
multiline: true,
})
.optional(),
])

let params = undefined
if (url) {
await ctx.redirect({ url: url.toString() })
} else if (action) {
if (paramsStr) {
try {
params = JSON.parse(paramsStr)
} catch (err) {
ctx.log('Invalid params object', paramsStr)
}
}

await ctx.redirect({ action, params })
} else {
throw new Error('Must enter either a URL or an action slug')
}

console.log({
url,
action,
params,
})

return {
url: url?.toString(),
action,
paramsStr,
}
},
},
})

Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const ctx: ActionCtx = {
get organization() { return getActionStore().ctx.organization },
get action() { return getActionStore().ctx.action },
get notify() { return getActionStore().ctx.notify },
get redirect() { return getActionStore().ctx.redirect },
}

export default class Interval {
Expand Down
26 changes: 24 additions & 2 deletions src/internalRpcSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { z } from 'zod'
import { deserializableRecord, serializableRecord } from './ioSchema'
import {
deserializableRecord,
linkSchema,
serializableRecord,
} from './ioSchema'

export const DUPLEX_MESSAGE_SCHEMA = z.object({
id: z.string(),
Expand Down Expand Up @@ -209,6 +213,15 @@ export const wsServerSchema = {
}),
returns: z.boolean(),
},
SEND_REDIRECT: {
inputs: z.intersection(
z.object({
transactionId: z.string(),
}),
linkSchema
),
returns: z.boolean(),
},
MARK_TRANSACTION_COMPLETE: {
inputs: z.object({
transactionId: z.string(),
Expand Down Expand Up @@ -275,7 +288,7 @@ export const clientSchema = {
TRANSACTION_COMPLETED: {
inputs: z.object({
transactionId: z.string(),
resultStatus: z.enum(['SUCCESS', 'FAILURE', 'CANCELED']),
resultStatus: z.enum(['SUCCESS', 'FAILURE', 'CANCELED', 'REDIRECTED']),
}),
returns: z.void().nullable(),
},
Expand Down Expand Up @@ -330,6 +343,15 @@ export const clientSchema = {
}),
returns: z.boolean(),
},
REDIRECT: {
inputs: z.intersection(
z.object({
transactionId: z.string(),
}),
linkSchema
),
returns: z.boolean(),
},
}

export type ClientSchema = typeof clientSchema
Expand Down
24 changes: 15 additions & 9 deletions src/ioSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ export const menuItem = z.intersection(
])
)

export const linkSchema = z.union([
z.object({
url: z.string(),
}),
z.object({
action: z.string(),
params: serializableRecord.optional(),
}),
])

export type LinkProps = z.infer<typeof linkSchema>

export const internalTableRow = z.object({
key: z.string(),
data: tableRow,
Expand Down Expand Up @@ -207,7 +219,7 @@ export const tableColumn = z.object({
}),
z.object({
action: z.string(),
params: serializableRecord,
params: serializableRecord.optional(),
}),
z.object({}),
])
Expand Down Expand Up @@ -472,15 +484,9 @@ export const ioSchema = {
}),
z.union([
z.object({
url: z.string().url(),
}),
z.object({
href: z.string().url(),
}),
z.object({
action: z.string(),
params: serializableRecord.optional(),
href: z.string(),
}),
linkSchema,
])
),
state: z.null(),
Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
IOFunctionReturnType,
T_IO_DISPLAY_METHOD_NAMES,
T_IO_INPUT_METHOD_NAMES,
LinkProps,
} from './ioSchema'
import type { HostSchema } from './internalRpcSchema'
import type { IOClient, IOClientRenderValidator } from './classes/IOClient'
Expand All @@ -35,6 +36,7 @@ export type ActionCtx = Pick<
loading: TransactionLoadingState
log: ActionLogFn
notify: NotifyFn
redirect: RedirectFn
organization: {
name: string
slug: string
Expand Down Expand Up @@ -184,6 +186,8 @@ export type NotifyConfig = {

export type NotifyFn = (config: NotifyConfig) => Promise<void>

export type RedirectFn = (props: LinkProps) => Promise<void>

export type ResponseHandlerFn = (fn: T_IO_RESPONSE) => void

export type Executor<
Expand Down

0 comments on commit 5ae05ad

Please sign in to comment.