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-1603]: add rules column to overview #1661

Merged
merged 16 commits into from
Oct 30, 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
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
Loading