Skip to content

Commit

Permalink
feat: Display values.yaml file and allow new file on upgrade (#536)
Browse files Browse the repository at this point in the history
  • Loading branch information
dogmar authored Dec 6, 2023
1 parent b33a271 commit f612118
Show file tree
Hide file tree
Showing 11 changed files with 610 additions and 121 deletions.
4 changes: 2 additions & 2 deletions assets/src/components/cd/services/ServiceSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function ServiceSettings({
)
}

function ChartUpdate({ repo, state, updateState }) {
export function ChartUpdate({ repo, state, updateState }) {
const { data } = useHelmRepositoryQuery({
variables: {
name: repo?.name || '',
Expand Down Expand Up @@ -178,7 +178,7 @@ export function ModalForm({
gap: theme.spacing.medium,
}}
>
{!serviceDeployment.helm?.chart && (
{serviceDeployment.repository && (
<>
<ServiceGitRefField
value={state.gitRef}
Expand Down
225 changes: 225 additions & 0 deletions assets/src/components/cd/services/ServiceUpdateHelmValues.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import { Button } from '@pluralsh/design-system'

import { useTheme } from 'styled-components'
import {
FormEvent,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react'
import isEmpty from 'lodash/isEmpty'

import {
HelmConfigAttributes,
ServiceDeploymentDetailsFragment,
ServiceDeploymentsRowFragment,
ServiceUpdateAttributes,
useServiceDeploymentQuery,
useUpdateServiceDeploymentMutation,
} from 'generated/graphql'

import { isNonNullable } from 'utils/isNonNullable'

import { GqlError } from 'components/utils/Alert'
import { ModalMountTransition } from 'components/utils/ModalMountTransition'
import { useUpdateState } from 'components/hooks/useUpdateState'
import LoadingIndicator from 'components/utils/LoadingIndicator'

import ModalAlt from '../ModalAlt'

import { ServiceSettingsHelmValues } from './deployModal/DeployServiceSettingsHelmValues'

export function ServiceUpdateHelmValues({
serviceDeployment,
refetch,
open,
onClose,
}: {
serviceDeployment: ServiceDeploymentsRowFragment
refetch: Nullable<() => void>
open: boolean
onClose: Nullable<() => void>
}) {
return (
<ModalMountTransition open={open}>
<ModalForm
serviceDeployment={serviceDeployment}
refetch={refetch}
open={open}
onClose={onClose}
/>
</ModalMountTransition>
)
}

export function ModalForm({
serviceDeployment,
...props
}: {
serviceDeployment: ServiceDeploymentsRowFragment
open: boolean
onClose: Nullable<() => void>
refetch: Nullable<() => void>
}) {
const repo = serviceDeployment.helm?.repository
const { data } = useServiceDeploymentQuery({
variables: {
id: serviceDeployment.id || '',
},
skip: !repo?.name || !repo?.namespace,
})

if (!data?.serviceDeployment) {
return <LoadingIndicator />
}

return (
<ModalFormInner
serviceDeployment={data.serviceDeployment}
{...props}
/>
)
}

export function ModalFormInner({
serviceDeployment,
open,
onClose,
refetch,
}: {
serviceDeployment: ServiceDeploymentDetailsFragment
open: boolean
onClose: Nullable<() => void>
refetch: Nullable<() => void>
}) {
const theme = useTheme()
const repo = serviceDeployment.helm?.repository
const { data } = useServiceDeploymentQuery({
variables: {
id: serviceDeployment.id || '',
},
skip: !repo?.name || !repo?.namespace,
})

const filteredValuesFiles =
data?.serviceDeployment?.helm?.valuesFiles?.filter(isNonNullable)

const {
state,
update: updateState,
hasUpdates,
} = useUpdateState({
helmValues: data?.serviceDeployment?.helm?.values ?? '',
helmValuesFiles:
filteredValuesFiles && !isEmpty(filteredValuesFiles)
? filteredValuesFiles
: [''],
})
const [errors, setErrors] = useState(false)

const attributes = useMemo<Pick<ServiceUpdateAttributes, 'helm'>>(() => {
const helm: Pick<HelmConfigAttributes, 'values' | 'valuesFiles'> = {
values: state.helmValues || '',
valuesFiles: (state.helmValuesFiles || []).filter((value) => !!value),
}

return { helm }
}, [state])

const [updateService, { loading, error }] =
useUpdateServiceDeploymentMutation({
variables: {
id: serviceDeployment.id,
attributes,
},
onCompleted: () => {
refetch?.()
onClose?.()
},
})
const closeModal = useCallback(() => {
onClose?.()
}, [onClose])

const disabled = !hasUpdates && !errors
const onSubmit = useCallback(
(e: FormEvent) => {
e.preventDefault()
if (disabled) {
return
}
updateService()
},
[disabled, updateService]
)

const inputRef = useRef<HTMLInputElement>()

useEffect(() => {
inputRef.current?.focus?.()
}, [])

return (
<ModalAlt
header="Update Helm values"
open={open}
portal
onClose={closeModal}
asForm
formProps={{ onSubmit }}
actions={
<>
<Button
type="submit"
disabled={disabled}
loading={loading}
primary
>
Update
</Button>
<Button
type="button"
secondary
onClick={closeModal}
>
Cancel
</Button>
</>
}
>
<div
css={{
display: 'flex',
flexDirection: 'column',
gap: theme.spacing.medium,
}}
>
<ServiceSettingsHelmValues
helmValues={state.helmValues}
setHelmValues={(next) =>
updateState({
helmValues:
typeof next === 'function' ? next(state.helmValues) : next,
})
}
helmValuesFiles={state.helmValuesFiles}
setHelmValuesFiles={(next) =>
updateState({
helmValuesFiles:
typeof next === 'function' ? next(state.helmValuesFiles) : next,
})
}
setHelmValuesErrors={setErrors}
/>
</div>
{error && (
<GqlError
header="Problem updating Helm values"
error={error}
/>
)}
</ModalAlt>
)
}
19 changes: 19 additions & 0 deletions assets/src/components/cd/services/ServicesColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
GitHubLogoIcon,
GlobeIcon,
ListBoxItem,
ListIcon,
PeopleIcon,
Tooltip,
TrashCanIcon,
Expand Down Expand Up @@ -33,6 +34,7 @@ import { ServiceDeprecations } from './ServiceDeprecations'
import { CreateGlobalService } from './CreateGlobalService'
import { DeleteGlobalService } from './DeleteGlobalService'
import { ServiceSettings } from './ServiceSettings'
import { ServiceUpdateHelmValues } from './ServiceUpdateHelmValues'

const columnHelper = createColumnHelper<Edge<ServiceDeploymentsRowFragment>>()

Expand Down Expand Up @@ -216,6 +218,7 @@ enum MenuItemKey {
DeleteGlobal = 'deleteGlobal',
Permissions = 'permissions',
Settings = 'settings',
HelmValues = 'helmValues',
Delete = 'delete',
}

Expand Down Expand Up @@ -273,6 +276,14 @@ export const ColActions = columnHelper.accessor(({ node }) => node?.id, {
label="Permissions"
textValue="Permissions"
/>
{serviceDeployment.helm && (
<ListBoxItem
key={MenuItemKey.HelmValues}
leftContent={<ListIcon />}
label="Helm values"
textValue="Helm values"
/>
)}
<ListBoxItem
key={MenuItemKey.Settings}
leftContent={<GearTrainIcon />}
Expand Down Expand Up @@ -314,6 +325,14 @@ export const ColActions = columnHelper.accessor(({ node }) => node?.id, {
setMenuKey('')
}}
/>
<ServiceUpdateHelmValues
serviceDeployment={serviceDeployment}
open={menuKey === MenuItemKey.HelmValues}
onClose={() => {
setMenuKey('')
}}
refetch={refetch}
/>
<ServiceSettings
serviceDeployment={serviceDeployment}
open={menuKey === MenuItemKey.Settings}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
Secret,
} from './DeployServiceSettingsSecrets'
import DeployServiceSettingsHelm from './DeployServiceSettingsHelm'
import { DeployServiceSettingsHelmValues } from './DeployServiceSettingsHelmValues'
import { ServiceSettingsHelmValues } from './DeployServiceSettingsHelmValues'

enum FormState {
Initial = 'initial',
Expand Down Expand Up @@ -430,7 +430,7 @@ export function DeployServiceModal({
</div>
</RepoKindSelector>
) : formState === FormState.HelmValues ? (
<DeployServiceSettingsHelmValues
<ServiceSettingsHelmValues
helmValues={helmValues}
setHelmValues={setHelmValues}
helmValuesFiles={helmValuesFiles}
Expand Down
Loading

0 comments on commit f612118

Please sign in to comment.