rules.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import {forwardRef} from 'react';
  2. import styled from '@emotion/styled';
  3. import Button from 'sentry/components/button';
  4. import TextOverflow from 'sentry/components/textOverflow';
  5. import {IconDelete, IconEdit} from 'sentry/icons';
  6. import {t} from 'sentry/locale';
  7. import space from 'sentry/styles/space';
  8. import {MethodType, Rule, RuleType} from './types';
  9. import {getMethodLabel, getRuleLabel} from './utils';
  10. type Props = {
  11. rules: Array<Rule>;
  12. disabled?: boolean;
  13. onDeleteRule?: (id: Rule['id']) => () => void;
  14. onEditRule?: (id: Rule['id']) => () => void;
  15. };
  16. const getListItemDescription = (rule: Rule) => {
  17. const {method, type, source} = rule;
  18. const methodLabel = getMethodLabel(method);
  19. const typeLabel = getRuleLabel(type);
  20. const descriptionDetails: Array<string> = [];
  21. descriptionDetails.push(`[${methodLabel.label}]`);
  22. descriptionDetails.push(
  23. rule.type === RuleType.PATTERN ? `[${rule.pattern}]` : `[${typeLabel}]`
  24. );
  25. if (rule.method === MethodType.REPLACE && rule.placeholder) {
  26. descriptionDetails.push(` with [${rule.placeholder}]`);
  27. }
  28. return `${descriptionDetails.join(' ')} ${t('from')} [${source}]`;
  29. };
  30. const Rules = forwardRef(function RulesList(
  31. {rules, onEditRule, onDeleteRule, disabled}: Props,
  32. ref: React.Ref<HTMLUListElement>
  33. ) {
  34. return (
  35. <List ref={ref} isDisabled={disabled} data-test-id="advanced-data-scrubbing-rules">
  36. {rules.map(rule => {
  37. const {id} = rule;
  38. return (
  39. <ListItem key={id}>
  40. <TextOverflow>{getListItemDescription(rule)}</TextOverflow>
  41. {onEditRule && (
  42. <Button
  43. aria-label={t('Edit Rule')}
  44. size="sm"
  45. onClick={onEditRule(id)}
  46. icon={<IconEdit />}
  47. disabled={disabled}
  48. />
  49. )}
  50. {onDeleteRule && (
  51. <Button
  52. aria-label={t('Delete Rule')}
  53. size="sm"
  54. onClick={onDeleteRule(id)}
  55. icon={<IconDelete />}
  56. disabled={disabled}
  57. />
  58. )}
  59. </ListItem>
  60. );
  61. })}
  62. </List>
  63. );
  64. });
  65. export default Rules;
  66. const List = styled('ul')<{
  67. isDisabled?: boolean;
  68. }>`
  69. list-style: none;
  70. margin: 0;
  71. padding: 0;
  72. margin-bottom: 0 !important;
  73. ${p =>
  74. p.isDisabled &&
  75. `
  76. color: ${p.theme.gray200};
  77. background: ${p.theme.backgroundSecondary};
  78. `}
  79. `;
  80. const ListItem = styled('li')`
  81. display: grid;
  82. grid-template-columns: auto max-content max-content;
  83. grid-column-gap: ${space(1)};
  84. align-items: center;
  85. padding: ${space(1)} ${space(2)};
  86. border-bottom: 1px solid ${p => p.theme.border};
  87. &:hover {
  88. background-color: ${p => p.theme.backgroundSecondary};
  89. }
  90. &:last-child {
  91. border-bottom: 0;
  92. }
  93. `;