'use client' import type { Getter } from 'jotai/vanilla' import { keepPreviousData, skipToken } from '@tanstack/react-query' import { atom } from 'jotai' import { atomWithInfiniteQuery, atomWithQuery } from 'jotai-tanstack-query' import { selectAtom } from 'jotai/utils' import { encodeDslContent } from '@/features/deployments/shared/domain/dsl' import { consoleQuery } from '@/service/client' import { effectiveMethodAtom, instanceNameAtom, submissionUnsupportedDslNodesAtom, } from './primitives' import { dslContentAtom, effectiveSelectedAppAtom, sourceReady } from './source' import { DEPLOYMENT_PAGE_SIZE, getNextPageParamFromPagination } from './utils' export const existingInstanceNamesQueryAtom = atomWithInfiniteQuery(() => consoleQuery.enterprise.appInstanceService.listAppInstances.infiniteOptions({ input: (pageParam) => ({ query: { pageNumber: Number(pageParam), resultsPerPage: DEPLOYMENT_PAGE_SIZE, }, }), getNextPageParam: (lastPage) => getNextPageParamFromPagination(lastPage.pagination), initialPageParam: 1, placeholderData: keepPreviousData, }), ) export const instanceNameConflictQueryAtom = atomWithQuery((get) => { const submittedInstanceName = get(instanceNameAtom).trim() return consoleQuery.enterprise.appInstanceService.listAppInstances.queryOptions({ input: { query: { pageNumber: 1, resultsPerPage: 1, displayName: submittedInstanceName, }, }, enabled: Boolean(submittedInstanceName), }) }) export const deployableEnvironmentsQueryAtom = atomWithQuery((get) => { return consoleQuery.enterprise.environmentService.listEnvironments.queryOptions({ input: { query: { // The guide offers every deployable environment at once; environment // count is capped well below the 100-per-page maximum. pageNumber: 1, resultsPerPage: 100, }, }, enabled: sourceReady(get), }) }) export const deployableEnvironmentsDataAtom = selectAtom( deployableEnvironmentsQueryAtom, (query) => query.data, ) export const deployableEnvironmentsIsErrorAtom = selectAtom( deployableEnvironmentsQueryAtom, (query) => query.isError, ) export const deployableEnvironmentsIsLoadingAtom = selectAtom( deployableEnvironmentsQueryAtom, (query) => query.isLoading, ) export const deployableEnvironmentsIsFetchingAtom = selectAtom( deployableEnvironmentsQueryAtom, (query) => query.isFetching, ) const precheckReleaseQueryAtom = atomWithQuery((get) => { const method = get(effectiveMethodAtom) const effectiveSelectedApp = get(effectiveSelectedAppAtom) const dslContent = get(dslContentAtom) const encodedDslContent = dslContent.trim() ? encodeDslContent(dslContent) : undefined const enabled = sourceReady(get) // PrecheckRelease takes exactly one source arm (dsl | sourceAppId). const precheckReleaseQueryOptions = method === 'importDsl' ? consoleQuery.enterprise.releaseService.precheckRelease.queryOptions({ input: encodedDslContent ? { body: { dsl: encodedDslContent, }, } : skipToken, enabled, retry: false, }) : consoleQuery.enterprise.releaseService.precheckRelease.queryOptions({ input: effectiveSelectedApp?.id ? { body: { sourceAppId: effectiveSelectedApp.id, }, } : skipToken, enabled: enabled && Boolean(effectiveSelectedApp?.id), retry: false, }) return precheckReleaseQueryOptions }) const precheckReleaseDataAtom = selectAtom(precheckReleaseQueryAtom, (query) => query.data) const precheckReleaseIsSuccessAtom = selectAtom( precheckReleaseQueryAtom, (query) => query.isSuccess, ) const precheckReleaseIsLoadingAtom = selectAtom( precheckReleaseQueryAtom, (query) => query.isLoading, ) const precheckReleaseIsFetchingAtom = selectAtom( precheckReleaseQueryAtom, (query) => query.isFetching, ) function precheckReleaseReady(get: Getter) { const precheckRelease = get(precheckReleaseDataAtom) return ( sourceReady(get) && get(precheckReleaseIsSuccessAtom) && Boolean(precheckRelease?.canCreate) && (precheckRelease?.unsupportedNodes.length ?? 0) === 0 && get(submissionUnsupportedDslNodesAtom).length === 0 ) } const deploymentOptionsQueryAtom = atomWithQuery((get) => { const method = get(effectiveMethodAtom) const effectiveSelectedApp = get(effectiveSelectedAppAtom) const dslContent = get(dslContentAtom) const encodedDslContent = dslContent.trim() ? encodeDslContent(dslContent) : undefined const enabled = precheckReleaseReady(get) // ComputeDeploymentOptions takes exactly one source arm (dsl | sourceAppId | releaseId). const deploymentOptionsQueryOptions = method === 'importDsl' ? consoleQuery.enterprise.releaseService.computeDeploymentOptions.queryOptions({ input: encodedDslContent ? { body: { dsl: encodedDslContent, }, } : skipToken, enabled, retry: false, }) : consoleQuery.enterprise.releaseService.computeDeploymentOptions.queryOptions({ input: effectiveSelectedApp?.id ? { body: { sourceAppId: effectiveSelectedApp.id, }, } : skipToken, enabled: enabled && Boolean(effectiveSelectedApp?.id), retry: false, }) return deploymentOptionsQueryOptions }) export const deploymentOptionsDataAtom = selectAtom( deploymentOptionsQueryAtom, (query) => query.data, ) export const deploymentOptionsIsErrorAtom = selectAtom( deploymentOptionsQueryAtom, (query) => query.isError, ) export const deploymentOptionsIsLoadingAtom = selectAtom( deploymentOptionsQueryAtom, (query) => query.isLoading, ) export const deploymentOptionsIsFetchingAtom = selectAtom( deploymentOptionsQueryAtom, (query) => query.isFetching, ) const deploymentOptionsIsSuccessAtom = selectAtom( deploymentOptionsQueryAtom, (query) => query.isSuccess, ) export const unsupportedDslNodesAtom = atom((get) => { const submissionUnsupportedDslNodes = get(submissionUnsupportedDslNodesAtom) if (submissionUnsupportedDslNodes.length > 0) return submissionUnsupportedDslNodes if (!sourceReady(get)) return [] return get(precheckReleaseDataAtom)?.unsupportedNodes ?? [] }) const precheckReleaseReadyAtom = atom((get) => { return precheckReleaseReady(get) }) export const deploymentOptionsReadyAtom = atom((get) => { return sourceReady(get) && get(precheckReleaseReadyAtom) && get(deploymentOptionsIsSuccessAtom) }) export const deploymentOptionsContentCheckedAtom = atom((get) => { const isLoadingOptions = get(deploymentOptionsIsLoadingAtom) || (get(deploymentOptionsIsFetchingAtom) && !get(deploymentOptionsDataAtom)) const isCheckingReleaseContent = get(precheckReleaseIsLoadingAtom) || (get(precheckReleaseIsFetchingAtom) && !get(precheckReleaseDataAtom)) if (!sourceReady(get) || isCheckingReleaseContent || isLoadingOptions) return false return get(precheckReleaseReadyAtom) && get(deploymentOptionsIsSuccessAtom) })