diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/terraform-variables.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/terraform-variables.tsx index 99b85e0ec34..359bb183890 100644 --- a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/terraform-variables.tsx +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/terraform-variables.tsx @@ -1,4 +1,14 @@ -import { createFileRoute } from '@tanstack/react-router' +import { createFileRoute, useParams } from '@tanstack/react-router' +import { Suspense } from 'react' +import { FormProvider, useForm, useFormContext } from 'react-hook-form' +import { match } from 'ts-pattern' +import { TerraformVariablesTable } from '@qovery/domains/service-settings/feature' +import { TerraformVariablesProvider, useTerraformVariablesContext } from '@qovery/domains/service-terraform/feature' +import { type Terraform } from '@qovery/domains/services/data-access' +import { type TerraformGeneralData, useEditService, useService } from '@qovery/domains/services/feature' +import { SettingsHeading } from '@qovery/shared/console-shared' +import { Button, LoaderSpinner, Section } from '@qovery/shared/ui' +import { buildEditServicePayload } from '@qovery/shared/util-services' export const Route = createFileRoute( '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/terraform-variables' @@ -6,6 +16,97 @@ export const Route = createFileRoute( component: RouteComponent, }) +const TerraformVariablesLoader = () => ( +
+ +
+) + +const TerraformVariablesSettingsForm = ({ service }: { service: Terraform }) => { + const { organizationId = '', projectId = '', environmentId = '' } = Route.useParams() + const { handleSubmit } = useFormContext() + const { serializeForApi, tfVarFiles, errors } = useTerraformVariablesContext() + + const { mutate: editService, isLoading: isLoadingEditService } = useEditService({ + organizationId, + projectId, + environmentId, + }) + + if (service?.serviceType !== 'TERRAFORM') { + return null + } + + const onSubmit = handleSubmit(() => { + // Edit the service with the updated variables and the updated order of tfvars files + const payload = buildEditServicePayload({ + service, + request: { + terraform_variables_source: { + ...service.terraform_variables_source, + tf_vars: serializeForApi(), + tf_var_file_paths: [...tfVarFiles.filter((file) => file.enabled)].reverse().map((file) => file.source), + }, + }, + }) + editService({ + serviceId: service.id, + payload, + }) + }) + + return ( + <> + +
+ +
+ + ) +} + +const TerraformVariablesContent = ({ service }: { service: Terraform }) => { + const methods = useForm({ + mode: 'onChange', + defaultValues: match(service) + .with({ serviceType: 'TERRAFORM' }, (s) => s) + .otherwise(() => ({})), + }) + + return ( +
+ +
+ + + + + +
+
+ ) +} + +const TerraformVariablesWrapper = () => { + const { serviceId } = useParams({ strict: false }) + const { data: service } = useService({ serviceId }) + + if (service?.serviceType !== 'TERRAFORM') { + return null + } + + return +} + function RouteComponent() { - return
Terraform variables
+ return ( + }> + + + ) } diff --git a/libs/domains/service-settings/feature/src/index.ts b/libs/domains/service-settings/feature/src/index.ts index 9bef3cb849a..741244c0d4f 100644 --- a/libs/domains/service-settings/feature/src/index.ts +++ b/libs/domains/service-settings/feature/src/index.ts @@ -9,3 +9,4 @@ export * from './lib/service-domain-settings/service-domain-settings/service-dom export * from './lib/service-deployment-restrictions-settings/service-deployment-restrictions-settings/service-deployment-restrictions-settings' export * from './lib/terraform-configuration-settings/terraform-configuration-settings' export * from './lib/terraform-arguments-settings/terraform-arguments-settings' +export * from './lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table' diff --git a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.spec.tsx b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.spec.tsx similarity index 95% rename from libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.spec.tsx rename to libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.spec.tsx index 97378bfe842..bd4e27d5495 100644 --- a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.spec.tsx +++ b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.spec.tsx @@ -1,7 +1,10 @@ import { FormProvider, useForm } from 'react-hook-form' +import { + TerraformVariablesContext, + type TerraformVariablesContextType, +} from '@qovery/domains/service-terraform/feature' +import { type TerraformGeneralData } from '@qovery/domains/services/feature' import { renderWithProviders, screen, within } from '@qovery/shared/util-tests' -import { type TerraformGeneralData } from '../terraform-configuration-settings/terraform-configuration-settings' -import { TerraformVariablesContext, type TerraformVariablesContextType } from '../terraform-variables-context' import { TfvarsFilesPopover } from './terraform-tfvars-popover' const WrapperComponent = ({ diff --git a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.tsx b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.tsx similarity index 76% rename from libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.tsx rename to libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.tsx index 54fbcab823a..a3adecbce4d 100644 --- a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.tsx +++ b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover.tsx @@ -1,6 +1,8 @@ import { type CheckedState } from '@radix-ui/react-checkbox' +import clsx from 'clsx' import { Reorder } from 'framer-motion' -import { useCallback, useEffect, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { type TfVarsFile, useTerraformVariablesContext } from '@qovery/domains/service-terraform/feature' import { Button, Checkbox, @@ -13,8 +15,6 @@ import { Skeleton, Tooltip, } from '@qovery/shared/ui' -import { twMerge } from '@qovery/shared/util-js' -import { type TfVarsFile, useTerraformVariablesContext } from '../terraform-variables-context' const TfvarItem = ({ file, @@ -41,13 +41,21 @@ const TfvarItem = ({ [tfVarFiles, file.source, setTfVarFiles] ) + const isLastItem = useMemo(() => index === tfVarFiles.length - 1, [index, tfVarFiles.length]) + useEffect(() => { setCurrentIndex(index.toString()) }, [index]) return (
setHoveredRow(file.source)} onMouseLeave={() => setHoveredRow(undefined)} > @@ -60,14 +68,14 @@ const TfvarItem = ({ className="ml-1 cursor-pointer" />
- +
- # + # { side="left" content={ {enabledFilesCount} @@ -161,29 +169,23 @@ export const TfvarsFilesPopover = () => { ) : ( - )}
- +
- Add and order .tfvars files + Add and order .tfvars files - +
-
+
{
) : ( )}
- {newPathErrorMessage &&
{newPathErrorMessage}
} + {newPathErrorMessage &&
{newPathErrorMessage}
}
{!areTfVarsFilesLoading && tfVarFiles.length !== 0 && ( -
- File order defines override priority. +
+ File order defines override priority. - +
)} -
+
{areTfVarsFilesLoading && tfVarFiles.length === 0 ? ( <> {Array.from({ length: 2 }).map((_, index) => ( -
+
@@ -245,16 +247,16 @@ export const TfvarsFilesPopover = () => { ))} ) : tfVarFiles.length > 0 ? ( - + {tfVarFiles?.map((file, index) => ( diff --git a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-settings.tsx b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-settings.tsx similarity index 100% rename from libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-settings.tsx rename to libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-settings.tsx diff --git a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.spec.tsx b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.spec.tsx similarity index 97% rename from libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.spec.tsx rename to libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.spec.tsx index c9f3581db3a..d9eacf9c5fd 100644 --- a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.spec.tsx +++ b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.spec.tsx @@ -1,12 +1,12 @@ import { type TfVarsFileResponse } from 'qovery-typescript-axios' import { FormProvider, useForm } from 'react-hook-form' -import { renderWithProviders, screen } from '@qovery/shared/util-tests' -import { type TerraformGeneralData } from '../terraform-configuration-settings/terraform-configuration-settings' import { CUSTOM_SOURCE, TerraformVariablesContext, type TerraformVariablesContextType, -} from '../terraform-variables-context' +} from '@qovery/domains/service-terraform/feature' +import { type TerraformGeneralData } from '@qovery/domains/services/feature' +import { renderWithProviders, screen } from '@qovery/shared/util-tests' import { TerraformVariablesTable } from './terraform-variables-table' const mockTfVarsFromRepo: TfVarsFileResponse[] = [] diff --git a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.tsx b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.tsx similarity index 74% rename from libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.tsx rename to libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.tsx index 0ad247cb716..4788497c3bf 100644 --- a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.tsx +++ b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-table/terraform-variables-table.tsx @@ -1,16 +1,19 @@ +import { clsx } from 'clsx' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useParams } from 'react-router-dom' -import { DropdownVariable } from '@qovery/domains/variables/feature' -import { Badge, Button, Checkbox, Icon, LoaderSpinner, Tooltip, truncateText } from '@qovery/shared/ui' -import { twMerge } from '@qovery/shared/util-js' -import { TfvarsFilesPopover } from '../terraform-tfvars-popover/terraform-tfvars-popover' -import { SECRET_UNCHANGED_VALUE, type UIVariable, useTerraformVariablesContext } from '../terraform-variables-context' import { + SECRET_UNCHANGED_VALUE, + type UIVariable, formatSource, getSourceBadgeClassName, isCustomVariable, isVariableChanged, -} from '../terraform-variables-utils' + useTerraformVariablesContext, +} from '@qovery/domains/service-terraform/feature' +import { DropdownVariable } from '@qovery/domains/variables/feature' +import { Badge, Button, Checkbox, Icon, LoaderSpinner, Tooltip, truncateText } from '@qovery/shared/ui' +import { twMerge } from '@qovery/shared/util-js' +import { TfvarsFilesPopover } from '../terraform-tfvars-popover/terraform-tfvars-popover' const SourceCell = ({ variable }: { variable: UIVariable }) => { const sourceCellRef = useRef(null) @@ -41,7 +44,7 @@ const SourceCell = ({ variable }: { variable: UIVariable }) => { return (
@@ -88,16 +91,15 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => { }, [isSecretPlaceholder, focusValueTextarea]) return ( -
+
-
+
selectRow(variable.id)} @@ -107,17 +109,12 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => { {/* Variable name cell */}
-
+
{variable.isNew ? ( { }} className={twMerge( 'peer h-full w-full bg-transparent px-4 text-sm outline-none', - isCellFocused('key') && 'bg-neutral-150 hover:bg-neutral-150' + isCellFocused('key') && 'bg-surface-neutral-component hover:bg-surface-neutral-component' )} onFocus={() => setFocusedCell('key')} onBlur={() => setFocusedCell(undefined)} @@ -140,12 +137,12 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => { spellCheck={false} /> ) : ( - {variable.key} + {variable.key} )} {variable.description && ( { )} {errors.get(variable.id)?.field === 'key' && ( -
- +
+
)} @@ -165,7 +162,7 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => {
{/* Variable value cell */}
{ setIsCellHovered(true) }} @@ -179,16 +176,24 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => {
{isSecretPlaceholder && ( -
- +
+ ● ● ● ● ● ● ● ●
@@ -203,7 +208,7 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => { onFocus={() => setFocusedCell('value')} onBlur={() => setFocusedCell(undefined)} className={twMerge( - 'vertical-align-middle h-5 w-full resize-none bg-transparent px-4 text-sm text-neutral-400 outline-none', + 'vertical-align-middle h-5 w-full resize-none bg-transparent px-4 text-sm text-neutral outline-none', isMultiline && 'h-full min-h-5 resize-y py-3' )} style={{ minHeight: textareaMinHeight }} @@ -212,10 +217,11 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => { />
{!isSecretPlaceholder && ( @@ -237,11 +243,11 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => { > )} @@ -249,24 +255,24 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => { )} {isVariableChanged(variable) && ( )} {errors.get(variable.id)?.field === 'value' && ( - + )} @@ -277,7 +283,7 @@ const VariableRow = ({ variable }: { variable: UIVariable }) => { {/* Secret toggle cell */}
@@ -315,23 +321,23 @@ const TerraformVariablesRows = () => { ) return ( -
-
-
+
+
+
-
- Variable +
+ Variable
-
- Value +
+ Value
-
- Source +
+ Source
@@ -344,12 +350,12 @@ const TerraformVariablesRows = () => { const TerraformVariablesLoadingState = () => { return ( -
+
- Fetching .tfvars files... - Pulling your Terraform variable definitions. + Fetching .tfvars files... + Pulling your Terraform variable definitions.
@@ -358,10 +364,10 @@ const TerraformVariablesLoadingState = () => { const TerraformVariablesEmptyState = () => { return ( -
+
- - + + Load a .tfvars file or manually add variables
to configure your Terraform service. @@ -384,9 +390,9 @@ export const TerraformVariablesTable = () => { }, [addVariable]) return ( -
+
- Variable configuration + Variable configuration
@@ -407,7 +413,7 @@ export const TerraformVariablesTable = () => { Delete selected )} - diff --git a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-utils.spec.ts b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-utils.spec.ts similarity index 96% rename from libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-utils.spec.ts rename to libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-utils.spec.ts index b843ad282d3..3b2c223224b 100644 --- a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-utils.spec.ts +++ b/libs/domains/service-settings/feature/src/lib/terraform-variables-settings/terraform-variables-utils.spec.ts @@ -1,6 +1,5 @@ import { type TerraformVariableDefinition } from 'qovery-typescript-axios' -import { type UIVariable } from './terraform-variables-context' -import { buildMetadataByKey, isVariableChanged } from './terraform-variables-utils' +import { type UIVariable, buildMetadataByKey, isVariableChanged } from '@qovery/domains/service-terraform/feature' describe('Terraform variables utility functions', () => { describe('buildMetadataByKey', () => { diff --git a/libs/domains/service-terraform/feature/src/index.ts b/libs/domains/service-terraform/feature/src/index.ts index 77a737ea7c2..04fe1afd4dc 100644 --- a/libs/domains/service-terraform/feature/src/index.ts +++ b/libs/domains/service-terraform/feature/src/index.ts @@ -1,10 +1,9 @@ export * from './source-setting/source-setting' -export * from './lib/terraform-variables-settings/terraform-variables-settings' -export * from './lib/terraform-variables-settings/terraform-variables-context' -export * from './lib/terraform-variables-settings/terraform-tfvars-popover/terraform-tfvars-popover' export * from './lib/hooks/use-terraform-resources/use-terraform-resources' export * from './lib/terraform-resources-section/terraform-resources-section' export * from './lib/resource-details/resource-details' export * from './lib/resource-tree-list/resource-tree-list' export * from './lib/hooks/use-terraform-available-versions/use-terraform-available-versions' export * from './lib/terraform-variables-settings/dockerfile-fragment-inline-setting/dockerfile-fragment-inline-setting' +export * from './lib/terraform-variables-context' +export * from './lib/terraform-variables-utils' diff --git a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-context.tsx b/libs/domains/service-terraform/feature/src/lib/terraform-variables-context.tsx similarity index 98% rename from libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-context.tsx rename to libs/domains/service-terraform/feature/src/lib/terraform-variables-context.tsx index 1579ea3188d..5d5692ea64f 100644 --- a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-context.tsx +++ b/libs/domains/service-terraform/feature/src/lib/terraform-variables-context.tsx @@ -1,3 +1,4 @@ +import { useParams } from '@tanstack/react-router' import { type AxiosError } from 'axios' import { GitProviderEnum, @@ -16,7 +17,6 @@ import { useState, } from 'react' import { useFormContext } from 'react-hook-form' -import { useParams } from 'react-router-dom' import { match } from 'ts-pattern' import { v4 as uuidv4 } from 'uuid' import { @@ -89,8 +89,8 @@ export const TerraformVariablesContext = createContext { // Initial data fetching... const { getValues } = useFormContext() - const { organizationId = '', applicationId = '' } = useParams() - const { data: serviceResponse } = useService({ serviceId: applicationId }) + const { organizationId = '', serviceId = '' } = useParams({ strict: false }) + const { data: serviceResponse } = useService({ serviceId, suspense: true }) const service = match(serviceResponse) .with({ serviceType: 'TERRAFORM' }, (s) => s) .otherwise(() => null) diff --git a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-utils.ts b/libs/domains/service-terraform/feature/src/lib/terraform-variables-utils.ts similarity index 84% rename from libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-utils.ts rename to libs/domains/service-terraform/feature/src/lib/terraform-variables-utils.ts index 5330bb433ec..1c4ed77cff5 100644 --- a/libs/domains/service-terraform/feature/src/lib/terraform-variables-settings/terraform-variables-utils.ts +++ b/libs/domains/service-terraform/feature/src/lib/terraform-variables-utils.ts @@ -49,13 +49,13 @@ export const isCustomVariable = (v: UIVariable) => { export const getSourceBadgeClassName = (variable: UIVariable) => { if (isCustomVariable(variable)) { - return 'text-[#65636D] bg-[#F2EFF3] border-[#D0CDD780]' + return 'text-neutral-subtle bg-surface-neutral-component border-neutral-component' } if (isVariableChanged(variable)) { - return 'text-[#AB6400] bg-[#FFF7C2] border-[#DC9B004D]' + return 'text-warning bg-surface-warning-component border-warning-subtle' } if (variable.source.includes('.tfvars')) { - return 'text-[#218358] bg-[#E6F6EB] border-[#008F3E33]' + return 'text-positive bg-surface-positive-component border-positive-subtle' } - return 'text-[#0D74CE] bg-[#E6F4FE] border-[#0083EB33]' + return 'text-info bg-surface-info-component border-info-subtle' } diff --git a/libs/shared/ui/src/lib/components/scroll-shadow-wrapper/scroll-shadow-wrapper.tsx b/libs/shared/ui/src/lib/components/scroll-shadow-wrapper/scroll-shadow-wrapper.tsx index 8bf7e0d64f8..14d24c193d5 100644 --- a/libs/shared/ui/src/lib/components/scroll-shadow-wrapper/scroll-shadow-wrapper.tsx +++ b/libs/shared/ui/src/lib/components/scroll-shadow-wrapper/scroll-shadow-wrapper.tsx @@ -4,10 +4,11 @@ export interface ScrollShadowWrapperProps { children: ReactNode className?: string style?: CSSProperties + hideSides?: boolean } export function ScrollShadowWrapper(props: ScrollShadowWrapperProps) { - const { children, className = '', style = {} } = props + const { children, className = '', style = {}, hideSides = false } = props const [scrollTop, setScrollTop] = useState(0) const [scrollHeight, setScrollHeight] = useState(0) @@ -52,19 +53,23 @@ export function ScrollShadowWrapper(props: ScrollShadowWrapperProps) { className={`relative overflow-y-auto pr-[1px] ${className}`} onScroll={onScrollHandler} > -
+ {!hideSides && ( +
+ )} {children} -
+ {!hideSides && ( +
+ )}
) }