Browse Source

fix(integrations): Fix dropdowns for project mapping (#60051)

this pr fixes the dropdowns for project mapping. 

before:
<img width="671" alt="Screenshot 2023-11-15 at 2 03 04 PM"
src="https://github.com/getsentry/sentry/assets/46740234/3ee7ca3d-ed6b-4143-b126-20555bef4f12">


after: 
![Screenshot 2023-11-15 at 2 03
30 PM](https://github.com/getsentry/sentry/assets/46740234/254248fd-5876-403c-98ae-b58d374a4d76)
Richard Roggenkemper 1 year ago
parent
commit
085097f27e
1 changed files with 45 additions and 78 deletions
  1. 45 78
      static/app/components/forms/fields/projectMapperField.tsx

+ 45 - 78
static/app/components/forms/fields/projectMapperField.tsx

@@ -95,11 +95,32 @@ export class RenderField extends Component<RenderProps, State> {
     // prevent a single mapped item from being associated with multiple Sentry projects
     const mappedValuesUsed = new Set(existingValues.map(tuple => tuple[1]));
 
-    const projectOptions = sentryProjects.map(({slug, id}) => ({label: slug, value: id}));
+    const renderIdBadge = ({id, hideName}: {hideName: boolean; id: number | null}) => {
+      const project = sentryProjectsById[id || ''];
+      return (
+        <IdBadge
+          project={project}
+          avatarProps={{consistentWidth: true}}
+          avatarSize={16}
+          disableLink
+          hideName={hideName}
+        />
+      );
+    };
+
+    const projectOptions = sentryProjects.map(({slug, id}) => ({
+      label: slug,
+      value: id,
+      leadingItems: renderIdBadge({id, hideName: true}),
+    }));
 
     const mappedItemsToShow = mappedDropdownItems.filter(
       item => !mappedValuesUsed.has(item.value)
     );
+    const mappedItemOptions = mappedItemsToShow.map(mappedItem => ({
+      ...mappedItem,
+      leadingItems: getIcon(iconType),
+    }));
 
     const handleSelectProject = ({value}: {value: number}) => {
       this.setState({selectedSentryProjectId: value});
@@ -173,69 +194,6 @@ export class RenderField extends Component<RenderProps, State> {
       );
     };
 
-    const customValueContainer = containerProps => {
-      // if no value set, we want to return the default component that is rendered
-      const project = sentryProjectsById[selectedSentryProjectId || ''];
-      if (!project) {
-        return <components.ValueContainer {...containerProps} />;
-      }
-      return (
-        <components.ValueContainer {...containerProps}>
-          <IdBadge
-            project={project}
-            avatarSize={20}
-            displayName={project.slug}
-            avatarProps={{consistentWidth: true}}
-            disableLink
-          />
-        </components.ValueContainer>
-      );
-    };
-
-    const customOptionProject = projectProps => {
-      const project = sentryProjectsById[projectProps.value];
-      // Should never happen for a dropdown item
-      if (!project) {
-        return null;
-      }
-      return (
-        <components.Option {...projectProps}>
-          <IdBadge
-            project={project}
-            avatarSize={20}
-            displayName={project.slug}
-            avatarProps={{consistentWidth: true}}
-            disableLink
-          />
-        </components.Option>
-      );
-    };
-
-    const customMappedValueContainer = containerProps => {
-      // if no value set, we want to return the default component that is rendered
-      const mappedValue = mappedItemsByValue[selectedMappedValue || ''];
-      if (!mappedValue) {
-        return <components.ValueContainer {...containerProps} />;
-      }
-      return (
-        <components.ValueContainer {...containerProps}>
-          <IntegrationIconWrapper>{getIcon(iconType)}</IntegrationIconWrapper>
-          <OptionLabelWrapper>{mappedValue.label}</OptionLabelWrapper>
-        </components.ValueContainer>
-      );
-    };
-
-    const customOptionMappedValue = optionProps => {
-      return (
-        <components.Option {...optionProps}>
-          <OptionWrapper>
-            <IntegrationIconWrapper>{getIcon(iconType)}</IntegrationIconWrapper>
-            <OptionLabelWrapper>{optionProps.label}</OptionLabelWrapper>
-          </OptionWrapper>
-        </components.Option>
-      );
-    };
-
     return (
       <Fragment>
         {existingValues.map(renderItem)}
@@ -243,10 +201,18 @@ export class RenderField extends Component<RenderProps, State> {
           <SelectControl
             placeholder={mappedValuePlaceholder}
             name="mappedDropdown"
-            options={mappedItemsToShow}
+            options={mappedItemOptions}
             components={{
-              Option: customOptionMappedValue,
-              ValueContainer: customMappedValueContainer,
+              SingleValue: containerProps => {
+                return (
+                  <components.ValueContainer {...containerProps}>
+                    <MappedValueContainer>
+                      {containerProps.data.leadingItems}
+                      {containerProps.children}
+                    </MappedValueContainer>
+                  </components.ValueContainer>
+                );
+              },
             }}
             onChange={handleSelectMappedValue}
             value={selectedMappedValue}
@@ -257,8 +223,13 @@ export class RenderField extends Component<RenderProps, State> {
             name="project"
             options={projectOptions}
             components={{
-              Option: customOptionProject,
-              ValueContainer: customValueContainer,
+              SingleValue: containerProps => {
+                return (
+                  <components.ValueContainer {...containerProps}>
+                    {renderIdBadge({id: selectedSentryProjectId, hideName: false})}
+                  </components.ValueContainer>
+                );
+              },
             }}
             onChange={handleSelectProject}
             value={selectedSentryProjectId}
@@ -370,10 +341,6 @@ const AddProjectWrapper = styled('div')`
   grid-area: manage-project;
 `;
 
-const OptionLabelWrapper = styled('div')`
-  margin-left: ${space(0.5)};
-`;
-
 const StyledFormField = styled(FormField)`
   padding: 0;
 `;
@@ -382,11 +349,6 @@ const StyledExternalLink = styled(ExternalLink)`
   display: flex;
 `;
 
-const OptionWrapper = styled('div')`
-  align-items: center;
-  display: flex;
-`;
-
 const FieldControlWrapper = styled('div')`
   position: relative;
   grid-area: field-control;
@@ -405,3 +367,8 @@ const NextButtonWrapper = styled('div')`
   gap: ${space(1)};
   align-items: center;
 `;
+
+const MappedValueContainer = styled('div')`
+  display: flex;
+  gap: ${space(1)};
+`;