Skip to content

Commit

Permalink
Merge pull request #1088 from kubeshop/razvantopliceanu/refactor/temp…
Browse files Browse the repository at this point in the history
…lates-pane-redesign

refactor: templates pane redesign
  • Loading branch information
topliceanurazvan authored Jan 21, 2022
2 parents 08e6312 + f6be514 commit a164f3d
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 126 deletions.
9 changes: 9 additions & 0 deletions src/assets/TemplateIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import {Button} from 'antd';

import {DeleteOutlined as RawDeleteOutlined, FormOutlined as RawFormOutlined} from '@ant-design/icons';
import {FormOutlined as RawFormOutlined} from '@ant-design/icons';

import styled from 'styled-components';

import Colors from '@styles/Colors';

export const AdditionalInformation = styled.div`
color: ${Colors.grey6};
line-height: 20px;
font-size: 12px;
margin: 10px 0px;
display: flex;
flex-direction: column;
`;

export const Container = styled.div`
display: grid;
grid-template-columns: max-content 1fr 40px;
grid-template-columns: max-content 1fr;
grid-column-gap: 18px;
position: relative;
margin-bottom: 16px;
`;

export const IconContainer = styled.div`
height: 50px;
width: 50px;
export const Description = styled.span`
color: ${Colors.grey7};
`;

export const Image = styled.img`
width: 32px;
height: 32px;
`;

export const InfoContainer = styled.div`
Expand All @@ -26,47 +39,17 @@ export const InfoContainer = styled.div`

export const Name = styled.span<{$width: number}>`
${props => `width: ${props.$width}`}
font-weight: 300;
color:${Colors.whitePure};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;

export const Description = styled.span<{$width: number}>`
${props => `width: ${props.$width}`}
font-weight: 300;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;

export const Footer = styled.span`
display: flex;
justify-content: space-between;
`;

export const Author = styled.span`
color: ${Colors.grey500};
`;

export const Version = styled.span`
font-style: italic;
`;

export const DeleteOutlined = styled(RawDeleteOutlined)`
position: absolute;
top: 5px;
right: 0px;
color: ${Colors.red7};
cursor: pointer;
margin-bottom: 10px;
`;

export const FormOutlined = styled(RawFormOutlined)`
font-size: 30px;
padding-top: 4px;
`;

export const OpenButton = styled(Button)`
margin-top: 8px;
width: 100px;
width: max-content;
`;
Original file line number Diff line number Diff line change
@@ -1,104 +1,51 @@
import React from 'react';
import {useMeasure} from 'react-use';

import {Popconfirm} from 'antd';
import {DeliveredProcedureOutlined} from '@ant-design/icons';

import {ExclamationOutlined} from '@ant-design/icons';
import _ from 'lodash';

import {AnyTemplate} from '@models/template';

import {useAppDispatch, useAppSelector} from '@redux/hooks';
import {
deletePlugin,
deleteStandalonTemplate,
deleteTemplatePack,
isPluginTemplate,
isStandaloneTemplate,
isTemplatePackTemplate,
} from '@redux/services/templates';
import TemplateIcon from '@assets/TemplateIcon.svg';

import * as S from './TemplateInformation.styled';

interface IProps {
template: AnyTemplate;
templatePath: string;
onClickOpenTemplate: () => void;
}

const getTemplatePackPluginPath = (templatePath: string) => {
const splittedTemplatePath = templatePath.split('\\');
splittedTemplatePath.pop();

return splittedTemplatePath.join('\\');
};

const TemplateInformation: React.FC<IProps> = props => {
const {template, templatePath, onClickOpenTemplate} = props;
const {template, onClickOpenTemplate} = props;

const [infoContainerRef, {width: infoContainerWidth}] = useMeasure<HTMLDivElement>();

const dispatch = useAppDispatch();
const pluginMap = useAppSelector(state => state.extension.pluginMap);
const pluginsDir = useAppSelector(state => state.extension.pluginsDir);
const templatesDir = useAppSelector(state => state.extension.templatesDir);
const templatePacksDir = useAppSelector(state => state.extension.templatePacksDir);
const templatePackMap = useAppSelector(state => state.extension.templatePackMap);

const handleDelete = () => {
if (templatesDir && isStandaloneTemplate(templatePath, templatesDir)) {
deleteStandalonTemplate(templatePath, dispatch);
} else if (templatePacksDir && isTemplatePackTemplate(templatePath, templatePacksDir)) {
const templatePackPath = getTemplatePackPluginPath(templatePath);
deleteTemplatePack(templatePackMap[templatePackPath], templatePackPath, dispatch);
} else if (pluginsDir && isPluginTemplate(templatePath, pluginsDir)) {
const pluginPath = getTemplatePackPluginPath(templatePath);
deletePlugin(pluginMap[pluginPath], pluginPath, dispatch);
}
};

return (
<S.Container>
<S.IconContainer>
<S.FormOutlined />
</S.IconContainer>
<S.Image src={template.icon ? template.icon : TemplateIcon} alt="Template_Icon" />

<S.InfoContainer ref={infoContainerRef}>
<S.Name $width={infoContainerWidth}>{template.name}</S.Name>
<span>Type: {template.type}</span>
<S.Description $width={infoContainerWidth}>{template.description}</S.Description>
<S.Footer>
<S.Author>{template.author}</S.Author> <S.Version>{template.version}</S.Version>
</S.Footer>
<S.OpenButton ghost size="small" type="primary" onClick={onClickOpenTemplate}>
Open

<S.Description>{_.truncate(template.description, {length: 140})}</S.Description>

<S.AdditionalInformation>
<span>Type: {template.type}</span>
<span>Author: {template.author}</span>
<span>Version: {template.version}</span>
</S.AdditionalInformation>

<S.OpenButton
icon={<DeliveredProcedureOutlined />}
ghost
size="small"
type="primary"
onClick={onClickOpenTemplate}
>
Use Template
</S.OpenButton>
</S.InfoContainer>

<Popconfirm
cancelText="Cancel"
okText="Delete"
okType="danger"
placement="bottom"
title={() => (
<>
<p>Are you sure you want to delete {template.name}?</p>
{templatePacksDir && isTemplatePackTemplate(templatePath, templatePacksDir) ? (
<p>
<ExclamationOutlined style={{color: 'red'}} />
This will delete all the templates corresponding to the pack.
</p>
) : pluginsDir && isPluginTemplate(templatePath, pluginsDir) ? (
<p>
<ExclamationOutlined style={{color: 'red'}} />
This will delete all the templates corresponding to the plugin.
</p>
) : null}
</>
)}
onConfirm={handleDelete}
>
<S.DeleteOutlined />
</Popconfirm>
</S.Container>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import {Input} from 'antd';

import styled from 'styled-components';

import {GlobalScrollbarStyle} from '@utils/scrollbar';

import Colors from '@styles/Colors';

export const Container = styled.div`
Expand All @@ -9,3 +13,20 @@ export const Container = styled.div`
export const NotFoundLabel = styled.span`
color: ${Colors.grey7};
`;

export const SearchInput = styled(Input.Search)`
background: ${Colors.grey1};
margin-bottom: 25px;
& input::placeholder {
color: ${Colors.grey7};
}
`;

export const TemplatesContainer = styled.div<{$height: number}>`
display: grid;
grid-row-gap: 25px;
${props => `height: ${props.$height}px;`}
overflow-y: auto;
${GlobalScrollbarStyle};
`;
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import React, {useCallback, useEffect, useMemo, useState} from 'react';

import {Button, Input, Skeleton, Tooltip} from 'antd';
import {Button, Skeleton, Tooltip} from 'antd';

import {ReloadOutlined} from '@ant-design/icons';

import {TEMPLATES_HEIGHT_OFFSET} from '@constants/constants';
import {TemplateManagerPaneReloadTooltip} from '@constants/tooltips';

import {AnyTemplate} from '@models/template';

import {useAppDispatch, useAppSelector} from '@redux/hooks';
import {isInPreviewModeSelector} from '@redux/selectors';
import {checkForExtensionsUpdates} from '@redux/services/extension';

import {TitleBar} from '@components/molecules';

import {useWindowSize} from '@utils/hooks';

import TemplateModal from '../TemplateModal';
import TemplateInformation from './TemplateInformation';
import * as S from './TemplateManagerPane.styled';
Expand All @@ -37,13 +41,16 @@ const TemplatesPane: React.FC = () => {

const isLoadingExistingTemplates = useAppSelector(state => state.extension.isLoadingExistingTemplates);
const isLoadingExistingTemplatePacks = useAppSelector(state => state.extension.isLoadingExistingTemplatePacks);
const isInPreviewMode = useAppSelector(isInPreviewModeSelector);
const templateMap = useAppSelector(state => state.extension.templateMap);
const pluginMap = useAppSelector(state => state.extension.pluginMap);
const templatePackMap = useAppSelector(state => state.extension.templatePackMap);

const [searchedValue, setSearchedValue] = useState<string>();
const [templatesToShow, setTemplatesToShow] = useState<Record<string, AnyTemplate>>();

const windowSize = useWindowSize();

const isLoading = useMemo(() => {
return isLoadingExistingTemplates || isLoadingExistingTemplatePacks;
}, [isLoadingExistingTemplates, isLoadingExistingTemplatePacks]);
Expand All @@ -52,6 +59,11 @@ const TemplatesPane: React.FC = () => {
return Object.values(templateMap);
}, [templateMap]);

const templatesHeight = useMemo(
() => windowSize.height - TEMPLATES_HEIGHT_OFFSET - (isInPreviewMode ? 25 : 0),
[windowSize.height, isInPreviewMode]
);

const onTemplateModalClose = useCallback(() => {
setSelectedTemplate(undefined);
}, []);
Expand Down Expand Up @@ -102,24 +114,24 @@ const TemplatesPane: React.FC = () => {
<p>No templates available.</p>
) : (
<>
<Input.Search
placeholder="Search template by name"
style={{marginBottom: '20px'}}
<S.SearchInput
placeholder="Search installed templates"
value={searchedValue}
onChange={e => setSearchedValue(e.target.value)}
/>

{!Object.keys(templatesToShow).length ? (
<S.NotFoundLabel>No templates found.</S.NotFoundLabel>
) : (
Object.entries(templatesToShow).map(([path, template]) => (
<TemplateInformation
key={template.id}
template={template}
templatePath={path}
onClickOpenTemplate={() => onClickOpenTemplate(template)}
/>
))
<S.TemplatesContainer $height={templatesHeight}>
{Object.values(templatesToShow).map(template => (
<TemplateInformation
key={template.id}
template={template}
onClickOpenTemplate={() => onClickOpenTemplate(template)}
/>
))}
</S.TemplatesContainer>
)}
</>
)}
Expand Down
1 change: 1 addition & 0 deletions src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export const DEFAULT_EDITOR_DEBOUNCE = 500;
export const DEFAULT_KUBECONFIG_DEBOUNCE = 1000;
export const ACTIONS_PANE_FOOTER_HEIGHT = 200;
export const ACTIONS_PANE_TAB_PANE_OFFSET = 106;
export const TEMPLATES_HEIGHT_OFFSET = 200;
1 change: 1 addition & 0 deletions src/styles/Colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum Colors {
grey5 = '#5A5A5A', // gray, gray 5
grey4 = '#303030', // gray, gray 4
grey3 = '#262626', // gray, gray 3
grey1 = '#141414', // gray, gray 1

// Notifications
greenOkay = '#09b89d',
Expand Down

0 comments on commit a164f3d

Please sign in to comment.