Skip to content

Commit

Permalink
[GEN-1603]: add rules column to overview (#1661)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenElferink authored Oct 30, 2024
1 parent 78eda6e commit 6a91aba
Show file tree
Hide file tree
Showing 23 changed files with 375 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const ACTION_OPTIONS: ActionOption[] = [
label: 'Error Sampler',
description: 'Sample errors based on percentage.',
type: ActionsType.ERROR_SAMPLER,
icon: getActionIcon('sampler'),
docsEndpoint: '/pipeline/actions/sampling/errorsampler',
docsDescription: 'The “Error Sampler” Odigos Action is a Global Action that supports error sampling by filtering out non-error traces.',
allowedSignals: ['TRACES'],
Expand All @@ -75,6 +76,7 @@ export const ACTION_OPTIONS: ActionOption[] = [
label: 'Probabilistic Sampler',
description: 'Sample traces based on percentage.',
type: ActionsType.PROBABILISTIC_SAMPLER,
icon: getActionIcon('sampler'),
docsEndpoint: '/pipeline/actions/sampling/probabilisticsampler',
docsDescription:
'The “Probabilistic Sampler” Odigos Action supports probabilistic sampling based on a configured sampling percentage applied to the TraceID.',
Expand All @@ -85,6 +87,7 @@ export const ACTION_OPTIONS: ActionOption[] = [
label: 'Latency Action',
description: 'Add latency to your traces.',
type: ActionsType.LATENCY_SAMPLER,
icon: getActionIcon('sampler'),
docsEndpoint: '/pipeline/actions/sampling/latencysampler',
docsDescription:
'The “Latency Sampler” Odigos Action is an Endpoint Action that samples traces based on their duration for a specific service and endpoint (HTTP route) filter.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ const Container = styled.section`
max-width: 640px;
height: 640px;
margin: 0 15vw;
padding-top: 64px;
padding: 64px 12px 0 12px;
display: flex;
flex-direction: column;
overflow-y: scroll;
`;

const Center = styled.div`
width: 100%;
margin-top: 24px;
display: flex;
flex-direction: column;
align-items: center;
Expand All @@ -32,7 +33,7 @@ interface AddActionModalProps {
export const AddActionModal: React.FC<AddActionModalProps> = ({ isModalOpen, handleCloseModal }) => {
const { formData, handleFormChange, resetFormData, validateForm } = useActionFormData();
const { createAction, loading } = useActionCRUD({ onSuccess: handleClose });
const [selectedItem, setSelectedItem] = useState<ActionOption | null>(null);
const [selectedItem, setSelectedItem] = useState<ActionOption | undefined>(undefined);

const isFormOk = useMemo(() => !!selectedItem && validateForm(), [selectedItem, formData]);

Expand All @@ -42,7 +43,7 @@ export const AddActionModal: React.FC<AddActionModalProps> = ({ isModalOpen, han

function handleClose() {
resetFormData();
setSelectedItem(null);
setSelectedItem(undefined);
handleCloseModal();
}

Expand Down Expand Up @@ -75,7 +76,7 @@ export const AddActionModal: React.FC<AddActionModalProps> = ({ isModalOpen, han
title='Define Action'
description='Actions are a way to modify the OpenTelemetry data recorded by Odigos sources before it is exported to your Odigos destinations. Choose an action type and provide necessary information.'
/>
<AutocompleteInput options={ACTION_OPTIONS} onOptionSelect={handleSelect} />
<AutocompleteInput options={ACTION_OPTIONS} selectedOption={selectedItem} onOptionSelect={handleSelect} style={{ marginTop: '24px' }} />

{!!selectedItem?.type ? (
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,17 @@ import React from 'react';
import { useRouter } from 'next/navigation';
import { NewActionCard } from '@/components';
import { KeyvalLink, KeyvalText } from '@/design.system';
import { ActionItemCard, InstrumentationRuleType } from '@/types';
import { ActionItemCard, RulesType } from '@/types';
import { ACTION, INSTRUMENTATION_RULES_DOCS_LINK, OVERVIEW } from '@/utils';
import {
ActionCardWrapper,
ActionsListWrapper,
DescriptionWrapper,
LinkWrapper,
} from './styled';
import { ActionCardWrapper, ActionsListWrapper, DescriptionWrapper, LinkWrapper } from './styled';

const ITEMS = [
{
id: 'payload-collection',
title: 'Payload Collection',
description: 'Record operation payloads as span attributes where supported.',
type: InstrumentationRuleType.PAYLOAD_COLLECTION,
icon: InstrumentationRuleType.PAYLOAD_COLLECTION,
type: RulesType.PAYLOAD_COLLECTION,
icon: RulesType.PAYLOAD_COLLECTION,
},
];

Expand All @@ -31,10 +26,7 @@ export function ChooseInstrumentationRuleContainer(): React.JSX.Element {
function renderActionsList() {
return ITEMS.map((item) => {
return (
<ActionCardWrapper
data-cy={'choose-instrumentation-rule-' + item.type}
key={item.id}
>
<ActionCardWrapper data-cy={'choose-instrumentation-rule-' + item.type} key={item.id}>
<NewActionCard item={item} onClick={onItemClick} />
</ActionCardWrapper>
);
Expand All @@ -44,17 +36,9 @@ export function ChooseInstrumentationRuleContainer(): React.JSX.Element {
return (
<>
<DescriptionWrapper>
<KeyvalText size={14}>
{OVERVIEW.INSTRUMENTATION_RULE_DESCRIPTION}
</KeyvalText>
<KeyvalText size={14}>{OVERVIEW.INSTRUMENTATION_RULE_DESCRIPTION}</KeyvalText>
<LinkWrapper>
<KeyvalLink
fontSize={14}
value={ACTION.LINK_TO_DOCS}
onClick={() =>
window.open(INSTRUMENTATION_RULES_DOCS_LINK, '_blank')
}
/>
<KeyvalLink fontSize={14} value={ACTION.LINK_TO_DOCS} onClick={() => window.open(INSTRUMENTATION_RULES_DOCS_LINK, '_blank')} />
</LinkWrapper>
</DescriptionWrapper>
<ActionsListWrapper>{renderActionsList()}</ActionsListWrapper>
Expand Down
10 changes: 7 additions & 3 deletions frontend/webapp/containers/main/overview/add-entity/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useState, useRef, useCallback } from 'react';
import Image from 'next/image';
import theme from '@/styles/theme';
import { useModalStore } from '@/store';
import { AddRuleModal } from '../../rules';
import { AddActionModal } from '../../actions';
import React, { useState, useRef } from 'react';
import styled, { css } from 'styled-components';
import { useActualSources, useOnClickOutside } from '@/hooks';
import { DropdownOption, OVERVIEW_ENTITY_TYPES } from '@/types';
Expand All @@ -29,7 +30,7 @@ const DropdownListContainer = styled.div`
right: 0;
top: 48px;
border-radius: 24px;
width: 131px;
width: 200px;
overflow-y: auto;
background-color: ${({ theme }) => theme.colors.dropdown_bg};
border: 1px solid ${({ theme }) => theme.colors.border};
Expand Down Expand Up @@ -62,6 +63,7 @@ const ButtonText = styled(Text)`

// Default options for the dropdown
const DEFAULT_OPTIONS: DropdownOption[] = [
{ id: OVERVIEW_ENTITY_TYPES.RULE, value: 'Instrumentation Rule' },
{ id: OVERVIEW_ENTITY_TYPES.SOURCE, value: 'Source' },
{ id: OVERVIEW_ENTITY_TYPES.ACTION, value: 'Action' },
{ id: OVERVIEW_ENTITY_TYPES.DESTINATION, value: 'Destination' },
Expand Down Expand Up @@ -100,6 +102,7 @@ const AddEntityButtonDropdown: React.FC<AddEntityButtonDropdownProps> = ({ optio
{isPolling ? <FadeLoader color={theme.colors.primary} /> : <Image src='/icons/common/plus-black.svg' width={16} height={16} alt='Add' />}
<ButtonText size={14}>{placeholder}</ButtonText>
</StyledButton>

{isDropdownOpen && (
<DropdownListContainer>
{options.map((option) => (
Expand All @@ -111,14 +114,15 @@ const AddEntityButtonDropdown: React.FC<AddEntityButtonDropdownProps> = ({ optio
</DropdownListContainer>
)}

<AddRuleModal isModalOpen={currentModal === OVERVIEW_ENTITY_TYPES.RULE} handleCloseModal={handleCloseModal} />
<AddSourceModal
isOpen={currentModal === OVERVIEW_ENTITY_TYPES.SOURCE}
onClose={handleCloseModal}
createSourcesForNamespace={createSourcesForNamespace}
persistNamespaceItems={persistNamespaceItems}
/>
<AddDestinationModal isModalOpen={currentModal === OVERVIEW_ENTITY_TYPES.DESTINATION} handleCloseModal={handleCloseModal} />
<AddActionModal isModalOpen={currentModal === OVERVIEW_ENTITY_TYPES.ACTION} handleCloseModal={handleCloseModal} />
<AddDestinationModal isModalOpen={currentModal === OVERVIEW_ENTITY_TYPES.DESTINATION} handleCloseModal={handleCloseModal} />
</Container>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ export function OverviewDataFlowContainer() {
const { sources } = useActualSources();
const { destinations } = useActualDestination();
const { containerRef, containerWidth } = useContainerWidth();
const { handleNodeClick } = useNodeDataFlowHandlers({ sources, actions, destinations });
const { handleNodeClick } = useNodeDataFlowHandlers({
rules: [],
sources,
actions,
destinations,
});

const columnWidth = 296;
const columnWidth = 255;

// Memoized node and edge builder to improve performance
const { nodes, edges } = useMemo(() => {
return buildNodesAndEdges({
rules: [],
sources,
actions,
destinations,
Expand All @@ -40,7 +46,7 @@ export function OverviewDataFlowContainer() {
<OverviewDataFlowWrapper ref={containerRef}>
<OverviewDrawer />
<OverviewActionMenuContainer />
<NodeBaseDataFlow nodes={nodes} edges={edges} onNodeClick={handleNodeClick} />
<NodeBaseDataFlow nodes={nodes} edges={edges} onNodeClick={handleNodeClick} columnWidth={columnWidth} />
</OverviewDataFlowWrapper>
);
}
104 changes: 104 additions & 0 deletions frontend/webapp/containers/main/rules/add-rule-modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import styled from 'styled-components';
import React, { useEffect, useState } from 'react';
import { RULE_OPTIONS, RuleOption } from './rule-options';
import { AutocompleteInput, Divider, FadeLoader, Modal, NavigationButtons, NotificationNote, SectionTitle } from '@/reuseable-components';

const Container = styled.section`
width: 100%;
max-width: 640px;
height: 640px;
margin: 0 15vw;
padding: 64px 12px 0 12px;
display: flex;
flex-direction: column;
overflow-y: scroll;
`;

const Center = styled.div`
width: 100%;
margin-top: 24px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
`;

interface Props {
isModalOpen: boolean;
handleCloseModal: () => void;
}

export const AddRuleModal: React.FC<Props> = ({ isModalOpen, handleCloseModal }) => {
// const { formData, handleFormChange, resetFormData, validateForm } = useRuleFormData();
// const { createRule, loading } = useRuleCRUD({ onSuccess: handleClose });
const [selectedItem, setSelectedItem] = useState<RuleOption | undefined>(undefined);

useEffect(() => {
if (!selectedItem) handleSelect(RULE_OPTIONS[0]);
}, [selectedItem]);

// const isFormOk = useMemo(() => !!selectedItem && validateForm(), [selectedItem, formData]);

const handleSubmit = async () => {
// createRule(formData);
};

function handleClose() {
// resetFormData();
setSelectedItem(undefined);
handleCloseModal();
}

const handleSelect = (item: RuleOption) => {
// resetFormData();
// handleFormChange('type', item.type);
setSelectedItem(item);
};

return (
<Modal
isOpen={isModalOpen}
onClose={handleClose}
header={{ title: 'Add Instrumentation Rule' }}
actionComponent={
<NavigationButtons
buttons={[
{
variant: 'primary',
label: 'DONE',
onClick: handleSubmit,
disabled: true,
},
]}
/>
}
>
<Container>
<SectionTitle
title='Define Instrumentation Rule'
description='Instrumentation rules control how telemetry is recorded from your application. Choose a rule type and provide necessary information.'
/>
<NotificationNote
type='info'
text='We currently support one rule. We’ll be adding new rule types in the near future.'
style={{ marginTop: '24px' }}
/>
<AutocompleteInput options={RULE_OPTIONS} selectedOption={selectedItem} onOptionSelect={handleSelect} style={{ marginTop: '12px' }} />

{!!selectedItem?.type ? (
<div>
<Divider margin='16px 0' />

{/* {loading ? ( */}
<Center>
<FadeLoader cssOverride={{ scale: 2 }} />
</Center>
{/* ) : (
<ChooseRuleBody rule={selectedItem} formData={formData} handleFormChange={handleFormChange} />
)} */}
</div>
) : null}
</Container>
</Modal>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { InstrumentationRuleType } from '@/types';
import { getRuleIcon } from '@/utils/functions';

export type RuleOption = {
id: string;
label: string;
type?: InstrumentationRuleType;
icon?: string;
description?: string;
docsEndpoint?: string;
docsDescription?: string;
items?: RuleOption[];
};

export const RULE_OPTIONS: RuleOption[] = [
{
id: 'payload_collection',
label: 'Payload Collection',
description: 'Collect span attributes containing payload data to traces.',
type: InstrumentationRuleType.PAYLOAD_COLLECTION,
icon: getRuleIcon(InstrumentationRuleType.PAYLOAD_COLLECTION),
docsEndpoint: '/pipeline/rules/payloadcollection',
docsDescription: 'The “Payload Collection” Rule can be used to add span attributes containing payload data to traces.',
},
];
1 change: 1 addition & 0 deletions frontend/webapp/containers/main/rules/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './add-rule-modal';
4 changes: 4 additions & 0 deletions frontend/webapp/hooks/overview/useNodeDataFlowHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { useDrawerStore, useModalStore } from '@/store';
import { K8sActualSource, ActualDestination, ActionDataParsed, OVERVIEW_ENTITY_TYPES, OVERVIEW_NODE_TYPES } from '@/types';

export function useNodeDataFlowHandlers({
rules,
sources,
actions,
destinations,
}: {
rules: any[];
sources: K8sActualSource[];
actions: ActionDataParsed[];
destinations: ActualDestination[];
Expand Down Expand Up @@ -50,6 +52,8 @@ export function useNodeDataFlowHandlers({
type,
item: selectedDrawerItem,
});
} else if (type === OVERVIEW_NODE_TYPES.ADD_RULE) {
setCurrentModal(OVERVIEW_ENTITY_TYPES.RULE);
} else if (type === OVERVIEW_NODE_TYPES.ADD_SOURCE) {
setCurrentModal(OVERVIEW_ENTITY_TYPES.SOURCE);
} else if (type === OVERVIEW_NODE_TYPES.ADD_ACTION) {
Expand Down
4 changes: 4 additions & 0 deletions frontend/webapp/public/icons/overview/rules.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/webapp/public/icons/rules/payloadcollection.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 6a91aba

Please sign in to comment.