mirror of
https://github.com/langgenius/dify.git
synced 2026-07-22 19:48:36 +08:00
600 lines
19 KiB
TypeScript
600 lines
19 KiB
TypeScript
'use client'
|
|
|
|
import type {
|
|
CreateReleaseResponse,
|
|
ListReleasesResponse,
|
|
ListReleaseSummariesResponse,
|
|
} from '@dify/contracts/enterprise/types.gen'
|
|
import type { Getter } from 'jotai/vanilla'
|
|
import type { UnsupportedDslNode } from '../../shared/domain/error'
|
|
import type { App } from '@/types/app'
|
|
import { keepPreviousData, queryOptions, skipToken } from '@tanstack/react-query'
|
|
import { atom } from 'jotai'
|
|
import { atomWithForm, createFormAtoms } from 'jotai-tanstack-form'
|
|
import {
|
|
atomWithInfiniteQuery,
|
|
atomWithMutation,
|
|
atomWithQuery,
|
|
queryClientAtom,
|
|
} from 'jotai-tanstack-query'
|
|
import { selectAtom } from 'jotai/utils'
|
|
import * as z from 'zod'
|
|
import { consoleQuery } from '@/service/client'
|
|
import { normalizeAppPagination } from '@/service/use-apps'
|
|
import { AppModeEnum } from '@/types/app'
|
|
import { encodeDslContent, isWorkflowDsl } from '../../shared/domain/dsl'
|
|
import { isDeploymentDslImportEnabled } from '../../shared/domain/feature-flags'
|
|
|
|
export type ReleaseSourceMode = 'sourceApp' | 'dsl'
|
|
|
|
export type SourceAppPickerValue = Pick<App, 'id' | 'name'> &
|
|
Partial<Pick<App, 'icon_type' | 'icon' | 'icon_background' | 'icon_url' | 'mode'>>
|
|
|
|
export type CreateReleaseFormValues = {
|
|
releaseSourceMode: ReleaseSourceMode
|
|
sourceApp?: SourceAppPickerValue
|
|
dslFile?: File
|
|
releaseName: string
|
|
releaseDescription: string
|
|
}
|
|
|
|
const DEFAULT_CREATE_RELEASE_FORM_VALUES: CreateReleaseFormValues = {
|
|
releaseSourceMode: 'sourceApp',
|
|
sourceApp: undefined,
|
|
dslFile: undefined,
|
|
releaseName: '',
|
|
releaseDescription: '',
|
|
}
|
|
|
|
export const RELEASE_NAME_REQUIRED_ERROR = 'releaseNameRequired'
|
|
|
|
const DEFAULT_SOURCE_RELEASE_PAGE_SIZE = 1
|
|
const CREATE_RELEASE_SOURCE_APP_PAGE_SIZE = 20
|
|
|
|
function deploymentReleaseSourceMode(mode: ReleaseSourceMode): ReleaseSourceMode {
|
|
return mode === 'dsl' && !isDeploymentDslImportEnabled ? 'sourceApp' : mode
|
|
}
|
|
|
|
function workflowSourceAppPickerValue(
|
|
value: unknown,
|
|
fallbackId: string,
|
|
): SourceAppPickerValue | undefined {
|
|
if (!value || typeof value !== 'object') return undefined
|
|
|
|
const record = value as Record<string, unknown>
|
|
const mode = typeof record.mode === 'string' ? record.mode : undefined
|
|
if (mode !== AppModeEnum.WORKFLOW) return undefined
|
|
|
|
const id = typeof record.id === 'string' && record.id ? record.id : fallbackId
|
|
const name = typeof record.name === 'string' && record.name ? record.name : id
|
|
|
|
return {
|
|
id,
|
|
name,
|
|
mode,
|
|
}
|
|
}
|
|
|
|
const createReleaseFormSchema = z.object({
|
|
releaseSourceMode: z.union([z.literal('sourceApp'), z.literal('dsl')]),
|
|
sourceApp: z.custom<CreateReleaseFormValues['sourceApp']>().optional(),
|
|
dslFile: z.custom<CreateReleaseFormValues['dslFile']>().optional(),
|
|
releaseName: z.string().trim().min(1, RELEASE_NAME_REQUIRED_ERROR),
|
|
releaseDescription: z.string(),
|
|
})
|
|
|
|
type CreateReleaseSubmit = (
|
|
value: CreateReleaseFormValues,
|
|
) => Promise<CreateReleaseResponse | undefined> | CreateReleaseResponse | undefined
|
|
|
|
type CreateReleaseSubmitMeta = {
|
|
createRelease: CreateReleaseSubmit
|
|
}
|
|
|
|
const noopCreateRelease: CreateReleaseSubmit = () => undefined
|
|
|
|
// Form state
|
|
export const createReleaseFormAtom = atomWithForm({
|
|
defaultValues: DEFAULT_CREATE_RELEASE_FORM_VALUES,
|
|
onSubmitMeta: {
|
|
createRelease: noopCreateRelease,
|
|
},
|
|
validators: {
|
|
onSubmit: createReleaseFormSchema,
|
|
},
|
|
onSubmit: ({ value, meta }) => meta.createRelease(value),
|
|
})
|
|
|
|
const createReleaseFormAtoms = createFormAtoms(createReleaseFormAtom)
|
|
|
|
export const createReleaseFormIsSubmittingAtom = createReleaseFormAtoms.isSubmittingAtom
|
|
export const createReleaseSourceModeFieldAtom =
|
|
createReleaseFormAtoms.fieldAtom('releaseSourceMode')
|
|
export const createReleaseSourceAppFieldAtom = createReleaseFormAtoms.fieldAtom('sourceApp')
|
|
export const createReleaseDslFileFieldAtom = createReleaseFormAtoms.fieldAtom('dslFile')
|
|
export const createReleaseNameFieldAtom = createReleaseFormAtoms.fieldAtom('releaseName')
|
|
export const createReleaseDescriptionFieldAtom =
|
|
createReleaseFormAtoms.fieldAtom('releaseDescription')
|
|
|
|
// Dialog and source primitives
|
|
export const createReleaseAppInstanceIdAtom = atom<string | undefined>(undefined)
|
|
export const createReleaseDialogOpenAtom = atom(false)
|
|
const createReleaseDslFileReadVersionAtom = atom(0)
|
|
|
|
function requiredAppInstanceId(get: Getter) {
|
|
const appInstanceId = get(createReleaseAppInstanceIdAtom)
|
|
if (!appInstanceId) throw new Error('Missing create release app instance id.')
|
|
|
|
return appInstanceId
|
|
}
|
|
|
|
// Query and remote data
|
|
const latestSourceReleaseQueryAtom = atomWithQuery((get) => {
|
|
const appInstanceId = get(createReleaseAppInstanceIdAtom)
|
|
|
|
return consoleQuery.enterprise.releaseService.listReleases.queryOptions({
|
|
input: appInstanceId
|
|
? {
|
|
params: { appInstanceId },
|
|
query: {
|
|
pageNumber: 1,
|
|
resultsPerPage: DEFAULT_SOURCE_RELEASE_PAGE_SIZE,
|
|
},
|
|
}
|
|
: skipToken,
|
|
enabled: Boolean(appInstanceId && get(createReleaseDialogOpenAtom)),
|
|
})
|
|
})
|
|
|
|
function latestReleaseSourceAppId(get: Getter) {
|
|
const latestReleaseQuery = get(latestSourceReleaseQueryAtom)
|
|
|
|
return latestReleaseQuery.data?.releases[0]?.sourceAppId
|
|
}
|
|
|
|
const defaultSourceAppQueryAtom = atomWithQuery((get) => {
|
|
const latestSourceAppId = latestReleaseSourceAppId(get)
|
|
|
|
return consoleQuery.apps.byAppId.get.queryOptions({
|
|
input: latestSourceAppId
|
|
? {
|
|
params: { app_id: latestSourceAppId },
|
|
}
|
|
: skipToken,
|
|
enabled: Boolean(get(createReleaseDialogOpenAtom) && latestSourceAppId),
|
|
})
|
|
})
|
|
|
|
function defaultSourceApp(get: Getter) {
|
|
const latestSourceAppId = latestReleaseSourceAppId(get)
|
|
if (!latestSourceAppId) return undefined
|
|
|
|
return workflowSourceAppPickerValue(get(defaultSourceAppQueryAtom).data, latestSourceAppId)
|
|
}
|
|
|
|
function submittedReleaseName(get: Getter) {
|
|
return get(createReleaseNameFieldAtom).value.trim()
|
|
}
|
|
|
|
function cachedReleaseDisplayNames(get: Getter) {
|
|
const appInstanceId = get(createReleaseAppInstanceIdAtom)
|
|
if (!appInstanceId) return []
|
|
|
|
const queryClient = get(queryClientAtom)
|
|
const releaseSummaryQueries = queryClient.getQueriesData<ListReleaseSummariesResponse>({
|
|
queryKey: consoleQuery.enterprise.releaseService.listReleaseSummaries.key({
|
|
type: 'query',
|
|
input: { params: { appInstanceId } },
|
|
}),
|
|
})
|
|
const releaseQueries = queryClient.getQueriesData<ListReleasesResponse>({
|
|
queryKey: consoleQuery.enterprise.releaseService.listReleases.key({
|
|
type: 'query',
|
|
input: { params: { appInstanceId } },
|
|
}),
|
|
})
|
|
|
|
return [
|
|
...releaseSummaryQueries.flatMap(([, data]) => {
|
|
return data?.releaseSummaries.map((summary) => summary.release.displayName) ?? []
|
|
}),
|
|
...releaseQueries.flatMap(([, data]) => {
|
|
return data?.releases.map((release) => release.displayName) ?? []
|
|
}),
|
|
]
|
|
}
|
|
|
|
export const createReleaseHasNameConflictAtom = atom((get) => {
|
|
const releaseName = submittedReleaseName(get)
|
|
if (!releaseName) return false
|
|
|
|
return cachedReleaseDisplayNames(get).some((displayName) => displayName.trim() === releaseName)
|
|
})
|
|
|
|
const createReleaseDslFileContentQueryAtom = atomWithQuery((get) => {
|
|
const file = get(createReleaseDslFileFieldAtom).value
|
|
const fileReadVersion = get(createReleaseDslFileReadVersionAtom)
|
|
|
|
return queryOptions({
|
|
queryKey: [
|
|
'createReleaseDslFileContent',
|
|
fileReadVersion,
|
|
file,
|
|
file?.name ?? '',
|
|
file?.size ?? 0,
|
|
file?.lastModified ?? 0,
|
|
],
|
|
queryFn: async () => (file ? await file.text() : ''),
|
|
enabled: Boolean(file),
|
|
retry: false,
|
|
})
|
|
})
|
|
|
|
// Source derived state
|
|
function effectiveCreateReleaseSourceMode(get: Getter) {
|
|
return deploymentReleaseSourceMode(get(createReleaseSourceModeFieldAtom).value)
|
|
}
|
|
|
|
export const createReleaseSourceModeAtom = atom((get) => {
|
|
return effectiveCreateReleaseSourceMode(get)
|
|
})
|
|
|
|
export const createReleaseSourceAppSearchTextAtom = atom('')
|
|
|
|
export const createReleaseSourceAppsQueryAtom = atomWithInfiniteQuery((get) => {
|
|
const searchText = get(createReleaseSourceAppSearchTextAtom)
|
|
|
|
return consoleQuery.apps.get.infiniteOptions({
|
|
input: (pageParam) => ({
|
|
query: {
|
|
page: Number(pageParam),
|
|
limit: CREATE_RELEASE_SOURCE_APP_PAGE_SIZE,
|
|
name: searchText,
|
|
mode: AppModeEnum.WORKFLOW,
|
|
},
|
|
}),
|
|
getNextPageParam: (lastPage) => (lastPage.has_more ? lastPage.page + 1 : undefined),
|
|
initialPageParam: 1,
|
|
placeholderData: keepPreviousData,
|
|
select: (data) => ({
|
|
...data,
|
|
pages: data.pages.map(normalizeAppPagination),
|
|
}),
|
|
enabled: Boolean(
|
|
get(createReleaseDialogOpenAtom) &&
|
|
effectiveCreateReleaseSourceMode(get) === 'sourceApp' &&
|
|
isDeploymentDslImportEnabled,
|
|
),
|
|
})
|
|
})
|
|
|
|
const createReleaseSourceAppsDataAtom = selectAtom(
|
|
createReleaseSourceAppsQueryAtom,
|
|
(query) => query.data,
|
|
)
|
|
export const createReleaseSourceAppsErrorAtom = selectAtom(
|
|
createReleaseSourceAppsQueryAtom,
|
|
(query) => query.error,
|
|
)
|
|
export const createReleaseSourceAppsFetchNextPageAtom = selectAtom(
|
|
createReleaseSourceAppsQueryAtom,
|
|
(query) => query.fetchNextPage,
|
|
)
|
|
export const createReleaseSourceAppsHasNextPageAtom = selectAtom(
|
|
createReleaseSourceAppsQueryAtom,
|
|
(query) => query.hasNextPage,
|
|
)
|
|
export const createReleaseSourceAppsIsFetchingAtom = selectAtom(
|
|
createReleaseSourceAppsQueryAtom,
|
|
(query) => query.isFetching,
|
|
)
|
|
export const createReleaseSourceAppsIsFetchingNextPageAtom = selectAtom(
|
|
createReleaseSourceAppsQueryAtom,
|
|
(query) => query.isFetchingNextPage,
|
|
)
|
|
export const createReleaseSourceAppsIsLoadingAtom = selectAtom(
|
|
createReleaseSourceAppsQueryAtom,
|
|
(query) => query.isLoading,
|
|
)
|
|
|
|
export const createReleaseSourceAppsAtom = atom((get) => {
|
|
return get(createReleaseSourceAppsDataAtom)?.pages.flatMap((page) => page.data) ?? []
|
|
})
|
|
|
|
export const createReleaseDslContentAtom = atom((get) => {
|
|
return get(createReleaseDslFileContentQueryAtom).data ?? ''
|
|
})
|
|
|
|
export const createReleaseDslReadErrorAtom = atom((get) => {
|
|
return Boolean(
|
|
get(createReleaseDslFileFieldAtom).value && get(createReleaseDslFileContentQueryAtom).isError,
|
|
)
|
|
})
|
|
|
|
export const isReadingCreateReleaseDslAtom = atom((get) => {
|
|
const file = get(createReleaseDslFileFieldAtom).value
|
|
const dslFileContentQuery = get(createReleaseDslFileContentQueryAtom)
|
|
|
|
return Boolean(file && (dslFileContentQuery.isLoading || dslFileContentQuery.isFetching))
|
|
})
|
|
|
|
export const createReleaseHasDslContentAtom = atom((get) => {
|
|
return Boolean(get(createReleaseDslContentAtom).trim())
|
|
})
|
|
|
|
export const createReleaseIsWorkflowDslContentAtom = atom((get) => {
|
|
const dslContent = get(createReleaseDslContentAtom)
|
|
|
|
return get(createReleaseHasDslContentAtom) ? isWorkflowDsl(dslContent) : false
|
|
})
|
|
|
|
export const createReleaseEncodedDslContentAtom = atom((get) => {
|
|
const dslContent = get(createReleaseDslContentAtom)
|
|
|
|
return get(createReleaseHasDslContentAtom) && get(createReleaseIsWorkflowDslContentAtom)
|
|
? encodeDslContent(dslContent)
|
|
: ''
|
|
})
|
|
|
|
export const createReleaseSelectedSourceAppAtom = atom((get) => {
|
|
if (effectiveCreateReleaseSourceMode(get) !== 'sourceApp') return undefined
|
|
|
|
const fieldSourceApp = get(createReleaseSourceAppFieldAtom).value
|
|
const fallbackSourceApp = defaultSourceApp(get)
|
|
|
|
if (!isDeploymentDslImportEnabled) return fallbackSourceApp
|
|
|
|
return fieldSourceApp ?? fallbackSourceApp
|
|
})
|
|
|
|
function selectedSourceAppId(get: Getter) {
|
|
return effectiveCreateReleaseSourceMode(get) === 'sourceApp'
|
|
? get(createReleaseSelectedSourceAppAtom)?.id
|
|
: undefined
|
|
}
|
|
|
|
function hasUnsupportedDslMode(get: Getter) {
|
|
if (effectiveCreateReleaseSourceMode(get) !== 'dsl') return false
|
|
|
|
return (
|
|
get(createReleaseHasDslContentAtom) &&
|
|
!get(isReadingCreateReleaseDslAtom) &&
|
|
!get(createReleaseDslReadErrorAtom) &&
|
|
!get(createReleaseIsWorkflowDslContentAtom)
|
|
)
|
|
}
|
|
|
|
export const createReleaseHasUnsupportedDslModeAtom = atom((get) => {
|
|
return hasUnsupportedDslMode(get)
|
|
})
|
|
|
|
function canCheckReleaseSourceContent(get: Getter) {
|
|
if (effectiveCreateReleaseSourceMode(get) === 'sourceApp')
|
|
return Boolean(selectedSourceAppId(get))
|
|
if (!isDeploymentDslImportEnabled) return false
|
|
|
|
return Boolean(
|
|
get(createReleaseHasDslContentAtom) &&
|
|
!get(isReadingCreateReleaseDslAtom) &&
|
|
!get(createReleaseDslReadErrorAtom) &&
|
|
!hasUnsupportedDslMode(get),
|
|
)
|
|
}
|
|
|
|
function canCheckReleaseContent(get: Getter) {
|
|
return Boolean(
|
|
get(createReleaseAppInstanceIdAtom) &&
|
|
get(createReleaseDialogOpenAtom) &&
|
|
canCheckReleaseSourceContent(get),
|
|
)
|
|
}
|
|
|
|
// Release content check
|
|
const precheckReleaseQueryAtom = atomWithQuery((get) => {
|
|
const appInstanceId = get(createReleaseAppInstanceIdAtom)
|
|
const releaseSourceMode = effectiveCreateReleaseSourceMode(get)
|
|
const sourceAppId = selectedSourceAppId(get)
|
|
const canCheck = canCheckReleaseContent(get)
|
|
|
|
return consoleQuery.enterprise.releaseService.precheckRelease.queryOptions({
|
|
input:
|
|
canCheck && appInstanceId
|
|
? releaseSourceMode === 'dsl'
|
|
? {
|
|
body: {
|
|
appInstanceId,
|
|
dsl: get(createReleaseEncodedDslContentAtom),
|
|
},
|
|
}
|
|
: sourceAppId
|
|
? {
|
|
body: {
|
|
appInstanceId,
|
|
sourceAppId,
|
|
},
|
|
}
|
|
: skipToken
|
|
: skipToken,
|
|
enabled: canCheck,
|
|
retry: false,
|
|
})
|
|
})
|
|
|
|
export const isCheckingCreateReleaseContentAtom = atom((get) => {
|
|
const canCheck = canCheckReleaseContent(get)
|
|
const precheckReleaseQuery = get(precheckReleaseQueryAtom)
|
|
|
|
return canCheck && (precheckReleaseQuery.isLoading || precheckReleaseQuery.isFetching)
|
|
})
|
|
|
|
export const createReleaseMatchedReleaseAtom = atom((get) => {
|
|
return canCheckReleaseContent(get)
|
|
? get(precheckReleaseQueryAtom).data?.matchedRelease
|
|
: undefined
|
|
})
|
|
|
|
export const createReleaseContentCheckFailedAtom = atom((get) => {
|
|
return canCheckReleaseContent(get) && get(precheckReleaseQueryAtom).isError
|
|
})
|
|
|
|
export const createReleaseUnsupportedDslNodesAtom = atom((get): UnsupportedDslNode[] => {
|
|
return canCheckReleaseContent(get)
|
|
? (get(precheckReleaseQueryAtom).data?.unsupportedNodes ?? [])
|
|
: []
|
|
})
|
|
|
|
export const createReleaseContentReadyAtom = atom((get) => {
|
|
const canCheck = canCheckReleaseContent(get)
|
|
const precheckReleaseQuery = get(precheckReleaseQueryAtom)
|
|
|
|
return (
|
|
canCheck &&
|
|
precheckReleaseQuery.isSuccess &&
|
|
!get(isCheckingCreateReleaseContentAtom) &&
|
|
!get(createReleaseContentCheckFailedAtom) &&
|
|
Boolean(precheckReleaseQuery.data?.canCreate) &&
|
|
get(createReleaseUnsupportedDslNodesAtom).length === 0
|
|
)
|
|
})
|
|
|
|
// Actions
|
|
const resetCreateReleaseDslFileAtom = atom(null, (get, set) => {
|
|
set(createReleaseDslFileFieldAtom, undefined)
|
|
set(createReleaseDslFileReadVersionAtom, get(createReleaseDslFileReadVersionAtom) + 1)
|
|
})
|
|
|
|
const resetCreateReleaseSourceAppSearchAtom = atom(null, (_get, set) => {
|
|
set(createReleaseSourceAppSearchTextAtom, '')
|
|
})
|
|
|
|
export const openCreateReleaseDialogAtom = atom(null, (_get, set) => {
|
|
set(resetCreateReleaseDslFileAtom)
|
|
set(resetCreateReleaseSourceAppSearchAtom)
|
|
set(createReleaseDialogOpenAtom, true)
|
|
})
|
|
|
|
export const closeCreateReleaseDialogAtom = atom(null, (_get, set) => {
|
|
set(createReleaseDialogOpenAtom, false)
|
|
set(resetCreateReleaseDslFileAtom)
|
|
set(resetCreateReleaseSourceAppSearchAtom)
|
|
})
|
|
|
|
export const requestCloseCreateReleaseDialogAtom = atom(null, (get, set) => {
|
|
if (get(createReleaseFormIsSubmittingAtom)) return
|
|
|
|
set(closeCreateReleaseDialogAtom)
|
|
})
|
|
|
|
export const selectCreateReleaseSourceModeAtom = atom(
|
|
null,
|
|
(_get, set, releaseSourceMode: ReleaseSourceMode) => {
|
|
const effectiveReleaseSourceMode = deploymentReleaseSourceMode(releaseSourceMode)
|
|
set(createReleaseSourceModeFieldAtom, effectiveReleaseSourceMode)
|
|
|
|
if (effectiveReleaseSourceMode === 'sourceApp') {
|
|
set(resetCreateReleaseDslFileAtom)
|
|
return
|
|
}
|
|
|
|
set(createReleaseSourceAppFieldAtom, undefined)
|
|
},
|
|
)
|
|
|
|
export const updateCreateReleaseSourceAppAtom = atom(
|
|
null,
|
|
(_get, set, sourceApp: CreateReleaseFormValues['sourceApp']) => {
|
|
set(createReleaseSourceAppFieldAtom, sourceApp)
|
|
},
|
|
)
|
|
|
|
export const updateCreateReleaseDslFileAtom = atom(
|
|
null,
|
|
(get, set, dslFile: CreateReleaseFormValues['dslFile']) => {
|
|
set(createReleaseDslFileFieldAtom, dslFile)
|
|
set(createReleaseDslFileReadVersionAtom, get(createReleaseDslFileReadVersionAtom) + 1)
|
|
},
|
|
)
|
|
|
|
// Submission
|
|
const createReleaseMutationAtom = atomWithMutation(() =>
|
|
consoleQuery.enterprise.releaseService.createRelease.mutationOptions(),
|
|
)
|
|
|
|
export const isCreatingReleaseAtom = atom((get) => {
|
|
return get(createReleaseMutationAtom).isPending
|
|
})
|
|
|
|
export class CreateReleaseSubmissionBlockedError extends Error {
|
|
reason: 'unsupportedDslMode'
|
|
|
|
constructor(reason: 'unsupportedDslMode') {
|
|
super(reason)
|
|
this.reason = reason
|
|
this.name = 'CreateReleaseSubmissionBlockedError'
|
|
}
|
|
}
|
|
|
|
const createReleaseSubmissionAtom = atom(null, async (get, set, value: CreateReleaseFormValues) => {
|
|
const releaseSourceMode = effectiveCreateReleaseSourceMode(get)
|
|
const sourceAppId = selectedSourceAppId(get)
|
|
const submittedReleaseName = value.releaseName.trim()
|
|
|
|
if (get(isCheckingCreateReleaseContentAtom) || !submittedReleaseName) return undefined
|
|
|
|
if (get(createReleaseHasNameConflictAtom)) return undefined
|
|
|
|
if (!canCheckReleaseSourceContent(get) || !get(createReleaseContentReadyAtom)) return undefined
|
|
|
|
const appInstanceId = requiredAppInstanceId(get)
|
|
const commonCreateReleaseRequest = {
|
|
appInstanceId,
|
|
displayName: submittedReleaseName,
|
|
description: value.releaseDescription.trim() || undefined,
|
|
createAppInstance: false,
|
|
}
|
|
|
|
if (releaseSourceMode === 'dsl') {
|
|
if (!get(createReleaseIsWorkflowDslContentAtom))
|
|
throw new CreateReleaseSubmissionBlockedError('unsupportedDslMode')
|
|
|
|
return await get(createReleaseMutationAtom).mutateAsync({
|
|
body: {
|
|
...commonCreateReleaseRequest,
|
|
dsl: get(createReleaseEncodedDslContentAtom),
|
|
},
|
|
})
|
|
}
|
|
|
|
if (!sourceAppId) return undefined
|
|
|
|
return await get(createReleaseMutationAtom).mutateAsync({
|
|
body: {
|
|
...commonCreateReleaseRequest,
|
|
sourceAppId,
|
|
},
|
|
})
|
|
})
|
|
|
|
export const submitCreateReleaseFormAtom = atom(null, (get, set) => {
|
|
const form = get(createReleaseFormAtom)
|
|
let submitResponse: CreateReleaseResponse | undefined
|
|
|
|
return form.api
|
|
.handleSubmit({
|
|
createRelease: async (value) => {
|
|
const response = await set(createReleaseSubmissionAtom, value)
|
|
submitResponse = response
|
|
|
|
return response
|
|
},
|
|
} satisfies CreateReleaseSubmitMeta)
|
|
.then(() => submitResponse)
|
|
})
|
|
|
|
// Scoped atoms
|
|
export const createReleaseLocalAtoms = [
|
|
createReleaseDialogOpenAtom,
|
|
createReleaseDslFileReadVersionAtom,
|
|
createReleaseSourceAppSearchTextAtom,
|
|
] as const
|