import { useCallback } from 'react'
import { Field, Form, Formik } from 'formik'
import { inferQueryOutput, inferMutationInput, trpc } from '~/utils/trpc'
import IVInputField from '~/components/IVInputField'
import IVTextInput from '~/components/IVTextInput'
import IVTextArea from '~/components/IVTextArea'
import { slugToName } from '~/utils/text'
import IVButton from '~/components/IVButton'
import IconInfo from '~/icons/compiled/Info'
import IVCheckbox from '~/components/IVCheckbox'
import { useDialogState } from '~/components/IVDialog'
import ArchiveDialog from '~/components/ActionSettings/ArchiveDialog'
import IVAlert from '~/components/IVAlert'
import { useIsFeatureEnabled } from '~/utils/useIsFeatureEnabled'
function OverrideMetaTextField({
id,
label,
helpText,
errorMessage,
metaValue,
actionValue,
defaultValue = '',
placeholder,
disabled,
onChange,
multiline = false,
}: {
id: string
label: string
errorMessage?: React.ReactNode
helpText?: string
metaValue: string | null | undefined
actionValue: string | null | undefined
defaultValue?: string
placeholder?: string
disabled?: boolean
onChange: (value: string | null) => void
multiline?: boolean
}) {
const isOverriding = metaValue != null
const InputComponent = multiline ? IVTextArea : IVTextInput
return (
<>
) => {
if (disabled) return
onChange(e.target.value)
}}
readOnly={!!actionValue && !isOverriding}
disabled={disabled || (!!actionValue && !isOverriding)}
placeholder={placeholder}
/>
{!disabled && actionValue != null && (
{
onChange(isOverriding ? null : actionValue ?? defaultValue)
}}
/>
)}
>
)
}
function OverrideMetaToggleField({
id,
label,
helpText,
metaValue,
actionValue,
defaultValue,
disabled,
onChange,
}: {
id: string
label: string
helpText?: string
metaValue: boolean | null | undefined
actionValue: boolean | null | undefined
defaultValue: false
disabled?: boolean
onChange: (value: boolean | null) => void
}) {
const isOverriding = metaValue != null
return (
{
if (disabled) return
onChange(e.target.checked)
}}
disabled={disabled || !isOverriding}
/>
{!disabled && actionValue != null && (
{
onChange(isOverriding ? null : actionValue ?? defaultValue)
}}
/>
)}
)
}
function OverrideNotice({ label, buttonLabel, onClick }) {
return (
{label}
)
}
export default function ActionGeneralSettings({
action,
onSuccess,
onError,
refetch,
}: {
action: inferQueryOutput<'action.one'>
onSuccess: () => void
onError: () => void
refetch: () => void
}) {
const archiveDialog = useDialogState()
const updateMeta = trpc.useMutation('action.general.update')
const generalConfigEnabled = useIsFeatureEnabled(
'ACTION_METADATA_GENERAL_CONFIG'
)
const validateName = useCallback(
(name: string | undefined | null) => {
name = name?.trim()
if (action.name && !name) return
if (!name) {
return 'Please enter a name.'
}
},
[action]
)
const isArchived = action.metadata?.archivedAt
return (
{isArchived && (
This action has been archived.{` `}
{' '}
to restore it to your Actions list.
)}
{!generalConfigEnabled && (
Actions are configured in code. See{' '}
defining actions documentation
{' '}
for more information.
)}
['data']>
initialTouched={{
name: true,
}}
initialValues={{
name:
action.metadata?.name ??
(action.name ? undefined : slugToName(action.slug)),
backgroundable: action.metadata?.backgroundable,
description: action.metadata?.description,
}}
validateOnBlur={false}
validateOnChange={false}
validate={({ name }) => {
const nameValidation = validateName(name)
if (nameValidation) {
return {
name: nameValidation,
}
}
}}
onSubmit={async data => {
if (updateMeta.isLoading || !generalConfigEnabled) return
if (
action.schedules.length &&
(data.backgroundable === false ||
(!action.backgroundable && !data.backgroundable))
) {
if (
!window.confirm(
"Turning off 'Allow running in background' will remove this action's schedule. Are you sure you want to turn off this setting?"
)
) {
return
}
}
updateMeta.mutate(
{ actionId: action.id, data },
{ onSuccess, onError }
)
}}
>
{({ errors, touched, isValid, values, setFieldValue }) => (
)}
)
}