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

UI Framework for deprecating pipeline functions #21467

Merged
merged 13 commits into from
Feb 3, 2025
5 changes: 5 additions & 0 deletions changelog/unreleased/pr-21467.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type = "f"
message = "UI Framework for deprecating pipeline functions"

pulls = ["21467"]
issues = ["19287"]
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ import * as React from 'react';
import { fireEvent, render, screen } from 'wrappedTestingLibrary';

import RuleBlockDisplay from './RuleBlockDisplay';
import { buildRuleBlock } from './fixtures';
import { RuleBuilderTypes } from './types';
import { actionsBlockDict, buildRuleBlock } from './fixtures';
import RuleBuilderProvider from './RuleBuilderProvider';

const block = buildRuleBlock({
Expand Down Expand Up @@ -52,7 +51,7 @@ describe('RuleBlockDisplay', () => {
it('shows the outputvariable and its return type', async () => {
render(
<RuleBuilderProvider>
<RuleBlockDisplay block={block} onDelete={mockDelete} onEdit={mockEdit} onNegate={mockNegate} onDuplicate={mockDuplicate} onInsertAbove={mockInsertAbove} onInsertBelow={mockInsertBelow} returnType={RuleBuilderTypes.Number} type={type} />
<RuleBlockDisplay block={block} onDelete={mockDelete} onEdit={mockEdit} onNegate={mockNegate} onDuplicate={mockDuplicate} onInsertAbove={mockInsertAbove} onInsertBelow={mockInsertBelow} selectedBlockDict={actionsBlockDict[1]} type={type} />
</RuleBuilderProvider>,
);

Expand Down Expand Up @@ -116,4 +115,14 @@ describe('RuleBlockDisplay', () => {

expect(screen.getByText('wrong 1, not right 2')).toBeInTheDocument();
});

it('shows a deprecated label for deprecating pipeline functions', async () => {
render(
<RuleBuilderProvider>
<RuleBlockDisplay block={block} onDelete={mockDelete} onEdit={mockEdit} onNegate={mockNegate} onDuplicate={mockDuplicate} onInsertAbove={mockInsertAbove} onInsertBelow={mockInsertBelow} selectedBlockDict={actionsBlockDict[0]} type={type} />
</RuleBuilderProvider>,
);

expect(screen.getByText('Deprecated')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { IconButton } from 'components/common';
import { MORE_ACTIONS_TITLE, MORE_ACTIONS_HOVER_TITLE } from 'components/common/EntityDataTable/Constants';
import OverlayDropdownButton from 'components/common/OverlayDropdownButton';

import type { BlockType, RuleBlock } from './types';
import type { BlockDict, BlockType, RuleBlock } from './types';
import { RuleBuilderTypes } from './types';
import { useRuleBuilder } from './RuleBuilderContext';

Expand All @@ -35,7 +35,7 @@ type Props = {
onDuplicate: () => void,
onInsertAbove: () => void,
onInsertBelow: () => void,
returnType?: RuleBuilderTypes,
selectedBlockDict?: BlockDict,
type: BlockType,
}

Expand Down Expand Up @@ -89,7 +89,11 @@ const EditIconButton = styled(IconButton)(({ theme }) => css`
margin-right: ${theme.spacings.xs};
`);

const RuleBlockDisplay = ({ block, negatable = false, onEdit, onDelete, onNegate, onDuplicate, onInsertAbove, onInsertBelow, returnType, type } : Props) => {
const DeprecatedLabel = styled(Label)`
padding: 2px 8px;
`;

const RuleBlockDisplay = ({ block = undefined, negatable = false, onEdit, onDelete, onNegate, onDuplicate, onInsertAbove, onInsertBelow, selectedBlockDict = undefined, type } : Props) => {
const [showActions, setShowActions] = useState<boolean>(false);
const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false);
const [highlightedOutput, setHighlightedOutput] = useRuleBuilder().useHighlightedOutput;
Expand All @@ -108,7 +112,7 @@ const RuleBlockDisplay = ({ block, negatable = false, onEdit, onDelete, onNegate
}
};

const returnTypeLabel = readableReturnType(returnType);
const returnTypeLabel = readableReturnType(selectedBlockDict?.return_type);

const highlightedRuleTitle = (termToHighlight: string, title: string = '') => {
const parts = title.split(/('\$.*?')/);
Expand All @@ -122,13 +126,10 @@ const RuleBlockDisplay = ({ block, negatable = false, onEdit, onDelete, onNegate
});

return (partsWithHighlight.map((item, index) => (

(

<React.Fragment key={index}>
{item}
</React.Fragment>
)
// eslint-disable-next-line react/no-array-index-key
<React.Fragment key={index}>
{item}
</React.Fragment>
)));
};

Expand All @@ -147,6 +148,9 @@ const RuleBlockDisplay = ({ block, negatable = false, onEdit, onDelete, onNegate
{highlightedOutput ? (
highlightedRuleTitle(highlightedOutput, block?.step_title)
) : block?.step_title}
{selectedBlockDict?.deprecated && (
<span>&nbsp;<DeprecatedLabel bsStyle="warning" bsSize="xs">Deprecated</DeprecatedLabel></span>
)}
{block?.errors?.length > 0 && (
<ErrorMessage title={errorMessage}>{errorMessage}</ErrorMessage>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,10 @@ describe('RuleBlockForm', () => {
expect(screen.getByText('wrong 1')).toBeInTheDocument();
expect(screen.getByText('not right 2')).toBeInTheDocument();
});

it('shows a deprecated label for deprecating pipeline functions', async () => {
render(comp({ selectedBlockDict: actionsBlockDict[0] }));

expect(screen.getByText('Deprecated')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { Formik } from 'formik';
import styled, { css } from 'styled-components';

import { FormSubmit, Icon, OverlayTrigger, Select, NestedForm } from 'components/common';
import { Button, Col, Row } from 'components/bootstrap';
import { Button, Col, Label, Row } from 'components/bootstrap';
import RuleBlockFormField from 'components/rules/rule-builder/RuleBlockFormField';
import { getPathnameWithoutId } from 'util/URLUtils';
import useLocation from 'routing/useLocation';
Expand All @@ -32,7 +32,7 @@ import type { BlockType, RuleBlock, BlockDict, BlockFieldDict, OutputVariables }

import RuleHelperTable from '../rule-helper/RulerHelperTable';

type Option = { label: string, value: any, description?: string | null };
type Option = { label: string, value: any, description?: string | null, deprecated?: boolean };

type Props = {
existingBlock?: RuleBlock,
Expand Down Expand Up @@ -81,16 +81,25 @@ const OptionDescription = styled.p<{ $isSelected: boolean }>(({ theme, $isSelect
overflow: hidden;
`);

const OptionContainer = styled.div`
display: flex;
justify-content: space-between;
`;

const DeprecatedLabel = styled.span`
float: right;
`;

const RuleBlockForm = ({
existingBlock,
existingBlock = undefined,
onAdd,
onCancel,
onSelect,
onUpdate,
options,
order,
outputVariableList,
selectedBlockDict,
outputVariableList = [],
selectedBlockDict = undefined,
type,
}: Props) => {
const [initialValues, setInitialValues] = useState<{}>({});
Expand Down Expand Up @@ -166,7 +175,10 @@ const RuleBlockForm = ({

const optionRenderer = (option: Option, isSelected: boolean) => (
<>
<OptionTitle>{option.label}</OptionTitle>
<OptionContainer>
<OptionTitle>{option.label}</OptionTitle>
<span>{option.deprecated && <Label bsStyle="warning" bsSize="xs">Deprecated</Label>}</span>
</OptionContainer>
{option.description && (<OptionDescription $isSelected={isSelected}>{option.description}</OptionDescription>)}
</>
);
Expand Down Expand Up @@ -210,6 +222,9 @@ const RuleBlockForm = ({
data-testid="funcSyntaxHelpIcon" />
</Button>
</OverlayTrigger>
{selectedBlockDict.deprecated && (
<DeprecatedLabel>&nbsp;<Label bsStyle="warning" bsSize="xs">Deprecated</Label></DeprecatedLabel>
)}
</h5>
<BlockDescription>{selectedBlockDict.description}</BlockDescription>
</Col>
Expand All @@ -225,8 +240,7 @@ const RuleBlockForm = ({
blockType={type}
resetField={(fieldName) => resetField(fieldName, setFieldValue)} />
</Row>
),
)}
))}

<Errors objectWithErrors={existingBlock} />
<FormSubmit bsSize="small"
Expand All @@ -237,7 +251,6 @@ const RuleBlockForm = ({
resetForm();
onCancel();
}} />

</SelectedBlock>
)}
</NestedForm>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ type Props = {
const RuleBuilderBlock = ({
type,
blockDict,
block,
block = undefined,
order,
outputVariableList,
outputVariableList = [],
addBlock,
updateBlock,
deleteBlock,
Expand Down Expand Up @@ -210,7 +210,7 @@ const RuleBuilderBlock = ({

const isBlockNegatable = (): boolean => type === 'condition';

const options = blockDict.map(({ name, description, rule_builder_name }) => ({ label: rule_builder_name, value: name, description: description }));
const options = blockDict.map(({ name, description, rule_builder_name, deprecated }) => ({ label: rule_builder_name, value: name, description, deprecated }));

const showForm = !block || editMode;

Expand All @@ -236,7 +236,7 @@ const RuleBuilderBlock = ({
onDuplicate={onDuplicate}
onInsertAbove={onInsertAbove}
onInsertBelow={onInsertBelow}
returnType={currentBlockDict?.return_type}
selectedBlockDict={currentBlockDict}
negatable={isBlockNegatable()}
type={type} />
{Boolean(insertMode) && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { RuleBuilderTypes } from './types';
const conditionsBlockDict: BlockDict[] = [
{
name: 'has_field_less_or_equal',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.Boolean,
params: [
Expand Down Expand Up @@ -50,6 +51,7 @@ const conditionsBlockDict: BlockDict[] = [
},
{
name: 'has_field',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.Boolean,
params: [
Expand Down Expand Up @@ -80,6 +82,7 @@ const conditionsBlockDict: BlockDict[] = [
},
{
name: 'has_field_greater_or_equal',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.Boolean,
params: [
Expand Down Expand Up @@ -111,6 +114,7 @@ const conditionsBlockDict: BlockDict[] = [
},
{
name: 'has_field_equals',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.Boolean,
params: [
Expand Down Expand Up @@ -144,6 +148,7 @@ const conditionsBlockDict: BlockDict[] = [
const actionsBlockDict: BlockDict[] = [
{
name: 'has_field',
deprecated: true,
pure: false,
return_type: RuleBuilderTypes.Boolean,
params: [
Expand Down Expand Up @@ -174,6 +179,7 @@ const actionsBlockDict: BlockDict[] = [
},
{
name: 'to_long',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.Number,
params: [
Expand Down Expand Up @@ -204,6 +210,7 @@ const actionsBlockDict: BlockDict[] = [
},
{
name: 'get_field',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.Object,
params: [
Expand Down Expand Up @@ -234,6 +241,7 @@ const actionsBlockDict: BlockDict[] = [
},
{
name: 'set_grok_to_fields',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.Void,
params: [
Expand Down Expand Up @@ -291,6 +299,7 @@ const actionsBlockDict: BlockDict[] = [
},
{
name: 'substring',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.String,
params: [
Expand Down Expand Up @@ -330,6 +339,7 @@ const actionsBlockDict: BlockDict[] = [
},
{
name: 'to_string',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.String,
params: [
Expand Down Expand Up @@ -360,6 +370,7 @@ const actionsBlockDict: BlockDict[] = [
},
{
name: 'set_field',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.Void,
params: [
Expand Down Expand Up @@ -426,6 +437,7 @@ const actionsBlockDict: BlockDict[] = [
},
{
name: 'format_date',
deprecated: false,
pure: false,
return_type: RuleBuilderTypes.String,
params: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export type BlockFieldDict = {
export type BlockDict = {
name: string,
pure: boolean,
deprecated: boolean,
return_type: RuleBuilderTypes,
params: Array<BlockFieldDict>,
description: string | null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
import React from 'react';

import { Table } from 'components/bootstrap';
import { Label, Table } from 'components/bootstrap';
import { Icon } from 'components/common';

import RuleHelperStyle from './RuleHelper.css';
Expand All @@ -30,7 +30,7 @@ type Props = {
onFunctionClick?: (functionName: string) => void
}

const RuleHelperTable = ({ entries, expanded = {}, onFunctionClick } : Props) => {
const RuleHelperTable = ({ entries, expanded = {}, onFunctionClick = undefined } : Props) => {
const parameters = (descriptor: BlockDict) => descriptor.params.map((p) => (
<tr key={p.name}>
<td className={RuleHelperStyle.adjustedTableCellWidth}>{p.name}</td>
Expand Down Expand Up @@ -72,17 +72,15 @@ const RuleHelperTable = ({ entries, expanded = {}, onFunctionClick } : Props) =>

return (
<tbody key={d.name}>
{onFunctionClick ? (
<tr onClick={() => onFunctionClick(d.name)} className={RuleHelperStyle.clickableRow}>
<td className={RuleHelperStyle.functionTableCell}><code>{functionSignature(d)}</code></td>
<td>{d.description}</td>
</tr>
) : (
<tr>
<td className={RuleHelperStyle.functionTableCell}><code>{functionSignature(d)}</code></td>
<td>{d.description}</td>
</tr>
)}
<tr onClick={onFunctionClick ? () => onFunctionClick(d.name) : undefined} className={onFunctionClick ? RuleHelperStyle.clickableRow : undefined}>
<td className={RuleHelperStyle.functionTableCell}><code>{functionSignature(d)}</code></td>
<td>
{d.deprecated && (
<span><Label bsStyle="warning" bsSize="xs">Deprecated</Label>&nbsp;</span>
)}
{d.description}
</td>
</tr>
{details}
</tbody>
);
Expand Down
Loading