Browse Source

feat(issue-priority): Add priority badge and dropdown components (#64615)

Malachi Willey 1 year ago
parent
commit
64918dc853

+ 29 - 0
static/app/components/group/groupPriority.stories.tsx

@@ -0,0 +1,29 @@
+import {useState} from 'react';
+
+import {
+  GroupPriorityBadge,
+  GroupPriorityDropdown,
+} from 'sentry/components/group/groupPriority';
+import SideBySide from 'sentry/components/stories/sideBySide';
+import storyBook from 'sentry/stories/storyBook';
+import {PriorityLevel} from 'sentry/types';
+
+const PRIORITIES = [PriorityLevel.HIGH, PriorityLevel.MEDIUM, PriorityLevel.LOW];
+
+export const Badge = storyBook(GroupPriorityBadge, story => {
+  story('Default', () => (
+    <SideBySide>
+      {PRIORITIES.map(priority => (
+        <GroupPriorityBadge key={priority} priority={priority} />
+      ))}
+    </SideBySide>
+  ));
+});
+
+export const Dropdown = storyBook(GroupPriorityDropdown, story => {
+  story('Default', () => {
+    const [value, setValue] = useState(PriorityLevel.MEDIUM);
+
+    return <GroupPriorityDropdown value={value} onChange={setValue} />;
+  });
+});

+ 95 - 0
static/app/components/group/groupPriority.tsx

@@ -0,0 +1,95 @@
+import {useMemo} from 'react';
+import type {Theme} from '@emotion/react';
+import styled from '@emotion/styled';
+
+import {Button} from 'sentry/components/button';
+import {DropdownMenu, type MenuItemProps} from 'sentry/components/dropdownMenu';
+import Tag from 'sentry/components/tag';
+import {IconChevron} from 'sentry/icons';
+import {t} from 'sentry/locale';
+import {space} from 'sentry/styles/space';
+import {PriorityLevel} from 'sentry/types';
+
+type GroupPriorityDropdownProps = {
+  onChange: (value: PriorityLevel) => void;
+  value: PriorityLevel;
+};
+
+type GroupPriorityBadgeProps = {
+  priority: PriorityLevel;
+  children?: React.ReactNode;
+};
+
+const PRIORITY_KEY_TO_LABEL: Record<PriorityLevel, string> = {
+  [PriorityLevel.HIGH]: t('High'),
+  [PriorityLevel.MEDIUM]: t('Medium'),
+  [PriorityLevel.LOW]: t('Low'),
+};
+
+const PRIORITY_OPTIONS = [PriorityLevel.HIGH, PriorityLevel.MEDIUM, PriorityLevel.LOW];
+
+function getTagTypeForPriority(priority: string): keyof Theme['tag'] {
+  switch (priority) {
+    case PriorityLevel.HIGH:
+      return 'error';
+    case PriorityLevel.MEDIUM:
+      return 'warning';
+    case PriorityLevel.LOW:
+    default:
+      return 'default';
+  }
+}
+
+export function GroupPriorityBadge({priority, children}: GroupPriorityBadgeProps) {
+  return (
+    <StyledTag type={getTagTypeForPriority(priority)}>
+      {PRIORITY_KEY_TO_LABEL[priority] ?? t('Unknown')}
+      {children}
+    </StyledTag>
+  );
+}
+
+export function GroupPriorityDropdown({value, onChange}: GroupPriorityDropdownProps) {
+  const options: MenuItemProps[] = useMemo(() => {
+    return PRIORITY_OPTIONS.map(priority => ({
+      textValue: PRIORITY_KEY_TO_LABEL[priority],
+      key: priority,
+      label: <GroupPriorityBadge priority={priority} />,
+      onAction: () => onChange(priority),
+    }));
+  }, [onChange]);
+
+  return (
+    <DropdownMenu
+      size="sm"
+      trigger={triggerProps => (
+        <DropdownButton
+          {...triggerProps}
+          aria-label={t('Modify issue priority')}
+          size="zero"
+        >
+          <GroupPriorityBadge priority={value}>
+            <IconChevron direction="down" size="xs" />
+          </GroupPriorityBadge>
+        </DropdownButton>
+      )}
+      items={options}
+    />
+  );
+}
+
+const DropdownButton = styled(Button)`
+  font-weight: normal;
+  border: none;
+  padding: 0;
+  height: unset;
+  border-radius: 10px;
+`;
+
+const StyledTag = styled(Tag)`
+  span {
+    display: flex;
+    align-items: center;
+    gap: ${space(0.5)};
+  }
+`;

+ 3 - 0
static/app/views/stories/storyFile.tsx

@@ -79,6 +79,9 @@ const FlexColumn = styled('section')`
 
 const StoryArea = styled('div')`
   overflow: scroll;
+  display: flex;
+  flex-direction: column;
+  gap: ${space(4)};
 `;
 
 const Header = styled('h2')`