'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) })