chore: Workflow execution JS-SDK (#8851)

This commit is contained in:
Oli Juhl
2024-08-29 11:22:43 +00:00
committed by GitHub
parent e396c01260
commit 00bd9271e3
19 changed files with 192 additions and 178 deletions
@@ -1,10 +1,8 @@
import { QueryKey, UseQueryOptions, useQuery } from "@tanstack/react-query" 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 { queryKeysFactory } from "../../lib/query-key-factory"
import { import { HttpTypes } from "@medusajs/types"
WorkflowExecutionListRes, import { FetchError } from "@medusajs/js-sdk"
WorkflowExecutionRes,
} from "../../types/api-responses"
const WORKFLOW_EXECUTIONS_QUERY_KEY = "workflow_executions" as const const WORKFLOW_EXECUTIONS_QUERY_KEY = "workflow_executions" as const
export const workflowExecutionsQueryKeys = queryKeysFactory( export const workflowExecutionsQueryKeys = queryKeysFactory(
@@ -12,19 +10,19 @@ export const workflowExecutionsQueryKeys = queryKeysFactory(
) )
export const useWorkflowExecutions = ( export const useWorkflowExecutions = (
query?: Record<string, any>, query?: HttpTypes.AdminGetWorkflowExecutionsParams,
options?: Omit< options?: Omit<
UseQueryOptions< UseQueryOptions<
WorkflowExecutionListRes, HttpTypes.AdminGetWorkflowExecutionsParams,
Error, FetchError,
WorkflowExecutionListRes, HttpTypes.AdminWorkflowExecutionListResponse,
QueryKey QueryKey
>, >,
"queryKey" | "queryFn" "queryKey" | "queryFn"
> >
) => { ) => {
const { data, ...rest } = useQuery({ const { data, ...rest } = useQuery({
queryFn: () => client.workflowExecutions.list(query), queryFn: () => sdk.admin.workflowExecution.list(query),
queryKey: workflowExecutionsQueryKeys.list(query), queryKey: workflowExecutionsQueryKeys.list(query),
...options, ...options,
}) })
@@ -34,19 +32,18 @@ export const useWorkflowExecutions = (
export const useWorkflowExecution = ( export const useWorkflowExecution = (
id: string, id: string,
query?: Record<string, any>,
options?: Omit< options?: Omit<
UseQueryOptions< UseQueryOptions<
WorkflowExecutionRes, HttpTypes.AdminWorkflowExecutionResponse,
Error, FetchError,
WorkflowExecutionRes, HttpTypes.AdminWorkflowExecutionResponse,
QueryKey QueryKey
>, >,
"queryKey" | "queryFn" "queryKey" | "queryFn"
> >
) => { ) => {
const { data, ...rest } = useQuery({ const { data, ...rest } = useQuery({
queryFn: () => client.workflowExecutions.retrieve(id, query), queryFn: () => sdk.admin.workflowExecution.retrieve(id),
queryKey: workflowExecutionsQueryKeys.detail(id), queryKey: workflowExecutionsQueryKeys.detail(id),
...options, ...options,
}) })
@@ -2,7 +2,6 @@ import Medusa from "@medusajs/js-sdk"
import { campaigns } from "./campaigns" import { campaigns } from "./campaigns"
import { categories } from "./categories" import { categories } from "./categories"
import { promotions } from "./promotions" import { promotions } from "./promotions"
import { workflowExecutions } from "./workflow-executions"
export const backendUrl = __BACKEND_URL__ ?? "http://localhost:9000" export const backendUrl = __BACKEND_URL__ ?? "http://localhost:9000"
@@ -10,7 +9,6 @@ export const client = {
campaigns: campaigns, campaigns: campaigns,
categories: categories, categories: categories,
promotions: promotions, promotions: promotions,
workflowExecutions: workflowExecutions,
} }
export const sdk = new Medusa({ export const sdk = new Medusa({
@@ -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,
}
@@ -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 { export enum TransactionStepStatus {
IDLE = "idle", IDLE = "idle",
OK = "ok", OK = "ok",
@@ -1,4 +1,4 @@
import { AdminGetWorkflowExecutionsParams } from "@medusajs/medusa" import { HttpTypes } from "@medusajs/types"
import { TFunction } from "i18next" import { TFunction } from "i18next"
import { import {
STEP_ERROR_STATES, STEP_ERROR_STATES,
@@ -11,7 +11,7 @@ import { TransactionState, TransactionStepState } from "./types"
export const adminExecutionKey = { export const adminExecutionKey = {
detail: (id: string) => ["workflow_executions", "detail", id], detail: (id: string) => ["workflow_executions", "detail", id],
list: (query?: AdminGetWorkflowExecutionsParams) => [ list: (query?: HttpTypes.AdminGetWorkflowExecutionsParams) => [
"workflow_executions", "workflow_executions",
"list", "list",
{ query }, { query },
@@ -8,15 +8,12 @@ import {
clx, clx,
} from "@medusajs/ui" } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import {
TransactionStepState,
WorkflowExecutionDTO,
WorkflowExecutionStep,
} from "../../../types"
import { getTransactionState, getTransactionStateColor } from "../../../utils" import { getTransactionState, getTransactionStateColor } from "../../../utils"
import { HttpTypes } from "@medusajs/types"
import { TransactionState, TransactionStepState } from "../../../types"
type WorkflowExecutionGeneralSectionProps = { type WorkflowExecutionGeneralSectionProps = {
execution: WorkflowExecutionDTO execution: HttpTypes.AdminWorkflowExecution
} }
export const WorkflowExecutionGeneralSection = ({ export const WorkflowExecutionGeneralSection = ({
@@ -25,8 +22,13 @@ export const WorkflowExecutionGeneralSection = ({
const { t } = useTranslation() const { t } = useTranslation()
const cleanId = execution.id.replace("wf_exec_", "") const cleanId = execution.id.replace("wf_exec_", "")
const translatedState = getTransactionState(t, execution.state) const translatedState = getTransactionState(
const stateColor = getTransactionStateColor(execution.state) t,
execution.state as TransactionState
)
const stateColor = getTransactionStateColor(
execution.state as TransactionState
)
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
@@ -68,7 +70,7 @@ const ROOT_PREFIX = "_root"
const Progress = ({ const Progress = ({
steps, steps,
}: { }: {
steps?: Record<string, WorkflowExecutionStep> | null steps?: Record<string, HttpTypes.AdminWorkflowExecutionStep> | null
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -19,17 +19,11 @@ import {
STEP_OK_STATES, STEP_OK_STATES,
STEP_SKIPPED_STATES, STEP_SKIPPED_STATES,
} from "../../../constants" } from "../../../constants"
import { import { TransactionStepState, TransactionStepStatus } from "../../../types"
StepError, import { HttpTypes } from "@medusajs/types"
StepInvoke,
TransactionStepState,
TransactionStepStatus,
WorkflowExecutionDTO,
WorkflowExecutionStep,
} from "../../../types"
type WorkflowExecutionHistorySectionProps = { type WorkflowExecutionHistorySectionProps = {
execution: WorkflowExecutionDTO execution: HttpTypes.AdminWorkflowExecution
} }
export const WorkflowExecutionHistorySection = ({ export const WorkflowExecutionHistorySection = ({
@@ -98,9 +92,9 @@ const Event = ({
isLast, isLast,
isUnreachable, isUnreachable,
}: { }: {
step: WorkflowExecutionStep step: HttpTypes.AdminWorkflowExecutionStep
stepInvokeContext: StepInvoke | undefined stepInvokeContext: HttpTypes.StepInvoke | undefined
stepError?: StepError | undefined stepError?: HttpTypes.StepError | undefined
isLast: boolean isLast: boolean
isUnreachable?: boolean isUnreachable?: boolean
}) => { }) => {
@@ -288,7 +282,7 @@ const StepState = ({
startedAt, startedAt,
isUnreachable, isUnreachable,
}: { }: {
state: TransactionStepState state: HttpTypes.TransactionStepState
startedAt?: number | null startedAt?: number | null
isUnreachable?: boolean isUnreachable?: boolean
}) => { }) => {
@@ -1,8 +1,8 @@
import { HttpTypes } from "@medusajs/types"
import { JsonViewSection } from "../../../../../components/common/json-view-section" import { JsonViewSection } from "../../../../../components/common/json-view-section"
import { WorkflowExecutionDTO } from "../../../types"
type WorkflowExecutionPayloadSectionProps = { type WorkflowExecutionPayloadSectionProps = {
execution: WorkflowExecutionDTO execution: HttpTypes.AdminWorkflowExecution
} }
export const WorkflowExecutionPayloadSection = ({ export const WorkflowExecutionPayloadSection = ({
@@ -17,10 +17,10 @@ import {
STEP_OK_STATES, STEP_OK_STATES,
STEP_SKIPPED_STATES, STEP_SKIPPED_STATES,
} from "../../../constants" } from "../../../constants"
import { WorkflowExecutionDTO, WorkflowExecutionStep } from "../../../types" import { HttpTypes } from "@medusajs/types"
type WorkflowExecutionTimelineSectionProps = { type WorkflowExecutionTimelineSectionProps = {
execution: WorkflowExecutionDTO execution: HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"]
} }
export const WorkflowExecutionTimelineSection = ({ 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( const actionableSteps = Object.values(steps).filter(
(step) => step.id !== "_root" (step) => step.id !== "_root"
) )
const clusters: Record<number, WorkflowExecutionStep[]> = {} const clusters: Record<number, HttpTypes.AdminWorkflowExecutionStep[]> = {}
actionableSteps.forEach((step) => { actionableSteps.forEach((step) => {
if (!clusters[step.depth]) { if (!clusters[step.depth]) {
@@ -59,7 +61,7 @@ const createNodeClusters = (steps: Record<string, WorkflowExecutionStep>) => {
} }
const getNextCluster = ( const getNextCluster = (
clusters: Record<number, WorkflowExecutionStep[]>, clusters: Record<number, HttpTypes.AdminWorkflowExecutionStep[]>,
depth: number depth: number
) => { ) => {
const nextDepth = depth + 1 const nextDepth = depth + 1
@@ -78,7 +80,11 @@ const MAX_ZOOM = 1.5
const MIN_ZOOM = 0.5 const MIN_ZOOM = 0.5
const ZOOM_STEP = 0.25 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 [zoom, setZoom] = useState<number>(1)
const [isDragging, setIsDragging] = useState(false) 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) { if (!next) {
return null 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") { if (step.id === "_root") {
return null return null
} }
@@ -1,13 +1,13 @@
import { LoaderFunctionArgs } from "react-router-dom" import { LoaderFunctionArgs } from "react-router-dom"
import { workflowExecutionsQueryKeys } from "../../../hooks/api/workflow-executions" import { workflowExecutionsQueryKeys } from "../../../hooks/api/workflow-executions"
import { client } from "../../../lib/client" import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client" import { queryClient } from "../../../lib/query-client"
import { WorkflowExecutionRes } from "../../../types/api-responses" import { WorkflowExecutionRes } from "../../../types/api-responses"
const executionDetailQuery = (id: string) => ({ const executionDetailQuery = (id: string) => ({
queryKey: workflowExecutionsQueryKeys.detail(id), queryKey: workflowExecutionsQueryKeys.detail(id),
queryFn: async () => client.workflowExecutions.retrieve(id), queryFn: async () => sdk.admin.workflowExecution.retrieve(id),
}) })
export const executionLoader = async ({ params }: LoaderFunctionArgs) => { export const executionLoader = async ({ params }: LoaderFunctionArgs) => {
@@ -3,17 +3,17 @@ import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { StatusCell } from "../../../../../components/table/table-cells/common/status-cell" import { StatusCell } from "../../../../../components/table/table-cells/common/status-cell"
import { import { TransactionStepState } from "../../../types"
TransactionStepState,
WorkflowExecutionDTO,
WorkflowExecutionStep,
} from "../../../types"
import { getTransactionState, getTransactionStateColor } from "../../../utils" 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< export const useWorkflowExecutionTableColumns = (): ColumnDef<
WorkflowExecutionDTO, HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"],
any any
>[] => { >[] => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -43,7 +43,7 @@ export const useWorkflowExecutionTableColumns = (): ColumnDef<
header: t("workflowExecutions.progressLabel"), header: t("workflowExecutions.progressLabel"),
cell: ({ getValue }) => { cell: ({ getValue }) => {
const steps = getValue()?.steps as const steps = getValue()?.steps as
| Record<string, WorkflowExecutionStep> | Record<string, HttpTypes.AdminWorkflowExecutionStep>
| undefined | undefined
if (!steps) { if (!steps) {
@@ -1,4 +1,4 @@
import { AdminGetWorkflowExecutionsParams } from "@medusajs/medusa" import { HttpTypes } from "@medusajs/types"
import { useQueryParams } from "../../../../../hooks/use-query-params" import { useQueryParams } from "../../../../../hooks/use-query-params"
export const useWorkflowExecutionTableQuery = ({ export const useWorkflowExecutionTableQuery = ({
@@ -12,7 +12,7 @@ export const useWorkflowExecutionTableQuery = ({
const { offset, ...rest } = raw const { offset, ...rest } = raw
const searchParams: AdminGetWorkflowExecutionsParams = { const searchParams: HttpTypes.AdminGetWorkflowExecutionsParams = {
limit: pageSize, limit: pageSize,
offset: offset ? parseInt(offset) : 0, offset: offset ? parseInt(offset) : 0,
...rest, ...rest,
@@ -4,20 +4,9 @@ import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table" import { DataTable } from "../../../../../components/table/data-table"
import { useWorkflowExecutions } from "../../../../../hooks/api/workflow-executions" import { useWorkflowExecutions } from "../../../../../hooks/api/workflow-executions"
import { useDataTable } from "../../../../../hooks/use-data-table" import { useDataTable } from "../../../../../hooks/use-data-table"
import { WorkflowExecutionDTO } from "../../../types"
import { useWorkflowExecutionTableColumns } from "./use-workflow-execution-table-columns" import { useWorkflowExecutionTableColumns } from "./use-workflow-execution-table-columns"
import { useWorkflowExecutionTableQuery } from "./use-workflow-execution-table-query" 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 const PAGE_SIZE = 20
export const WorkflowExecutionListTable = () => { export const WorkflowExecutionListTable = () => {
+3
View File
@@ -37,6 +37,7 @@ import { TaxRate } from "./tax-rate"
import { TaxRegion } from "./tax-region" import { TaxRegion } from "./tax-region"
import { Upload } from "./upload" import { Upload } from "./upload"
import { User } from "./user" import { User } from "./user"
import { WorkflowExecution } from "./workflow-execution"
export class Admin { export class Admin {
public invite: Invite public invite: Invite
@@ -75,6 +76,7 @@ export class Admin {
public refundReason: RefundReason public refundReason: RefundReason
public paymentCollection: PaymentCollection public paymentCollection: PaymentCollection
public apiKey: ApiKey public apiKey: ApiKey
public workflowExecution: WorkflowExecution
public reservation: Reservation public reservation: Reservation
public customerGroup: CustomerGroup public customerGroup: CustomerGroup
@@ -115,6 +117,7 @@ export class Admin {
this.exchange = new Exchange(client) this.exchange = new Exchange(client)
this.paymentCollection = new PaymentCollection(client) this.paymentCollection = new PaymentCollection(client)
this.apiKey = new ApiKey(client) this.apiKey = new ApiKey(client)
this.workflowExecution = new WorkflowExecution(client)
this.reservation = new Reservation(client) this.reservation = new Reservation(client)
this.customerGroup = new CustomerGroup(client) this.customerGroup = new CustomerGroup(client)
} }
@@ -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,
}
)
}
}
@@ -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 { export interface AdminWorkflowExecution {
id: string id: string
workflow_id: string workflow_id: string
transaction_id: string transaction_id: string
execution: string execution: AdminWorkflowExecutionExecution
context: string context: WorkflowExecutionContext
state: any state: TransactionState
created_at: Date created_at: Date
updated_at: Date updated_at: Date
deleted_at: Date deleted_at?: Date | null
} }
@@ -1,2 +1,3 @@
export * from "./entities" export * from "./entities"
export * from "./responses" export * from "./queries"
export * from "./responses"
@@ -0,0 +1,6 @@
import { FindParams } from "../../common"
export interface AdminGetWorkflowExecutionsParams extends FindParams {
transaction_id?: string | string[]
workflow_id?: string | string[]
}
@@ -1,5 +1,5 @@
import { PaginatedResponse } from "../../common/response"; import { PaginatedResponse } from "../../common/response"
import { AdminWorkflowExecution } from "./entities"; import { AdminWorkflowExecution } from "./entities"
export interface AdminWorkflowExecutionResponse { export interface AdminWorkflowExecutionResponse {
workflow_execution: AdminWorkflowExecution workflow_execution: AdminWorkflowExecution
@@ -7,4 +7,4 @@ export interface AdminWorkflowExecutionResponse {
export type AdminWorkflowExecutionListResponse = PaginatedResponse<{ export type AdminWorkflowExecutionListResponse = PaginatedResponse<{
workflow_executions: AdminWorkflowExecution[] workflow_executions: AdminWorkflowExecution[]
}> }>