fix: disable deployment DSL imports (#37745)

This commit is contained in:
Stephen Zhou 2026-06-22 16:14:08 +08:00 committed by GitHub
parent 084f122814
commit 25b90229bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 301 additions and 64 deletions

View File

@ -0,0 +1,73 @@
import type { Getter } from 'jotai'
import { atom, createStore } from 'jotai'
import { describe, expect, it, vi } from 'vitest'
vi.mock('jotai-tanstack-query', () => ({
atomWithInfiniteQuery: (createOptions: (get: Getter) => Record<string, unknown>) => atom((get) => {
const options = createOptions(get)
return {
...options,
data: { pages: [{ data: [] }] },
hasNextPage: false,
isFetching: false,
isFetchingNextPage: false,
isLoading: false,
isPlaceholderData: false,
fetchNextPage: vi.fn(),
}
}),
atomWithMutation: () => atom(() => ({
isPending: false,
mutateAsync: vi.fn(),
})),
atomWithQuery: (createOptions: (get: Getter) => Record<string, unknown>) => atom(get => ({
...createOptions(get),
data: undefined,
isError: false,
isFetching: false,
isLoading: false,
isSuccess: false,
})),
}))
vi.mock('@/service/client', () => ({
consoleQuery: {
apps: {
list: {
infiniteOptions: (options: Record<string, unknown>) => ({
...options,
queryKey: ['apps', 'list'],
}),
},
},
},
}))
async function loadState() {
return await import('../index')
}
describe('create deployment guide state', () => {
it('should keep the guide on source app mode when DSL import is disabled', async () => {
const state = await loadState()
const store = createStore()
store.set(state.selectMethodAtom, 'importDsl')
expect(store.get(state.methodAtom)).toBe('bindApp')
expect(store.get(state.effectiveMethodAtom)).toBe('bindApp')
})
it('should keep source app loading enabled if stale state points to DSL import', async () => {
const state = await loadState()
const store = createStore()
store.set(state.methodAtom, 'importDsl')
const sourceAppsQuery = store.get(state.sourceAppsQueryAtom) as unknown as { enabled?: boolean }
expect(store.get(state.effectiveMethodAtom)).toBe('bindApp')
expect(sourceAppsQuery.enabled).toBe(true)
})
})

View File

@ -27,6 +27,7 @@ import {
isWorkflowDsl,
} from '@/features/deployments/shared/domain/dsl'
import { unsupportedDslNodeError } from '@/features/deployments/shared/domain/error'
import { isDeploymentDslImportEnabled } from '@/features/deployments/shared/domain/feature-flags'
import { createDeploymentIdempotencyKey } from '@/features/deployments/shared/domain/idempotency'
import {
DEPLOYMENT_PAGE_SIZE,
@ -41,6 +42,12 @@ export type GuideMethod = 'bindApp' | 'importDsl'
export type GuideStep = 'source' | 'release' | 'target'
export type WorkflowSourceApp = App & { mode: Extract<AppModeEnum, 'workflow'> }
function deploymentGuideMethod(method: GuideMethod): GuideMethod {
return method === 'importDsl' && !isDeploymentDslImportEnabled
? 'bindApp'
: method
}
const RANDOM_SUFFIX_ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
const RANDOM_SUFFIX_LENGTH = 4
const RANDOM_SUFFIX_FALLBACK_LENGTH = 6
@ -124,6 +131,7 @@ function envVarInput(slot: EnvVarBindingSlot, selection: EnvVarValueSelection |
// Workflow primitives
export const stepAtom = atom<GuideStep>('source')
export const methodAtom = atom<GuideMethod>('bindApp')
export const effectiveMethodAtom = atom(get => deploymentGuideMethod(get(methodAtom)))
// Source primitives
export const sourceSearchTextAtom = atom('')
@ -145,7 +153,7 @@ export const dslDefaultAppNameAtom = atom((get) => {
export const dslUnsupportedModeAtom = atom((get) => {
const dslContent = get(dslContentAtom)
return get(methodAtom) === 'importDsl'
return get(effectiveMethodAtom) === 'importDsl'
&& Boolean(dslContent.trim())
&& !get(isReadingDslAtom)
&& !get(dslReadErrorAtom)
@ -199,7 +207,7 @@ export const sourceAppsQueryAtom = atomWithInfiniteQuery((get) => {
initialPageParam: 1,
placeholderData: keepPreviousData,
}),
enabled: get(methodAtom) === 'bindApp',
enabled: get(effectiveMethodAtom) === 'bindApp',
}
})
@ -218,7 +226,7 @@ export const effectiveSelectedAppAtom = atom((get) => {
})
function sourceReady(get: Getter) {
const method = get(methodAtom)
const method = get(effectiveMethodAtom)
return method === 'importDsl'
? get(importDslReadyAtom)
@ -269,7 +277,7 @@ export const deployableEnvironmentsQueryAtom = atomWithQuery((get) => {
})
const precheckReleaseQueryAtom = atomWithQuery((get) => {
const method = get(methodAtom)
const method = get(effectiveMethodAtom)
const effectiveSelectedApp = get(effectiveSelectedAppAtom)
const dslContent = get(dslContentAtom)
const enabled = sourceReady(get)
@ -310,7 +318,7 @@ function precheckReleaseReady(get: Getter) {
}
export const deploymentOptionsQueryAtom = atomWithQuery((get) => {
const method = get(methodAtom)
const method = get(effectiveMethodAtom)
const effectiveSelectedApp = get(effectiveSelectedAppAtom)
const dslContent = get(dslContentAtom)
const enabled = precheckReleaseReady(get)
@ -378,7 +386,7 @@ const deploymentOptionsContentCheckedAtom = atom((get) => {
})
export const sourceCanGoNextAtom = atom((get) => {
const method = get(methodAtom)
const method = get(effectiveMethodAtom)
const effectiveSelectedApp = get(effectiveSelectedAppAtom)
const importDslReady = method === 'importDsl' && get(importDslReadyAtom)
const bindAppReady = method === 'bindApp' && Boolean(effectiveSelectedApp?.id)
@ -416,7 +424,7 @@ export const continueFromSourceAtom = atom(null, (get, set, {
if (!get(sourceCanGoNextAtom))
return
const method = get(methodAtom)
const method = get(effectiveMethodAtom)
const effectiveSelectedApp = get(effectiveSelectedAppAtom)
if (method === 'bindApp' && effectiveSelectedApp)
set(selectSourceAppAtom, effectiveSelectedApp)
@ -606,7 +614,7 @@ const requiredBindingsReadyAtom = atom((get) => {
})
export const deploymentTargetEnvVarSlotsAtom = atom((get) => {
const method = get(methodAtom)
const method = get(effectiveMethodAtom)
const deploymentOptionsQuery = get(deploymentOptionsQueryAtom)
const slots = sourceReady(get) ? deploymentOptionsQuery.data?.options?.envVarSlots : undefined
const dslContent = get(dslContentAtom)
@ -702,7 +710,7 @@ export const setEnvVarAtom = atom(null, (get, set, key: string, value: EnvVarVal
// Workflow actions
export const selectMethodAtom = atom(null, (_get, set, method: GuideMethod) => {
set(methodAtom, method)
set(methodAtom, deploymentGuideMethod(method))
set(selectedEnvironmentIdAtom, '')
set(manualBindingSelectionsAtom, {})
set(envVarValuesAtom, {})
@ -738,7 +746,7 @@ export const createDeploymentGuideSubmissionAtom = atom(null, async (get, set, {
}: {
deployToEnvironment: boolean
}) => {
const method = get(methodAtom)
const method = get(effectiveMethodAtom)
const dslContent = get(dslContentAtom)
const submittedInstanceName = get(instanceNameAtom).trim()
const submittedReleaseName = get(releaseNameAtom).trim()

View File

@ -0,0 +1,49 @@
import { render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { SourceStepContent } from '../source-step'
vi.mock('@/features/deployments/create-guide/state', async () => {
const { atom } = await import('jotai')
const methodAtom = atom<'bindApp' | 'importDsl'>('bindApp')
const emptyActionAtom = atom(null, () => undefined)
return {
continueFromSourceAtom: emptyActionAtom,
dslFileAtom: atom<File | undefined>(undefined),
dslReadErrorAtom: atom(false),
dslUnsupportedModeAtom: atom(false),
effectiveMethodAtom: atom(get => get(methodAtom)),
effectiveSelectedAppAtom: atom(undefined),
isReadingDslAtom: atom(false),
methodAtom,
selectDslFileAtom: emptyActionAtom,
selectMethodAtom: atom(null, (_get, set, value: 'bindApp' | 'importDsl') => {
set(methodAtom, value)
}),
selectSourceAppAtom: emptyActionAtom,
setSourceSearchTextAtom: emptyActionAtom,
sourceAppsQueryAtom: atom({
data: { pages: [{ data: [] }] },
hasNextPage: false,
isFetching: false,
isFetchingNextPage: false,
isLoading: false,
isPlaceholderData: false,
fetchNextPage: vi.fn(),
}),
sourceCanGoNextAtom: atom(false),
sourceSearchTextAtom: atom(''),
unsupportedDslNodesAtom: atom([]),
}
})
describe('SourceStepContent', () => {
it('should hide the import DSL option when deployment DSL import is disabled', () => {
render(<SourceStepContent />)
expect(screen.getByText(/createGuide\.methods\.bindApp\.title/)).toBeInTheDocument()
expect(screen.queryByText(/createGuide\.methods\.importDsl\.title/)).not.toBeInTheDocument()
expect(screen.queryByText(/createGuide\.methods\.importDsl\.description/)).not.toBeInTheDocument()
expect(screen.getByRole('textbox', { name: /createGuide\.source\.sourceApp/ })).toBeInTheDocument()
})
})

View File

@ -7,10 +7,10 @@ import { useTranslation } from 'react-i18next'
import {
continueFromReleaseAtom,
dslDefaultAppNameAtom,
effectiveMethodAtom,
hasInstanceNameConflictAtom,
instanceDescriptionAtom,
instanceNameAtom,
methodAtom,
releaseCanGoNextAtom,
releaseDescriptionAtom,
releaseNameAtom,
@ -74,7 +74,7 @@ function InstanceNameField() {
const { t } = useTranslation('deployments')
const instanceName = useAtomValue(instanceNameAtom)
const setInstanceName = useSetAtom(setInstanceNameAtom)
const method = useAtomValue(methodAtom)
const method = useAtomValue(effectiveMethodAtom)
const selectedApp = useAtomValue(selectedAppAtom)
const dslDefaultAppName = useAtomValue(dslDefaultAppNameAtom)
const instanceNamePlaceholder = method === 'importDsl'

View File

@ -19,9 +19,9 @@ import {
dslFileAtom,
dslReadErrorAtom,
dslUnsupportedModeAtom,
effectiveMethodAtom,
effectiveSelectedAppAtom,
isReadingDslAtom,
methodAtom,
selectDslFileAtom,
selectMethodAtom,
selectSourceAppAtom,
@ -31,12 +31,13 @@ import {
sourceSearchTextAtom,
unsupportedDslNodesAtom,
} from '@/features/deployments/create-guide/state'
import { isDeploymentDslImportEnabled } from '@/features/deployments/shared/domain/feature-flags'
import { StepShell } from './layout'
const sourceAppSkeletonKeys = ['first-source-app', 'second-source-app', 'third-source-app']
export function SourceStepContent() {
const method = useAtomValue(methodAtom)
const method = useAtomValue(effectiveMethodAtom)
const unsupportedDslNodes = useAtomValue(unsupportedDslNodesAtom)
return (
@ -55,7 +56,7 @@ export function SourceStepContent() {
function SourceMethodSection() {
const { t } = useTranslation('deployments')
const method = useAtomValue(methodAtom)
const method = useAtomValue(effectiveMethodAtom)
const selectMethod = useSetAtom(selectMethodAtom)
return (
@ -76,12 +77,14 @@ function SourceMethodSection() {
title={t('createGuide.methods.bindApp.title')}
description={t('createGuide.methods.bindApp.description')}
/>
<SourceMethodCard
value="importDsl"
icon="i-ri-file-code-line"
title={t('createGuide.methods.importDsl.title')}
description={t('createGuide.methods.importDsl.description')}
/>
{isDeploymentDslImportEnabled && (
<SourceMethodCard
value="importDsl"
icon="i-ri-file-code-line"
title={t('createGuide.methods.importDsl.title')}
description={t('createGuide.methods.importDsl.description')}
/>
)}
</RadioGroup>
</StepShell>
)

View File

@ -0,0 +1,34 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen } from '@testing-library/react'
import { describe, expect, it } from 'vitest'
import { SourceAppPicker } from '../source-app-picker'
function renderSourceAppPicker(disabled: boolean) {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
})
return render(
<QueryClientProvider client={queryClient}>
<SourceAppPicker
value={{ id: 'app-1', name: 'Workflow 1' }}
onChange={() => undefined}
ariaLabel="Source app"
disabled={disabled}
/>
</QueryClientProvider>,
)
}
describe('SourceAppPicker', () => {
it('should disable the switch control when disabled', () => {
renderSourceAppPicker(true)
expect(screen.getByText('Workflow 1')).toBeInTheDocument()
expect(screen.getByRole('combobox', { name: 'Source app' })).toBeDisabled()
})
})

View File

@ -0,0 +1,36 @@
import type { CreateReleaseSourceSelection } from '../use-release-content-check'
import { describe, expect, it } from 'vitest'
import { canCheckReleaseSourceContent } from '../use-release-content-check'
function releaseSource(overrides: Partial<CreateReleaseSourceSelection> = {}): CreateReleaseSourceSelection {
return {
dslContent: '',
dslReadError: false,
encodedDslContent: '',
hasDslContent: false,
hasUnsupportedDslMode: false,
isReadingDsl: false,
isWorkflowDslContent: false,
releaseSourceMode: 'sourceApp',
selectedSourceAppId: undefined,
...overrides,
}
}
describe('canCheckReleaseSourceContent', () => {
it('should allow source app releases when a source app is selected', () => {
expect(canCheckReleaseSourceContent(releaseSource({
selectedSourceAppId: 'app-1',
}))).toBe(true)
})
it('should block DSL release content checks when deployment DSL import is disabled', () => {
expect(canCheckReleaseSourceContent(releaseSource({
dslContent: 'app:\n mode: workflow',
encodedDslContent: 'encoded-dsl',
hasDslContent: true,
isWorkflowDslContent: true,
releaseSourceMode: 'dsl',
}))).toBe(false)
})
})

View File

@ -8,6 +8,7 @@ import { ScopeProvider } from 'jotai-scope'
import { useEffect, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { consoleQuery } from '@/service/client'
import { isDeploymentDslImportEnabled } from '../../shared/domain/feature-flags'
import {
closeCreateReleaseDialogAtom,
createReleaseDialogOpenAtom,
@ -87,13 +88,19 @@ function CreateReleaseDefaultSourceApp({ formValues }: {
const defaultSourceApp = latestSourceAppId
? workflowSourceAppPickerValue(defaultSourceAppQuery.data, latestSourceAppId)
: undefined
const sourceAppLocked = !isDeploymentDslImportEnabled
const releaseSourceMode = formValues.releaseSourceMode === 'dsl' && !isDeploymentDslImportEnabled
? 'sourceApp'
: formValues.releaseSourceMode
useEffect(() => {
if (!isDialogOpen || formValues.releaseSourceMode !== 'sourceApp' || formValues.sourceApp || !defaultSourceApp)
if (!isDialogOpen || releaseSourceMode !== 'sourceApp' || !defaultSourceApp)
return
if (formValues.sourceApp && (!sourceAppLocked || formValues.sourceApp.id === defaultSourceApp.id))
return
form.setFieldValue('sourceApp', defaultSourceApp)
}, [defaultSourceApp, form, formValues.releaseSourceMode, formValues.sourceApp, isDialogOpen])
}, [defaultSourceApp, form, formValues.sourceApp, isDialogOpen, releaseSourceMode, sourceAppLocked])
return null
}

View File

@ -31,16 +31,20 @@ function sourceAppSearchText(app: App) {
return `${app.name} ${app.id}`.toLowerCase()
}
function SourceAppTrigger({ open, app }: {
function SourceAppTrigger({ open, app, disabled }: {
open: boolean
app?: SourceAppPickerValue
disabled: boolean
}) {
const { t } = useTranslation('deployments')
return (
<span
className={cn(
'group flex h-10 cursor-pointer items-center gap-2 rounded-lg border border-transparent bg-components-input-bg-normal px-3 text-left hover:border-components-input-border-hover hover:bg-components-input-bg-hover',
'group flex h-10 items-center gap-2 rounded-lg border border-transparent bg-components-input-bg-normal px-3 text-left',
disabled
? 'cursor-not-allowed text-components-input-text-disabled'
: 'cursor-pointer hover:border-components-input-border-hover hover:bg-components-input-bg-hover',
open && 'border-components-input-border-active bg-components-input-bg-active shadow-xs',
app && 'pl-2',
)}
@ -70,6 +74,7 @@ function SourceAppTrigger({ open, app }: {
<span
className={cn(
'i-ri-arrow-down-s-line size-4 shrink-0 text-text-quaternary group-hover:text-text-secondary',
disabled && 'opacity-50 group-hover:text-text-quaternary',
open && 'text-text-secondary',
)}
aria-hidden="true"
@ -123,10 +128,11 @@ function SourceAppPickerSkeleton() {
)
}
export function SourceAppPicker({ value, onChange, ariaLabel }: {
export function SourceAppPicker({ value, onChange, ariaLabel, disabled = false }: {
value?: SourceAppPickerValue
onChange: (app: App) => void
ariaLabel?: string
disabled?: boolean
}) {
const { t } = useTranslation('deployments')
const [isShow, setIsShow] = useState(false)
@ -152,6 +158,7 @@ export function SourceAppPicker({ value, onChange, ariaLabel }: {
initialPageParam: 1,
placeholderData: keepPreviousData,
}),
enabled: !disabled,
})
const apps = data?.pages.flatMap(page => page.data).filter(isWorkflowApp) ?? []
@ -159,11 +166,18 @@ export function SourceAppPicker({ value, onChange, ariaLabel }: {
return (
<Combobox<App>
items={apps}
open={isShow}
open={!disabled && isShow}
inputValue={searchText}
onOpenChange={setIsShow}
onInputValueChange={setSearchText}
onOpenChange={(open) => {
setIsShow(disabled ? false : open)
}}
onInputValueChange={(value) => {
if (!disabled)
setSearchText(value)
}}
onValueChange={(app) => {
if (disabled)
return
if (!app)
return
onChange(app)
@ -182,14 +196,14 @@ export function SourceAppPicker({ value, onChange, ariaLabel }: {
return app.id
}}
filter={(app, query) => sourceAppSearchText(app).includes(query.toLowerCase())}
disabled={false}
disabled={disabled}
>
<ComboboxTrigger
aria-label={ariaLabel ?? t('createModal.sourceApp')}
icon={false}
className="block h-auto w-full border-0 bg-transparent p-0 text-left hover:bg-transparent focus-visible:bg-transparent focus-visible:ring-0 data-open:bg-transparent"
>
<SourceAppTrigger open={isShow} app={value} />
<SourceAppTrigger open={!disabled && isShow} app={value} disabled={disabled} />
</ComboboxTrigger>
<ComboboxContent
placement="bottom-start"

View File

@ -5,6 +5,7 @@ import { SegmentedControl, SegmentedControlItem } from '@langgenius/dify-ui/segm
import { useAtomValue, useSetAtom } from 'jotai'
import { useTranslation } from 'react-i18next'
import Uploader from '@/app/components/app/create-from-dsl-modal/uploader'
import { isDeploymentDslImportEnabled } from '../../shared/domain/feature-flags'
import {
clearCreateReleaseSubmissionErrorAtom,
createReleaseDslStateAtom,
@ -32,39 +33,41 @@ export function ReleaseSourceSection() {
<label id="release-source-mode-label" className="system-xs-medium-uppercase text-text-tertiary">
{t('versions.releaseSourceLabel')}
</label>
<SegmentedControl<ReleaseSourceMode>
aria-labelledby="release-source-mode-label"
value={[modeField.state.value]}
onValueChange={(value) => {
const nextMode = selectedReleaseSourceMode(value)
if (!nextMode || nextMode === modeField.state.value)
return
{isDeploymentDslImportEnabled && (
<SegmentedControl<ReleaseSourceMode>
aria-labelledby="release-source-mode-label"
value={[modeField.state.value]}
onValueChange={(value) => {
const nextMode = selectedReleaseSourceMode(value)
if (!nextMode || nextMode === modeField.state.value)
return
clearSubmissionError()
modeField.handleChange(nextMode)
if (nextMode === 'sourceApp') {
form.setFieldValue('dslFile', undefined)
resetDslFile()
}
else {
form.setFieldValue('sourceApp', undefined)
}
}}
className="shrink-0"
>
<SegmentedControlItem value="sourceApp" className="gap-1.5">
<span className="i-ri-apps-2-line size-4 shrink-0" aria-hidden="true" />
<span>{t('versions.sourceAppOption')}</span>
</SegmentedControlItem>
<SegmentedControlItem value="dsl" className="gap-1.5">
<span className="i-ri-upload-cloud-2-line size-4 shrink-0" aria-hidden="true" />
<span>{t('versions.manualDslOption')}</span>
</SegmentedControlItem>
</SegmentedControl>
clearSubmissionError()
modeField.handleChange(nextMode)
if (nextMode === 'sourceApp') {
form.setFieldValue('dslFile', undefined)
resetDslFile()
}
else {
form.setFieldValue('sourceApp', undefined)
}
}}
className="shrink-0"
>
<SegmentedControlItem value="sourceApp" className="gap-1.5">
<span className="i-ri-apps-2-line size-4 shrink-0" aria-hidden="true" />
<span>{t('versions.sourceAppOption')}</span>
</SegmentedControlItem>
<SegmentedControlItem value="dsl" className="gap-1.5">
<span className="i-ri-upload-cloud-2-line size-4 shrink-0" aria-hidden="true" />
<span>{t('versions.manualDslOption')}</span>
</SegmentedControlItem>
</SegmentedControl>
)}
</div>
<div className="min-h-12">
{modeField.state.value === 'sourceApp'
{modeField.state.value === 'sourceApp' || !isDeploymentDslImportEnabled
? <SourceAppField />
: <DslFileField />}
</div>
@ -78,6 +81,7 @@ function SourceAppField() {
const { t } = useTranslation('deployments')
const form = useCreateReleaseFormApi()
const clearSubmissionError = useSetAtom(clearCreateReleaseSubmissionErrorAtom)
const sourceAppLocked = !isDeploymentDslImportEnabled
return (
<form.Field name="sourceApp">
@ -90,6 +94,7 @@ function SourceAppField() {
clearSubmissionError()
}}
ariaLabel={t('versions.sourceAppOption')}
disabled={sourceAppLocked}
/>
</div>
)}

View File

@ -65,7 +65,7 @@ export function useCreateReleaseSubmission(formValues: CreateReleaseFormValues)
if (!canCheckReleaseSourceContent(sourceSelection) || !releaseContent.releaseContentReady)
return
if (value.releaseSourceMode === 'dsl') {
if (sourceSelection.releaseSourceMode === 'dsl') {
if (!sourceSelection.isWorkflowDslContent) {
toast.error(t('versions.dslUnsupportedMode'))
return

View File

@ -5,6 +5,7 @@ import type { CreateReleaseFormValues, ReleaseSourceMode } from '../state/types'
import { skipToken, useQuery } from '@tanstack/react-query'
import { useAtomValue } from 'jotai'
import { consoleQuery } from '@/service/client'
import { isDeploymentDslImportEnabled } from '../../shared/domain/feature-flags'
import {
createReleaseDialogOpenAtom,
createReleaseDslStateAtom,
@ -21,17 +22,20 @@ function createReleaseSourceSelection(
formValues: CreateReleaseFormValues,
dslState: CreateReleaseDslState,
): CreateReleaseSourceSelection {
const hasUnsupportedDslMode = formValues.releaseSourceMode === 'dsl'
const releaseSourceMode = formValues.releaseSourceMode === 'dsl' && !isDeploymentDslImportEnabled
? 'sourceApp'
: formValues.releaseSourceMode
const hasUnsupportedDslMode = releaseSourceMode === 'dsl'
&& dslState.hasDslContent
&& !dslState.isReadingDsl
&& !dslState.dslReadError
&& !dslState.isWorkflowDslContent
const selectedSourceAppId = formValues.releaseSourceMode === 'sourceApp' ? formValues.sourceApp?.id : undefined
const selectedSourceAppId = releaseSourceMode === 'sourceApp' ? formValues.sourceApp?.id : undefined
return {
...dslState,
hasUnsupportedDslMode,
releaseSourceMode: formValues.releaseSourceMode,
releaseSourceMode,
selectedSourceAppId,
}
}
@ -39,6 +43,8 @@ function createReleaseSourceSelection(
export function canCheckReleaseSourceContent(releaseSource: CreateReleaseSourceSelection) {
if (releaseSource.releaseSourceMode === 'sourceApp')
return Boolean(releaseSource.selectedSourceAppId)
if (!isDeploymentDslImportEnabled)
return false
return Boolean(
releaseSource.hasDslContent

View File

@ -0,0 +1,2 @@
// Temporary kill switch for deployment DSL import flows. Flip to true to restore them.
export const isDeploymentDslImportEnabled = false