Skip to content

Commit

Permalink
Merge pull request #4089 from kubeshop/mm/fix/helmstartproject
Browse files Browse the repository at this point in the history
fix: add helm to start new project
  • Loading branch information
mortada-codes authored Jun 20, 2023
2 parents 7ff4849 + abb1d4f commit 7c21f2f
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/assets/newProject/FromHelm.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/organisms/GlobalModals/GlobalModals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {Project} from '@shared/models/config';
import electronStore from '@shared/utils/electronStore';
import {isInClusterModeSelector} from '@shared/utils/selectors';

import HelmRepoModal from '../HelmRepoModal/HelmRepoModal';

const GitCloneModal = React.lazy(() => import('@organisms/GitCloneModal'));

const AboutModal = React.lazy(() => import('@organisms/AboutModal'));
Expand Down Expand Up @@ -74,6 +76,7 @@ const GlobalModals = () => {
const isScaleModalVisible = useAppSelector(state => state.ui.scaleModal.isOpen);
const isWelcomeModalVisible = useAppSelector(state => state.ui.welcomeModal.isVisible);
const isNewAiResourceWizardVisible = useAppSelector(state => state.ui.newAiResourceWizard.isOpen);
const isHelmRepoModalVisible = useAppSelector(state => state.ui.helmRepoModal.isOpen);

const isClusterResourceDiffModalVisible = useMemo(
() => Boolean(targetResourceId) && isInClusterMode,
Expand Down Expand Up @@ -185,6 +188,7 @@ const GlobalModals = () => {
)}
{isTemplateExplorerVisible && <TemplateExplorer />}
{isWelcomeModalVisible && <WelcomeModal />}
{isHelmRepoModalVisible && <HelmRepoModal />}
</Suspense>
</>
);
Expand Down
158 changes: 158 additions & 0 deletions src/components/organisms/HelmRepoModal/HelmRepoModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import {useCallback, useEffect, useRef} from 'react';

import {Button, Form, Modal, TableColumnProps, Typography} from 'antd';

import {RightOutlined, SearchOutlined} from '@ant-design/icons';

import {debounce} from 'lodash';

import {useAppDispatch, useAppSelector} from '@redux/hooks';
import {
closeHelmRepoModal,
setHelmPaneChartSearch,
setHelmPaneSelectedChart,
setIsInQuickClusterMode,
setLeftMenuSelection,
toggleStartProjectPane,
} from '@redux/reducers/ui';

import {sortChartsByName, useSearchHelmCharts} from '@hooks/useSearchHelmCharts';

import {ChartInfo} from '@shared/models/ui';
import {trackEvent} from '@shared/utils';

import * as S from './styled';

const columns: TableColumnProps<ChartInfo>[] = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
ellipsis: true,
sorter: {
compare: sortChartsByName,
multiple: 3,
},
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
ellipsis: true,
},
{
title: 'Version',
dataIndex: 'version',
key: 'version',
},
{
title: 'App Version',
dataIndex: 'app_version',
key: 'app_version',
},
{
title: '',
dataIndex: '',
key: 'x',
responsive: ['sm'],
width: 40,

render: () => (
<S.HoverArea>
<RightOutlined style={{fontSize: 14}} />
</S.HoverArea>
),
},
];

const CHART_NAME_REGEX = /^[a-z]([-a-z0-9]*[a-z0-9])?(\/[a-z]([-a-z0-9]*[a-z0-9])?)*$/gi;

const SearchForm = ({onChangeSearchInputHandler}: {onChangeSearchInputHandler: (q: string) => void}) => {
const [form] = Form.useForm();
const initialValue = useAppSelector(state => state.ui.helmPane.chartSearchToken);

const helmRepoSearch = Form.useWatch('searchToken', form);
useEffect(() => {
onChangeSearchInputHandler(helmRepoSearch);
}, [helmRepoSearch, onChangeSearchInputHandler]);

return (
<Form form={form}>
<Form.Item
style={{marginBottom: 0}}
name="searchToken"
rules={[
{
pattern: CHART_NAME_REGEX,
message: 'Invalid input. please type a valid helm chart name.',
},
]}
initialValue={initialValue}
>
<S.Input placeholder="Refine your Chart search" prefix={<SearchOutlined />} />
</Form.Item>
</Form>
);
};

const HelmRepoModal = () => {
const dispatch = useAppDispatch();
const helmRepoSearch = useAppSelector(state => state.ui.helmPane.chartSearchToken);
const {result, loading} = useSearchHelmCharts(helmRepoSearch, false);

const searchResultCount = result.length;
const debouncedSearchRef = useRef(
debounce((search: string) => {
dispatch(setHelmPaneChartSearch(search));
}, 400)
);

const onChangeSearchInputHandler = useCallback((search: string) => {
debouncedSearchRef.current(search);
}, []);

const onCancelClickHandler = () => {
dispatch(closeHelmRepoModal());
};

const onItemClick = useCallback(
(chart: ChartInfo) => {
dispatch(setHelmPaneSelectedChart(chart));
dispatch(closeHelmRepoModal());
dispatch(setIsInQuickClusterMode(true));
dispatch(setLeftMenuSelection('helm'));
dispatch(toggleStartProjectPane());
trackEvent('helm_repo/select');
},
[dispatch]
);

return (
<Modal
open
title="Start from a Helm Chart"
okText="Cancel"
okType="default"
footer={<Button onClick={onCancelClickHandler}>Cancel</Button>}
width="75vw"
>
<div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24}}>
<Typography.Text>{searchResultCount} Helm Charts available. Select desired one to proceed.</Typography.Text>
<SearchForm onChangeSearchInputHandler={onChangeSearchInputHandler} />
</div>
<S.Table
columns={columns}
dataSource={result}
loading={loading}
pagination={false}
rowKey="name"
scroll={{y: 300}}
onRow={(record: ChartInfo) => ({
onClick: () => onItemClick(record),
})}
/>
</Modal>
);
};

export default HelmRepoModal;
1 change: 1 addition & 0 deletions src/components/organisms/HelmRepoModal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default} from './HelmRepoModal';
66 changes: 66 additions & 0 deletions src/components/organisms/HelmRepoModal/styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {Input as AntInput, Table as AntTable} from 'antd';

import styled from 'styled-components';

import {Colors} from '@shared/styles';

export const Table = styled(props => <AntTable {...props} />)`
.ant-table {
border: 1px solid ${Colors.grey4};
border-radius: 2px;
}
.ant-table-header {
background-color: #1f2628;
color: ${Colors.grey9};
font-size: 14px !important;
font-weight: 700 !important;
border-bottom: 1px solid ${Colors.grey4};
margin-bottom: 0;
scrollbar-gutter: stable both-edges;
}
& .ant-table-header .ant-table-cell {
font-size: 14px;
font-weight: 700;
color: ${Colors.grey9};
}
.ant-table-thead .ant-table-cell::before {
display: none;
}
.ant-table-body .ant-table-row {
background-color: #191f21;
border-bottom: 1px solid ${Colors.grey4};
font-size: 14px;
font-weight: 400;
line-height: 18px;
color: ${Colors.grey9};
}
.ant-table-body .ant-table-row:hover {
background-color: ${Colors.blue6};
}
.ant-table-body .ant-table-row:hover .hover-area {
visibility: visible;
}
.row-selected {
background-color: ${Colors.cyan8} !important;
color: ${Colors.grey2} !important;
}
`;

export const HoverArea = styled.div.attrs({
className: 'hover-area',
})`
display: flex;
align-items: center;
visibility: hidden;
`;

export const Input = styled(AntInput)`
min-width: 300px;
`;
12 changes: 12 additions & 0 deletions src/components/organisms/NewProject/NewProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {useAppDispatch, useAppSelector} from '@redux/hooks';
import {
openCreateProjectModal,
openFolderExplorer,
openHelmRepoModal,
setIsInQuickClusterMode,
setLeftMenuSelection,
toggleStartProjectPane,
Expand All @@ -11,6 +12,7 @@ import {
import ClusterLive from '@assets/newProject/ClusterLive.svg';
import SelectFolder from '@assets/newProject/FromFolder.svg';
import CreateFromGit from '@assets/newProject/FromGit.svg';
import CreateFromHelm from '@assets/newProject/FromHelm.svg';
import SampleProject from '@assets/newProject/FromSampleProject.svg';
import CreateFromScratch from '@assets/newProject/FromScratch.svg';
import CreateFromTemplate from '@assets/newProject/FromTemplate.svg';
Expand Down Expand Up @@ -95,6 +97,16 @@ const NewProject: React.FC = () => {
}
},
},
{
disabled: false,
itemId: 'start-from-helm',
itemLogo: CreateFromHelm,
itemTitle: 'Start from a Helm Chart',
itemDescription: 'Create a new project from a Helm Chart in a Helm repository, and save it locally.',
itemAction: () => {
dispatch(openHelmRepoModal());
},
},
];

return (
Expand Down
3 changes: 3 additions & 0 deletions src/redux/initialState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ const initialUiState: UiState = {
chartDetailsTab: 'info',
isSearchHubIncluded: false,
},
helmRepoModal: {
isOpen: false,
},
};

const initialExtensionState: ExtensionState = {
Expand Down
8 changes: 8 additions & 0 deletions src/redux/reducers/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,12 @@ export const uiSlice = createSlice({
toggleHelmPanSearchHub: (state: Draft<UiState>) => {
state.helmPane.isSearchHubIncluded = !state.helmPane.isSearchHubIncluded;
},
openHelmRepoModal: (state: Draft<UiState>) => {
state.helmRepoModal.isOpen = true;
},
closeHelmRepoModal: (state: Draft<UiState>) => {
state.helmRepoModal.isOpen = false;
},
},
extraReducers: builder => {
builder
Expand Down Expand Up @@ -590,5 +596,7 @@ export const {
setHelmPaneSelectedChart,
setHelmPaneChartDetailsTab,
toggleHelmPanSearchHub,
openHelmRepoModal,
closeHelmRepoModal,
} = uiSlice.actions;
export default uiSlice.reducer;
3 changes: 3 additions & 0 deletions src/shared/models/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ type UiState = {
chartDetailsTab: HelmChartDetailsTab;
isSearchHubIncluded: boolean;
};
helmRepoModal: {
isOpen: boolean;
};
};

type HelmRepoMenu = 'browse-charts' | 'manage-repositories';
Expand Down

0 comments on commit 7c21f2f

Please sign in to comment.