Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GEN-1837]: "other agent" for new UI #1994

Merged
merged 3 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useState } from 'react';
import Image from 'next/image';
import styled from 'styled-components';
import { extractMonitors } from '@/utils';
import { DeleteWarning } from '@/components';
import { IAppState, useAppStore } from '@/store';
import { OVERVIEW_ENTITY_TYPES, type ConfiguredDestination } from '@/types';
import { Button, DataCardFields, Divider, ExtendIcon, Text } from '@/reuseable-components';
import { DataCardFields, DataTab, IconButton, Text } from '@/reuseable-components';

const Container = styled.div`
display: flex;
Expand All @@ -18,128 +19,26 @@ const Container = styled.div`
overflow-y: scroll;
`;

const ListItem = styled.div`
width: 100%;
border-radius: 16px;
background: ${({ theme }) => theme.colors.translucent_bg};
`;

const ListItemBody = styled.div`
width: 100%;
padding: 16px;
`;

const ListItemHeader = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 16px 0px;
`;

const ListItemContent = styled.div`
display: flex;
gap: 12px;
margin-left: 16px;
`;

const DestinationIconWrapper = styled.div`
display: flex;
width: 36px;
height: 36px;
justify-content: center;
align-items: center;
gap: 8px;
border-radius: 8px;
background: linear-gradient(180deg, rgba(249, 249, 249, 0.06) 0%, rgba(249, 249, 249, 0.02) 100%);
`;

const SignalsWrapper = styled.div`
display: flex;
align-items: center;
gap: 4px;
`;

const SignalText = styled(Text)`
color: rgba(249, 249, 249, 0.8);
font-size: 10px;
text-transform: capitalize;
`;

const TextWrapper = styled.div`
display: flex;
flex-direction: column;
height: 36px;
justify-content: space-between;
`;

const IconsContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
margin-right: 16px;
`;

const IconButton = styled(Button)<{ $expand?: boolean }>`
transition: background 0.3s ease 0s, transform 0.3s ease 0s;
transform: ${({ $expand }) => ($expand ? 'rotate(-180deg)' : 'rotate(0deg)')};
`;

const ConfiguredDestinationsListItem: React.FC<{ item: ConfiguredDestination; isLastItem: boolean }> = ({ item, isLastItem }) => {
const [expand, setExpand] = useState(false);
const [deleteWarning, setDeleteWarning] = useState(false);
const ListItem: React.FC<{ item: ConfiguredDestination; isLastItem: boolean }> = ({ item, isLastItem }) => {
const { removeConfiguredDestination } = useAppStore((state) => state);

function renderSupportedSignals(item: ConfiguredDestination) {
const supportedSignals = item.exportedSignals;
const signals = Object.keys(supportedSignals);
const supportedSignalsList = signals.filter((signal) => supportedSignals[signal].supported);

return Object.keys(supportedSignals).map(
(signal, index) =>
supportedSignals[signal] && (
<SignalsWrapper key={index}>
<Image src={`/icons/monitors/${signal}.svg`} alt='monitor' width={10} height={16} />

<SignalText>{signal}</SignalText>
{index < supportedSignalsList.length - 1 && <SignalText>·</SignalText>}
</SignalsWrapper>
),
);
}
const [deleteWarning, setDeleteWarning] = useState(false);

return (
<>
<ListItem>
<ListItemHeader style={{ paddingBottom: expand ? 0 : 16 }}>
<ListItemContent>
<DestinationIconWrapper>
<Image src={item.imageUrl} alt='destination' width={20} height={20} />
</DestinationIconWrapper>
<TextWrapper>
<Text size={14}>{item.displayName}</Text>
<SignalsWrapper>{renderSupportedSignals(item)}</SignalsWrapper>
</TextWrapper>
</ListItemContent>

<IconsContainer>
<IconButton variant='tertiary' onClick={() => setDeleteWarning(true)}>
<Image src='/icons/common/trash.svg' alt='delete' width={16} height={16} />
</IconButton>
<Divider orientation='vertical' length='16px' />
<IconButton variant='tertiary' onClick={() => setExpand(!expand)}>
<ExtendIcon extend={expand} />
</IconButton>
</IconsContainer>
</ListItemHeader>

{expand && (
<ListItemBody>
<Divider margin='0 0 16px 0' length='calc(100% - 32px)' />
<DataCardFields data={item.destinationTypeDetails} />
</ListItemBody>
<DataTab
title={item.displayName}
subTitle=''
logo={item.imageUrl}
monitors={extractMonitors(item.exportedSignals)}
monitorsWithLabels
withExtend
renderExtended={() => <DataCardFields data={item.destinationTypeDetails} />}
renderActions={() => (
<IconButton onClick={() => setDeleteWarning(true)}>
<Image src='/icons/common/trash.svg' alt='delete' width={16} height={16} />
</IconButton>
)}
</ListItem>
/>

<DeleteWarning
isOpen={deleteWarning}
Expand All @@ -157,7 +56,7 @@ export const ConfiguredDestinationsList: React.FC<{ data: IAppState['configuredD
return (
<Container>
{data.map(({ stored }) => (
<ConfiguredDestinationsListItem key={stored.displayName} item={stored} isLastItem={data.length === 1} />
<ListItem key={stored.displayName} item={stored} isLastItem={data.length === 1} />
))}
</Container>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useDescribeSource, useSourceCRUD } from '@/hooks';
import OverviewDrawer from '../../overview/overview-drawer';
import { OVERVIEW_ENTITY_TYPES, type WorkloadId, type K8sActualSource } from '@/types';
import { ConditionDetails, DataCard, DataCardRow, DataCardFieldTypes } from '@/reuseable-components';
import { ACTION, DATA_CARDS, getMainContainerLanguage, getProgrammingLanguageIcon, safeJsonStringify } from '@/utils';
import { ACTION, BACKEND_BOOLEAN, DATA_CARDS, getMainContainerLanguage, getProgrammingLanguageIcon, safeJsonStringify } from '@/utils';

interface Props {}

Expand Down Expand Up @@ -79,13 +79,17 @@ export const SourceDrawer: React.FC<Props> = () => {

const { item } = selectedItem as { item: K8sActualSource };

const hasPresenceOfOtherAgent = item.instrumentedApplicationDetails.conditions.some(
(condition) => condition.status === BACKEND_BOOLEAN.FALSE && condition.message.includes('device not added to any container due to the presence of another agent'),
);

return (
item.instrumentedApplicationDetails.containers.map(
(container) =>
({
type: DataCardFieldTypes.SOURCE_CONTAINER,
width: '100%',
value: JSON.stringify(container),
value: JSON.stringify({ ...container, hasPresenceOfOtherAgent }),
} as DataCardRow),
) || []
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const ConditionDetails: React.FC<Props> = ({ conditions }) => {
({hasErrors ? errors.length : conditions.length}/{conditions.length})
</Text>

<ExtendIcon extend={extend} />
<ExtendIcon extend={extend} align='right' />
</Header>

{extend && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useId } from 'react';
import styled from 'styled-components';
import { ActiveStatus, Code, DataTab, Divider, InstrumentStatus, MonitorsIcons, Text, Tooltip } from '@/reuseable-components';
import { ActiveStatus, Code, DataTab, Divider, InstrumentStatus, MonitorsIcons, NotificationNote, Text, Tooltip } from '@/reuseable-components';
import { capitalizeFirstLetter, getProgrammingLanguageIcon, parseJsonStringToPrettyString, safeJsonParse, WORKLOAD_PROGRAMMING_LANGUAGES } from '@/utils';
import { NOTIFICATION_TYPE } from '@/types';

export enum DataCardFieldTypes {
DIVIDER = 'divider',
Expand Down Expand Up @@ -81,20 +82,37 @@ const renderValue = (type: DataCardRow['type'], value: DataCardRow['value']) =>
return <ActiveStatus isActive={value == 'true'} size={10} withIcon withBorder />;

case DataCardFieldTypes.SOURCE_CONTAINER: {
const { containerName, language, runtimeVersion } = safeJsonParse(value, {
const { containerName, language, runtimeVersion, otherAgent, hasPresenceOfOtherAgent } = safeJsonParse(value, {
containerName: '-',
language: WORKLOAD_PROGRAMMING_LANGUAGES.UNKNOWN,
runtimeVersion: '-',
otherAgent: null,
hasPresenceOfOtherAgent: false,
});

// Determine if running concurrently is possible based on language and other_agent
const canRunInParallel = !hasPresenceOfOtherAgent && (language === WORKLOAD_PROGRAMMING_LANGUAGES.PYTHON || language === WORKLOAD_PROGRAMMING_LANGUAGES.JAVA);

return (
<DataTab
title={containerName}
subTitle={`${language === WORKLOAD_PROGRAMMING_LANGUAGES.JAVASCRIPT ? 'Node.js' : capitalizeFirstLetter(language)} • Runtime Version: ${runtimeVersion}`}
logo={getProgrammingLanguageIcon(language)}
>
<InstrumentStatus language={language} />
</DataTab>
isExtended={!!otherAgent}
renderExtended={() => (
<NotificationNote
type={NOTIFICATION_TYPE.INFO}
message={
hasPresenceOfOtherAgent
? `By default, we do not operate alongside the ${otherAgent} Agent. Please contact the Odigos team for guidance on enabling this configuration.`
: canRunInParallel
? `We are operating alongside the ${otherAgent} Agent, which is not the recommended configuration. We suggest disabling the ${otherAgent} Agent for optimal performance.`
: `Concurrent execution with the ${otherAgent} is not supported. Please disable one of the agents to enable proper instrumentation.`
}
/>
)}
renderActions={() => <InstrumentStatus language={language} />}
/>
);
}

Expand Down
Loading
Loading