chore: Workflow execution JS-SDK (#8851)

This commit is contained in:
Oli Juhl
2024-08-29 13:22:43 +02:00
committed by GitHub
parent e396c01260
commit 00bd9271e3
19 changed files with 192 additions and 178 deletions

View File

@@ -1,10 +1,8 @@
import { QueryKey, UseQueryOptions, useQuery } from "@tanstack/react-query"
import { client } from "../../lib/client"
import { sdk } from "../../lib/client"
import { queryKeysFactory } from "../../lib/query-key-factory"
import {
WorkflowExecutionListRes,
WorkflowExecutionRes,
} from "../../types/api-responses"
import { HttpTypes } from "@medusajs/types"
import { FetchError } from "@medusajs/js-sdk"
const WORKFLOW_EXECUTIONS_QUERY_KEY = "workflow_executions" as const
export const workflowExecutionsQueryKeys = queryKeysFactory(
@@ -12,19 +10,19 @@ export const workflowExecutionsQueryKeys = queryKeysFactory(
)
export const useWorkflowExecutions = (
query?: Record<string, any>,
query?: HttpTypes.AdminGetWorkflowExecutionsParams,
options?: Omit<
UseQueryOptions<
WorkflowExecutionListRes,
Error,
WorkflowExecutionListRes,
HttpTypes.AdminGetWorkflowExecutionsParams,
FetchError,
HttpTypes.AdminWorkflowExecutionListResponse,
QueryKey
>,
"queryKey" | "queryFn"
>
) => {
const { data, ...rest } = useQuery({
queryFn: () => client.workflowExecutions.list(query),
queryFn: () => sdk.admin.workflowExecution.list(query),
queryKey: workflowExecutionsQueryKeys.list(query),
...options,
})
@@ -34,19 +32,18 @@ export const useWorkflowExecutions = (
export const useWorkflowExecution = (
id: string,
query?: Record<string, any>,
options?: Omit<
UseQueryOptions<
WorkflowExecutionRes,
Error,
WorkflowExecutionRes,
HttpTypes.AdminWorkflowExecutionResponse,
FetchError,
HttpTypes.AdminWorkflowExecutionResponse,
QueryKey
>,
"queryKey" | "queryFn"
>
) => {
const { data, ...rest } = useQuery({
queryFn: () => client.workflowExecutions.retrieve(id, query),
queryFn: () => sdk.admin.workflowExecution.retrieve(id),
queryKey: workflowExecutionsQueryKeys.detail(id),
...options,
})

View File

@@ -2,7 +2,6 @@ import Medusa from "@medusajs/js-sdk"
import { campaigns } from "./campaigns"
import { categories } from "./categories"
import { promotions } from "./promotions"
import { workflowExecutions } from "./workflow-executions"
export const backendUrl = __BACKEND_URL__ ?? "http://localhost:9000"
@@ -10,7 +9,6 @@ export const client = {
campaigns: campaigns,
categories: categories,
promotions: promotions,
workflowExecutions: workflowExecutions,
}
export const sdk = new Medusa({

View File

@@ -1,27 +0,0 @@
import {
WorkflowExecutionListRes,
WorkflowExecutionRes,
} from "../../types/api-responses"
import { getRequest } from "./common"
async function retrieveWorkflowExecution(
id: string,
query?: Record<string, any>
) {
return getRequest<WorkflowExecutionRes>(
`/admin/workflows-executions/${id}`,
query
)
}
async function listWorkflowExecutionss(query?: Record<string, any>) {
return getRequest<WorkflowExecutionListRes>(
`/admin/workflows-executions`,
query
)
}
export const workflowExecutions = {
retrieve: retrieveWorkflowExecution,
list: listWorkflowExecutionss,
}

View File

@@ -1,71 +1,3 @@
export type WorkflowExecutionStep = {
id: string
invoke: {
state: TransactionStepState
status: TransactionStepStatus
}
definition: {
async?: boolean
compensateAsync?: boolean
noCompensation?: boolean
continueOnPermanentFailure?: boolean
maxRetries?: number
noWait?: boolean
retryInterval?: number
retryIntervalAwaiting?: number
saveResponse?: boolean
timeout?: number
}
compensate: {
state: TransactionStepState
status: TransactionStepStatus
}
depth: number
startedAt: number
}
export type StepInvoke = {
output: {
output: unknown
compensateInput: unknown
}
}
export type StepError = {
error: Record<string, unknown>
action: string
handlerType: string
}
export type WorkflowExecutionContext = {
data: {
invoke: Record<string, StepInvoke>
payload?: unknown
}
compensate: Record<string, unknown>
errors: StepError[]
}
type WorflowExecutionExecution = {
steps: Record<string, WorkflowExecutionStep>
}
/**
* Re-implements WorkflowExecutionDTO as it is currently only exported from `@medusajs/workflows-sdk`.
* Also adds type definitions for fields that have vague types, such as `execution` and `context`.
*/
export interface WorkflowExecutionDTO {
id: string
workflow_id: string
transaction_id: string
execution: WorflowExecutionExecution | null
context: WorkflowExecutionContext | null
state: any
created_at: Date
updated_at: Date
deleted_at: Date
}
export enum TransactionStepStatus {
IDLE = "idle",
OK = "ok",

View File

@@ -1,4 +1,4 @@
import { AdminGetWorkflowExecutionsParams } from "@medusajs/medusa"
import { HttpTypes } from "@medusajs/types"
import { TFunction } from "i18next"
import {
STEP_ERROR_STATES,
@@ -11,7 +11,7 @@ import { TransactionState, TransactionStepState } from "./types"
export const adminExecutionKey = {
detail: (id: string) => ["workflow_executions", "detail", id],
list: (query?: AdminGetWorkflowExecutionsParams) => [
list: (query?: HttpTypes.AdminGetWorkflowExecutionsParams) => [
"workflow_executions",
"list",
{ query },

View File

@@ -8,15 +8,12 @@ import {
clx,
} from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import {
TransactionStepState,
WorkflowExecutionDTO,
WorkflowExecutionStep,
} from "../../../types"
import { getTransactionState, getTransactionStateColor } from "../../../utils"
import { HttpTypes } from "@medusajs/types"
import { TransactionState, TransactionStepState } from "../../../types"
type WorkflowExecutionGeneralSectionProps = {
execution: WorkflowExecutionDTO
execution: HttpTypes.AdminWorkflowExecution
}
export const WorkflowExecutionGeneralSection = ({
@@ -25,8 +22,13 @@ export const WorkflowExecutionGeneralSection = ({
const { t } = useTranslation()
const cleanId = execution.id.replace("wf_exec_", "")
const translatedState = getTransactionState(t, execution.state)
const stateColor = getTransactionStateColor(execution.state)
const translatedState = getTransactionState(
t,
execution.state as TransactionState
)
const stateColor = getTransactionStateColor(
execution.state as TransactionState
)
return (
<Container className="divide-y p-0">
@@ -68,7 +70,7 @@ const ROOT_PREFIX = "_root"
const Progress = ({
steps,
}: {
steps?: Record<string, WorkflowExecutionStep> | null
steps?: Record<string, HttpTypes.AdminWorkflowExecutionStep> | null
}) => {
const { t } = useTranslation()

View File

@@ -19,17 +19,11 @@ import {
STEP_OK_STATES,
STEP_SKIPPED_STATES,
} from "../../../constants"
import {
StepError,
StepInvoke,
TransactionStepState,
TransactionStepStatus,
WorkflowExecutionDTO,
WorkflowExecutionStep,
} from "../../../types"
import { TransactionStepState, TransactionStepStatus } from "../../../types"
import { HttpTypes } from "@medusajs/types"
type WorkflowExecutionHistorySectionProps = {
execution: WorkflowExecutionDTO
execution: HttpTypes.AdminWorkflowExecution
}
export const WorkflowExecutionHistorySection = ({
@@ -98,9 +92,9 @@ const Event = ({
isLast,
isUnreachable,
}: {
step: WorkflowExecutionStep
stepInvokeContext: StepInvoke | undefined
stepError?: StepError | undefined
step: HttpTypes.AdminWorkflowExecutionStep
stepInvokeContext: HttpTypes.StepInvoke | undefined
stepError?: HttpTypes.StepError | undefined
isLast: boolean
isUnreachable?: boolean
}) => {
@@ -288,7 +282,7 @@ const StepState = ({
startedAt,
isUnreachable,
}: {
state: TransactionStepState
state: HttpTypes.TransactionStepState
startedAt?: number | null
isUnreachable?: boolean
}) => {

View File

@@ -1,8 +1,8 @@
import { HttpTypes } from "@medusajs/types"
import { JsonViewSection } from "../../../../../components/common/json-view-section"
import { WorkflowExecutionDTO } from "../../../types"
type WorkflowExecutionPayloadSectionProps = {
execution: WorkflowExecutionDTO
execution: HttpTypes.AdminWorkflowExecution
}
export const WorkflowExecutionPayloadSection = ({

View File

@@ -17,10 +17,10 @@ import {
STEP_OK_STATES,
STEP_SKIPPED_STATES,
} from "../../../constants"
import { WorkflowExecutionDTO, WorkflowExecutionStep } from "../../../types"
import { HttpTypes } from "@medusajs/types"
type WorkflowExecutionTimelineSectionProps = {
execution: WorkflowExecutionDTO
execution: HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"]
}
export const WorkflowExecutionTimelineSection = ({
@@ -40,12 +40,14 @@ export const WorkflowExecutionTimelineSection = ({
)
}
const createNodeClusters = (steps: Record<string, WorkflowExecutionStep>) => {
const createNodeClusters = (
steps: Record<string, HttpTypes.AdminWorkflowExecutionStep>
) => {
const actionableSteps = Object.values(steps).filter(
(step) => step.id !== "_root"
)
const clusters: Record<number, WorkflowExecutionStep[]> = {}
const clusters: Record<number, HttpTypes.AdminWorkflowExecutionStep[]> = {}
actionableSteps.forEach((step) => {
if (!clusters[step.depth]) {
@@ -59,7 +61,7 @@ const createNodeClusters = (steps: Record<string, WorkflowExecutionStep>) => {
}
const getNextCluster = (
clusters: Record<number, WorkflowExecutionStep[]>,
clusters: Record<number, HttpTypes.AdminWorkflowExecutionStep[]>,
depth: number
) => {
const nextDepth = depth + 1
@@ -78,7 +80,11 @@ const MAX_ZOOM = 1.5
const MIN_ZOOM = 0.5
const ZOOM_STEP = 0.25
const Canvas = ({ execution }: { execution: WorkflowExecutionDTO }) => {
const Canvas = ({
execution,
}: {
execution: HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"]
}) => {
const [zoom, setZoom] = useState<number>(1)
const [isDragging, setIsDragging] = useState(false)
@@ -338,7 +344,7 @@ const Arrow = ({ depth }: { depth: number }) => {
)
}
const Line = ({ next }: { next?: WorkflowExecutionStep[] }) => {
const Line = ({ next }: { next?: HttpTypes.AdminWorkflowExecutionStep[] }) => {
if (!next) {
return null
}
@@ -357,7 +363,7 @@ const Line = ({ next }: { next?: WorkflowExecutionStep[] }) => {
)
}
const Node = ({ step }: { step: WorkflowExecutionStep }) => {
const Node = ({ step }: { step: HttpTypes.AdminWorkflowExecutionStep }) => {
if (step.id === "_root") {
return null
}

View File

@@ -1,13 +1,13 @@
import { LoaderFunctionArgs } from "react-router-dom"
import { workflowExecutionsQueryKeys } from "../../../hooks/api/workflow-executions"
import { client } from "../../../lib/client"
import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client"
import { WorkflowExecutionRes } from "../../../types/api-responses"
const executionDetailQuery = (id: string) => ({
queryKey: workflowExecutionsQueryKeys.detail(id),
queryFn: async () => client.workflowExecutions.retrieve(id),
queryFn: async () => sdk.admin.workflowExecution.retrieve(id),
})
export const executionLoader = async ({ params }: LoaderFunctionArgs) => {

View File

@@ -3,17 +3,17 @@ import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react"
import { useTranslation } from "react-i18next"
import { StatusCell } from "../../../../../components/table/table-cells/common/status-cell"
import {
TransactionStepState,
WorkflowExecutionDTO,
WorkflowExecutionStep,
} from "../../../types"
import { TransactionStepState } from "../../../types"
import { getTransactionState, getTransactionStateColor } from "../../../utils"
import { HttpTypes } from "@medusajs/types"
const columnHelper = createColumnHelper<WorkflowExecutionDTO>()
const columnHelper =
createColumnHelper<
HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"]
>()
export const useWorkflowExecutionTableColumns = (): ColumnDef<
WorkflowExecutionDTO,
HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"],
any
>[] => {
const { t } = useTranslation()
@@ -43,7 +43,7 @@ export const useWorkflowExecutionTableColumns = (): ColumnDef<
header: t("workflowExecutions.progressLabel"),
cell: ({ getValue }) => {
const steps = getValue()?.steps as
| Record<string, WorkflowExecutionStep>
| Record<string, HttpTypes.AdminWorkflowExecutionStep>
| undefined
if (!steps) {

View File

@@ -1,4 +1,4 @@
import { AdminGetWorkflowExecutionsParams } from "@medusajs/medusa"
import { HttpTypes } from "@medusajs/types"
import { useQueryParams } from "../../../../../hooks/use-query-params"
export const useWorkflowExecutionTableQuery = ({
@@ -12,7 +12,7 @@ export const useWorkflowExecutionTableQuery = ({
const { offset, ...rest } = raw
const searchParams: AdminGetWorkflowExecutionsParams = {
const searchParams: HttpTypes.AdminGetWorkflowExecutionsParams = {
limit: pageSize,
offset: offset ? parseInt(offset) : 0,
...rest,

View File

@@ -4,20 +4,9 @@ import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table"
import { useWorkflowExecutions } from "../../../../../hooks/api/workflow-executions"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { WorkflowExecutionDTO } from "../../../types"
import { useWorkflowExecutionTableColumns } from "./use-workflow-execution-table-columns"
import { useWorkflowExecutionTableQuery } from "./use-workflow-execution-table-query"
/**
* Type isn't exported from the package
*/
type WorkflowExecutionsRes = {
workflow_executions: WorkflowExecutionDTO[]
count: number
offset: number
limit: number
}
const PAGE_SIZE = 20
export const WorkflowExecutionListTable = () => {

View File

@@ -37,6 +37,7 @@ import { TaxRate } from "./tax-rate"
import { TaxRegion } from "./tax-region"
import { Upload } from "./upload"
import { User } from "./user"
import { WorkflowExecution } from "./workflow-execution"
export class Admin {
public invite: Invite
@@ -75,6 +76,7 @@ export class Admin {
public refundReason: RefundReason
public paymentCollection: PaymentCollection
public apiKey: ApiKey
public workflowExecution: WorkflowExecution
public reservation: Reservation
public customerGroup: CustomerGroup
@@ -115,6 +117,7 @@ export class Admin {
this.exchange = new Exchange(client)
this.paymentCollection = new PaymentCollection(client)
this.apiKey = new ApiKey(client)
this.workflowExecution = new WorkflowExecution(client)
this.reservation = new Reservation(client)
this.customerGroup = new CustomerGroup(client)
}

View File

@@ -0,0 +1,32 @@
import { HttpTypes } from "@medusajs/types"
import { Client } from "../client"
import { ClientHeaders } from "../types"
export class WorkflowExecution {
private client: Client
constructor(client: Client) {
this.client = client
}
async list(
queryParams?: HttpTypes.AdminGetWorkflowExecutionsParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminWorkflowExecutionListResponse>(
`/admin/workflows-executions`,
{
query: queryParams,
headers,
}
)
}
async retrieve(id: string, headers?: ClientHeaders) {
return await this.client.fetch<HttpTypes.AdminWorkflowExecutionResponse>(
`/admin/workflows-executions/${id}`,
{
headers,
}
)
}
}

View File

@@ -1,11 +1,92 @@
export type TransactionStepStatus =
| "idle"
| "ok"
| "waiting_response"
| "temp_failure"
| "permanent_failure"
export type TransactionState =
| "not_started"
| "invoking"
| "waiting_to_compensate"
| "compensating"
| "done"
| "reverted"
| "failed"
export type TransactionStepState =
| "not_started"
| "invoking"
| "compensating"
| "done"
| "reverted"
| "failed"
| "dormant"
| "skipped"
| "skipped_failure"
| "timeout"
interface AdminWorkflowExecutionExecution {
steps: Record<string, AdminWorkflowExecutionStep>
}
export type StepInvokeResult = {
output: {
output: unknown
compensateInput: unknown
}
}
export type StepError = {
error: Record<string, unknown>
action: string
handlerType: string
}
export interface WorkflowExecutionContext {
data: {
invoke: Record<string, StepInvokeResult>
payload?: unknown
}
compensate: Record<string, unknown>
errors: StepError[]
}
export interface WorkflowExecutionDefinition {
async?: boolean
compensateAsync?: boolean
noCompensation?: boolean
continueOnPermanentFailure?: boolean
maxRetries?: number
noWait?: boolean
retryInterval?: number
retryIntervalAwaiting?: number
saveResponse?: boolean
timeout?: number
}
export interface WorkflowExecutionFn {
state: TransactionStepState
status: TransactionStepStatus
}
export interface AdminWorkflowExecutionStep {
id: string
invoke: WorkflowExecutionFn
definition: WorkflowExecutionDefinition
compensate: WorkflowExecutionFn
depth: number
startedAt: number
}
export interface AdminWorkflowExecution {
id: string
workflow_id: string
transaction_id: string
execution: string
context: string
state: any
execution: AdminWorkflowExecutionExecution
context: WorkflowExecutionContext
state: TransactionState
created_at: Date
updated_at: Date
deleted_at: Date
}
deleted_at?: Date | null
}

View File

@@ -1,2 +1,3 @@
export * from "./entities"
export * from "./responses"
export * from "./queries"
export * from "./responses"

View File

@@ -0,0 +1,6 @@
import { FindParams } from "../../common"
export interface AdminGetWorkflowExecutionsParams extends FindParams {
transaction_id?: string | string[]
workflow_id?: string | string[]
}

View File

@@ -1,5 +1,5 @@
import { PaginatedResponse } from "../../common/response";
import { AdminWorkflowExecution } from "./entities";
import { PaginatedResponse } from "../../common/response"
import { AdminWorkflowExecution } from "./entities"
export interface AdminWorkflowExecutionResponse {
workflow_execution: AdminWorkflowExecution
@@ -7,4 +7,4 @@ export interface AdminWorkflowExecutionResponse {
export type AdminWorkflowExecutionListResponse = PaginatedResponse<{
workflow_executions: AdminWorkflowExecution[]
}>
}>