diff --git a/src/components/create-job/plugins/PluginsSection.tsx b/src/components/create-job/plugins/PluginsSection.tsx index 0763c335..0e44b940 100644 --- a/src/components/create-job/plugins/PluginsSection.tsx +++ b/src/components/create-job/plugins/PluginsSection.tsx @@ -5,12 +5,13 @@ import { POLICY_TYPES } from '@data/policyTypes'; import { InteractionContextType, useInteractionContext } from '@lib/contexts/interaction'; import { generatePluginName, getPluginName } from '@lib/pluginNames'; import { SlateCard } from '@shared/cards/SlateCard'; +import Expander from '@shared/Expander'; import DeeployErrorAlert from '@shared/jobs/DeeployErrorAlert'; import AddJobCard from '@shared/projects/AddJobCard'; import { SmallTag } from '@shared/SmallTag'; import { computeDependencyTree } from '@lib/dependencyTree'; import { BasePluginType, GenericPlugin, Plugin, PluginType } from '@typedefs/steps/deploymentStepTypes'; -import { useEffect, useMemo, useRef } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { useFieldArray, useFormContext, useWatch } from 'react-hook-form'; import toast from 'react-hot-toast'; import { RiBox3Line, RiDeleteBin2Line, RiTerminalBoxLine } from 'react-icons/ri'; @@ -81,6 +82,7 @@ export default function PluginsSection() { }); const plugins = fields as PluginWithId[]; + const [expandedPlugins, setExpandedPlugins] = useState>({}); const previousPluginsLengthRef = useRef(plugins.length); @@ -112,7 +114,20 @@ export default function PluginsSection() { // Clean stale shmem references when a plugin is removed const handleRemovePlugin = (indexToRemove: number) => { + const removedPluginId = plugins[indexToRemove]?.id; const removedName = watchedPlugins[indexToRemove]?.pluginName; + + if (removedPluginId) { + setExpandedPlugins((previous) => { + if (!(removedPluginId in previous)) { + return previous; + } + + const { [removedPluginId]: _removed, ...next } = previous; + return next; + }); + } + remove(indexToRemove); if (!removedName) return; @@ -252,6 +267,20 @@ export default function PluginsSection() { previousPluginsLengthRef.current = plugins.length; }, [plugins]); + useEffect(() => { + const pluginIds = new Set(plugins.map((plugin) => plugin.id)); + + setExpandedPlugins((previous) => { + const next = Object.fromEntries(Object.entries(previous).filter(([id]) => pluginIds.has(id))); + + if (Object.keys(next).length === Object.keys(previous).length) { + return previous; + } + + return next; + }); + }, [plugins]); + return (
{fields.length < 5 && ( @@ -265,11 +294,25 @@ export default function PluginsSection() {
{plugins.map((plugin, index) => { const { title, element } = getPluginAlias(plugin, index); + const isExpanded = expandedPlugins[plugin.id] ?? true; return (
+ + setExpandedPlugins((previous) => ({ + ...previous, + [plugin.id]: !(previous[plugin.id] ?? true), + })) + } + /> + {element} +
+ } label={
} > - <> - {plugin.basePluginType === BasePluginType.Generic ? ( - <> - {(plugin as GenericPlugin).deploymentType.pluginType === PluginType.Container ? ( - - ) : ( - - )} - - ) : ( - - )} - + {isExpanded ? ( + <> + {plugin.basePluginType === BasePluginType.Generic ? ( + <> + {(plugin as GenericPlugin).deploymentType.pluginType === PluginType.Container ? ( + + ) : ( + + )} + + ) : ( + + )} + + ) : null}
); diff --git a/src/shared/cards/SlateCard.tsx b/src/shared/cards/SlateCard.tsx index a5039005..ba20f8d9 100644 --- a/src/shared/cards/SlateCard.tsx +++ b/src/shared/cards/SlateCard.tsx @@ -1,4 +1,4 @@ -import { FunctionComponent, PropsWithChildren } from 'react'; +import { Children, FunctionComponent, PropsWithChildren } from 'react'; interface Props { title?: string; @@ -7,6 +7,8 @@ interface Props { } export const SlateCard: FunctionComponent> = ({ children, title, titleElement, label }) => { + const hasChildren = Children.count(children) > 0; + return (
{(!!title || !!titleElement || !!label) && ( @@ -17,7 +19,7 @@ export const SlateCard: FunctionComponent> = ({ childre
)} -
{children}
+ {hasChildren &&
{children}
}
); };