Skip to content

Commit

Permalink
[ResponseOps][Alerting] Show missing Slack connectors in the new rule…
Browse files Browse the repository at this point in the history
… form (elastic#202315)

Closes elastic#201673

## Summary

- changed the logic to create the connectorsMap (which gives us the
connector type filters):
- Only the '**slack'** and **'slack API'** connector types include a
`subtype` array. I updated the logic so that when the `actionTypeModel`
has **hideInUi** set to true (indicating a 'slack API' connector), it
searches for a **'slack'** connector in the subtype. If a **'slack'**
connector is found, `otherActionTypeId` is set to 'slack'; otherwise, it
is set to `undefined`. This effectively "maps" the 'slack API' type to
the 'slack' type within the `connectorsMap`

- changed the logic to create the `filteredConnectors` (which gives us
the connectors to display, filtered after the type):
- The **selectedConnectorType** can only be '**slack'** because, in the
`connectorsMap`, the '**slack API'** option has already been mapped to
'**slack'** and is no longer included as a separate type.
- If the `subtype` includes **'slack',** the filter will return
connectors with `actionTypeId` of either 'slack' or 'slack API'.
- This ensures that both 'slack' and 'slack API' connectors are
displayed, as 'slack API' is associated with the 'slack' type through
the subtype.
    


https://github.com/user-attachments/assets/9cccaf42-b6db-4eea-b2fd-8f37f0e24745

## Release note
Fix Slack API connectors not displayed under Slack connector type when
adding new connector to rule.
  • Loading branch information
georgianaonoleata1904 authored Dec 4, 2024
1 parent 720ddd7 commit 2884d90
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,92 @@ describe('ruleActionsConnectorsModal', () => {
expect(screen.queryByText('connector2')).not.toBeInTheDocument();
});

test('should not render connector filter if hideInUi is true', async () => {
const actionTypeRegistry = new TypeRegistry<ActionTypeModel>();
actionTypeRegistry.register(
getActionTypeModel('1', {
id: 'actionType-1',
subtype: [
{ id: 'actionType-1', name: 'connector-1' },
{ id: 'actionType-2', name: 'connector-2' },
],
})
);
actionTypeRegistry.register(
getActionTypeModel('2', {
id: 'actionType-2',
hideInUi: true,
subtype: [
{ id: 'actionType-1', name: 'connector-1' },
{ id: 'actionType-2', name: 'connector-2' },
],
})
);
useRuleFormState.mockReturnValue({
plugins: {
actionTypeRegistry,
},
formData: {
actions: [],
},
connectors: mockConnectors,
connectorTypes: mockActionTypes,
});

render(
<RuleActionsConnectorsModal onClose={mockOnClose} onSelectConnector={mockOnSelectConnector} />
);
const filterButtonGroup = screen.getByTestId('ruleActionsConnectorsModalFilterButtonGroup');
expect(within(filterButtonGroup).getByText('actionType: 1')).toBeInTheDocument();
expect(within(filterButtonGroup).queryByText('actionType: 2')).not.toBeInTheDocument();
expect(within(filterButtonGroup).getByText('All')).toBeInTheDocument();

expect(screen.getAllByTestId('ruleActionsConnectorsModalFilterButton').length).toEqual(2);
});

test('should display connectors if hideInUi is true and it has subtype', async () => {
const actionTypeRegistry = new TypeRegistry<ActionTypeModel>();
actionTypeRegistry.register(
getActionTypeModel('1', {
id: 'actionType-1',
subtype: [
{ id: 'actionType-1', name: 'connector-1' },
{ id: 'actionType-2', name: 'connector-2' },
],
})
);
actionTypeRegistry.register(
getActionTypeModel('2', {
id: 'actionType-2',
hideInUi: true,
subtype: [
{ id: 'actionType-1', name: 'connector-1' },
{ id: 'actionType-2', name: 'connector-2' },
],
})
);
useRuleFormState.mockReturnValue({
plugins: {
actionTypeRegistry,
},
formData: {
actions: [],
},
connectors: mockConnectors,
connectorTypes: mockActionTypes,
});

render(
<RuleActionsConnectorsModal onClose={mockOnClose} onSelectConnector={mockOnSelectConnector} />
);
const filterButtonGroup = screen.getByTestId('ruleActionsConnectorsModalFilterButtonGroup');

await userEvent.click(within(filterButtonGroup).getByText('actionType: 1'));
expect(screen.getAllByTestId('ruleActionsConnectorsModalCard').length).toEqual(2);
expect(screen.getByText('connector-1')).toBeInTheDocument();
expect(screen.getByText('connector-2')).toBeInTheDocument();
});

test('should not render connector if actionsParamsField doesnt exist', () => {
const actionTypeRegistry = new TypeRegistry<ActionTypeModel>();
actionTypeRegistry.register(getActionTypeModel('1', { id: 'actionType-1' }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@ export const RuleActionsConnectorsModal = (props: RuleActionsConnectorsModalProp
if (!actionType) {
return false;
}
if (actionTypeModel.hideInUi) {
return false;
}

if (!actionTypeModel.actionParamsFields) {
return false;
}
Expand All @@ -92,6 +90,7 @@ export const RuleActionsConnectorsModal = (props: RuleActionsConnectorsModalProp
if (!actionType.enabledInConfig && !checkEnabledResult.isEnabled) {
return false;
}

return true;
});
}, [connectors, connectorTypes, preconfiguredConnectors, actionTypeRegistry]);
Expand Down Expand Up @@ -119,29 +118,43 @@ export const RuleActionsConnectorsModal = (props: RuleActionsConnectorsModalProp

const connectorsMap: ConnectorsMap | null = useMemo(() => {
return availableConnectors.reduce<ConnectorsMap>((result, { actionTypeId }) => {
if (result[actionTypeId]) {
result[actionTypeId].total += 1;
const actionTypeModel = actionTypeRegistry.get(actionTypeId);
const subtype = actionTypeModel.subtype;

const shownActionTypeId = actionTypeModel.hideInUi
? subtype?.filter((type) => type.id !== actionTypeId)[0].id
: undefined;

const currentActionTypeId = shownActionTypeId ? shownActionTypeId : actionTypeId;

if (result[currentActionTypeId]) {
result[currentActionTypeId].total += 1;
} else {
result[actionTypeId] = {
actionTypeId,
result[currentActionTypeId] = {
actionTypeId: currentActionTypeId,
total: 1,
name: connectorTypes.find(({ id }) => actionTypeId === id)?.name || '',
name: connectorTypes.find(({ id }) => id === currentActionTypeId)?.name || '',
};
}

return result;
}, {});
}, [availableConnectors, connectorTypes]);
}, [availableConnectors, connectorTypes, actionTypeRegistry]);

const filteredConnectors = useMemo(() => {
return availableConnectors
.filter(({ actionTypeId }) => {
const subtype = actionTypeRegistry.get(actionTypeId).subtype?.map((type) => type.id);

if (selectedConnectorType === 'all' || selectedConnectorType === '') {
return true;
}
if (selectedConnectorType === actionTypeId) {
return true;

if (subtype?.includes(selectedConnectorType)) {
return subtype.includes(actionTypeId);
}
return false;

return selectedConnectorType === actionTypeId;
})
.filter(({ actionTypeId, name }) => {
const trimmedSearchValue = searchValue.trim().toLocaleLowerCase();
Expand Down

0 comments on commit 2884d90

Please sign in to comment.