From 0e3ca0deedefef430b65cedc443b33a14bcbe4d2 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Fri, 29 Sep 2023 12:21:23 +0300 Subject: [PATCH 01/43] refactor: extract ResourceTitleBar component --- .../organisms/NavigatorPane/NavigatorPane.tsx | 147 +----------------- .../NavigatorPane/ResourceTitleBar.tsx | 122 +++++++++++++++ .../{NavigatorPane.styled.tsx => styled.tsx} | 16 ++ 3 files changed, 145 insertions(+), 140 deletions(-) create mode 100644 src/components/organisms/NavigatorPane/ResourceTitleBar.tsx rename src/components/organisms/NavigatorPane/{NavigatorPane.styled.tsx => styled.tsx} (69%) diff --git a/src/components/organisms/NavigatorPane/NavigatorPane.tsx b/src/components/organisms/NavigatorPane/NavigatorPane.tsx index b2dbee1b45..8be47e8174 100644 --- a/src/components/organisms/NavigatorPane/NavigatorPane.tsx +++ b/src/components/organisms/NavigatorPane/NavigatorPane.tsx @@ -1,59 +1,23 @@ -import {useCallback, useMemo} from 'react'; - -import {Dropdown, Tooltip} from 'antd'; - -import AntdIcon from '@ant-design/icons'; - -import styled from 'styled-components'; - -import {TOOLTIP_DELAY} from '@constants/constants'; -import { - CollapseResourcesTooltip, - DisabledAddResourceTooltip, - ExpandResourcesTooltip, - NewResourceTooltip, -} from '@constants/tooltips'; +import {useCallback} from 'react'; import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {collapseResourceKinds, expandResourceKinds, toggleResourceFilters} from '@redux/reducers/ui'; -import {activeResourceCountSelector, navigatorResourceKindsSelector} from '@redux/selectors/resourceMapSelectors'; +import {toggleResourceFilters} from '@redux/reducers/ui'; import {CheckedResourcesActionsMenu, ResourceFilter} from '@molecules'; -import {CollapseIcon, ExpandIcon} from '@components/atoms/Icons'; -import {TitleBarWrapper} from '@components/atoms/StyledComponents/TitleBarWrapper'; - -import {useNewResourceMenuItems} from '@hooks/menuItemsHooks'; - -import {useSelectorWithRef} from '@utils/hooks'; - -import {TitleBar} from '@monokle/components'; -import {ROOT_FILE_ENTRY} from '@shared/constants/fileEntry'; -import {Colors} from '@shared/styles'; -import {trackEvent} from '@shared/utils'; -import {isInClusterModeSelector, isInPreviewModeSelector} from '@shared/utils/selectors'; - -import NavigatorDescription from './NavigatorDescription'; -import * as S from './NavigatorPane.styled'; import ResourceNavigator from './ResourceNavigator'; +import {ResourceTitleBar} from './ResourceTitleBar'; + +import * as S from './styled'; const NavPane: React.FC = () => { const dispatch = useAppDispatch(); const checkedResourceIdentifiers = useAppSelector(state => state.main.checkedResourceIdentifiers); - const isFolderOpen = useAppSelector(state => Boolean(state.main.fileMap[ROOT_FILE_ENTRY])); - const isInClusterMode = useAppSelector(isInClusterModeSelector); - const isInPreviewMode = useAppSelector(isInPreviewModeSelector); + const isPreviewLoading = useAppSelector(state => state.main.previewOptions.isLoading); const isResourceFiltersOpen = useAppSelector(state => state.ui.isResourceFiltersOpen); - const newResourceMenuItems = useNewResourceMenuItems(); - - const isAddResourceDisabled = useMemo( - () => !isFolderOpen || isInPreviewMode || isInClusterMode, - [isFolderOpen, isInClusterMode, isInPreviewMode] - ); - const resourceFilterButtonHandler = useCallback(() => { dispatch(toggleResourceFilters()); }, [dispatch]); @@ -65,46 +29,7 @@ const NavPane: React.FC = () => { ) : ( - - } - descriptionStyle={{paddingTop: '5px'}} - actions={ - - - - - - - New - - - - - } - /> - + )} @@ -117,61 +42,3 @@ const NavPane: React.FC = () => { }; export default NavPane; - -function CollapseAction() { - const dispatch = useAppDispatch(); - const [hasAnyActiveResources, hasAnyActiveResourcesRef] = useSelectorWithRef( - state => activeResourceCountSelector(state) > 0 - ); - - const [collapsedKinds, collapsedKindsRef] = useSelectorWithRef(s => s.ui.navigator.collapsedResourceKinds); - const [navigatorKinds, navigatorKindsRef] = useSelectorWithRef(navigatorResourceKindsSelector); - - const isCollapsed = useMemo( - () => collapsedKinds.length === navigatorKinds.length, - [collapsedKinds.length, navigatorKinds.length] - ); - - const onClick = useCallback(() => { - if (!hasAnyActiveResourcesRef.current) { - return; - } - - if (collapsedKindsRef.current.length === navigatorKindsRef.current.length) { - dispatch(expandResourceKinds(navigatorKindsRef.current)); - trackEvent('navigator/expand_all'); - return; - } - - dispatch(collapseResourceKinds(navigatorKindsRef.current)); - trackEvent('navigator/collapse_all'); - }, [hasAnyActiveResourcesRef, collapsedKindsRef, navigatorKindsRef, dispatch]); - - return ( - <> - - {isCollapsed ? ( - - ) : ( - - )} - - - ); -} - -// Styled Components - -const StyledFullscreenOutlined = styled(AntdIcon)<{$disabled: boolean}>` - color: ${({$disabled}) => ($disabled ? Colors.grey6 : Colors.blue6)}; - cursor: ${({$disabled}) => ($disabled ? 'not-allowed' : 'pointer')}; - padding-right: 10px; - font-size: 16px; -`; - -const StyledFullscreenExitOutlined = styled(AntdIcon)<{$disabled: boolean}>` - color: ${({$disabled}) => ($disabled ? Colors.grey6 : Colors.blue6)}; - cursor: ${({$disabled}) => ($disabled ? 'not-allowed' : 'pointer')}; - padding-right: 10px; - font-size: 16px; -`; diff --git a/src/components/organisms/NavigatorPane/ResourceTitleBar.tsx b/src/components/organisms/NavigatorPane/ResourceTitleBar.tsx new file mode 100644 index 0000000000..5f052e4df1 --- /dev/null +++ b/src/components/organisms/NavigatorPane/ResourceTitleBar.tsx @@ -0,0 +1,122 @@ +import {useCallback, useMemo} from 'react'; + +import {Dropdown, Tooltip} from 'antd'; + +import {TOOLTIP_DELAY} from '@constants/constants'; +import { + CollapseResourcesTooltip, + DisabledAddResourceTooltip, + ExpandResourcesTooltip, + NewResourceTooltip, +} from '@constants/tooltips'; + +import {useAppDispatch, useAppSelector} from '@redux/hooks'; +import {collapseResourceKinds, expandResourceKinds} from '@redux/reducers/ui'; +import {activeResourceCountSelector, navigatorResourceKindsSelector} from '@redux/selectors/resourceMapSelectors'; + +import {TitleBarWrapper} from '@components/atoms'; +import {CollapseIcon, ExpandIcon} from '@components/atoms/Icons'; + +import {useNewResourceMenuItems} from '@hooks/menuItemsHooks'; + +import {useSelectorWithRef} from '@utils/hooks'; + +import {TitleBar} from '@monokle/components'; +import {ROOT_FILE_ENTRY} from '@shared/constants/fileEntry'; +import {isInClusterModeSelector, isInPreviewModeSelector, trackEvent} from '@shared/utils'; + +import NavigatorDescription from './NavigatorDescription'; + +import * as S from './styled'; + +export const ResourceTitleBar = () => { + const isFolderOpen = useAppSelector(state => Boolean(state.main.fileMap[ROOT_FILE_ENTRY])); + const isInClusterMode = useAppSelector(isInClusterModeSelector); + const isInPreviewMode = useAppSelector(isInPreviewModeSelector); + + const newResourceMenuItems = useNewResourceMenuItems(); + + const isAddResourceDisabled = useMemo( + () => !isFolderOpen || isInPreviewMode || isInClusterMode, + [isFolderOpen, isInClusterMode, isInPreviewMode] + ); + return ( + + } + descriptionStyle={{paddingTop: '5px'}} + actions={ + + + + + + + New + + + + + } + /> + + ); +}; + +function CollapseAction() { + const dispatch = useAppDispatch(); + const [hasAnyActiveResources, hasAnyActiveResourcesRef] = useSelectorWithRef( + state => activeResourceCountSelector(state) > 0 + ); + + const [collapsedKinds, collapsedKindsRef] = useSelectorWithRef(s => s.ui.navigator.collapsedResourceKinds); + const [navigatorKinds, navigatorKindsRef] = useSelectorWithRef(navigatorResourceKindsSelector); + + const isCollapsed = useMemo( + () => collapsedKinds.length === navigatorKinds.length, + [collapsedKinds.length, navigatorKinds.length] + ); + + const onClick = useCallback(() => { + if (!hasAnyActiveResourcesRef.current) { + return; + } + + if (collapsedKindsRef.current.length === navigatorKindsRef.current.length) { + dispatch(expandResourceKinds(navigatorKindsRef.current)); + trackEvent('navigator/expand_all'); + return; + } + + dispatch(collapseResourceKinds(navigatorKindsRef.current)); + trackEvent('navigator/collapse_all'); + }, [hasAnyActiveResourcesRef, collapsedKindsRef, navigatorKindsRef, dispatch]); + + return ( + <> + + {isCollapsed ? ( + + ) : ( + + )} + + + ); +} diff --git a/src/components/organisms/NavigatorPane/NavigatorPane.styled.tsx b/src/components/organisms/NavigatorPane/styled.tsx similarity index 69% rename from src/components/organisms/NavigatorPane/NavigatorPane.styled.tsx rename to src/components/organisms/NavigatorPane/styled.tsx index 71fd6f2839..ddd6f4fc63 100644 --- a/src/components/organisms/NavigatorPane/NavigatorPane.styled.tsx +++ b/src/components/organisms/NavigatorPane/styled.tsx @@ -1,3 +1,5 @@ +import AntdIcon from '@ant-design/icons'; + import styled from 'styled-components'; import {DEFAULT_PANE_TITLE_HEIGHT} from '@constants/constants'; @@ -56,3 +58,17 @@ export const TitleBarRightButtons = styled.div` display: flex; align-items: center; `; + +export const FullscreenOutlined = styled(AntdIcon)<{$disabled: boolean}>` + color: ${({$disabled}) => ($disabled ? Colors.grey6 : Colors.blue6)}; + cursor: ${({$disabled}) => ($disabled ? 'not-allowed' : 'pointer')}; + padding-right: 10px; + font-size: 16px; +`; + +export const FullscreenExitOutlined = styled(AntdIcon)<{$disabled: boolean}>` + color: ${({$disabled}) => ($disabled ? Colors.grey6 : Colors.blue6)}; + cursor: ${({$disabled}) => ($disabled ? 'not-allowed' : 'pointer')}; + padding-right: 10px; + font-size: 16px; +`; From 14540d334bf846696ecaf1b4b08582559b50a84e Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:24:30 +0300 Subject: [PATCH 02/43] refactor: Dry-run navigator title bar --- .../NavigatorPane/DryRunTitleBar.tsx | 60 +++++++++++++++++++ .../NavigatorDescription.styled.tsx | 4 +- .../NavigatorPane/NavigatorDescription.tsx | 6 +- .../organisms/NavigatorPane/NavigatorPane.tsx | 6 ++ src/redux/selectors.tsx | 37 ++++++++++++ src/shared/styles/colors.ts | 1 + 6 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 src/components/organisms/NavigatorPane/DryRunTitleBar.tsx diff --git a/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx b/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx new file mode 100644 index 0000000000..733d647d85 --- /dev/null +++ b/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx @@ -0,0 +1,60 @@ +import {Tooltip} from 'antd'; + +import {CloseCircleFilled, ReloadOutlined} from '@ant-design/icons'; + +import styled from 'styled-components'; + +import {TOOLTIP_DELAY} from '@constants/constants'; + +import {useAppDispatch, useAppSelector} from '@redux/hooks'; +import {previewLabelSelector} from '@redux/selectors'; +import {restartPreview, stopPreview} from '@redux/thunks/preview'; + +import {TitleBarWrapper} from '@components/atoms'; + +import {Icon, TitleBar} from '@monokle/components'; +import {Colors} from '@shared/styles'; + +import NavigatorDescription from './NavigatorDescription'; + +const DryRunTitleBar = () => { + const dispatch = useAppDispatch(); + const preview = useAppSelector(state => state.main.preview); + const previewLabel = useAppSelector(previewLabelSelector); + + return ( + + + + + + preview && dispatch(restartPreview(preview))} /> + + + dispatch(stopPreview())} /> + + + } + description={} + headerStyle={{background: Colors.dryRun}} + descriptionStyle={{ + background: `${Colors.dryRun}20`, + paddingTop: '5px', + }} + /> + + ); +}; + +export default DryRunTitleBar; + +const Label = styled.span` + margin-right: 8px; +`; + +const ReloadIcon = styled(ReloadOutlined)` + margin-right: 8px; +`; diff --git a/src/components/organisms/NavigatorPane/NavigatorDescription.styled.tsx b/src/components/organisms/NavigatorPane/NavigatorDescription.styled.tsx index e8b021351f..0f7fcd2b6e 100644 --- a/src/components/organisms/NavigatorPane/NavigatorDescription.styled.tsx +++ b/src/components/organisms/NavigatorPane/NavigatorDescription.styled.tsx @@ -21,10 +21,10 @@ export const ProblemCountContainer = styled.div` cursor: pointer; `; -export const ResourcesCount = styled.span` - color: ${Colors.grey6}; +export const ResourcesCount = styled.span<{$isPreview: boolean}>` font-size: 10px; font-weight: 700; + color: ${props => (props.$isPreview ? Colors.dryRun : Colors.grey6)}; `; export const WarningsErrorsContainer = styled.div` diff --git a/src/components/organisms/NavigatorPane/NavigatorDescription.tsx b/src/components/organisms/NavigatorPane/NavigatorDescription.tsx index 7f77e24649..cf0f53b977 100644 --- a/src/components/organisms/NavigatorPane/NavigatorDescription.tsx +++ b/src/components/organisms/NavigatorPane/NavigatorDescription.tsx @@ -10,11 +10,13 @@ import {setValidationFilters} from '@redux/validation/validation.slice'; import {useRefSelector} from '@utils/hooks'; import {ProblemIcon} from '@monokle/components'; +import {isInPreviewModeSelector} from '@shared/utils'; import * as S from './NavigatorDescription.styled'; const NavigatorDescription: React.FC = () => { const dispatch = useAppDispatch(); + const isInPreviewMode = useAppSelector(isInPreviewModeSelector); const navigatorResourcesCount = useAppSelector(navigatorResourcesCountSelector); const errorsCount = useAppSelector(errorsByResourcesFilterCountSelector); @@ -31,7 +33,7 @@ const NavigatorDescription: React.FC = () => { {navigatorResourcesCount ? ( <> - {navigatorResourcesCount} objects + {navigatorResourcesCount} objects handleSetFilters('error')}> {errorsCount} @@ -43,7 +45,7 @@ const NavigatorDescription: React.FC = () => { ) : ( - No objects found + No objects found )} ); diff --git a/src/components/organisms/NavigatorPane/NavigatorPane.tsx b/src/components/organisms/NavigatorPane/NavigatorPane.tsx index 8be47e8174..0d7d16f095 100644 --- a/src/components/organisms/NavigatorPane/NavigatorPane.tsx +++ b/src/components/organisms/NavigatorPane/NavigatorPane.tsx @@ -5,6 +5,9 @@ import {toggleResourceFilters} from '@redux/reducers/ui'; import {CheckedResourcesActionsMenu, ResourceFilter} from '@molecules'; +import {isInPreviewModeSelector} from '@shared/utils'; + +import DryRunTitleBar from './DryRunTitleBar'; import ResourceNavigator from './ResourceNavigator'; import {ResourceTitleBar} from './ResourceTitleBar'; @@ -15,6 +18,7 @@ const NavPane: React.FC = () => { const checkedResourceIdentifiers = useAppSelector(state => state.main.checkedResourceIdentifiers); + const isInPreviewMode = useAppSelector(isInPreviewModeSelector); const isPreviewLoading = useAppSelector(state => state.main.previewOptions.isLoading); const isResourceFiltersOpen = useAppSelector(state => state.ui.isResourceFiltersOpen); @@ -28,6 +32,8 @@ const NavPane: React.FC = () => { + ) : isInPreviewMode ? ( + ) : ( )} diff --git a/src/redux/selectors.tsx b/src/redux/selectors.tsx index df3bb45637..1f873e7c64 100644 --- a/src/redux/selectors.tsx +++ b/src/redux/selectors.tsx @@ -199,3 +199,40 @@ export const kustomizationResourcesCountSelector = createSelector( return size(kustomizationResources); } ); + +export const previewLabelSelector = createSelector( + [ + (state: RootState) => state.main.preview, + (state: RootState) => state.main.resourceMetaMapByStorage.local, + (state: RootState) => state.main.helmChartMap, + (state: RootState) => state.config.projectConfig?.helm?.previewConfigurationMap, + (state: RootState) => state.config.projectConfig?.savedCommandMap, + ], + (preview, localResourceMetaMap, helmChartMap, previewConfigurationMap, savedCommandMap) => { + if (!preview) { + return undefined; + } + + if (preview.type === 'kustomize') { + const resource = localResourceMetaMap[preview.kustomizationId]; + return resource?.name; + } + + if (preview.type === 'helm') { + const helmChart = helmChartMap[preview.chartId]; + return helmChart?.name; + } + + if (preview.type === 'helm-config') { + const config = previewConfigurationMap?.[preview.configId]; + return config?.name; + } + + if (preview.type === 'command') { + const command = savedCommandMap?.[preview.commandId]; + return command?.label; + } + + return undefined; + } +); diff --git a/src/shared/styles/colors.ts b/src/shared/styles/colors.ts index 127380b3c6..3afa4b3748 100644 --- a/src/shared/styles/colors.ts +++ b/src/shared/styles/colors.ts @@ -119,6 +119,7 @@ export enum Colors { diffBackgroundHover = '#27220f', blueBgColor = '#202C4D', blueWrapperColor = '#2b3759', + dryRun = cyan6, } export enum PanelColors { From 3db51448dab8ae340a87ad030c92385fd928fb67 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:31:55 +0300 Subject: [PATCH 03/43] chore: remove old preview controls --- .../organisms/PageHeader/PageHeader.tsx | 6 +-- .../PageHeader/PreviewControl/ExitButton.tsx | 35 ------------ .../PreviewControl/PreviewControls.tsx | 26 --------- .../PreviewControl/PreviewLabel.tsx | 54 ------------------- 4 files changed, 2 insertions(+), 119 deletions(-) delete mode 100644 src/components/organisms/PageHeader/PreviewControl/ExitButton.tsx delete mode 100644 src/components/organisms/PageHeader/PreviewControl/PreviewControls.tsx delete mode 100644 src/components/organisms/PageHeader/PreviewControl/PreviewLabel.tsx diff --git a/src/components/organisms/PageHeader/PageHeader.tsx b/src/components/organisms/PageHeader/PageHeader.tsx index ac11e4356d..98c821fe92 100644 --- a/src/components/organisms/PageHeader/PageHeader.tsx +++ b/src/components/organisms/PageHeader/PageHeader.tsx @@ -39,7 +39,7 @@ import {showGitErrorModal} from '@utils/terminal'; import MonokleKubeshopLogo from '@assets/NewMonokleLogoDark.svg'; import {Icon} from '@monokle/components'; -import {isInClusterModeSelector, isInPreviewModeSelector} from '@shared/utils/selectors'; +import {isInClusterModeSelector} from '@shared/utils/selectors'; import {trackEvent} from '@shared/utils/telemetry'; import CloudSync from './CloudSync'; @@ -47,7 +47,6 @@ import {ClusterControls} from './ClusterControl/ClusterControls'; import DownloadProgress from './DownloadProgress'; import {K8sVersionSelection} from './K8sVersionSelection'; import * as S from './PageHeader.styled'; -import {PreviewControls} from './PreviewControl/PreviewControls'; const PageHeader = () => { const dispatch = useAppDispatch(); @@ -57,7 +56,6 @@ const PageHeader = () => { const gitLoading = useAppSelector(state => state.git.loading); const hasGitRepo = useAppSelector(state => Boolean(state.git.repo)); const isGitInstalled = useAppSelector(state => state.git.isGitInstalled); - const isInPreviewMode = useAppSelector(isInPreviewModeSelector); const layoutSize = useAppSelector(state => state.ui.layoutSize); const unseenNotificationsCount = useAppSelector(state => state.main.notifications.filter(n => !n.hasSeen).length); const isNewVersionAvailable = useAppSelector(state => state.config.isNewVersionAvailable); @@ -284,7 +282,7 @@ const PageHeader = () => {
- {isInPreviewMode ? : } + diff --git a/src/components/organisms/PageHeader/PreviewControl/ExitButton.tsx b/src/components/organisms/PageHeader/PreviewControl/ExitButton.tsx deleted file mode 100644 index 1c6b93cf19..0000000000 --- a/src/components/organisms/PageHeader/PreviewControl/ExitButton.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import {useCallback} from 'react'; - -import {Button} from 'antd'; - -import {CloseCircleFilled} from '@ant-design/icons'; - -import styled from 'styled-components'; - -import {useAppDispatch} from '@redux/hooks'; -import {stopPreview} from '@redux/thunks/preview'; - -import {Colors} from '@shared/styles'; - -export function ExitButton() { - const dispatch = useAppDispatch(); - - const onClickExit = useCallback(() => { - dispatch(stopPreview()); - }, [dispatch]); - - return ( - - - - ); -} - -const CloseBtn = styled(Button)` - border-radius: 4px; - padding: 0px; - height: 30px; - min-width: 20px; - border: none; - color: ${Colors.cyan6}; -`; diff --git a/src/components/organisms/PageHeader/PreviewControl/PreviewControls.tsx b/src/components/organisms/PageHeader/PreviewControl/PreviewControls.tsx deleted file mode 100644 index bdcd2deaad..0000000000 --- a/src/components/organisms/PageHeader/PreviewControl/PreviewControls.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import styled from 'styled-components'; - -import {useAppSelector} from '@redux/hooks'; - -import {ExitButton} from './ExitButton'; -import {PreviewLabel} from './PreviewLabel'; - -export function PreviewControls() { - const preview = useAppSelector(state => state.main.preview); - - if (!preview) { - return null; - } - - return ( - - - - - ); -} - -const Box = styled.div` - display: flex; - gap: 8px; -`; diff --git a/src/components/organisms/PageHeader/PreviewControl/PreviewLabel.tsx b/src/components/organisms/PageHeader/PreviewControl/PreviewLabel.tsx deleted file mode 100644 index 234de5e9b8..0000000000 --- a/src/components/organisms/PageHeader/PreviewControl/PreviewLabel.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import styled from 'styled-components'; - -import {useAppSelector} from '@redux/hooks'; -import {selectPreviewDisplayContent} from '@redux/reducers/main/selectors'; - -import {Tooltip} from '@components/atoms/Tooltip/Tooltip'; - -import {Icon} from '@monokle/components'; -import {AnyPreview} from '@shared/models/preview'; -import {Colors} from '@shared/styles'; - -export function PreviewLabel() { - const preview = useAppSelector(state => state.main.preview); - const previewDisplayContent = useAppSelector(selectPreviewDisplayContent); - - if (!preview) { - return null; - } - - return ( - - - {PREVIEW_ICON_MAP[preview.type]} - - Performing Dry-run {previewDisplayContent.name} - - - - ); -} - -const LabelBox = styled.div` - display: flex; - gap: 4px; - align-items: center; - border-radius: 4px; - padding: 0 1rem; - height: 30px; - background-color: ${Colors.cyan6}; - color: ${Colors.grey3}; - border: none; -`; - -const LabelContent = styled.div` - font-size: 12px; - cursor: pointer; -`; - -const PREVIEW_ICON_MAP: Record = { - helm: , - 'helm-config': , - kustomize: , - command: , -}; From e265c35160f0844271472b6fe03d6594475427c9 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:59:44 +0300 Subject: [PATCH 04/43] refactor: explorer left menu panes --- .../ExplorerPane/DryRunsPane/DryRunsPane.tsx | 9 ++ .../ExplorerPane/DryRunsPane/index.ts | 1 + .../organisms/ExplorerPane/ExplorerPane.tsx | 73 +++++----------- .../ExplorerPane/FilePane/FilePane.styled.tsx | 9 ++ .../ExplorerPane/FilePane/FilePane.tsx | 86 ++++++++----------- 5 files changed, 76 insertions(+), 102 deletions(-) create mode 100644 src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx create mode 100644 src/components/organisms/ExplorerPane/DryRunsPane/index.ts diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx new file mode 100644 index 0000000000..a8b041065f --- /dev/null +++ b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx @@ -0,0 +1,9 @@ +const DryRunsPane = () => { + return ( +
+

Dry runs

+
+ ); +}; + +export default DryRunsPane; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/index.ts b/src/components/organisms/ExplorerPane/DryRunsPane/index.ts new file mode 100644 index 0000000000..e2595c2f6c --- /dev/null +++ b/src/components/organisms/ExplorerPane/DryRunsPane/index.ts @@ -0,0 +1 @@ +export {default} from './DryRunsPane'; diff --git a/src/components/organisms/ExplorerPane/ExplorerPane.tsx b/src/components/organisms/ExplorerPane/ExplorerPane.tsx index 70d68f7ec4..00f1012460 100644 --- a/src/components/organisms/ExplorerPane/ExplorerPane.tsx +++ b/src/components/organisms/ExplorerPane/ExplorerPane.tsx @@ -1,68 +1,39 @@ -import {Collapse as RawCollapse} from 'antd'; - +import {Allotment} from 'allotment'; import styled from 'styled-components'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {setExplorerSelectedSection} from '@redux/reducers/ui'; +import {PANEL_HEADER_HEIGHT} from '@components/atoms/AccordionPanel/AccordionPanel'; -import {isInClusterModeSelector} from '@shared/utils/selectors'; -import {trackEvent} from '@shared/utils/telemetry'; +import {Colors, PanelColors} from '@monokle/components'; +import DryRunsPane from './DryRunsPane'; import FilePane from './FilePane'; -import HelmPane from './HelmPane'; -import ImagesPane from './ImagesPane'; -import KustomizePane from './KustomizePane'; -import PreviewConfigurationPane from './PreviewConfigurationPane'; const ExplorerPane: React.FC = () => { - const dispatch = useAppDispatch(); - const explorerSelectedSection = useAppSelector(state => state.ui.explorerSelectedSection); - const isInClusterMode = useAppSelector(isInClusterModeSelector); - return ( - - { - if (isInClusterMode) { - return; - } - dispatch(setExplorerSelectedSection(key)); - trackEvent('left-menu/activity-changed', {activity: 'explorer', section: key}); - }} - > - - - - - - - + + + + + + + + + + + + ); }; export default ExplorerPane; -const Collapse = styled(RawCollapse)` - padding-top: 18px; - box-sizing: border-box; +const PaneContainer = styled.div` + background: ${PanelColors.toolBar}; height: 100%; - padding-bottom: 14px !important; - overflow: hidden; - max-height: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - min-height: 0; - - .ant-collapse-header { - padding: 2px 20px 0px 20px !important; - } `; -const CollapseContainer = styled.div` - width: 100%; - height: 100%; +const StyledAllotment = styled(Allotment)` + --sash-hover-size: 3px; + --separator-border: ${Colors.backgroundGrey}; + --focus-border: ${Colors.geekblue7}; `; diff --git a/src/components/organisms/ExplorerPane/FilePane/FilePane.styled.tsx b/src/components/organisms/ExplorerPane/FilePane/FilePane.styled.tsx index 2c3cd42d32..1ac696f1d3 100644 --- a/src/components/organisms/ExplorerPane/FilePane/FilePane.styled.tsx +++ b/src/components/organisms/ExplorerPane/FilePane/FilePane.styled.tsx @@ -95,3 +95,12 @@ export const TitleBarActions = styled.div` font-size: 16px; } `; + +export const Container = styled.div` + position: relative; + height: 100%; +`; + +export const TitleBarContainer = styled.div` + padding: 16px 24px 0px 16px; +`; diff --git a/src/components/organisms/ExplorerPane/FilePane/FilePane.tsx b/src/components/organisms/ExplorerPane/FilePane/FilePane.tsx index 486278d0ec..e85a135715 100644 --- a/src/components/organisms/ExplorerPane/FilePane/FilePane.tsx +++ b/src/components/organisms/ExplorerPane/FilePane/FilePane.tsx @@ -1,6 +1,6 @@ import {memo, useMemo} from 'react'; -import {Button, CollapsePanelProps, Tooltip} from 'antd'; +import {Button, Tooltip} from 'antd'; import AntdIcon, {ExclamationCircleOutlined, ReloadOutlined} from '@ant-design/icons'; @@ -11,30 +11,25 @@ import {useAppDispatch, useAppSelector} from '@redux/hooks'; import {setFileExplorerExpandedFolders} from '@redux/reducers/ui'; import {setRootFolder} from '@redux/thunks/setRootFolder'; -import {AccordionPanel} from '@components/atoms'; import {CollapseIcon, ExpandIcon} from '@components/atoms/Icons'; import {useRefSelector} from '@utils/hooks'; -import {TitleBar, TitleBarCount} from '@monokle/components'; +import {TitleBar} from '@monokle/components'; import {ROOT_FILE_ENTRY} from '@shared/constants/fileEntry'; import {InjectedPanelProps} from '@shared/models/explorer'; import {trackEvent} from '@shared/utils'; import {isEqual} from '@shared/utils/isEqual'; -import {isInClusterModeSelector} from '@shared/utils/selectors'; import * as S from './FilePane.styled'; import FileSystemTree from './FileSystemTree'; import {useSetFolderFromMainThread} from './useSetFolderFromMainThread'; -const FilePane: React.FC = props => { - const {isActive, panelKey} = props; - +const FilePane: React.FC = () => { const dispatch = useAppDispatch(); const fileExplorerExpandedFolders = useAppSelector(state => state.ui.fileExplorerExpandedFolders); const fileMap = useAppSelector(state => state.main.fileMap); const isFolderLoading = useAppSelector(state => state.ui.isFolderLoading); - const isInClusterMode = useAppSelector(isInClusterModeSelector); const isScanExcludesUpdated = useAppSelector(state => state.config.isScanExcludesUpdated); const rootEntry = useAppSelector(state => state.main.fileMap[ROOT_FILE_ENTRY]); @@ -53,50 +48,41 @@ const FilePane: React.FC = props => { useSetFolderFromMainThread(); return ( - + e.stopPropagation()}> - {isScanExcludesUpdated === 'outdated' && ( - - - - )} - - - - - - - onClickDelete()}> - - - - ); -}; - -export default PreviewConfigurationQuickAction; - -// Styled Components - -const Button = styled.span<{isItemSelected: boolean}>` - margin-right: 15px; - font-size: 12px; - font-weight: 500; - cursor: pointer; - color: ${props => (props.isItemSelected ? Colors.blackPure : Colors.blue6)}; -`; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/PreviewConfigurationRenderer.styled.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/PreviewConfigurationRenderer.styled.tsx deleted file mode 100644 index ff76d29222..0000000000 --- a/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/PreviewConfigurationRenderer.styled.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import styled from 'styled-components'; - -import {Colors} from '@shared/styles/colors'; - -type ItemContainerProps = { - isDisabled: boolean; - isSelected: boolean; - isHovered: boolean; -}; - -type ItemNameProps = { - isDisabled: boolean; - isSelected: boolean; -}; - -export const ItemContainer = styled.span` - display: flex; - align-items: center; - width: 100%; - user-select: none; - > { - min-width: 0; - } - padding-left: 47px; - padding-right: 8px; - margin-bottom: 2px; - cursor: pointer; - - ${props => { - if (props.isDisabled) { - return; - } - - if (props.isSelected) { - if (props.isHovered) { - return `background: ${Colors.selectionColorHover};`; - } - return `background: ${Colors.selectionColor};`; - } - - if (props.isHovered) { - return `background: ${Colors.blackPearl};`; - } - }}; -`; - -export const ItemName = styled.div` - padding: 2px 0; - font-size: 12px; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - ${props => { - if (props.isSelected) { - return `font-weight: 700;`; - } - }}; - ${props => { - if (props.isDisabled) { - return `color: ${Colors.grey7};`; - } - - if (props.isSelected) { - return `color: ${Colors.blackPure};`; - } - - return `color: ${Colors.blue10};`; - }}; -`; - -export const PrefixContainer = styled.span` - display: flex; - align-items: center; - margin-right: 7px; -`; - -export const QuickActionContainer = styled.span``; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/PreviewConfigurationRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/PreviewConfigurationRenderer.tsx deleted file mode 100644 index 5bb58533d0..0000000000 --- a/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/PreviewConfigurationRenderer.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import {memo, useState} from 'react'; - -import {EyeOutlined} from '@ant-design/icons'; - -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {selectPreviewConfiguration} from '@redux/reducers/main'; - -import {Colors} from '@shared/styles/colors'; -import {trackEvent} from '@shared/utils'; -import {isInClusterModeSelector} from '@shared/utils/selectors'; - -import PreviewConfigurationQuickAction from './PreviewConfigurationQuickAction'; -import * as S from './PreviewConfigurationRenderer.styled'; - -type IProps = { - id: string; -}; - -const PreviewConfigurationRenderer: React.FC = props => { - const {id} = props; - - const dispatch = useAppDispatch(); - const previewConfiguration = useAppSelector(state => state.config.projectConfig?.helm?.previewConfigurationMap?.[id]); - const isDisabled = useAppSelector(isInClusterModeSelector); - const isSelected = useAppSelector( - state => - state.main.selection?.type === 'preview.configuration' && - state.main.selection.previewConfigurationId === previewConfiguration?.id - ); - - const [isHovered, setIsHovered] = useState(false); - - if (!previewConfiguration) { - return null; - } - - return ( - setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - onClick={() => { - dispatch(selectPreviewConfiguration({previewConfigurationId: id})); - trackEvent('explore/select_preview_configuration'); - }} - > - - - - - - {previewConfiguration.name} - - -
{ - e.stopPropagation(); - }} - > - - - -
-
- ); -}; - -export default memo(PreviewConfigurationRenderer); diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/index.ts b/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/index.ts deleted file mode 100644 index 881806e46b..0000000000 --- a/src/components/organisms/ExplorerPane/DryRunsPane/PreviewConfigurationRenderer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default} from './PreviewConfigurationRenderer'; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/oldDryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/oldDryRunsPane.tsx deleted file mode 100644 index e3d27dc2cc..0000000000 --- a/src/components/organisms/ExplorerPane/DryRunsPane/oldDryRunsPane.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import {basename} from 'path'; -import styled from 'styled-components'; - -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {helmValuesFilesByChartNameSelector, kustomizationResourcesSelectors} from '@redux/selectors'; - -import {TitleBarWrapper} from '@components/atoms'; - -import {Colors, Icon, TitleBar} from '@monokle/components'; - -function DryRunsPane() { - const dispatch = useAppDispatch(); - const preview = useAppSelector(state => state.main.preview); - - const helmGroups = useAppSelector(helmValuesFilesByChartNameSelector); - const kustomizations = useAppSelector(kustomizationResourcesSelectors); - - return ( - - - - - - {helmGroups.map(([chartName, valuesFiles]) => ( - - - - {chartName} - -
- {valuesFiles.map(valuesFile => ( -
{basename(valuesFile.filePath)}
- ))} -
-
- ))} - - - - - kustomize - -
- {kustomizations.map(kustomization => ( -
{basename(kustomization.name)}
- ))} -
-
-
- ); -} - -export default DryRunsPane; - -export const PanelContainer = styled.div` - height: 100%; - max-height: inherit; - background-color: ${Colors.grey10}; - overflow: hidden; - z-index: -2; - padding-bottom: 12px; - display: flex; - flex-flow: column; - overflow-y: auto; -`; - -const Container = styled(PanelContainer)` - display: flex; - flex-flow: column; - overflow-y: auto; -`; - -const StyledUl = styled.ul` - flex: auto 0; - padding: 0 8px; - margin: 0; - margin-bottom: 16px; -`; - -const Subheading = styled.li` - display: flex; - align-items: center; - gap: 10px; - padding-left: 12px; - font-size: 12px; - font-weight: 700; - color: #fff; -`; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx index 1564046d7a..0a6d0feefc 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx @@ -2,12 +2,18 @@ import styled from 'styled-components'; import {Colors} from '@shared/styles/colors'; -type ItemContainerProps = {isDisabled: boolean; isPreviewed: boolean; isHighlighted: boolean; isHovered: boolean}; +type ItemContainerProps = { + isDisabled?: boolean; + isPreviewed: boolean; + isHighlighted?: boolean; + isHovered: boolean; + indent?: number; +}; type ItemNameProps = { - isDisabled: boolean; + isDisabled?: boolean; + isHighlighted?: boolean; isPreviewed: boolean; - isHighlighted: boolean; }; export const ItemContainer = styled.span` @@ -18,7 +24,7 @@ export const ItemContainer = styled.span` > { min-width: 0; } - padding-left: 20px; + padding-left: ${props => `${20 + (props.indent ?? 0)}px`}; padding-right: 8px; margin-bottom: 2px; cursor: pointer; From 4ace23cc67e683eb407dc6b4bd3a26c5baf3e529 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:09:12 +0300 Subject: [PATCH 19/43] fix: file tree scroll to file --- .../FileSystemTree/FileSystemTree.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/components/organisms/ExplorerPane/FilePane/FileSystemTree/FileSystemTree.tsx b/src/components/organisms/ExplorerPane/FilePane/FileSystemTree/FileSystemTree.tsx index 9d5223fb1b..43d2d3fdad 100644 --- a/src/components/organisms/ExplorerPane/FilePane/FileSystemTree/FileSystemTree.tsx +++ b/src/components/organisms/ExplorerPane/FilePane/FileSystemTree/FileSystemTree.tsx @@ -15,6 +15,7 @@ import {ROOT_FILE_ENTRY} from '@shared/constants/fileEntry'; import {isFileSelection} from '@shared/models/selection'; import {isHelmValuesFile, trackEvent} from '@shared/utils'; +// import { TreeRef } from 'antd'; import * as S from './FileSystemTree.styled'; import FileSystemTreeNode from './TreeNode'; @@ -28,6 +29,7 @@ const FileSystemTree: React.FC = () => { const [firstHighlightedFile, firstHighlightedFileRef] = useSelectorWithRef(state => state.main.highlights.find(isFileSelection) ); + const filePathToScrollTo = useRef(); const [containerRef, {height: containerHeight}] = useMeasure(); @@ -36,11 +38,13 @@ const FileSystemTree: React.FC = () => { const treeData = useAppSelector(projectFileTreeSelector); useLayoutEffect(() => { - if (!firstHighlightedFile) { + const targetFilePath = selectedFilePath ?? firstHighlightedFile?.filePath; + + if (!targetFilePath) { return; } - const parentFolderPaths = getAllParentFolderPaths(firstHighlightedFile.filePath).filter( + const parentFolderPaths = getAllParentFolderPaths(targetFilePath).filter( folderPath => !fileExplorerExpandedFoldersRef.current.includes(folderPath) ); @@ -48,18 +52,19 @@ const FileSystemTree: React.FC = () => { dispatch( setFileExplorerExpandedFolders([...new Set([...fileExplorerExpandedFoldersRef.current, ...parentFolderPaths])]) ); - } else { - treeRef.current?.scrollTo({key: firstHighlightedFile.filePath}); } - }, [dispatch, fileExplorerExpandedFoldersRef, firstHighlightedFile]); + + filePathToScrollTo.current = targetFilePath; + }, [dispatch, selectedFilePath, fileExplorerExpandedFoldersRef, firstHighlightedFile]); useLayoutEffect(() => { - if (!firstHighlightedFileRef.current) { + if (!filePathToScrollTo.current) { return; } setTimeout(() => { - treeRef.current?.scrollTo({key: firstHighlightedFileRef.current?.filePath}); + treeRef.current?.scrollTo({key: filePathToScrollTo.current}); + filePathToScrollTo.current = undefined; }, 50); }, [fileExplorerExpandedFolders, firstHighlightedFileRef]); From 60665c88f7d0a4803bbd549f2c7057b847836e72 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:10:20 +0300 Subject: [PATCH 20/43] chore: remove padding bottom from dry runs pane --- .../organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx index 7939245362..c01471fd8e 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx @@ -140,7 +140,6 @@ export const PanelContainer = styled.div` background-color: ${Colors.grey10}; overflow: hidden; z-index: -2; - padding-bottom: 12px; display: flex; flex-flow: column; overflow-y: auto; From ba334c70fe9b52a65509846e6f7da7564da35999 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:11:49 +0300 Subject: [PATCH 21/43] refactor: show commands only if they exist --- src/redux/selectors/dryRunsSelectors.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/redux/selectors/dryRunsSelectors.ts b/src/redux/selectors/dryRunsSelectors.ts index eca7300110..dccf3721d5 100644 --- a/src/redux/selectors/dryRunsSelectors.ts +++ b/src/redux/selectors/dryRunsSelectors.ts @@ -138,14 +138,16 @@ export const dryRunNodesSelector = createSelector( .filter(isDefined) .sort((a, b) => a.label.localeCompare(b.label)); - list.push({type: 'heading', title: 'commands', icon: 'command'}); - commands.forEach(command => { - list.push({ - type: 'command', - commandId: command.id, - commandName: command.label, + if (commands.length > 0) { + list.push({type: 'heading', title: 'commands', icon: 'command'}); + commands.forEach(command => { + list.push({ + type: 'command', + commandId: command.id, + commandName: command.label, + }); }); - }); + } return list; } From d5b2e25555467e816ec287142194cdee3cebad7b Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:15:24 +0300 Subject: [PATCH 22/43] fix: ellipsis on previewable files --- .../FilePane/FileSystemTree/TreeNode/TreeNode.styled.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/organisms/ExplorerPane/FilePane/FileSystemTree/TreeNode/TreeNode.styled.tsx b/src/components/organisms/ExplorerPane/FilePane/FileSystemTree/TreeNode/TreeNode.styled.tsx index b8152119eb..fdd0fc93ca 100644 --- a/src/components/organisms/ExplorerPane/FilePane/FileSystemTree/TreeNode/TreeNode.styled.tsx +++ b/src/components/organisms/ExplorerPane/FilePane/FileSystemTree/TreeNode/TreeNode.styled.tsx @@ -57,8 +57,8 @@ export const SpinnerContainer = styled.div` export const TitleContainer = styled.div<{$actionButtonsWidth: number; $isHovered: boolean}>` display: flex; align-items: center; - max-width: ${({$actionButtonsWidth, $isHovered}) => ($isHovered ? `calc(100% - ${$actionButtonsWidth}px)` : '100%')}; - width: ${({$actionButtonsWidth, $isHovered}) => ($isHovered ? `calc(100% - ${$actionButtonsWidth}px)` : '100%')}; + max-width: ${({$actionButtonsWidth}) => `calc(100% - ${$actionButtonsWidth}px)`}; + width: ${({$actionButtonsWidth}) => `calc(100% - ${$actionButtonsWidth}px)`}; `; export const TitleText = styled.span<{ From a6ae88371f6c304d07355c211f5533ddbdeb840f Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:20:06 +0300 Subject: [PATCH 23/43] feat: scroll to current dry run --- .../ExplorerPane/DryRunsPane/DryRunsPane.tsx | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx index c01471fd8e..9efdc7e6ae 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx @@ -1,4 +1,4 @@ -import {useRef} from 'react'; +import {useLayoutEffect, useRef} from 'react'; import {Skeleton} from 'antd'; @@ -27,6 +27,8 @@ const DryRunsPane: React.FC = () => { const list = useAppSelector(dryRunNodesSelector); const isLoading = useAppSelector(state => (state.main.previewOptions.isLoading ? true : state.ui.isFolderLoading)); + const preview = useAppSelector(state => state.main.preview); + const ref = useRef(null); const rowVirtualizer = useVirtualizer({ @@ -36,6 +38,30 @@ const DryRunsPane: React.FC = () => { scrollToFn: elementScroll, }); + useLayoutEffect(() => { + if (!preview) { + return; + } + + const index = list.findIndex(item => { + if (item.type === 'command' && preview.type === 'command') { + return item.commandId === preview.commandId; + } + if (item.type === 'helm-values' && preview.type === 'helm') { + return item.valuesId === preview.valuesFileId; + } + if (item.type === 'helm-config' && preview.type === 'helm-config') { + return item.configId === preview.configId; + } + if (item.type === 'kustomize' && preview.type === 'kustomize') { + return item.kustomizationId === preview.kustomizationId; + } + return false; + }); + + rowVirtualizer.scrollToIndex(index); + }, [preview, list, rowVirtualizer]); + if (isLoading) { return (
From 02e124b97e233f39e1b860075eb6615269e2fbe3 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:38:08 +0300 Subject: [PATCH 24/43] fix: dry run title bar label --- src/redux/selectors/dryRunsSelectors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redux/selectors/dryRunsSelectors.ts b/src/redux/selectors/dryRunsSelectors.ts index dccf3721d5..7771c0e000 100644 --- a/src/redux/selectors/dryRunsSelectors.ts +++ b/src/redux/selectors/dryRunsSelectors.ts @@ -168,7 +168,7 @@ export const dryRunLabelSelector = createSelector( if (preview.type === 'kustomize') { const resource = localResourceMetaMap[preview.kustomizationId]; - return resource?.name; + return basename(resource.name); } if (preview.type === 'helm') { From ec41b513b373421943c459dffec4ebe81abf7592 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:52:08 +0300 Subject: [PATCH 25/43] feat: new dropdown for dry run configs --- .../ExplorerPane/DryRunsPane/DryRunsPane.tsx | 25 ++++++++-- .../DryRunsPane/useNewDryRunsMenuItems.tsx | 47 +++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/components/organisms/ExplorerPane/DryRunsPane/useNewDryRunsMenuItems.tsx diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx index 9efdc7e6ae..d4785217cb 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx @@ -1,6 +1,6 @@ import {useLayoutEffect, useRef} from 'react'; -import {Skeleton} from 'antd'; +import {Button, Dropdown, Skeleton} from 'antd'; import {CodeOutlined} from '@ant-design/icons'; @@ -20,6 +20,7 @@ import CommandRenderer from './CommandRenderer'; import HelmConfigRenderer from './HelmConfigRenderer'; import HelmValueRenderer from './HelmValueRenderer'; import KustomizeRenderer from './KustomizeRenderer'; +import {useNewDryRunsMenuItems} from './useNewDryRunsMenuItems'; const ROW_HEIGHT = 26; @@ -28,7 +29,7 @@ const DryRunsPane: React.FC = () => { const isLoading = useAppSelector(state => (state.main.previewOptions.isLoading ? true : state.ui.isFolderLoading)); const preview = useAppSelector(state => state.main.preview); - + const menuItems = useNewDryRunsMenuItems(); const ref = useRef(null); const rowVirtualizer = useVirtualizer({ @@ -77,7 +78,21 @@ const DryRunsPane: React.FC = () => { return ( - + + + + New + + +
+ } + />
[ + { + key: 'from-scratch', + label: Dry run Configuration, + onClick: () => { + dispatch(openPreviewConfigurationEditor({})); + }, + }, + { + key: 'from-template', + label: Command Dry run, + onClick: () => { + dispatch(openSaveEditCommandModal({})); + }, + }, + ], + [dispatch] + ); + + return items; +} + +const MenuItem = styled.div` + display: flex; + align-items: center; + gap: 12px; + color: ${Colors.whitePure}; + font-weight: 700; + height: 30px; + font-size: 12px; +`; From 23bb34d3950ca48a18f5129b6ffeb388377faa45 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:39:45 +0300 Subject: [PATCH 26/43] refactor: optimistic loading for dry runs --- .../DryRunsPane/CommandRenderer.tsx | 20 ++++--- .../ExplorerPane/DryRunsPane/DryRunsPane.tsx | 2 +- .../DryRunsPane/HelmConfigRenderer.tsx | 21 ++++--- .../DryRunsPane/HelmValueRenderer.tsx | 20 ++++--- .../DryRunsPane/KustomizeRenderer.tsx | 32 ++++++----- .../ExplorerPane/DryRunsPane/styled.tsx | 7 +++ .../DryRunsPane/usePreviewTrigger.tsx | 56 +++++++++++++++++++ .../NavigatorPane/DryRunTitleBar.tsx | 25 ++++++--- .../organisms/NavigatorPane/NavigatorPane.tsx | 2 +- src/redux/hooks.ts | 4 ++ src/redux/thunks/preview/startPreview.ts | 8 +-- 11 files changed, 143 insertions(+), 54 deletions(-) create mode 100644 src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/CommandRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/CommandRenderer.tsx index 09a4202fac..b5c0022c11 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/CommandRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/CommandRenderer.tsx @@ -1,7 +1,10 @@ import {memo, useState} from 'react'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {startPreview} from '@redux/thunks/preview'; +import {useAppSelector} from '@redux/hooks'; + +import {CommandPreview} from '@shared/models/preview'; + +import {usePreviewTrigger} from './usePreviewTrigger'; import * as S from './styled'; @@ -14,10 +17,12 @@ const CommandRenderer: React.FC = props => { const command = useAppSelector(state => state.config.projectConfig?.savedCommandMap?.[id]); - const dispatch = useAppDispatch(); const isPreviewed = useAppSelector( state => state.main.preview?.type === 'command' && state.main.preview.commandId === command?.id ); + const thisPreview: CommandPreview = {type: 'command', commandId: id}; + const {isOptimisticLoading, triggerPreview} = usePreviewTrigger(thisPreview); + const mightBePreview = isPreviewed || isOptimisticLoading; const [isHovered, setIsHovered] = useState(false); @@ -29,14 +34,13 @@ const CommandRenderer: React.FC = props => { setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} - onClick={() => { - dispatch(startPreview({type: 'command', commandId: id})); - }} + onClick={triggerPreview} > - {command.label} + {command.label} + {isOptimisticLoading && } ); }; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx index d4785217cb..744c4bd66a 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx @@ -26,7 +26,7 @@ const ROW_HEIGHT = 26; const DryRunsPane: React.FC = () => { const list = useAppSelector(dryRunNodesSelector); - const isLoading = useAppSelector(state => (state.main.previewOptions.isLoading ? true : state.ui.isFolderLoading)); + const isLoading = useAppSelector(state => state.ui.isFolderLoading); const preview = useAppSelector(state => state.main.preview); const menuItems = useNewDryRunsMenuItems(); diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx index 6f3c044a88..a8779fdc5d 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx @@ -1,7 +1,10 @@ import {memo, useState} from 'react'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {startPreview} from '@redux/thunks/preview'; +import {useAppSelector} from '@redux/hooks'; + +import {HelmConfigPreview} from '@shared/models/preview'; + +import {usePreviewTrigger} from './usePreviewTrigger'; import * as S from './styled'; @@ -12,13 +15,14 @@ type IProps = { const HelmConfigRenderer: React.FC = props => { const {id} = props; - const dispatch = useAppDispatch(); const previewConfiguration = useAppSelector(state => state.config.projectConfig?.helm?.previewConfigurationMap?.[id]); const isPreviewed = useAppSelector( state => state.main.preview?.type === 'helm-config' && state.main.preview.configId === previewConfiguration?.id ); - + const thisPreview: HelmConfigPreview = {type: 'helm-config', configId: id}; + const {isOptimisticLoading, triggerPreview} = usePreviewTrigger(thisPreview); const [isHovered, setIsHovered] = useState(false); + const mightBePreview = isPreviewed || isOptimisticLoading; if (!previewConfiguration) { return null; @@ -28,14 +32,13 @@ const HelmConfigRenderer: React.FC = props => { setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} - onClick={() => { - dispatch(startPreview({type: 'helm-config', configId: id})); - }} + onClick={triggerPreview} > - {previewConfiguration.name} + {previewConfiguration.name} + {isOptimisticLoading && } ); }; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmValueRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmValueRenderer.tsx index fba6f65ffe..1b2e6d63e0 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/HelmValueRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmValueRenderer.tsx @@ -1,7 +1,10 @@ import {memo, useState} from 'react'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {startPreview} from '@redux/thunks/preview'; +import {useAppSelector} from '@redux/hooks'; + +import {HelmPreview} from '@shared/models/preview'; + +import {usePreviewTrigger} from './usePreviewTrigger'; import * as S from './styled'; @@ -12,12 +15,14 @@ type IProps = { const HelmValuesRenderer: React.FC = props => { const {id} = props; - const dispatch = useAppDispatch(); const helmValues = useAppSelector(state => state.main.helmValuesMap[id]); const isPreviewed = useAppSelector( state => state.main.preview?.type === 'helm' && state.main.preview?.valuesFileId === helmValues.id ); + const thisPreview: HelmPreview = {type: 'helm', chartId: helmValues.helmChartId, valuesFileId: id}; + const {isOptimisticLoading, triggerPreview} = usePreviewTrigger(thisPreview); + const mightBePreview = isPreviewed || isOptimisticLoading; const [isHovered, setIsHovered] = useState(false); @@ -27,14 +32,13 @@ const HelmValuesRenderer: React.FC = props => { setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} - onClick={() => { - dispatch(startPreview({type: 'helm', chartId: helmValues.helmChartId, valuesFileId: id})); - }} + onClick={triggerPreview} > - {helmValues.name} + {helmValues.name} + {isOptimisticLoading && } ); }; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/KustomizeRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/KustomizeRenderer.tsx index 83aa43151c..3000ce3014 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/KustomizeRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/KustomizeRenderer.tsx @@ -2,15 +2,17 @@ import {memo, useMemo, useState} from 'react'; import {basename, dirname} from 'path'; -import {useAppDispatch, useAppSelector} from '@redux/hooks'; +import {useAppSelector} from '@redux/hooks'; import {useResourceMeta} from '@redux/selectors/resourceSelectors'; import {isResourceHighlighted} from '@redux/services/resource'; -import {startPreview} from '@redux/thunks/preview'; import {ResourceRefsIconPopover} from '@components/molecules'; +import {KustomizePreview} from '@shared/models/preview'; import {isEqual} from '@shared/utils/isEqual'; +import {usePreviewTrigger} from './usePreviewTrigger'; + import * as S from './styled'; type IProps = { @@ -21,7 +23,6 @@ const KustomizeRenderer: React.FC = props => { const {kustomizationId} = props; const identifier = {id: kustomizationId, storage: 'local' as const}; - const dispatch = useAppDispatch(); const resourceMeta = useResourceMeta(identifier); const isHighlighted = useAppSelector(state => Boolean(identifier && isResourceHighlighted(identifier, state.main.highlights)) @@ -29,6 +30,12 @@ const KustomizeRenderer: React.FC = props => { const isPreviewed = useAppSelector( state => state.main.preview?.type === 'kustomize' && state.main.preview.kustomizationId === identifier.id ); + const thisPreview: KustomizePreview = { + type: 'kustomize', + kustomizationId: identifier.id, + }; + const {isOptimisticLoading, triggerPreview} = usePreviewTrigger(thisPreview); + const mightBePreview = isPreviewed || isOptimisticLoading; const kustomizationName = useMemo(() => { if (!resourceMeta) { @@ -47,36 +54,31 @@ const KustomizeRenderer: React.FC = props => { return ( setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} - onClick={() => { - dispatch( - startPreview({ - type: 'kustomize', - kustomizationId: identifier.id, - }) - ); - }} + onClick={triggerPreview} > - + {kustomizationName} + + {isOptimisticLoading && } ); }; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx index 0a6d0feefc..ce03b0e675 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx @@ -1,3 +1,5 @@ +import {ReloadOutlined} from '@ant-design/icons'; + import styled from 'styled-components'; import {Colors} from '@shared/styles/colors'; @@ -81,3 +83,8 @@ export const ItemName = styled.div` return `color: ${Colors.blue10};`; }}; `; + +export const ReloadIcon = styled(ReloadOutlined)` + color: ${Colors.blackPure}; + margin-left: 8px; +`; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx new file mode 100644 index 0000000000..344f38e20c --- /dev/null +++ b/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx @@ -0,0 +1,56 @@ +import {useCallback, useEffect, useState} from 'react'; + +import {AnyAction, isAnyOf, removeListener} from '@reduxjs/toolkit'; + +import {isEqual} from 'lodash'; + +import {addAppListener, useAppDispatch, useAppSelector} from '@redux/hooks'; +import {startPreview} from '@redux/thunks/preview'; + +import {AnyPreview} from '@shared/models/preview'; + +export const usePreviewTrigger = (preview: AnyPreview) => { + const dispatch = useAppDispatch(); + const [isOptimisticLoading, setIsOptimisticLoading] = useState(false); + const isPreviewLoading = useAppSelector(state => state.main.previewOptions.isLoading); + + // the reload of a preview can be triggered from multiple places, not only from where this hook is used + // so we have to listen to startPreview in case our state is not up to date + useEffect(() => { + const listener = { + matcher: isAnyOf(startPreview.pending, startPreview.rejected, startPreview.fulfilled), + effect: (action: AnyAction) => { + if (startPreview.pending.match(action) && isEqual(action.meta.arg, preview)) { + setIsOptimisticLoading(true); + } + + if (isAnyOf(startPreview.fulfilled, startPreview.rejected)(action)) { + setIsOptimisticLoading(false); + } + }, + }; + dispatch(addAppListener(listener)); + return () => { + dispatch(removeListener(listener)); + }; + }, [dispatch, preview]); + + useEffect(() => { + if (!isPreviewLoading) { + setIsOptimisticLoading(false); + } + }, [isPreviewLoading]); + + const triggerPreview = useCallback(() => { + if (isPreviewLoading) { + return; + } + setIsOptimisticLoading(true); + dispatch(startPreview(preview)); + }, [preview, dispatch, isPreviewLoading]); + + return { + triggerPreview, + isOptimisticLoading, + }; +}; diff --git a/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx b/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx index ea117e18b8..40e2f265f7 100644 --- a/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx +++ b/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx @@ -22,20 +22,28 @@ const DryRunTitleBar = () => { const preview = useAppSelector(state => state.main.preview); const previewLabel = useAppSelector(dryRunLabelSelector); + const isLoading = useAppSelector(state => state.main.previewOptions.isLoading); + return ( - - - - preview && dispatch(restartPreview(preview))} /> - - - dispatch(stopPreview())} /> - + {preview?.type && ( + + )} + + {!isLoading && ( + <> + + preview && dispatch(restartPreview(preview))} /> + + + dispatch(stopPreview())} /> + + + )}
} description={} @@ -44,6 +52,7 @@ const DryRunTitleBar = () => { background: `${Colors.dryRun}20`, paddingTop: '5px', }} + actions={isLoading ? : null} /> ); diff --git a/src/components/organisms/NavigatorPane/NavigatorPane.tsx b/src/components/organisms/NavigatorPane/NavigatorPane.tsx index 0d7d16f095..cfe764d837 100644 --- a/src/components/organisms/NavigatorPane/NavigatorPane.tsx +++ b/src/components/organisms/NavigatorPane/NavigatorPane.tsx @@ -32,7 +32,7 @@ const NavPane: React.FC = () => { - ) : isInPreviewMode ? ( + ) : isInPreviewMode || isPreviewLoading ? ( ) : ( diff --git a/src/redux/hooks.ts b/src/redux/hooks.ts index 831ad648b5..cbb2fba01b 100644 --- a/src/redux/hooks.ts +++ b/src/redux/hooks.ts @@ -1,7 +1,11 @@ import {TypedUseSelectorHook, useDispatch, useSelector} from 'react-redux'; +import {TypedAddListener, addListener} from '@reduxjs/toolkit'; + import {AppDispatch} from '@shared/models/appDispatch'; import {RootState} from '@shared/models/rootState'; export const useAppDispatch = () => useDispatch(); export const useAppSelector: TypedUseSelectorHook = useSelector; + +export const addAppListener = addListener as TypedAddListener; diff --git a/src/redux/thunks/preview/startPreview.ts b/src/redux/thunks/preview/startPreview.ts index 013515e94b..099ec93adb 100644 --- a/src/redux/thunks/preview/startPreview.ts +++ b/src/redux/thunks/preview/startPreview.ts @@ -16,16 +16,16 @@ export const startPreview = createAsyncThunk Date: Fri, 6 Oct 2023 12:06:11 +0300 Subject: [PATCH 27/43] refactor: improved preview controls --- .../DryRunsPane/CommandRenderer.tsx | 3 +- .../DryRunsPane/HelmConfigRenderer.tsx | 3 +- .../DryRunsPane/HelmValueRenderer.tsx | 3 +- .../DryRunsPane/KustomizeRenderer.tsx | 6 ++-- .../ExplorerPane/DryRunsPane/styled.tsx | 7 ++++- .../DryRunsPane/usePreviewTrigger.tsx | 28 +++++++++++++++++-- .../NavigatorPane/DryRunTitleBar.tsx | 4 +-- 7 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/CommandRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/CommandRenderer.tsx index b5c0022c11..1f36fcac4a 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/CommandRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/CommandRenderer.tsx @@ -21,7 +21,7 @@ const CommandRenderer: React.FC = props => { state => state.main.preview?.type === 'command' && state.main.preview.commandId === command?.id ); const thisPreview: CommandPreview = {type: 'command', commandId: id}; - const {isOptimisticLoading, triggerPreview} = usePreviewTrigger(thisPreview); + const {isOptimisticLoading, triggerPreview, renderPreviewControls} = usePreviewTrigger(thisPreview); const mightBePreview = isPreviewed || isOptimisticLoading; const [isHovered, setIsHovered] = useState(false); @@ -41,6 +41,7 @@ const CommandRenderer: React.FC = props => { > {command.label} {isOptimisticLoading && } + {renderPreviewControls()} ); }; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx index a8779fdc5d..e4268c8317 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx @@ -20,7 +20,7 @@ const HelmConfigRenderer: React.FC = props => { state => state.main.preview?.type === 'helm-config' && state.main.preview.configId === previewConfiguration?.id ); const thisPreview: HelmConfigPreview = {type: 'helm-config', configId: id}; - const {isOptimisticLoading, triggerPreview} = usePreviewTrigger(thisPreview); + const {isOptimisticLoading, triggerPreview, renderPreviewControls} = usePreviewTrigger(thisPreview); const [isHovered, setIsHovered] = useState(false); const mightBePreview = isPreviewed || isOptimisticLoading; @@ -39,6 +39,7 @@ const HelmConfigRenderer: React.FC = props => { > {previewConfiguration.name} {isOptimisticLoading && } + {renderPreviewControls()} ); }; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmValueRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmValueRenderer.tsx index 1b2e6d63e0..63528bf6f5 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/HelmValueRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmValueRenderer.tsx @@ -21,7 +21,7 @@ const HelmValuesRenderer: React.FC = props => { state => state.main.preview?.type === 'helm' && state.main.preview?.valuesFileId === helmValues.id ); const thisPreview: HelmPreview = {type: 'helm', chartId: helmValues.helmChartId, valuesFileId: id}; - const {isOptimisticLoading, triggerPreview} = usePreviewTrigger(thisPreview); + const {isOptimisticLoading, triggerPreview, renderPreviewControls} = usePreviewTrigger(thisPreview); const mightBePreview = isPreviewed || isOptimisticLoading; const [isHovered, setIsHovered] = useState(false); @@ -39,6 +39,7 @@ const HelmValuesRenderer: React.FC = props => { > {helmValues.name} {isOptimisticLoading && } + {renderPreviewControls()} ); }; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/KustomizeRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/KustomizeRenderer.tsx index 3000ce3014..38df40cf37 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/KustomizeRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/KustomizeRenderer.tsx @@ -34,7 +34,7 @@ const KustomizeRenderer: React.FC = props => { type: 'kustomize', kustomizationId: identifier.id, }; - const {isOptimisticLoading, triggerPreview} = usePreviewTrigger(thisPreview); + const {isOptimisticLoading, triggerPreview, renderPreviewControls} = usePreviewTrigger(thisPreview); const mightBePreview = isPreviewed || isOptimisticLoading; const kustomizationName = useMemo(() => { @@ -66,19 +66,17 @@ const KustomizeRenderer: React.FC = props => { type="incoming" placeholderWidth={22} /> - {kustomizationName} - - {isOptimisticLoading && } + {renderPreviewControls()} ); }; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx index ce03b0e675..bcc06ea522 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx @@ -1,4 +1,4 @@ -import {ReloadOutlined} from '@ant-design/icons'; +import {CloseCircleOutlined, ReloadOutlined} from '@ant-design/icons'; import styled from 'styled-components'; @@ -88,3 +88,8 @@ export const ReloadIcon = styled(ReloadOutlined)` color: ${Colors.blackPure}; margin-left: 8px; `; + +export const CloseIcon = styled(CloseCircleOutlined)` + color: ${Colors.blackPure}; + margin-left: 8px; +`; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx index 344f38e20c..3fb6006a5d 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx @@ -1,18 +1,25 @@ import {useCallback, useEffect, useState} from 'react'; +import {Tooltip} from 'antd'; + import {AnyAction, isAnyOf, removeListener} from '@reduxjs/toolkit'; import {isEqual} from 'lodash'; +import {TOOLTIP_DELAY} from '@constants/constants'; + import {addAppListener, useAppDispatch, useAppSelector} from '@redux/hooks'; -import {startPreview} from '@redux/thunks/preview'; +import {restartPreview, startPreview, stopPreview} from '@redux/thunks/preview'; import {AnyPreview} from '@shared/models/preview'; +import * as S from './styled'; + export const usePreviewTrigger = (preview: AnyPreview) => { const dispatch = useAppDispatch(); const [isOptimisticLoading, setIsOptimisticLoading] = useState(false); const isPreviewLoading = useAppSelector(state => state.main.previewOptions.isLoading); + const isPreviewed = useAppSelector(state => isEqual(state.main.preview, preview)); // the reload of a preview can be triggered from multiple places, not only from where this hook is used // so we have to listen to startPreview in case our state is not up to date @@ -49,8 +56,25 @@ export const usePreviewTrigger = (preview: AnyPreview) => { dispatch(startPreview(preview)); }, [preview, dispatch, isPreviewLoading]); + const renderPreviewControls = useCallback(() => { + if (!isPreviewed) { + return null; + } + return ( + <> + + preview && dispatch(restartPreview(preview))} /> + + + dispatch(stopPreview())} /> + + + ); + }, [dispatch, isPreviewed, preview, isOptimisticLoading]); + return { triggerPreview, - isOptimisticLoading, + isOptimisticLoading: isPreviewed ? false : isOptimisticLoading, + renderPreviewControls, }; }; diff --git a/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx b/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx index 40e2f265f7..8710d08efa 100644 --- a/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx +++ b/src/components/organisms/NavigatorPane/DryRunTitleBar.tsx @@ -1,6 +1,6 @@ import {Tooltip} from 'antd'; -import {CloseCircleFilled, ReloadOutlined} from '@ant-design/icons'; +import {CloseCircleOutlined, ReloadOutlined} from '@ant-design/icons'; import styled from 'styled-components'; @@ -40,7 +40,7 @@ const DryRunTitleBar = () => { preview && dispatch(restartPreview(preview))} />
- dispatch(stopPreview())} /> + dispatch(stopPreview())} /> )} From 706639655cc695ad61fc038d0bf6e25f5ce4d2d2 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Fri, 6 Oct 2023 12:13:15 +0300 Subject: [PATCH 28/43] chore: update electron dependency --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2914f054a4..dbba6123f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,7 +135,7 @@ "concurrently": "8.0.1", "craco-less": "2.0.0", "cross-env": "7.0.3", - "electron": "26.2.2", + "electron": "26.3.0", "electron-builder": "24.6.4", "electron-reload": "2.0.0-alpha.1", "eslint-config-airbnb": "19.0.4", @@ -11524,9 +11524,9 @@ } }, "node_modules/electron": { - "version": "26.2.2", - "resolved": "https://registry.npmjs.org/electron/-/electron-26.2.2.tgz", - "integrity": "sha512-Ihb3Zt4XYnHF52DYSq17ySkgFqJV4OT0VnfhUYZASAql7Vembz3VsAq7mB3OALBHXltAW34P8BxTIwTqZaMS3g==", + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-26.3.0.tgz", + "integrity": "sha512-7ZpvSHu+jmqialSvywTZnOQZZGLqlyj+yV5HGDrEzFnMiFaXBRpbByHgoUhaExJ/8t/0xKQjKlMRAY65w+zNZQ==", "dev": true, "hasInstallScript": true, "dependencies": { diff --git a/package.json b/package.json index 6c27529607..08209a9c0d 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "concurrently": "8.0.1", "craco-less": "2.0.0", "cross-env": "7.0.3", - "electron": "26.2.2", + "electron": "26.3.0", "electron-builder": "24.6.4", "electron-reload": "2.0.0-alpha.1", "eslint-config-airbnb": "19.0.4", From 1f3befe16c403f0d905a642c4e38794e605ebcfd Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Fri, 6 Oct 2023 13:32:53 +0300 Subject: [PATCH 29/43] fix: selecting the file of current dry run --- .../DryRunsPane/usePreviewTrigger.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx index 3fb6006a5d..ee59d1025f 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/usePreviewTrigger.tsx @@ -9,6 +9,7 @@ import {isEqual} from 'lodash'; import {TOOLTIP_DELAY} from '@constants/constants'; import {addAppListener, useAppDispatch, useAppSelector} from '@redux/hooks'; +import {selectFile} from '@redux/reducers/main'; import {restartPreview, startPreview, stopPreview} from '@redux/thunks/preview'; import {AnyPreview} from '@shared/models/preview'; @@ -20,6 +21,15 @@ export const usePreviewTrigger = (preview: AnyPreview) => { const [isOptimisticLoading, setIsOptimisticLoading] = useState(false); const isPreviewLoading = useAppSelector(state => state.main.previewOptions.isLoading); const isPreviewed = useAppSelector(state => isEqual(state.main.preview, preview)); + const previewFilePath = useAppSelector(state => { + if (preview?.type === 'kustomize') { + return state.main.resourceMetaMapByStorage.local[preview.kustomizationId]?.origin.filePath; + } + if (preview?.type === 'helm') { + return state.main.helmValuesMap[preview.valuesFileId]?.filePath; + } + return undefined; + }); // the reload of a preview can be triggered from multiple places, not only from where this hook is used // so we have to listen to startPreview in case our state is not up to date @@ -49,12 +59,16 @@ export const usePreviewTrigger = (preview: AnyPreview) => { }, [isPreviewLoading]); const triggerPreview = useCallback(() => { - if (isPreviewLoading) { + if (previewFilePath) { + dispatch(selectFile({filePath: previewFilePath})); + } + + if (isPreviewed || isPreviewLoading) { return; } setIsOptimisticLoading(true); dispatch(startPreview(preview)); - }, [preview, dispatch, isPreviewLoading]); + }, [preview, dispatch, isPreviewed, isPreviewLoading, previewFilePath]); const renderPreviewControls = useCallback(() => { if (!isPreviewed) { From 0618e919d4db726047e66272d606f89c9fcbead2 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Fri, 6 Oct 2023 13:42:01 +0300 Subject: [PATCH 30/43] feat: context menu for helm chart dry runs --- .../ExplorerPane/DryRunsPane/DryRunsPane.tsx | 3 + .../DryRunsPane/HelmChartRenderer.tsx | 81 +++++++ .../DryRunsPane/HelmContextMenu.tsx | 215 ++++++++++++++++++ .../ExplorerPane/DryRunsPane/styled.tsx | 2 + src/redux/selectors/dryRunsSelectors.ts | 11 +- 5 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 src/components/organisms/ExplorerPane/DryRunsPane/HelmChartRenderer.tsx create mode 100644 src/components/organisms/ExplorerPane/DryRunsPane/HelmContextMenu.tsx diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx index 744c4bd66a..d13198a14a 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx @@ -17,6 +17,7 @@ import {Colors} from '@shared/styles/colors'; import {elementScroll, useVirtualizer} from '@tanstack/react-virtual'; import CommandRenderer from './CommandRenderer'; +import HelmChartRenderer from './HelmChartRenderer'; import HelmConfigRenderer from './HelmConfigRenderer'; import HelmValueRenderer from './HelmValueRenderer'; import KustomizeRenderer from './KustomizeRenderer'; @@ -125,6 +126,8 @@ const DryRunsPane: React.FC = () => { ) : node.type === 'kustomize' ? ( + ) : node.type === 'helm-chart' ? ( + ) : node.type === 'helm-values' ? ( ) : node.type === 'helm-config' ? ( diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmChartRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmChartRenderer.tsx new file mode 100644 index 0000000000..240471348e --- /dev/null +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmChartRenderer.tsx @@ -0,0 +1,81 @@ +import {memo, useMemo, useState} from 'react'; + +import styled from 'styled-components'; + +import {useAppDispatch, useAppSelector} from '@redux/hooks'; +import {selectFile} from '@redux/reducers/main'; + +import {Icon} from '@monokle/components'; +import {trackEvent} from '@shared/utils'; + +import HelmContextMenu from './HelmContextMenu'; + +import * as S from './styled'; + +type IProps = { + id: string; +}; + +const HelmChartRenderer: React.FC = props => { + const {id} = props; + + const dispatch = useAppDispatch(); + const helmChartMap = useAppSelector(state => state.main.helmChartMap); + const helmChart = useAppSelector(state => state.main.helmChartMap[id]); + + const [isHovered, setIsHovered] = useState(false); + + const chartName = useMemo(() => { + let name = helmChart.name; + let parentChart = helmChart.parentChartId ? helmChartMap[helmChart.parentChartId] : undefined; + while (parentChart) { + name = `${parentChart.name}/${name}`; + parentChart = parentChart.parentChartId ? helmChartMap[parentChart.parentChartId] : undefined; + } + + return name; + }, [helmChart, helmChartMap]); + + return ( + setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + onClick={() => { + dispatch(selectFile({filePath: helmChart.filePath})); + trackEvent('explore/select_chart'); + }} + > + + + {chartName} + + {isHovered && ( +
{ + e.stopPropagation(); + }} + > + + + +
+ )} +
+ ); +}; + +export default memo(HelmChartRenderer); + +const Heading = styled.span` + display: flex; + align-items: center; + gap: 10px; + padding-left: 8px; + font-size: 12px; + font-weight: 700; + color: #fff; + justify-content: left; +`; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmContextMenu.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmContextMenu.tsx new file mode 100644 index 0000000000..531c839acb --- /dev/null +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmContextMenu.tsx @@ -0,0 +1,215 @@ +import {useMemo} from 'react'; + +import {Modal, Tooltip} from 'antd'; + +import {ExclamationCircleOutlined} from '@ant-design/icons'; + +import path from 'path'; +import styled from 'styled-components'; + +import {useAppDispatch, useAppSelector} from '@redux/hooks'; +import {selectFile} from '@redux/reducers/main'; +import {setExplorerSelectedSection, setLeftMenuSelection} from '@redux/reducers/ui'; +import {runHelmCommand} from '@redux/thunks/runHelmCommand'; + +import {ContextMenu, Dots} from '@atoms'; + +import {useDuplicate, useRename} from '@hooks/fileTreeHooks'; + +import {deleteFileEntry, dispatchDeleteAlert} from '@utils/files'; + +import {ROOT_FILE_ENTRY} from '@shared/constants/fileEntry'; +import {HelmValuesFile} from '@shared/models/helm'; +import {Colors} from '@shared/styles/colors'; +import {isInClusterModeSelector, isInPreviewModeSelector} from '@shared/utils/selectors'; +import {showItemInFolder} from '@shared/utils/shell'; + +type IProps = { + id: string; + isSelected?: boolean; +}; + +// TODO: temporary solution for renaming value file +const DEFAULT_HELM_VALUE: HelmValuesFile = { + filePath: '', + id: '', + name: '', + helmChartId: '', + values: [], +}; + +const HelmContextMenu: React.FC = props => { + const {id, isSelected} = props; + + const dispatch = useAppDispatch(); + + const fileOrFolderContainedInFilter = useAppSelector(state => state.main.resourceFilter.fileOrFolderContainedIn); + const helmChartMap = useAppSelector(state => state.main.helmChartMap); + const helmTemplatesMap = useAppSelector(state => state.main.helmTemplatesMap); + const helmValuesMap = useAppSelector(state => state.main.helmValuesMap); + const isInClusterMode = useAppSelector(isInClusterModeSelector); + const isInPreviewMode = useAppSelector(isInPreviewModeSelector); + const osPlatform = useAppSelector(state => state.config.osPlatform); + const rootFolderPath = useAppSelector(state => state.main.fileMap[ROOT_FILE_ENTRY].filePath); + + const {onDuplicate} = useDuplicate(); + const {onRename} = useRename(); + + const helmItem = useMemo( + () => helmValuesMap[id] || helmChartMap[id] || helmTemplatesMap[id] || DEFAULT_HELM_VALUE, + [helmChartMap, helmTemplatesMap, helmValuesMap, id] + ); + + const fileEntry = useAppSelector(state => state.main.fileMap[helmItem.filePath]); + + const absolutePath = useMemo(() => path.join(rootFolderPath, helmItem.filePath), [rootFolderPath, helmItem]); + const basename = useMemo( + () => (osPlatform === 'win32' ? path.win32.basename(absolutePath) : path.basename(absolutePath)), + [absolutePath, osPlatform] + ); + const dirname = useMemo( + () => (osPlatform === 'win32' ? path.win32.dirname(absolutePath) : path.dirname(absolutePath)), + [absolutePath, osPlatform] + ); + const platformFileManagerName = useMemo(() => (osPlatform === 'darwin' ? 'Finder' : 'Explorer'), [osPlatform]); + + const menuItems = useMemo( + () => [ + helmChartMap[id] && { + key: 'update_dependencies', + label: Update Dependencies, + disabled: isInPreviewMode || isInClusterMode, + onClick: (): void => { + dispatch(runHelmCommand({chart: id, command: ['dependency', 'update']})); + }, + }, + helmChartMap[id] && {key: 'divider-1', type: 'divider'}, + { + key: 'show_file', + label: 'Go to file', + disabled: isInPreviewMode || isInClusterMode, + onClick: () => { + if (!helmItem) { + return; + } + + dispatch(setLeftMenuSelection('explorer')); + dispatch(setExplorerSelectedSection('files')); + dispatch(selectFile({filePath: helmItem.filePath})); + }, + }, + {key: 'divider-2', type: 'divider'}, + { + key: 'create_resource', + label: 'Add Resource', + disabled: true, + onClick: () => {}, + }, + {key: 'divider-3', type: 'divider'}, + { + key: 'filter_on_this_file', + label: + fileOrFolderContainedInFilter && helmItem.filePath === fileOrFolderContainedInFilter + ? 'Remove from filter' + : 'Filter on this file', + disabled: true, + onClick: () => {}, + }, + { + key: 'add_to_files_exclude', + label: 'Add to Files: Exclude', + disabled: true, + onClick: () => {}, + }, + {key: 'divider-4', type: 'divider'}, + { + key: 'copy_full_path', + label: 'Copy Path', + onClick: () => { + navigator.clipboard.writeText(absolutePath); + }, + }, + { + key: 'copy_relative_path', + label: 'Copy Relative Path', + onClick: () => { + navigator.clipboard.writeText(helmItem.filePath); + }, + }, + {key: 'divider-5', type: 'divider'}, + { + key: 'duplicate_entity', + label: 'Duplicate', + disabled: isInPreviewMode || isInClusterMode, + onClick: () => { + onDuplicate(absolutePath, basename, dirname); + }, + }, + { + key: 'rename_entity', + label: 'Rename', + disabled: isInPreviewMode || isInClusterMode, + onClick: () => { + onRename(absolutePath); + }, + }, + { + key: 'delete_entity', + label: 'Delete', + disabled: isInPreviewMode || isInClusterMode, + onClick: () => { + Modal.confirm({ + title: `Are you sure you want to delete "${basename}"?`, + icon: , + onOk() { + deleteFileEntry(fileEntry).then(result => dispatchDeleteAlert(dispatch, result)); + }, + }); + }, + }, + {key: 'divider-6', type: 'divider'}, + { + key: 'reveal_in_finder', + label: `Reveal in ${platformFileManagerName}`, + onClick: () => { + showItemInFolder(absolutePath); + }, + }, + ], + [ + absolutePath, + basename, + dirname, + dispatch, + fileOrFolderContainedInFilter, + helmItem, + helmChartMap, + isInPreviewMode, + isInClusterMode, + onDuplicate, + onRename, + platformFileManagerName, + fileEntry, + id, + ] + ); + + return ( + + + + + + ); +}; + +export default HelmContextMenu; + +// Styled Components + +const ActionsMenuIconContainer = styled.span<{isSelected?: boolean}>` + cursor: pointer; + padding: 8px; + display: flex; + align-items: center; +`; diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx index bcc06ea522..9d17526e9e 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx @@ -93,3 +93,5 @@ export const CloseIcon = styled(CloseCircleOutlined)` color: ${Colors.blackPure}; margin-left: 8px; `; + +export const ContextMenuContainer = styled.span``; diff --git a/src/redux/selectors/dryRunsSelectors.ts b/src/redux/selectors/dryRunsSelectors.ts index 7771c0e000..eb9ec84eeb 100644 --- a/src/redux/selectors/dryRunsSelectors.ts +++ b/src/redux/selectors/dryRunsSelectors.ts @@ -11,11 +11,16 @@ import {getResourceMetaMapFromState} from './resourceMapGetters'; type HeadingNode = { type: 'heading'; - icon: 'helm' | 'kustomize' | 'command'; + icon: 'kustomize' | 'command'; subtitle?: string; title: string; }; +type HelmChartNode = { + type: 'helm-chart'; + chartId: string; +}; + type HelmValuesNode = { type: 'helm-values'; chartId: string; @@ -41,7 +46,7 @@ type CommandNode = { commandName: string; }; -type DryRunNode = HeadingNode | HelmValuesNode | HelmConfigNode | KustomizeNode | CommandNode; +type DryRunNode = HeadingNode | HelmChartNode | HelmValuesNode | HelmConfigNode | KustomizeNode | CommandNode; const getKustomizeFolderInfo = (str: string) => { const parentFolder = basename(str); @@ -109,7 +114,7 @@ export const dryRunNodesSelector = createSelector( const helmCharts = Object.values(helmChartMap).sort((a, b) => a.name.localeCompare(b.name)); helmCharts.forEach(helmChart => { - list.push({type: 'heading', title: helmChart.name, icon: 'helm'}); + list.push({type: 'helm-chart', chartId: helmChart.id}); const helmValues = helmChart.valueFileIds.map(id => helmValuesMap[id]).filter(isDefined); helmValues.forEach(helmValue => { list.push({ From 7cb9071e733983aa9374eab033836f06e586b0a3 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:58:30 +0300 Subject: [PATCH 31/43] fix: preview & cluster states --- src/redux/reducers/main/mainSlice.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/redux/reducers/main/mainSlice.ts b/src/redux/reducers/main/mainSlice.ts index fc623b68d0..98b457c697 100644 --- a/src/redux/reducers/main/mainSlice.ts +++ b/src/redux/reducers/main/mainSlice.ts @@ -24,6 +24,7 @@ import {resetSelectionHistory} from '@redux/services/selectionHistory'; import {loadClusterResources, reloadClusterResources, stopClusterConnection} from '@redux/thunks/cluster'; import {multiplePathsAdded} from '@redux/thunks/multiplePathsAdded'; import {multiplePathsChanged} from '@redux/thunks/multiplePathsChanged'; +import {startPreview} from '@redux/thunks/preview'; import {removeResources} from '@redux/thunks/removeResources'; import {saveTransientResources} from '@redux/thunks/saveTransientResources'; import {setRootFolder} from '@redux/thunks/setRootFolder'; @@ -155,6 +156,13 @@ const addResourceReducer = (state: AppState, resource: K8sResource) => { resourceContentMap[content.id] = content; }; +const stopClusterConnectionReducer = (state: Draft) => { + resetSelectionHistory(state); + clearSelectionReducer(state); + state.clusterConnectionOptions.isLoading = false; + state.clusterConnection = undefined; +}; + export const mainSlice = createSlice({ name: 'main', initialState: initialState.main, @@ -360,6 +368,8 @@ export const mainSlice = createSlice({ state.clusterConnectionOptions.isLoading = true; }) .addCase(loadClusterResources.fulfilled, (state, action) => { + clearPreviewReducer(state); + state.clusterConnectionOptions.isLoading = false; resetSelectionHistory(state); clearSelectionReducer(state); @@ -417,10 +427,11 @@ export const mainSlice = createSlice({ }); builder.addCase(stopClusterConnection.fulfilled, state => { - resetSelectionHistory(state); - clearSelectionReducer(state); - state.clusterConnectionOptions.isLoading = false; - state.clusterConnection = undefined; + stopClusterConnectionReducer(state); + }); + + builder.addCase(startPreview.fulfilled, state => { + stopClusterConnectionReducer(state); }); builder.addCase(setRootFolder.pending, state => { From e2103033432951f1b47e9e20c194e361aef979ec Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:58:41 +0300 Subject: [PATCH 32/43] fix: titlebars styling --- src/components/atoms/StyledComponents/TitleBarWrapper.tsx | 7 +++++-- .../organisms/ActionsPane/ActionsPane.styled.tsx | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/atoms/StyledComponents/TitleBarWrapper.tsx b/src/components/atoms/StyledComponents/TitleBarWrapper.tsx index e6546344d3..f1527eb07b 100644 --- a/src/components/atoms/StyledComponents/TitleBarWrapper.tsx +++ b/src/components/atoms/StyledComponents/TitleBarWrapper.tsx @@ -1,11 +1,14 @@ import styled from 'styled-components'; export const TitleBarWrapper = styled.div<{$editor?: boolean; $navigator?: boolean}>` - padding: 20px 20px 10px 20px; + padding: 16px 20px 0px 16px; ${({$editor, $navigator}) => { if ($editor) { - return `padding-bottom: 6px;`; + return ` + padding-bottom: 6px; + padding-right: 16px; + `; } if ($navigator) { diff --git a/src/components/organisms/ActionsPane/ActionsPane.styled.tsx b/src/components/organisms/ActionsPane/ActionsPane.styled.tsx index 84d10384eb..bc92b66ea1 100644 --- a/src/components/organisms/ActionsPane/ActionsPane.styled.tsx +++ b/src/components/organisms/ActionsPane/ActionsPane.styled.tsx @@ -53,7 +53,7 @@ export const Tabs = styled(RawTabs)<{$height: number}>` width: 100%; height: ${({$height}) => `${$height}px`}; overflow: visible; - padding: 0px 20px 0px 20px; + padding: 0px 16px 0px 16px; margin-top: -10px; & .ant-tabs-nav { From 439b63333779ead3ec9f8fabdeb0a4579ceaf5a8 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Mon, 9 Oct 2023 14:08:46 +0300 Subject: [PATCH 33/43] fix: cloud policy polling --- src/redux/validation/validation.hooks.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/redux/validation/validation.hooks.ts b/src/redux/validation/validation.hooks.ts index 4c6d83afa8..e04e102f1f 100644 --- a/src/redux/validation/validation.hooks.ts +++ b/src/redux/validation/validation.hooks.ts @@ -30,7 +30,9 @@ export const pollCloudPolicy = async (state: RootState, dispatch: AppDispatch) = const previousCloudPolicy = state.validation.cloudPolicy; if (!cloudPolicy) { - dispatch(setCloudPolicy(undefined)); + if (previousCloudPolicy) { + dispatch(setCloudPolicy(undefined)); + } return; } @@ -45,6 +47,7 @@ export const pollCloudPolicy = async (state: RootState, dispatch: AppDispatch) = title: 'Repository connected to Cloud Project', message: 'This repository has been connected successfully to a Cloud Project. The Policy is now being synchronized.', + silent: true, }) ); } else { @@ -53,6 +56,7 @@ export const pollCloudPolicy = async (state: RootState, dispatch: AppDispatch) = type: AlertEnum.Success, title: 'Cloud Policy updated', message: 'The Policy has been changed in the Cloud Project and is now being synchronized.', + silent: true, }) ); } @@ -93,8 +97,7 @@ export const useCloudPolicy = () => { useInterval(() => { pollCloudPolicy(store.getState(), dispatch); - updateProjectInfo(); - }, 10 * 1000); + }, 20 * 1000); return {cloudPolicy, projectInfo, policyInfo}; }; From fa087780d6ea635f73ac954883e3dc045a84b077 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Mon, 9 Oct 2023 14:51:59 +0300 Subject: [PATCH 34/43] refactor: dry runs hoverable new button --- .../atoms/HoverableButton/HoverableButton.tsx | 27 +++++++++++++++++++ src/components/atoms/HoverableButton/index.ts | 1 + .../StyledComponents/TitleBarWrapper.tsx | 2 +- .../ExplorerPane/DryRunsPane/DryRunsPane.tsx | 15 ++++++++--- 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 src/components/atoms/HoverableButton/HoverableButton.tsx create mode 100644 src/components/atoms/HoverableButton/index.ts diff --git a/src/components/atoms/HoverableButton/HoverableButton.tsx b/src/components/atoms/HoverableButton/HoverableButton.tsx new file mode 100644 index 0000000000..61994ef90c --- /dev/null +++ b/src/components/atoms/HoverableButton/HoverableButton.tsx @@ -0,0 +1,27 @@ +import {PropsWithChildren, forwardRef, useMemo, useState} from 'react'; + +import {Button, ButtonProps} from 'antd'; + +type Props = PropsWithChildren< + ButtonProps & { + hoverProps?: ButtonProps; + } +>; + +const HoverableButton = forwardRef((props, ref) => { + const {hoverProps = {}, children, ...buttonProps} = props; + const [isHovered, setIsHovered] = useState(false); + + const thisProps = useMemo( + () => (isHovered ? {...buttonProps, ...hoverProps} : buttonProps), + [isHovered, buttonProps, hoverProps] + ); + + return ( + + ); +}); + +export default HoverableButton; diff --git a/src/components/atoms/HoverableButton/index.ts b/src/components/atoms/HoverableButton/index.ts new file mode 100644 index 0000000000..3188b3fc60 --- /dev/null +++ b/src/components/atoms/HoverableButton/index.ts @@ -0,0 +1 @@ +export {default} from './HoverableButton'; diff --git a/src/components/atoms/StyledComponents/TitleBarWrapper.tsx b/src/components/atoms/StyledComponents/TitleBarWrapper.tsx index f1527eb07b..9bc8b085f6 100644 --- a/src/components/atoms/StyledComponents/TitleBarWrapper.tsx +++ b/src/components/atoms/StyledComponents/TitleBarWrapper.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; export const TitleBarWrapper = styled.div<{$editor?: boolean; $navigator?: boolean}>` - padding: 16px 20px 0px 16px; + padding: 16px 20px 10px 16px; ${({$editor, $navigator}) => { if ($editor) { diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx index d13198a14a..a12ca8fe97 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx @@ -1,6 +1,6 @@ import {useLayoutEffect, useRef} from 'react'; -import {Button, Dropdown, Skeleton} from 'antd'; +import {Dropdown, Skeleton} from 'antd'; import {CodeOutlined} from '@ant-design/icons'; @@ -11,6 +11,7 @@ import {useAppSelector} from '@redux/hooks'; import {dryRunNodesSelector} from '@redux/selectors/dryRunsSelectors'; import {TitleBarWrapper} from '@components/atoms'; +import HoverableButton from '@components/atoms/HoverableButton'; import {Icon, TitleBar} from '@monokle/components'; import {Colors} from '@shared/styles/colors'; @@ -87,7 +88,15 @@ const DryRunsPane: React.FC = () => { actions={
- + New @@ -200,6 +209,6 @@ const Prefix = styled.span` color: ${Colors.grey6}; `; -const NewButton = styled(Button)` +const NewButton = styled(HoverableButton)` font-size: 12px; `; From 661c977203470c7b6d250121d52871ae0932cb45 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:48:49 +0300 Subject: [PATCH 35/43] refactor: empty display for dry runs --- .../ExplorerPane/DryRunsPane/DryRunsPane.tsx | 121 ++++++++++-------- 1 file changed, 71 insertions(+), 50 deletions(-) diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx index a12ca8fe97..550622be83 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/DryRunsPane.tsx @@ -2,7 +2,7 @@ import {useLayoutEffect, useRef} from 'react'; import {Dropdown, Skeleton} from 'antd'; -import {CodeOutlined} from '@ant-design/icons'; +import {CloseCircleFilled, CodeOutlined} from '@ant-design/icons'; import {size} from 'lodash'; import styled from 'styled-components'; @@ -73,10 +73,6 @@ const DryRunsPane: React.FC = () => { ); } - if (!size(list)) { - return No Dry runs found in the current project.; - } - return ( @@ -104,51 +100,61 @@ const DryRunsPane: React.FC = () => { } /> - -
- {rowVirtualizer.getVirtualItems().map(virtualItem => { - const node = list[virtualItem.index]; - - if (!node) { - return null; - } - - return ( - - {node.type === 'heading' ? ( - - {node.icon === 'command' ? : } - {node.title.trim() !== '' && {node.title}} - {node.subtitle && {node.subtitle}} - - ) : node.type === 'kustomize' ? ( - - ) : node.type === 'helm-chart' ? ( - - ) : node.type === 'helm-values' ? ( - - ) : node.type === 'helm-config' ? ( - - ) : node.type === 'command' ? ( - - ) : null} - - ); - })} -
-
+ {!size(list) ? ( + + +

+ No dry runs available for this repository. Dry runs allow you to simulate the + installation of a chart or other component without actually creating any resources in the cluster. +

+
+ ) : ( + +
+ {rowVirtualizer.getVirtualItems().map(virtualItem => { + const node = list[virtualItem.index]; + + if (!node) { + return null; + } + + return ( + + {node.type === 'heading' ? ( + + {node.icon === 'command' ? : } + {node.title.trim() !== '' && {node.title}} + {node.subtitle && {node.subtitle}} + + ) : node.type === 'kustomize' ? ( + + ) : node.type === 'helm-chart' ? ( + + ) : node.type === 'helm-values' ? ( + + ) : node.type === 'helm-config' ? ( + + ) : node.type === 'command' ? ( + + ) : null} + + ); + })} +
+
+ )}
); }; @@ -212,3 +218,18 @@ const Prefix = styled.span` const NewButton = styled(HoverableButton)` font-size: 12px; `; + +const BoldSpan = styled.span` + font-weight: 700; +`; + +const EmptyContainer = styled.div` + padding: 0 20px; + color: ${Colors.grey7}; +`; + +const EmptyIcon = styled(CloseCircleFilled)` + color: ${Colors.grey6}; + font-size: 24px; + padding: 8px 0; +`; From 183068678d2c36e9bd63d36e914f1c913dd2d128 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:58:46 +0300 Subject: [PATCH 36/43] chore: remove old HelmPane --- .../ExplorerPane/HelmPane/HelmList.tsx | 103 ------------------ .../ExplorerPane/HelmPane/HelmPane.tsx | 42 ------- .../organisms/ExplorerPane/HelmPane/index.ts | 1 - .../ExplorerPane/HelmPane/useScroll.ts | 55 ---------- 4 files changed, 201 deletions(-) delete mode 100644 src/components/organisms/ExplorerPane/HelmPane/HelmList.tsx delete mode 100644 src/components/organisms/ExplorerPane/HelmPane/HelmPane.tsx delete mode 100644 src/components/organisms/ExplorerPane/HelmPane/index.ts delete mode 100644 src/components/organisms/ExplorerPane/HelmPane/useScroll.ts diff --git a/src/components/organisms/ExplorerPane/HelmPane/HelmList.tsx b/src/components/organisms/ExplorerPane/HelmPane/HelmList.tsx deleted file mode 100644 index 9baa3a2751..0000000000 --- a/src/components/organisms/ExplorerPane/HelmPane/HelmList.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import {useRef} from 'react'; - -import {Skeleton} from 'antd'; - -import {size} from 'lodash'; -import styled from 'styled-components'; - -import {useAppSelector} from '@redux/hooks'; -import {helmChartListSelector} from '@redux/selectors/helmSelectors'; - -import {Colors} from '@shared/styles/colors'; -import {elementScroll, useVirtualizer} from '@tanstack/react-virtual'; - -import {useScroll} from './useScroll'; - -const ROW_HEIGHT = 26; - -const HelmList: React.FC = () => { - const list = useAppSelector(helmChartListSelector); - const ref = useRef(null); - const isLoading = useAppSelector(state => state.ui.isFolderLoading); - - const rowVirtualizer = useVirtualizer({ - count: list.length, - estimateSize: () => ROW_HEIGHT, - getScrollElement: () => ref.current, - scrollToFn: elementScroll, - }); - - useScroll({ - list, - scrollTo: index => - rowVirtualizer.scrollToIndex(index, { - align: 'center', - behavior: 'smooth', - }), - }); - - if (isLoading) { - return ( -
- -
- ); - } - - if (!size(list)) { - return No Helm Charts found in the current project.; - } - - return ( - -
- {rowVirtualizer.getVirtualItems().map(virtualItem => { - const node = list[virtualItem.index]; - - if (!node) { - return null; - } - - return ( - - ); - })} -
-
- ); -}; - -export default HelmList; - -// Styled Components - -const EmptyText = styled.div` - padding: 16px; - color: ${Colors.grey8}; -`; - -const ListContainer = styled.ul` - height: 100%; - overflow-y: auto; - padding: 0px 0px 12px; -`; - -const VirtualItem = styled.div` - position: absolute; - top: 0; - left: 0; - width: 100%; - overflow: hidden; -`; diff --git a/src/components/organisms/ExplorerPane/HelmPane/HelmPane.tsx b/src/components/organisms/ExplorerPane/HelmPane/HelmPane.tsx deleted file mode 100644 index 956d821c3c..0000000000 --- a/src/components/organisms/ExplorerPane/HelmPane/HelmPane.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import {memo} from 'react'; - -import {CollapsePanelProps} from 'antd'; - -import {useAppSelector} from '@redux/hooks'; -import {helmChartsCountSelector} from '@redux/selectors'; - -import {AccordionPanel} from '@components/atoms'; - -import {TitleBar, TitleBarCount} from '@monokle/components'; -import {InjectedPanelProps} from '@shared/models/explorer'; -import {isInClusterModeSelector} from '@shared/utils/selectors'; - -import HelmList from './HelmList'; - -const HelmPane: React.FC = props => { - const {isActive, panelKey} = props; - - const isInClusterMode = useAppSelector(isInClusterModeSelector); - const helmChartsCount = useAppSelector(helmChartsCountSelector); - - return ( - } - /> - } - showArrow={false} - key={panelKey as CollapsePanelProps['key']} - > - - - ); -}; - -export default memo(HelmPane); diff --git a/src/components/organisms/ExplorerPane/HelmPane/index.ts b/src/components/organisms/ExplorerPane/HelmPane/index.ts deleted file mode 100644 index c2c4ae1cbe..0000000000 --- a/src/components/organisms/ExplorerPane/HelmPane/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default} from './HelmPane'; diff --git a/src/components/organisms/ExplorerPane/HelmPane/useScroll.ts b/src/components/organisms/ExplorerPane/HelmPane/useScroll.ts deleted file mode 100644 index bd63fb1fd6..0000000000 --- a/src/components/organisms/ExplorerPane/HelmPane/useScroll.ts +++ /dev/null @@ -1,55 +0,0 @@ -import {useLayoutEffect, useMemo, useRef} from 'react'; -import {usePrevious} from 'react-use'; - -import {useRefSelector, useSelectorWithRef} from '@utils/hooks'; - -import {HelmListNode} from '@shared/models/helm'; -import {isEqual} from '@shared/utils/isEqual'; - -type ScrollType = { - list: HelmListNode[]; - scrollTo: (index: number) => void; -}; - -export function useScroll({scrollTo, list}: ScrollType) { - const [selection, selectionRef] = useSelectorWithRef(state => state.main.selection); - const previousSelection = usePrevious(selection); - const changed = useMemo(() => !isEqual(selection, previousSelection), [selection, previousSelection]); - const highlightsRef = useRefSelector(state => state.main.highlights); - const listRef = useRef(list); - listRef.current = list; - const scrollToRef = useRef(scrollTo); - scrollToRef.current = scrollTo; - - useLayoutEffect(() => { - if (!selectionRef.current || !changed) { - return; - } - - let helmChartFilePathToScrollTo: string | undefined; - let helmValueIdToScrollTo: string | undefined; - - // helm chart - if (selectionRef.current.type === 'file') { - helmChartFilePathToScrollTo = selectionRef.current.filePath; - } - - // helm value - if (selectionRef.current.type === 'helm.values.file') { - helmValueIdToScrollTo = selectionRef.current.valuesFileId; - } - - let index: number = -1; - - if (helmChartFilePathToScrollTo) { - index = listRef.current.findIndex( - item => item.type === 'helm-chart' && item.filePath === helmChartFilePathToScrollTo - ); - } else if (helmValueIdToScrollTo) { - index = listRef.current.findIndex(item => item.type === 'helm-value' && item.id === helmValueIdToScrollTo); - } - - if (index === -1) return; - scrollToRef.current(index); - }, [changed, highlightsRef, selectionRef]); -} From a363eb3bd371226c36002c3df74a21f119cd6253 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:58:58 +0300 Subject: [PATCH 37/43] chore: remove old ImagesPane --- .../ImagesPane/ImageFilteredTag.tsx | 51 --------- .../ImageOutgoingResourcesPopover.styled.tsx | 49 -------- .../ImageOutgoingResourcesPopover.tsx | 87 -------------- .../ImageRenderer/ImageQuickAction.tsx | 47 -------- .../ImageRenderer/ImageRenderer.styled.tsx | 86 -------------- .../ImageRenderer/ImageRenderer.tsx | 52 --------- .../ImagesPane/ImageRenderer/ImageSuffix.tsx | 50 -------- .../ExplorerPane/ImagesPane/ImageSearch.tsx | 30 ----- .../ExplorerPane/ImagesPane/ImagesList.tsx | 107 ------------------ .../ExplorerPane/ImagesPane/ImagesPane.tsx | 61 ---------- .../ExplorerPane/ImagesPane/index.ts | 1 - .../ExplorerPane/ImagesPane/useScroll.tsx | 48 -------- 12 files changed, 669 deletions(-) delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImageFilteredTag.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageOutgoingResourcesPopover.styled.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageOutgoingResourcesPopover.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageQuickAction.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageRenderer.styled.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageRenderer.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageSuffix.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImageSearch.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImagesList.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/ImagesPane.tsx delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/index.ts delete mode 100644 src/components/organisms/ExplorerPane/ImagesPane/useScroll.tsx diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImageFilteredTag.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImageFilteredTag.tsx deleted file mode 100644 index 2bb20bcadf..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImageFilteredTag.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import {rgba} from 'polished'; -import styled from 'styled-components'; - -import {kubeConfigContextColorSelector} from '@redux/appConfig'; -import {useAppSelector} from '@redux/hooks'; - -import {ClusterColors} from '@shared/models/cluster'; -import {BackgroundColors, Colors} from '@shared/styles/colors'; -import {isInClusterModeSelector, isInPreviewModeSelector} from '@shared/utils/selectors'; - -const ImageFilteredTag: React.FC = () => { - const isInClusterMode = useAppSelector(isInClusterModeSelector); - const isInPreviewMode = useAppSelector(isInPreviewModeSelector); - const kubeConfigContextColor = useAppSelector(kubeConfigContextColorSelector); - - if (isInClusterMode) { - return ( - Filtered by Cluster Mode - ); - } - - if (isInPreviewMode) { - return Filtered By Dry-run; - } - - return null; -}; - -export default ImageFilteredTag; - -// Styled Components - -const OutputTag = styled.div` - font-size: 12px; - border-radius: 4px; - padding: 0px 5px; - width: max-content; - margin-top: 10px; -`; - -const ClusterOutputTag = styled(OutputTag)<{$kubeConfigContextColor: ClusterColors}>` - ${({$kubeConfigContextColor}) => ` - color: ${$kubeConfigContextColor || Colors.volcano8}; - background: ${rgba($kubeConfigContextColor || Colors.volcano8, 0.2)}; - `} -`; - -const PreviewOutputTag = styled(OutputTag)` - color: ${BackgroundColors.previewModeBackground}; - background: ${rgba(BackgroundColors.previewModeBackground, 0.2)}; -`; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageOutgoingResourcesPopover.styled.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageOutgoingResourcesPopover.styled.tsx deleted file mode 100644 index 3dee281701..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageOutgoingResourcesPopover.styled.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import {Divider as RawDivider, Typography} from 'antd'; - -import styled from 'styled-components'; - -import {Colors, FontColors} from '@shared/styles/colors'; - -export const Container = styled.div` - margin: 0; - padding: 0 8px; - max-height: 350px; - overflow-y: auto; -`; - -export const Divider = styled(RawDivider)` - margin: 5px 0; -`; - -export const PopoverTitle = styled(Typography.Text)` - font-weight: 500; -`; - -export const PositionText = styled.span` - margin-left: 5px; - color: ${FontColors.grey}; -`; - -export const RefContainer = styled.div` - display: block; - margin: 5px 0; -`; - -export const RefLinkContainer = styled.div` - display: flex; - align-items: center; -`; - -export const ResourceKindLabel = styled.span` - margin-left: 8px; - font-style: italic; - color: ${Colors.grey7}; -`; - -export const ResourceNameLabel = styled.span` - cursor: pointer; - - &:hover { - text-decoration: underline; - } -`; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageOutgoingResourcesPopover.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageOutgoingResourcesPopover.tsx deleted file mode 100644 index 08673ed393..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageOutgoingResourcesPopover.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import {useMemo} from 'react'; - -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {selectResource} from '@redux/reducers/main'; -import {setMonacoEditor} from '@redux/reducers/ui'; -import {useActiveResourceMetaMap} from '@redux/selectors/resourceMapSelectors'; -import {isResourceSelected} from '@redux/services/resource'; - -import {getRefRange} from '@utils/refs'; - -import {ResourceRef} from '@monokle/validation'; -import {ResourceMeta} from '@shared/models/k8sResource'; - -import * as S from './ImageOutgoingResourcesPopover.styled'; - -interface IProps { - resourcesIds: string[]; -} - -const ImageOutgoingResourcesPopover: React.FC = ({resourcesIds}) => { - const dispatch = useAppDispatch(); - const activeResourceMetaMap = useActiveResourceMetaMap(); - const selection = useAppSelector(state => state.main.selection); - - const refs = useMemo(() => { - return resourcesIds.reduce((currentRefs: {[key: string]: ResourceRef[]}, id) => { - const resourceMeta = activeResourceMetaMap[id]; - const resourceRefs = resourceMeta?.refs; - - if (!resourceRefs) { - return currentRefs; - } - - const imageRefs = resourceRefs.filter(ref => ref.type === 'outgoing' && ref.target?.type === 'image'); - - if (imageRefs.length) { - currentRefs[id] = imageRefs; - } - - return currentRefs; - }, {}); - }, [activeResourceMetaMap, resourcesIds]); - - const handleOnResourceClick = ( - e: React.MouseEvent, - resource: ResourceMeta, - ref: ResourceRef - ) => { - e.stopPropagation(); - - if (!isResourceSelected(resource, selection)) { - dispatch(selectResource({resourceIdentifier: resource})); - } - - const refRange = getRefRange(ref); - - if (refRange) { - setImmediate(() => { - dispatch(setMonacoEditor({selection: {type: 'resource', resourceId: resource.id, range: refRange}})); - }); - } - }; - - return ( - - Resources Links - - {Object.entries(refs).map(([resourceId, resourceRefs]) => { - const resourceMeta = activeResourceMetaMap[resourceId]; - return resourceRefs.map(ref => ( - - - handleOnResourceClick(e, resourceMeta, ref)}> - {resourceMeta.name} - - - {resourceMeta.kind} - {ref.position && Ln {ref.position.line}} - - - )); - })} - - ); -}; - -export default ImageOutgoingResourcesPopover; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageQuickAction.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageQuickAction.tsx deleted file mode 100644 index ecbef3ef9d..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageQuickAction.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import styled from 'styled-components'; - -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {openReplaceImageModal} from '@redux/reducers/ui'; - -import {Colors} from '@shared/styles/colors'; -import {isInClusterModeSelector, isInPreviewModeSelector} from '@shared/utils/selectors'; - -type IProps = { - id: string; - isSelected: boolean; -}; - -const ImageQuickAction: React.FC = props => { - const {id, isSelected} = props; - - const dispatch = useAppDispatch(); - const isInPreviewMode = useAppSelector(isInPreviewModeSelector); - const isInClusterMode = useAppSelector(isInClusterModeSelector); - - const onReplaceHandler = () => { - if (isInPreviewMode || isInClusterMode) { - return; - } - - dispatch(openReplaceImageModal(id)); - }; - - return ( - - Replace - - ); -}; - -export default ImageQuickAction; - -// Styled Components - -export const ReplaceSpan = styled.span<{$isDisabled: boolean; $isSelected: boolean}>` - font-weight: 500; - font-size: 12px; - margin: 0 15px 0 auto; - color: ${({$isDisabled, $isSelected}) => - $isSelected ? Colors.blackPure : $isDisabled ? Colors.grey6 : Colors.blue6}; - cursor: ${({$isDisabled}) => ($isDisabled ? 'not-allowed' : 'pointer')}; -`; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageRenderer.styled.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageRenderer.styled.tsx deleted file mode 100644 index 4101c19e58..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageRenderer.styled.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import styled from 'styled-components'; - -import {Colors} from '@shared/styles/colors'; - -type ItemContainerProps = { - isSelected: boolean; - isHighlighted: boolean; - isHovered: boolean; -}; - -type ItemNameProps = { - isSelected: boolean; - isHighlighted?: boolean; - isDirty?: boolean; - isDisabled?: boolean; -}; - -export const ItemContainer = styled.span` - display: flex; - align-items: center; - width: 100%; - user-select: none; - > { - min-width: 0; - } - padding-left: 20px; - padding-right: 8px; - margin-bottom: 2px; - cursor: pointer; - ${props => { - if (!props.isSelected && props.isHighlighted) { - if (props.isHovered) { - return `background: ${Colors.highlightColorHover};`; - } - return `background: ${Colors.highlightColor};`; - } - if (props.isSelected) { - if (props.isHovered) { - return `background: ${Colors.selectionColorHover};`; - } - return `background: ${Colors.selectionColor};`; - } - if (props.isHovered) { - return `background: ${Colors.blackPearl};`; - } - }}; - ${props => !props.isHovered && 'padding-right: 46px;'} -`; - -export const ItemName = styled.div` - padding: 2px 0; - font-size: 12px; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - ${props => { - if (props.isSelected) { - return `font-weight: 700;`; - } - if (props.isHighlighted) { - return `font-weight: 500;`; - } - }}; - ${props => { - if (props.isDisabled) { - return `color: ${Colors.grey7};`; - } - if (!props.isSelected && props.isDirty) { - return `color: ${Colors.yellow7};`; - } - if (!props.isSelected && props.isHighlighted) { - return `color: ${Colors.cyan7};`; - } - if (props.isSelected) { - return `color: ${Colors.blackPure};`; - } - return `color: ${Colors.blue10};`; - }}; -`; - -export const SuffixContainer = styled.span` - display: flex; - align-items: center; -`; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageRenderer.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageRenderer.tsx deleted file mode 100644 index 4180a0493b..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageRenderer.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import {memo, useState} from 'react'; - -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {selectImage} from '@redux/reducers/main'; -import {isImageHighlighted, isImageSelected} from '@redux/services/image'; - -import {trackEvent} from '@shared/utils'; - -import ImageQuickAction from './ImageQuickAction'; -import * as S from './ImageRenderer.styled'; -import ImageSuffix from './ImageSuffix'; - -type IProps = { - id: string; -}; - -const ImageRenderer: React.FC = props => { - const {id} = props; - - const dispatch = useAppDispatch(); - const image = useAppSelector(state => state.main.imageMap[id]); - const isHighlighted = useAppSelector(state => isImageHighlighted(id, state.main.highlights)); - const isSelected = useAppSelector(state => isImageSelected(id, state.main.selection)); - - const [isHovered, setIsHovered] = useState(false); - - return ( - setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - isHovered={isHovered} - isSelected={isSelected} - isHighlighted={isHighlighted} - onClick={() => { - dispatch(selectImage({imageId: id})); - trackEvent('explore/select_image'); - }} - > - - {id} - - - - - - - {isHovered && } - - ); -}; - -export default memo(ImageRenderer); diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageSuffix.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageSuffix.tsx deleted file mode 100644 index 61d1f3424b..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImageRenderer/ImageSuffix.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import {Popover} from 'antd'; - -import styled from 'styled-components'; - -import {Icon} from '@monokle/components'; -import {Colors, FontColors} from '@shared/styles/colors'; - -import ImageOutgoingResourcesPopover from './ImageOutgoingResourcesPopover'; - -type IProps = { - isSelected: boolean; - resourcesIds: string[]; -}; - -const ImageSuffix: React.FC = props => { - const {isSelected, resourcesIds} = props; - - return ( - - {resourcesIds.length} - - } - placement="rightTop" - > - - - - ); -}; - -export default ImageSuffix; - -// Styled Components - -export const Container = styled.div` - display: flex; - align-items: center; - gap: 8px; -`; - -export const Counter = styled.span<{$selected: boolean}>` - ${({$selected}) => ` - color: ${$selected ? Colors.blackPure : FontColors.grey}; - `} - - margin-left: 6px; - font-size: 12px; -`; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImageSearch.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImageSearch.tsx deleted file mode 100644 index 7a0a61a618..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImageSearch.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import {useState} from 'react'; -import {useDebounce} from 'react-use'; - -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {setImagesSearchedValue} from '@redux/reducers/main'; - -import {SearchInput} from '@monokle/components'; - -const ImageSearch: React.FC = () => { - const dispatch = useAppDispatch(); - const searchedValue = useAppSelector(state => state.main.imagesSearchedValue); - - const [value, setValue] = useState(searchedValue ?? ''); - - useDebounce( - () => { - if (value) { - dispatch(setImagesSearchedValue(value)); - } else { - dispatch(setImagesSearchedValue('')); - } - }, - 250, - [value] - ); - - return setValue(e.target.value)} />; -}; - -export default ImageSearch; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImagesList.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImagesList.tsx deleted file mode 100644 index 64e3d7aefd..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImagesList.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import {useRef} from 'react'; - -import {Skeleton} from 'antd'; - -import {size} from 'lodash'; -import styled from 'styled-components'; - -import {useAppSelector} from '@redux/hooks'; -import {imageListSelector} from '@redux/selectors/imageSelectors'; - -import {Colors} from '@shared/styles/colors'; -import {elementScroll, useVirtualizer} from '@tanstack/react-virtual'; - -import ImageRenderer from './ImageRenderer/ImageRenderer'; -import {useScroll} from './useScroll'; - -const ROW_HEIGHT = 23; - -const ImagesList: React.FC = () => { - const list = useAppSelector(imageListSelector); - const ref = useRef(null); - const isLoading = useAppSelector(state => state.ui.isFolderLoading); - - const rowVirtualizer = useVirtualizer({ - count: list.length, - estimateSize: () => ROW_HEIGHT, - getScrollElement: () => ref.current, - scrollToFn: elementScroll, - }); - - useScroll({ - list, - scrollTo: index => - rowVirtualizer.scrollToIndex(index, { - align: 'center', - behavior: 'smooth', - }), - }); - - if (isLoading) { - return ( -
- -
- ); - } - - if (!size(list)) { - return No images were found in the current project.; - } - - return ( - -
- {rowVirtualizer.getVirtualItems().map(virtualItem => { - const node = list[virtualItem.index]; - - if (!node) { - return null; - } - - return ( - - {node.type === 'image' ? : null} - - ); - })} -
-
- ); -}; - -export default ImagesList; - -// Styled Components - -const EmptyText = styled.div` - padding: 16px; - color: ${Colors.grey8}; -`; - -const ListContainer = styled.ul` - height: 100%; - overflow-y: auto; - padding: 0px 0px 12px; - margin-top: 15px; -`; - -const VirtualItem = styled.div` - position: absolute; - top: 0; - left: 0; - width: 100%; - overflow: hidden; -`; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/ImagesPane.tsx b/src/components/organisms/ExplorerPane/ImagesPane/ImagesPane.tsx deleted file mode 100644 index fa8b9d10c5..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/ImagesPane.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import {memo} from 'react'; - -import {CollapsePanelProps} from 'antd'; - -import {size} from 'lodash'; -import styled from 'styled-components'; - -import {useAppSelector} from '@redux/hooks'; - -import {AccordionPanel} from '@components/atoms'; - -import {TitleBar, TitleBarCount} from '@monokle/components'; -import {InjectedPanelProps} from '@shared/models/explorer'; -import {Colors} from '@shared/styles/colors'; - -import ImageFilteredTag from './ImageFilteredTag'; -import ImageSearch from './ImageSearch'; -import ImagesList from './ImagesList'; - -const ImagesPane: React.FC = props => { - const {isActive, panelKey} = props; - - const imageMap = useAppSelector(state => state.main.imageMap); - - return ( - } - /> - } - showArrow={false} - key={panelKey as CollapsePanelProps['key']} - > - - - - - - - - ); -}; - -export default memo(ImagesPane); - -// Styled Components - -const ImageTopContainer = styled.div` - width: 100%; - display: flex; - flex-direction: column; - gap: 20px; - padding: 2px 14px 16px 16px; - font-size: 12px; - color: ${Colors.grey9}; -`; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/index.ts b/src/components/organisms/ExplorerPane/ImagesPane/index.ts deleted file mode 100644 index 4d6fec494e..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default} from './ImagesPane'; diff --git a/src/components/organisms/ExplorerPane/ImagesPane/useScroll.tsx b/src/components/organisms/ExplorerPane/ImagesPane/useScroll.tsx deleted file mode 100644 index e8bca1b6c6..0000000000 --- a/src/components/organisms/ExplorerPane/ImagesPane/useScroll.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import {useLayoutEffect, useMemo, useRef} from 'react'; -import {usePrevious} from 'react-use'; - -import {useRefSelector, useSelectorWithRef} from '@utils/hooks'; - -import {ImageNode} from '@shared/models/appState'; -import {isImageSelection} from '@shared/models/selection'; -import {isEqual} from '@shared/utils/isEqual'; - -type ScrollType = { - list: ImageNode[]; - scrollTo: (index: number) => void; -}; - -export function useScroll({scrollTo, list}: ScrollType) { - const [selection, selectionRef] = useSelectorWithRef(state => state.main.selection); - const previousSelection = usePrevious(selection); - const changed = useMemo(() => !isEqual(selection, previousSelection), [selection, previousSelection]); - const highlightsRef = useRefSelector(state => state.main.highlights); - const listRef = useRef(list); - listRef.current = list; - const scrollToRef = useRef(scrollTo); - scrollToRef.current = scrollTo; - - useLayoutEffect(() => { - if (!selectionRef.current || !changed) { - return; - } - - let imageIdToScrollTo: string | undefined; - - if (selectionRef.current.type === 'resource') { - const firstImageHighlight = highlightsRef.current.find(h => h.type === 'image'); - if (isImageSelection(firstImageHighlight)) { - imageIdToScrollTo = firstImageHighlight.imageId; - } - } - - if (selectionRef.current.type === 'image') { - imageIdToScrollTo = selectionRef.current.imageId; - } - - const index = listRef.current.findIndex(item => item.type === 'image' && item.id === imageIdToScrollTo); - - if (index === -1) return; - scrollToRef.current(index); - }, [changed, highlightsRef, selectionRef]); -} From 7231547fe078d8fae4e26f2d8d04c8f069b922de Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:59:16 +0300 Subject: [PATCH 38/43] chore: remove old KustomizePane --- .../KustomizeHeaderRenderer.styled.tsx | 82 ------------ .../KustomizeHeaderRenderer.tsx | 85 ------------ .../KustomizeHeaderRenderer/index.ts | 1 - .../KustomizePane/KustomizeList.tsx | 121 ------------------ .../KustomizePane/KustomizePane.tsx | 42 ------ .../ExplorerPane/KustomizePane/index.ts | 1 - .../ExplorerPane/KustomizePane/useScroll.ts | 44 ------- 7 files changed, 376 deletions(-) delete mode 100644 src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/KustomizeHeaderRenderer.styled.tsx delete mode 100644 src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/KustomizeHeaderRenderer.tsx delete mode 100644 src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/index.ts delete mode 100644 src/components/organisms/ExplorerPane/KustomizePane/KustomizeList.tsx delete mode 100644 src/components/organisms/ExplorerPane/KustomizePane/KustomizePane.tsx delete mode 100644 src/components/organisms/ExplorerPane/KustomizePane/index.ts delete mode 100644 src/components/organisms/ExplorerPane/KustomizePane/useScroll.ts diff --git a/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/KustomizeHeaderRenderer.styled.tsx b/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/KustomizeHeaderRenderer.styled.tsx deleted file mode 100644 index 1c80bcc8de..0000000000 --- a/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/KustomizeHeaderRenderer.styled.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import styled from 'styled-components'; - -import {Colors, FontColors} from '@shared/styles/colors'; - -type NameProps = { - $isSelected?: boolean; - $isHighlighted?: boolean; -}; - -type NameContainerProps = { - isHovered?: boolean; - isCheckable?: boolean; -}; - -type SectionContainerProps = { - isSelected?: boolean; - isHighlighted?: boolean; - isHovered?: boolean; - isCollapsed?: boolean; -}; - -export const Name = styled.span` - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - padding-left: 20px; - font-weight: 600; - font-size: 15px; - - cursor: pointer; - - ${props => { - if (props.$isSelected) { - return `color: ${Colors.blackPure};`; - } - return `color: ${Colors.whitePure};`; - }} -`; - -export const KustomizationsCounter = styled.span<{selected: boolean}>` - margin-left: 8px; - font-size: 14px; - cursor: pointer; - ${props => (props.selected ? `color: ${Colors.blackPure};` : `color: ${FontColors.grey};`)} -`; - -export const NameContainer = styled.span` - display: flex; - align-items: center; - width: 100%; - height: 26px; - padding-left: 0; - ${props => !props.isHovered && 'padding-right: 30px;'} -`; - -export const SectionContainer = styled.li` - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - width: 100%; - cursor: pointer; - user-select: none; - ${props => { - if (!props.isSelected && props.isHighlighted) { - if (props.isHovered) { - return `background: ${Colors.highlightColorHover};`; - } - return `background: ${Colors.highlightColor};`; - } - if (props.isSelected) { - if (props.isHovered) { - return `background: ${Colors.selectionColorHover};`; - } - return `background: ${Colors.selectionColor};`; - } - if (props.isHovered) { - return `background: ${Colors.blackPearl};`; - } - }}; - height: 26px; -`; diff --git a/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/KustomizeHeaderRenderer.tsx b/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/KustomizeHeaderRenderer.tsx deleted file mode 100644 index a1e9c8a32e..0000000000 --- a/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/KustomizeHeaderRenderer.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import {memo, useCallback, useState} from 'react'; - -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {collapseKustomizeKinds, expandKustomizeKinds} from '@redux/reducers/ui'; -import {getResourceMetaFromState} from '@redux/selectors/resourceGetters'; -import {isKustomizationPatch} from '@redux/services/kustomize'; - -import {useSelectorWithRef} from '@utils/hooks'; - -import {KustomizeKindNode} from '@shared/models/kustomize'; -import {isEqual} from '@shared/utils/isEqual'; - -import * as S from './KustomizeHeaderRenderer.styled'; - -type IProps = { - node: KustomizeKindNode; -}; - -const KustomizeHeaderRenderer: React.FC = props => { - const { - node: {count, label, kind}, - } = props; - - const dispatch = useAppDispatch(); - const [isCollapsed, isCollapsedRef] = useSelectorWithRef(state => state.ui.collapsedKustomizeKinds.includes(kind)); - const isHighlighted = useAppSelector(state => - state.main.highlights.some(highlight => { - if (highlight.type !== 'resource') { - return false; - } - - const resourceMeta = getResourceMetaFromState(state, highlight.resourceIdentifier); - - if (!resourceMeta) { - return false; - } - - return resourceMeta.kind === kind && (kind !== 'Kustomization' ? isKustomizationPatch(resourceMeta) : true); - }) - ); - const isSelected = useAppSelector(state => { - if (state.main.selection?.type !== 'resource') { - return false; - } - - const resourceMeta = getResourceMetaFromState(state, state.main.selection.resourceIdentifier); - - if (!resourceMeta) { - return false; - } - - return resourceMeta.kind === kind && (kind !== 'Kustomization' ? isKustomizationPatch(resourceMeta) : true); - }); - - const [isHovered, setIsHovered] = useState(false); - - const toggleCollapse = useCallback(() => { - if (isCollapsedRef.current) { - dispatch(expandKustomizeKinds([kind])); - } else { - dispatch(collapseKustomizeKinds([kind])); - } - }, [kind, isCollapsedRef, dispatch]); - - return ( - setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - > - - - {label} - - - {count} - - - ); -}; - -export default memo(KustomizeHeaderRenderer, isEqual); diff --git a/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/index.ts b/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/index.ts deleted file mode 100644 index e4f0c3c5fa..0000000000 --- a/src/components/organisms/ExplorerPane/KustomizePane/KustomizeHeaderRenderer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default} from './KustomizeHeaderRenderer'; diff --git a/src/components/organisms/ExplorerPane/KustomizePane/KustomizeList.tsx b/src/components/organisms/ExplorerPane/KustomizePane/KustomizeList.tsx deleted file mode 100644 index c3d64bae62..0000000000 --- a/src/components/organisms/ExplorerPane/KustomizePane/KustomizeList.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import {useRef} from 'react'; - -import {Skeleton} from 'antd'; - -import {size} from 'lodash'; -import styled from 'styled-components'; - -import {useAppSelector} from '@redux/hooks'; -import {kustomizeListSelector} from '@redux/selectors/kustomizeSelectors'; - -import ResourceRenderer from '@components/organisms/NavigatorPane/ResourceRenderer'; - -import {Colors} from '@shared/styles/colors'; -import {elementScroll, useVirtualizer} from '@tanstack/react-virtual'; - -import KustomizeHeaderRenderer from './KustomizeHeaderRenderer'; -// import KustomizeRenderer from './KustomizeRenderer'; -import {useScroll} from './useScroll'; - -const ROW_HEIGHT = 26; - -const KustomizeList: React.FC = () => { - const list = useAppSelector(kustomizeListSelector); - const isLoading = useAppSelector(state => - Boolean(state.main.previewOptions.isLoading) && state.main.preview?.type !== 'kustomize' - ? true - : state.ui.isFolderLoading - ); - - const ref = useRef(null); - - const rowVirtualizer = useVirtualizer({ - count: list.length, - estimateSize: () => ROW_HEIGHT, - getScrollElement: () => ref.current, - scrollToFn: elementScroll, - }); - - useScroll({ - list, - scrollTo: index => - rowVirtualizer.scrollToIndex(index, { - align: 'center', - behavior: 'smooth', - }), - }); - - if (isLoading) { - return ( -
- -
- ); - } - - if (!size(list)) { - return No Kustomize Overlays found in the current project.; - } - - return ( - -
- {rowVirtualizer.getVirtualItems().map(virtualItem => { - const node = list[virtualItem.index]; - - if (!node) { - return null; - } - - return ( - - {node.type === 'kustomize-kind' ? ( - - ) : node.type === 'kustomize' ? ( - // -
- ) : node.type === 'kustomize-resource' ? ( - - ) : null} - - ); - })} -
- - ); -}; - -export default KustomizeList; - -// Styled Components - -const EmptyText = styled.div` - padding: 16px; - color: ${Colors.grey8}; -`; - -const ListContainer = styled.ul` - height: 100%; - overflow-y: auto; - padding: 0px 0px; -`; - -const VirtualItem = styled.div` - position: absolute; - top: 0; - left: 0; - width: 100%; - overflow: hidden; -`; diff --git a/src/components/organisms/ExplorerPane/KustomizePane/KustomizePane.tsx b/src/components/organisms/ExplorerPane/KustomizePane/KustomizePane.tsx deleted file mode 100644 index c5bf09fbc0..0000000000 --- a/src/components/organisms/ExplorerPane/KustomizePane/KustomizePane.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import {memo} from 'react'; - -import {CollapsePanelProps} from 'antd'; - -import {useAppSelector} from '@redux/hooks'; -import {kustomizationResourcesSelectors} from '@redux/selectors'; - -import {AccordionPanel} from '@components/atoms'; - -import {TitleBar, TitleBarCount} from '@monokle/components'; -import {InjectedPanelProps} from '@shared/models/explorer'; -import {isInClusterModeSelector} from '@shared/utils/selectors'; - -import KustomizeList from './KustomizeList'; - -const KustomizePane: React.FC = props => { - const {isActive, panelKey} = props; - - const isInClusterMode = useAppSelector(isInClusterModeSelector); - const kustomizationsResources = useAppSelector(kustomizationResourcesSelectors); - - return ( - } - /> - } - showArrow={false} - key={panelKey as CollapsePanelProps['key']} - > - - - ); -}; - -export default memo(KustomizePane); diff --git a/src/components/organisms/ExplorerPane/KustomizePane/index.ts b/src/components/organisms/ExplorerPane/KustomizePane/index.ts deleted file mode 100644 index 3e9130016c..0000000000 --- a/src/components/organisms/ExplorerPane/KustomizePane/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default} from './KustomizePane'; diff --git a/src/components/organisms/ExplorerPane/KustomizePane/useScroll.ts b/src/components/organisms/ExplorerPane/KustomizePane/useScroll.ts deleted file mode 100644 index a8b5046a5b..0000000000 --- a/src/components/organisms/ExplorerPane/KustomizePane/useScroll.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {useLayoutEffect, useMemo, useRef} from 'react'; -import {usePrevious} from 'react-use'; - -import {useRefSelector, useSelectorWithRef} from '@utils/hooks'; - -import {KustomizeListNode} from '@shared/models/kustomize'; -import {isResourceSelection} from '@shared/models/selection'; -import {isEqual} from '@shared/utils/isEqual'; - -export function useScroll({scrollTo, list}: {scrollTo: (index: number) => void; list: KustomizeListNode[]}) { - const [selection, selectionRef] = useSelectorWithRef(state => state.main.selection); - const previousSelection = usePrevious(selection); - const changed = useMemo(() => !isEqual(selection, previousSelection), [selection, previousSelection]); - const highlightsRef = useRefSelector(state => state.main.highlights); - const listRef = useRef(list); - listRef.current = list; - const scrollToRef = useRef(scrollTo); - scrollToRef.current = scrollTo; - - useLayoutEffect(() => { - if (!selectionRef.current || !changed) { - return; - } - - let resourceIdToScrollTo: string | undefined; - - if (selectionRef.current.type === 'resource') { - const firstResourceHighlight = highlightsRef.current.find(h => h.type === 'resource'); - if (isResourceSelection(firstResourceHighlight)) { - resourceIdToScrollTo = firstResourceHighlight.resourceIdentifier.id; - } - } - - if (selectionRef.current.type === 'resource') { - resourceIdToScrollTo = selectionRef.current.resourceIdentifier.id; - } - - const index = listRef.current.findIndex( - item => item.type !== 'kustomize-kind' && item.identifier.id === resourceIdToScrollTo - ); - if (index === -1) return; - scrollToRef.current(index); - }, [changed, selectionRef, highlightsRef]); -} From caf23fe55bedb96684cdc5bbd12631ab0c722dd4 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:02:15 +0300 Subject: [PATCH 39/43] chore: remove old PreviewConfigPane --- .../HelmChartRenderer/HelmChartCollapse.tsx | 40 -------- .../HelmChartRenderer.styled.tsx | 40 -------- .../HelmChartRenderer/HelmChartRenderer.tsx | 40 -------- .../HelmChartRenderer/index.ts | 1 - .../PreviewConfigurationAdd.tsx | 41 -------- .../PreviewConfigurationList.tsx | 96 ------------------- .../PreviewConfigurationPane.tsx | 76 --------------- .../PreviewConfigurationPane/index.ts | 1 - 8 files changed, 335 deletions(-) delete mode 100644 src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartCollapse.tsx delete mode 100644 src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartRenderer.styled.tsx delete mode 100644 src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartRenderer.tsx delete mode 100644 src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/index.ts delete mode 100644 src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationAdd.tsx delete mode 100644 src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationList.tsx delete mode 100644 src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationPane.tsx delete mode 100644 src/components/organisms/ExplorerPane/PreviewConfigurationPane/index.ts diff --git a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartCollapse.tsx b/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartCollapse.tsx deleted file mode 100644 index abc25bbfaf..0000000000 --- a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartCollapse.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import {useCallback} from 'react'; - -import {MinusSquareOutlined, PlusSquareOutlined} from '@ant-design/icons'; - -import {useAppDispatch, useAppSelector} from '@redux/hooks'; -import {collapsePreviewConfigurationsHelmChart, togglePreviewConfigurationsHelmChart} from '@redux/reducers/ui'; - -import {Colors} from '@shared/styles/colors'; - -type IProps = { - id: string; -}; - -const HelmChartCollapse: React.FC = props => { - const {id} = props; - - const dispatch = useAppDispatch(); - const isSectionCollapsed = useAppSelector(state => state.ui.collapsedPreviewConfigurationsHelmCharts.includes(id)); - - const onClickHandler = useCallback( - (e: React.MouseEvent) => { - e.stopPropagation(); - - if (isSectionCollapsed) { - dispatch(togglePreviewConfigurationsHelmChart(id)); - } else { - dispatch(collapsePreviewConfigurationsHelmChart(id)); - } - }, - [dispatch, id, isSectionCollapsed] - ); - - if (isSectionCollapsed) { - return ; - } - - return ; -}; - -export default HelmChartCollapse; diff --git a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartRenderer.styled.tsx b/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartRenderer.styled.tsx deleted file mode 100644 index 8ed86a39f3..0000000000 --- a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartRenderer.styled.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import styled from 'styled-components'; - -import {Colors} from '@shared/styles/colors'; - -export const ItemContainer = styled.span` - display: flex; - align-items: center; - width: 100%; - user-select: none; - > { - min-width: 0; - } - padding-left: 26px; - padding-right: 20px; - margin-bottom: 2px; -`; - -export const ItemName = styled.div` - padding: 2px 0; - font-size: 12px; - white-space: nowrap; - color: ${Colors.grey9}; -`; - -export const PrefixContainer = styled.span` - display: flex; - align-items: center; - gap: 8px; - margin-right: 7px; -`; - -export const SuffixContainer = styled.span` - min-width: 0; - color: ${Colors.grey6}; - margin-left: 8px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-size: 12px; -`; diff --git a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartRenderer.tsx b/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartRenderer.tsx deleted file mode 100644 index 5951e597ce..0000000000 --- a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/HelmChartRenderer.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import {Tooltip} from 'antd'; - -import {dirname} from 'path'; - -import {TOOLTIP_DELAY} from '@constants/constants'; - -import {useAppSelector} from '@redux/hooks'; - -import {Icon} from '@monokle/components'; -import {Colors} from '@shared/styles/colors'; - -import HelmChartCollapse from './HelmChartCollapse'; -import * as S from './HelmChartRenderer.styled'; - -type IProps = { - id: string; -}; - -const HelmChartRenderer: React.FC = props => { - const {id} = props; - - const helmChart = useAppSelector(state => state.main.helmChartMap[id]); - - return ( - - - - - - - {helmChart.name} - - - {dirname(helmChart.filePath)} - - - ); -}; - -export default HelmChartRenderer; diff --git a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/index.ts b/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/index.ts deleted file mode 100644 index 7516b3f858..0000000000 --- a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/HelmChartRenderer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default} from './HelmChartRenderer'; diff --git a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationAdd.tsx b/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationAdd.tsx deleted file mode 100644 index 00a6efc736..0000000000 --- a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationAdd.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import {Button, Tooltip} from 'antd'; - -import {PlusOutlined} from '@ant-design/icons'; - -import styled from 'styled-components'; - -import {TOOLTIP_DELAY} from '@constants/constants'; -import {NewPreviewConfigurationTooltip} from '@constants/tooltips'; - -import {useAppDispatch} from '@redux/hooks'; -import {openPreviewConfigurationEditor} from '@redux/reducers/main'; - -const PreviewConfigurationAdd: React.FC = () => { - const dispatch = useAppDispatch(); - - return ( - - } - onClick={() => { - dispatch(openPreviewConfigurationEditor({})); - }} - > - Create dry-run configuration - - - ); -}; - -export default PreviewConfigurationAdd; - -// Styled Components - -const AddButton = styled(Button)` - border-radius: 4px; - font-size: 13px; - padding-left: 11px; -`; diff --git a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationList.tsx b/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationList.tsx deleted file mode 100644 index 1ac19d5ee7..0000000000 --- a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationList.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import {useRef} from 'react'; - -import {Skeleton} from 'antd'; - -import {size} from 'lodash'; -import styled from 'styled-components'; - -import {useAppSelector} from '@redux/hooks'; -import {previewConfigurationListSelector} from '@redux/selectors/helmSelectors'; - -import {Colors} from '@shared/styles/colors'; -import {elementScroll, useVirtualizer} from '@tanstack/react-virtual'; - -import HelmChartRenderer from './HelmChartRenderer'; - -const ROW_HEIGHT = 26; - -const PreviewConfigurationList: React.FC = () => { - const list = useAppSelector(previewConfigurationListSelector); - const ref = useRef(null); - const isLoading = useAppSelector(state => state.ui.isFolderLoading); - - const rowVirtualizer = useVirtualizer({ - count: list.length, - estimateSize: () => ROW_HEIGHT, - getScrollElement: () => ref.current, - scrollToFn: elementScroll, - }); - - if (isLoading) { - return ( -
- -
- ); - } - - if (!size(list)) { - return No Dry-run Configurations found in the current project.; - } - - return ( - -
- {rowVirtualizer.getVirtualItems().map(virtualItem => { - const node = list[virtualItem.index]; - - if (!node) { - return null; - } - - return ( - - {node.type === 'preview-configuration-helm-chart' ? : null} - - ); - })} -
-
- ); -}; - -export default PreviewConfigurationList; - -// Styled Components - -const EmptyText = styled.div` - padding: 0px 14px 0px 16px; - color: ${Colors.grey8}; -`; - -const ListContainer = styled.ul` - height: 100%; - overflow-y: auto; - padding: 0px 0px 12px; -`; - -const VirtualItem = styled.div` - position: absolute; - top: 0; - left: 0; - width: 100%; - overflow: hidden; -`; diff --git a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationPane.tsx b/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationPane.tsx deleted file mode 100644 index bb659422a7..0000000000 --- a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/PreviewConfigurationPane.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import {memo, useMemo} from 'react'; - -import {CollapsePanelProps} from 'antd'; - -import {isEmpty, size} from 'lodash'; -import styled from 'styled-components'; - -import {useAppSelector} from '@redux/hooks'; - -import {AccordionPanel} from '@components/atoms'; - -import {TitleBar, TitleBarCount} from '@monokle/components'; -import {InjectedPanelProps} from '@shared/models/explorer'; -import {isDefined} from '@shared/utils/filter'; -import {isInClusterModeSelector} from '@shared/utils/selectors'; - -import PreviewConfigurationAdd from './PreviewConfigurationAdd'; -import PreviewConfigurationList from './PreviewConfigurationList'; - -const PreviewConfigurationPane: React.FC = props => { - const {isActive, panelKey} = props; - - const isInClusterMode = useAppSelector(isInClusterModeSelector); - const fileMap = useAppSelector(state => state.main.fileMap); - const previewConfigurationMap = useAppSelector(state => state.config.projectConfig?.helm?.previewConfigurationMap); - - const count = useMemo( - () => - isDefined(previewConfigurationMap) - ? size( - Object.values(previewConfigurationMap).filter( - previewConfiguration => - isDefined(previewConfiguration) && - !isEmpty(previewConfiguration) && - fileMap[previewConfiguration.helmChartFilePath] - ) - ) - : 0, - [fileMap, previewConfigurationMap] - ); - - return ( - } - /> - } - showArrow={false} - key={panelKey as CollapsePanelProps['key']} - > - - - - - - - ); -}; - -export default memo(PreviewConfigurationPane); - -// Styled Components - -const PreviewConfigurationTopContainer = styled.div` - width: 100%; - /* padding: 4px 14px 16px 16px; */ - margin-top: -6px; - padding-left: 20px; - padding-bottom: 12px; -`; diff --git a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/index.ts b/src/components/organisms/ExplorerPane/PreviewConfigurationPane/index.ts deleted file mode 100644 index 1b1d4b30e4..0000000000 --- a/src/components/organisms/ExplorerPane/PreviewConfigurationPane/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default} from './PreviewConfigurationPane'; From e2f55cda39223d8c190e0264eba78eedb944e82c Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:05:38 +0300 Subject: [PATCH 40/43] feat: edit action for dry run configs --- .../DryRunsPane/HelmConfigRenderer.tsx | 24 +++++++++++++++++-- .../ExplorerPane/DryRunsPane/styled.tsx | 7 +++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx index e4268c8317..ac4c48464c 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx @@ -1,6 +1,7 @@ -import {memo, useState} from 'react'; +import {memo, useCallback, useState} from 'react'; -import {useAppSelector} from '@redux/hooks'; +import {useAppDispatch, useAppSelector} from '@redux/hooks'; +import {openPreviewConfigurationEditor} from '@redux/reducers/main'; import {HelmConfigPreview} from '@shared/models/preview'; @@ -15,6 +16,8 @@ type IProps = { const HelmConfigRenderer: React.FC = props => { const {id} = props; + const dispatch = useAppDispatch(); + const previewConfiguration = useAppSelector(state => state.config.projectConfig?.helm?.previewConfigurationMap?.[id]); const isPreviewed = useAppSelector( state => state.main.preview?.type === 'helm-config' && state.main.preview.configId === previewConfiguration?.id @@ -24,6 +27,22 @@ const HelmConfigRenderer: React.FC = props => { const [isHovered, setIsHovered] = useState(false); const mightBePreview = isPreviewed || isOptimisticLoading; + const helmChart = useAppSelector(state => + previewConfiguration + ? Object.values(state.main.helmChartMap).find(h => h.filePath === previewConfiguration.helmChartFilePath) + : undefined + ); + + const onClickEdit = useCallback(() => { + if (!previewConfiguration || !helmChart) { + return; + } + + dispatch( + openPreviewConfigurationEditor({helmChartId: helmChart.id, previewConfigurationId: previewConfiguration.id}) + ); + }, [previewConfiguration, helmChart, dispatch]); + if (!previewConfiguration) { return null; } @@ -39,6 +58,7 @@ const HelmConfigRenderer: React.FC = props => { > {previewConfiguration.name} {isOptimisticLoading && } + {renderPreviewControls()} ); diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx index 9d17526e9e..28afbe8c40 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx @@ -1,4 +1,4 @@ -import {CloseCircleOutlined, ReloadOutlined} from '@ant-design/icons'; +import {CloseCircleOutlined, EditOutlined, ReloadOutlined} from '@ant-design/icons'; import styled from 'styled-components'; @@ -84,6 +84,11 @@ export const ItemName = styled.div` }}; `; +export const EditIcon = styled(EditOutlined)` + color: ${Colors.blackPure}; + margin-left: 8px; +`; + export const ReloadIcon = styled(ReloadOutlined)` color: ${Colors.blackPure}; margin-left: 8px; From 176566e6c7ebeec4f2ad9d1d923fdf5980f1d71e Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:08:48 +0300 Subject: [PATCH 41/43] fix: dry run config edit icon --- .../DryRunsPane/HelmConfigRenderer.tsx | 23 +++++++++++-------- .../ExplorerPane/DryRunsPane/styled.tsx | 4 ++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx index ac4c48464c..8837eb0410 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx @@ -33,15 +33,20 @@ const HelmConfigRenderer: React.FC = props => { : undefined ); - const onClickEdit = useCallback(() => { - if (!previewConfiguration || !helmChart) { - return; - } + const onClickEdit = useCallback>( + e => { + e.stopPropagation(); - dispatch( - openPreviewConfigurationEditor({helmChartId: helmChart.id, previewConfigurationId: previewConfiguration.id}) - ); - }, [previewConfiguration, helmChart, dispatch]); + if (!previewConfiguration || !helmChart) { + return; + } + + dispatch( + openPreviewConfigurationEditor({helmChartId: helmChart.id, previewConfigurationId: previewConfiguration.id}) + ); + }, + [previewConfiguration, helmChart, dispatch] + ); if (!previewConfiguration) { return null; @@ -58,7 +63,7 @@ const HelmConfigRenderer: React.FC = props => { > {previewConfiguration.name} {isOptimisticLoading && } - + {renderPreviewControls()} ); diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx index 28afbe8c40..6b41441f83 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx @@ -84,8 +84,8 @@ export const ItemName = styled.div` }}; `; -export const EditIcon = styled(EditOutlined)` - color: ${Colors.blackPure}; +export const EditIcon = styled(EditOutlined)<{$isPreviewed: boolean}>` + color: ${props => (props.$isPreviewed ? Colors.blackPure : Colors.blue6)}; margin-left: 8px; `; From 7fcc8d20a951b34dabd815f5f3910b12c058b0f9 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:15:01 +0300 Subject: [PATCH 42/43] feat: delete action for dry run config --- .../DryRunsPane/HelmConfigRenderer.tsx | 27 +++++++++++++++++-- .../ExplorerPane/DryRunsPane/styled.tsx | 7 ++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx index 8837eb0410..aa6471df6f 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/HelmConfigRenderer.tsx @@ -1,7 +1,12 @@ import {memo, useCallback, useState} from 'react'; +import {Popconfirm} from 'antd'; + +import {DeletePreviewConfigurationTooltip} from '@constants/tooltips'; + import {useAppDispatch, useAppSelector} from '@redux/hooks'; import {openPreviewConfigurationEditor} from '@redux/reducers/main'; +import {deletePreviewConfiguration} from '@redux/thunks/preview'; import {HelmConfigPreview} from '@shared/models/preview'; @@ -36,7 +41,6 @@ const HelmConfigRenderer: React.FC = props => { const onClickEdit = useCallback>( e => { e.stopPropagation(); - if (!previewConfiguration || !helmChart) { return; } @@ -48,6 +52,18 @@ const HelmConfigRenderer: React.FC = props => { [previewConfiguration, helmChart, dispatch] ); + const onClickDelete = useCallback<(e?: React.MouseEvent) => void>( + e => { + e?.stopPropagation(); + if (!previewConfiguration) { + return; + } + + dispatch(deletePreviewConfiguration(previewConfiguration.id)); + }, + [previewConfiguration, dispatch] + ); + if (!previewConfiguration) { return null; } @@ -63,7 +79,14 @@ const HelmConfigRenderer: React.FC = props => { > {previewConfiguration.name} {isOptimisticLoading && } - + {(isHovered || mightBePreview) && ( + <> + + + e.stopPropagation()} /> + + + )} {renderPreviewControls()} ); diff --git a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx index 6b41441f83..51feb61e67 100644 --- a/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx +++ b/src/components/organisms/ExplorerPane/DryRunsPane/styled.tsx @@ -1,4 +1,4 @@ -import {CloseCircleOutlined, EditOutlined, ReloadOutlined} from '@ant-design/icons'; +import {CloseCircleOutlined, DeleteOutlined, EditOutlined, ReloadOutlined} from '@ant-design/icons'; import styled from 'styled-components'; @@ -89,6 +89,11 @@ export const EditIcon = styled(EditOutlined)<{$isPreviewed: boolean}>` margin-left: 8px; `; +export const DeleteIcon = styled(DeleteOutlined)<{$isPreviewed: boolean}>` + color: ${props => (props.$isPreviewed ? Colors.blackPure : Colors.blue6)}; + margin-left: 8px; +`; + export const ReloadIcon = styled(ReloadOutlined)` color: ${Colors.blackPure}; margin-left: 8px; From 911ad18be7903476c8bc5442ca71184f54cd7da3 Mon Sep 17 00:00:00 2001 From: Dev Catalin <20538711+devcatalin@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:23:30 +0300 Subject: [PATCH 43/43] chore(release): 2.4.1 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80937fc39a..100ff5f77a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,35 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [2.4.1](https://github.com/kubeshop/monokle/compare/v2.4.1-nightly-2023-10-11.0...v2.4.1) (2023-10-11) + + +### Features + +* context menu for helm chart dry runs ([0618e91](https://github.com/kubeshop/monokle/commit/0618e919d4db726047e66272d606f89c9fcbead2)) +* delete action for dry run config ([7fcc8d2](https://github.com/kubeshop/monokle/commit/7fcc8d20a951b34dabd815f5f3910b12c058b0f9)) +* edit action for dry run configs ([e2f55cd](https://github.com/kubeshop/monokle/commit/e2f55cda39223d8c190e0264eba78eedb944e82c)) +* grouping for kustomizations ([f808a18](https://github.com/kubeshop/monokle/commit/f808a18521ea25f1fb473885323f0c198fec4b52)) +* new dropdown for dry run configs ([ec41b51](https://github.com/kubeshop/monokle/commit/ec41b513b373421943c459dffec4ebe81abf7592)) +* new selectors for dry runs ([105b89f](https://github.com/kubeshop/monokle/commit/105b89f44dd7b6c01b68e27b30567ac15e311e3f)) +* scroll to current dry run ([a6ae883](https://github.com/kubeshop/monokle/commit/a6ae88371f6c304d07355c211f5533ddbdeb840f)) +* show list of existing dry runs ([c37a98a](https://github.com/kubeshop/monokle/commit/c37a98ad772967a8a4e0b3a8247dc90aadfba521)) +* v1 of new DryRuns panel ([1b473d4](https://github.com/kubeshop/monokle/commit/1b473d4b34c6041d45066203327eb91d7e7fc0ef)) +* virtualization for dry runs pane ([e4fcf8a](https://github.com/kubeshop/monokle/commit/e4fcf8ab7dc99fa4eaddf248145433050c87349c)) + + +### Bug Fixes + +* cloud policy polling ([439b633](https://github.com/kubeshop/monokle/commit/439b63333779ead3ec9f8fabdeb0a4579ceaf5a8)) +* dry run config edit icon ([176566e](https://github.com/kubeshop/monokle/commit/176566e6c7ebeec4f2ad9d1d923fdf5980f1d71e)) +* dry run title bar label ([02e124b](https://github.com/kubeshop/monokle/commit/02e124b97e233f39e1b860075eb6615269e2fbe3)) +* ellipsis on previewable files ([d5b2e25](https://github.com/kubeshop/monokle/commit/d5b2e25555467e816ec287142194cdee3cebad7b)) +* file tree height ([f2934c5](https://github.com/kubeshop/monokle/commit/f2934c5a26f790f6807f9f642bcd4bb90e29b277)) +* file tree scroll to file ([4ace23c](https://github.com/kubeshop/monokle/commit/4ace23cc67e683eb407dc6b4bd3a26c5baf3e529)) +* preview & cluster states ([7cb9071](https://github.com/kubeshop/monokle/commit/7cb9071e733983aa9374eab033836f06e586b0a3)) +* selecting the file of current dry run ([1f3befe](https://github.com/kubeshop/monokle/commit/1f3befe16c403f0d905a642c4e38794e605ebcfd)) +* titlebars styling ([e210303](https://github.com/kubeshop/monokle/commit/e2103033432951f1b47e9e20c194e361aef979ec)) + ## [2.4.0](https://github.com/kubeshop/monokle/compare/v2.4.1-nightly-2023-09-28.0...v2.4.0) (2023-09-28) diff --git a/package-lock.json b/package-lock.json index dbba6123f5..9d675e92f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "monokle", - "version": "2.4.0", + "version": "2.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "monokle", - "version": "2.4.0", + "version": "2.4.1", "hasInstallScript": true, "dependencies": { "@ant-design/icons": "4.8.0", diff --git a/package.json b/package.json index 08209a9c0d..a30f680ddc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "monokle", - "version": "2.4.0", + "version": "2.4.1", "author": "Kubeshop", "description": "UI for managing k8s manifests", "homepage": "./",