Skip to content

Commit

Permalink
[GEN-2165] create "Segment" component, and replace "ToggleButtons" & …
Browse files Browse the repository at this point in the history
…"ToggleCode" (#2140)

This pull request includes significant changes to the frontend codebase,
focusing on replacing the `ToggleCodeComponent` and `ToggleButtons`
components with a new `Segment` component. The updates span across
multiple files, simplifying the code and improving the user interface.

Component Replacement and Refactoring:

* Removed `ToggleCodeComponent` and replaced it with the new `Segment`
component in `describe-drawer.tsx`, `source-drawer-container/index.tsx`,
and `action-form-body/index.tsx` to toggle between code and pretty
modes.
[[1]](diffhunk://#diff-840f9f31ab7f0b7437b98105569846f658412a1c2ae133dfa36c129ef518a262L20-R42)
[[2]](diffhunk://#diff-d4745da2f63be90cb1f7af8ea29fb2f37cf0a80f0f04a207b6fc9149855ca6d5L53-R53)
[[3]](diffhunk://#diff-13a4f6f896b629d2504615533aa1d48fe792fbadb7132f640b09c03312243ee9L33-R42)
* Removed `ToggleButtons` and replaced it with the `Segment` component
in `rule-form-body/index.tsx` and `action-form-body/index.tsx` to toggle
between active and inactive statuses.
[[1]](diffhunk://#diff-6624df2f04a59bc64a0825c4c5bad0f3ff91baeb56c89e3bf286f61b77167065L33-R42)
[[2]](diffhunk://#diff-13a4f6f896b629d2504615533aa1d48fe792fbadb7132f640b09c03312243ee9L33-R42)

File and Import Cleanup:

* Removed the `toggle-code-component` export from `index.ts` files and
deleted the `toggle-code-component/index.tsx` file.
[[1]](diffhunk://#diff-7d82b799a8e9e094527658980bb418eed24947d6ca0daa65fabb9cab8305ce91L1)
[[2]](diffhunk://#diff-41caeebe24ebfb15cef4fb61e0b64cef8522a865e6da945fd260c5366cc80995L1-L40)
* Removed the `toggle-buttons` export from `index.ts` files and deleted
the `toggle-buttons/index.tsx` file.
[[1]](diffhunk://#diff-6d130f82a4bd07ed79a48c836695e61245cb93220e180db6e494a4234c129e67L1)
[[2]](diffhunk://#diff-f9e56033127f413a93fdcc202e25f7922a065208c18cd38c0a9ffe6967bd4296L1-L93)
* Added the `segment` export to `reuseable-components/index.ts`.

New Component Addition:

* Added the new `Segment` component in
`reuseable-components/segment/index.tsx`, which provides a flexible and
reusable segmented control for toggling between different states.
  • Loading branch information
BenElferink authored Jan 6, 2025
1 parent 9a7bcce commit 409bb0b
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 153 deletions.
1 change: 0 additions & 1 deletion frontend/webapp/components/common/buttons/index.ts

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion frontend/webapp/components/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './buttons';
export * from './dropdowns';
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import { CodeBracketsIcon } from '@/assets';
import { useDescribeOdigos } from '@/hooks';
import { DATA_CARDS, safeJsonStringify } from '@/utils';
import { ToggleCodeComponent } from '@/components/common';
import { DataCard, DataCardFieldTypes } from '@/reuseable-components';
import { CodeBracketsIcon, CodeIcon, ListIcon } from '@/assets';
import OverviewDrawer from '@/containers/main/overview/overview-drawer';
import { DataCard, DataCardFieldTypes, Segment } from '@/reuseable-components';

interface Props {}

Expand All @@ -17,21 +16,30 @@ const DataContainer = styled.div`

export const DescribeDrawer: React.FC<Props> = () => {
const { data: describe, restructureForPrettyMode } = useDescribeOdigos();
const [isCodeMode, setIsCodeMode] = useState(false);
const [isPrettyMode, setIsPrettyMode] = useState(true);

return (
<OverviewDrawer title={DATA_CARDS.DESCRIBE_ODIGOS} icon={CodeBracketsIcon}>
<DataContainer>
<DataCard
title=''
action={<ToggleCodeComponent isCodeMode={isCodeMode} setIsCodeMode={setIsCodeMode} />}
action={
<Segment
options={[
{ icon: ListIcon, value: true },
{ icon: CodeIcon, value: false },
]}
selected={isPrettyMode}
setSelected={setIsPrettyMode}
/>
}
data={[
{
type: DataCardFieldTypes.CODE,
value: JSON.stringify({
language: 'json',
code: safeJsonStringify(isCodeMode ? describe : restructureForPrettyMode(describe)),
pretty: !isCodeMode,
code: safeJsonStringify(isPrettyMode ? restructureForPrettyMode(describe) : describe),
pretty: isPrettyMode,
}),
width: 'inherit',
},
Expand Down
13 changes: 11 additions & 2 deletions frontend/webapp/containers/main/actions/action-form-body/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react';
import theme from '@/styles/theme';
import styled from 'styled-components';
import { type ActionInput } from '@/types';
import ActionCustomFields from './custom-fields';
import { CheckCircledIcon, CrossCircledIcon } from '@/assets';
import { type ActionOption } from '../action-modal/action-options';
import { DocsButton, Input, Text, TextArea, MonitoringCheckboxes, SectionTitle, ToggleButtons } from '@/reuseable-components';
import { DocsButton, Input, Text, TextArea, MonitoringCheckboxes, SectionTitle, Segment } from '@/reuseable-components';

interface Props {
isUpdate?: boolean;
Expand All @@ -30,7 +32,14 @@ export const ActionFormBody: React.FC<Props> = ({ isUpdate, action, formData, fo
{isUpdate && (
<div>
<FieldTitle>Status</FieldTitle>
<ToggleButtons initialValue={!formData.disable} onChange={(bool) => handleFormChange('disable', !bool)} />
<Segment
options={[
{ icon: CheckCircledIcon, label: 'active', value: false, selectedBgColor: theme.colors.dark_green },
{ icon: CrossCircledIcon, label: 'inactive', value: true, selectedBgColor: theme.colors.darker_red },
]}
selected={formData.disable}
setSelected={(bool) => handleFormChange('disable', bool)}
/>
</div>
)}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react';
import theme from '@/styles/theme';
import styled from 'styled-components';
import RuleCustomFields from './custom-fields';
import type { InstrumentationRuleInput } from '@/types';
import type { RuleOption } from '../rule-modal/rule-options';
import { DocsButton, Input, Text, TextArea, SectionTitle, ToggleButtons } from '@/reuseable-components';
import { CheckCircledIcon, CrossCircledIcon } from '@/assets';
import { DocsButton, Input, Text, TextArea, SectionTitle, Segment } from '@/reuseable-components';

interface Props {
isUpdate?: boolean;
Expand All @@ -30,7 +32,14 @@ export const RuleFormBody: React.FC<Props> = ({ isUpdate, rule, formData, formEr
{isUpdate && (
<div>
<FieldTitle>Status</FieldTitle>
<ToggleButtons initialValue={!formData.disabled} onChange={(bool) => handleFormChange('disabled', !bool)} />
<Segment
options={[
{ icon: CheckCircledIcon, label: 'active', value: false, selectedBgColor: theme.colors.dark_green },
{ icon: CrossCircledIcon, label: 'inactive', value: true, selectedBgColor: theme.colors.darker_red },
]}
selected={formData.disabled}
setSelected={(bool) => handleFormChange('disabled', bool)}
/>
</div>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import React, { useEffect, useMemo, useState } from 'react';
import buildCard from './build-card';
import styled from 'styled-components';
import { useDrawerStore } from '@/store';
import { CodeIcon, ListIcon } from '@/assets';
import buildDrawerItem from './build-drawer-item';
import { ToggleCodeComponent } from '@/components';
import { UpdateSourceBody } from '../update-source-body';
import { useDescribeSource, useSourceCRUD } from '@/hooks';
import OverviewDrawer from '../../overview/overview-drawer';
import { OVERVIEW_ENTITY_TYPES, type WorkloadId, type K8sActualSource } from '@/types';
import { ACTION, BACKEND_BOOLEAN, DATA_CARDS, getEntityIcon, safeJsonStringify } from '@/utils';
import { ConditionDetails, DataCard, DataCardRow, DataCardFieldTypes } from '@/reuseable-components';
import { ConditionDetails, DataCard, DataCardRow, DataCardFieldTypes, Segment } from '@/reuseable-components';

interface Props {}

Expand Down Expand Up @@ -50,7 +50,7 @@ export const SourceDrawer: React.FC<Props> = () => {
},
});

const [isCodeMode, setIsCodeMode] = useState(false); // for "describe source"
const [isPrettyMode, setIsPrettyMode] = useState(true); // for "describe source"
const [isEditing, setIsEditing] = useState(false);
const [isFormDirty, setIsFormDirty] = useState(false);
const [formData, setFormData] = useState({ ...EMPTY_FORM });
Expand Down Expand Up @@ -153,14 +153,23 @@ export const SourceDrawer: React.FC<Props> = () => {
<DataCard title={DATA_CARDS.DETECTED_CONTAINERS} titleBadge={containersData.length} description={DATA_CARDS.DETECTED_CONTAINERS_DESCRIPTION} data={containersData} />
<DataCard
title={DATA_CARDS.DESCRIBE_SOURCE}
action={<ToggleCodeComponent isCodeMode={isCodeMode} setIsCodeMode={setIsCodeMode} />}
action={
<Segment
options={[
{ icon: ListIcon, value: true },
{ icon: CodeIcon, value: false },
]}
selected={isPrettyMode}
setSelected={setIsPrettyMode}
/>
}
data={[
{
type: DataCardFieldTypes.CODE,
value: JSON.stringify({
language: 'json',
code: safeJsonStringify(isCodeMode ? describe : restructureForPrettyMode(describe)),
pretty: !isCodeMode,
code: safeJsonStringify(isPrettyMode ? restructureForPrettyMode(describe) : describe),
pretty: isPrettyMode,
}),
width: 'inherit',
},
Expand Down
2 changes: 1 addition & 1 deletion frontend/webapp/reuseable-components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export * from './tooltip';
export * from './dropdown';
export * from './divider';
export * from './toggle';
export * from './toggle-buttons';
export * from './checkbox';
export * from './modal';
export * from './modal/warning-modal';
Expand Down Expand Up @@ -39,3 +38,4 @@ export * from './data-tab';
export * from './code';
export * from './icon-button';
export * from './icon-wrapped';
export * from './segment';
109 changes: 109 additions & 0 deletions frontend/webapp/reuseable-components/segment/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, { CSSProperties, useEffect, useRef, useState } from 'react';
import { SVG } from '@/assets';
import { Text } from '../text';
import { FlexRow } from '@/styles';
import styled from 'styled-components';

type SelectedValue = any;

interface Props {
options: {
icon?: SVG;
label?: string;
value: SelectedValue;
selectedBgColor?: CSSProperties['backgroundColor'];
}[];
selected: SelectedValue;
setSelected: (value: SelectedValue) => void;
}

const Container = styled(FlexRow)`
position: relative;
gap: 0;
`;

const Button = styled.button<{ $isFirstItem: boolean; $isLastItem: boolean }>`
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
padding: 6px 12px;
background-color: transparent;
border-radius: ${({ $isFirstItem, $isLastItem }) => ($isFirstItem ? '32px 0px 0px 32px' : $isLastItem ? '0px 32px 32px 0px' : '0')};
border: 1px solid ${({ theme }) => theme.colors.border};
cursor: pointer;
&:hover {
border: 1px solid ${({ theme }) => theme.colors.secondary};
}
`;

const Background = styled.div<{ $bgColor?: CSSProperties['backgroundColor']; $width: number; $height: number; $x: number; $y: number; $isFirstItem: boolean; $isLastItem: boolean }>`
position: absolute;
top: ${({ $y }) => $y}px;
left: ${({ $x }) => $x}px;
z-index: -1;
width: ${({ $width }) => $width}px;
height: ${({ $height }) => $height}px;
background-color: ${({ theme, $bgColor }) => $bgColor || theme.colors.white_opacity['008']};
border-radius: ${({ $isFirstItem, $isLastItem }) => ($isFirstItem ? '32px 0px 0px 32px' : $isLastItem ? '0px 32px 32px 0px' : '0')};
transition: all 0.3s;
`;

export const Segment: React.FC<Props> = ({ options = [], selected, setSelected }) => {
const selectedIdx = options.findIndex((option) => option.value === selected);
const [bgColor, setBgColor] = useState(options[selectedIdx]?.selectedBgColor || '');
const [bgSize, setBgSize] = useState({ width: 0, height: 0 });
const [bgPosition, setBgPosition] = useState({ x: 0, y: 0 });
const selectedRef = useRef<HTMLButtonElement>(null);

useEffect(() => {
if (!!selectedRef.current) {
setBgSize({
width: selectedRef.current.offsetWidth,
height: selectedRef.current.offsetHeight,
});
setBgPosition({
x: selectedRef.current.offsetWidth * selectedIdx,
y: 0,
});
}
}, [selected, selectedIdx]);

return (
<Container>
{options.map(({ icon: Icon, label, value, selectedBgColor }, idx) => {
const isSelected = selected === value;

return (
<Button
ref={isSelected ? selectedRef : undefined}
$isFirstItem={idx === 0}
$isLastItem={idx === options.length - 1}
onClick={() => {
setSelected(value);
setBgColor(selectedBgColor || '');
}}
>
{Icon && <Icon />}
{label && (
<Text size={12} family='secondary' decoration='underline'>
{label}
</Text>
)}
</Button>
);
})}

<Background
$bgColor={bgColor}
$width={bgSize.width}
$height={bgSize.height}
$x={bgPosition.x}
$y={bgPosition.y}
$isFirstItem={selectedIdx === 0}
$isLastItem={selectedIdx === options.length - 1}
/>
</Container>
);
};
Loading

0 comments on commit 409bb0b

Please sign in to comment.