|
@@ -5,6 +5,7 @@ import isEqual from 'lodash/isEqual';
|
|
|
import partition from 'lodash/partition';
|
|
|
|
|
|
import {updateProjects} from 'sentry/actionCreators/pageFilters';
|
|
|
+import Badge from 'sentry/components/badge';
|
|
|
import MultipleProjectSelector from 'sentry/components/organizations/multipleProjectSelector';
|
|
|
import PageFilterDropdownButton from 'sentry/components/organizations/pageFilters/pageFilterDropdownButton';
|
|
|
import PlatformList from 'sentry/components/platformList';
|
|
@@ -16,6 +17,7 @@ import PageFiltersStore from 'sentry/stores/pageFiltersStore';
|
|
|
import {useLegacyStore} from 'sentry/stores/useLegacyStore';
|
|
|
import space from 'sentry/styles/space';
|
|
|
import {MinimalProject} from 'sentry/types';
|
|
|
+import {trimSlug} from 'sentry/utils/trimSlug';
|
|
|
import useOrganization from 'sentry/utils/useOrganization';
|
|
|
import useProjects from 'sentry/utils/useProjects';
|
|
|
|
|
@@ -36,6 +38,12 @@ type Props = WithRouterProps & {
|
|
|
*/
|
|
|
lockedMessageSubject?: string;
|
|
|
|
|
|
+ /**
|
|
|
+ * Max character length for the dropdown title. Default is 20. This number
|
|
|
+ * is used to determine how many projects to show, and how much to truncate.
|
|
|
+ */
|
|
|
+ maxTitleLength?: number;
|
|
|
+
|
|
|
/**
|
|
|
* A project will be forced from parent component (selection is disabled, and if user
|
|
|
* does not have multi-project support enabled, it will not try to auto select a project).
|
|
@@ -61,7 +69,12 @@ type Props = WithRouterProps & {
|
|
|
specificProjectSlugs?: string[];
|
|
|
};
|
|
|
|
|
|
-export function ProjectPageFilter({router, specificProjectSlugs, ...otherProps}: Props) {
|
|
|
+export function ProjectPageFilter({
|
|
|
+ router,
|
|
|
+ specificProjectSlugs,
|
|
|
+ maxTitleLength = 20,
|
|
|
+ ...otherProps
|
|
|
+}: Props) {
|
|
|
const [currentSelectedProjects, setCurrentSelectedProjects] = useState<number[] | null>(
|
|
|
null
|
|
|
);
|
|
@@ -104,15 +117,24 @@ export function ProjectPageFilter({router, specificProjectSlugs, ...otherProps}:
|
|
|
const customProjectDropdown = ({getActorProps, selectedProjects, isOpen}) => {
|
|
|
const selectedProjectIds = new Set(selection.projects);
|
|
|
const hasSelected = !!selectedProjects.length;
|
|
|
+
|
|
|
+ // Show 2 projects only if the combined string does not exceed maxTitleLength.
|
|
|
+ // Otherwise show only 1 project.
|
|
|
+ const projectsToShow =
|
|
|
+ selectedProjects[0]?.slug?.length + selectedProjects[1]?.slug?.length <=
|
|
|
+ maxTitleLength - 2
|
|
|
+ ? selectedProjects.slice(0, 2)
|
|
|
+ : selectedProjects.slice(0, 1);
|
|
|
+
|
|
|
const title = hasSelected
|
|
|
- ? selectedProjects.map(({slug}) => slug).join(', ')
|
|
|
+ ? projectsToShow.map(proj => trimSlug(proj.slug, maxTitleLength)).join(', ')
|
|
|
: selectedProjectIds.has(ALL_ACCESS_PROJECTS)
|
|
|
? t('All Projects')
|
|
|
: t('My Projects');
|
|
|
+
|
|
|
const icon = hasSelected ? (
|
|
|
<PlatformList
|
|
|
- platforms={selectedProjects.map(p => p.platform ?? 'other').reverse()}
|
|
|
- max={5}
|
|
|
+ platforms={projectsToShow.map(p => p.platform ?? 'other').reverse()}
|
|
|
/>
|
|
|
) : (
|
|
|
<IconProject />
|
|
@@ -128,6 +150,9 @@ export function ProjectPageFilter({router, specificProjectSlugs, ...otherProps}:
|
|
|
<DropdownTitle>
|
|
|
{icon}
|
|
|
<TitleContainer>{title}</TitleContainer>
|
|
|
+ {selectedProjects.length > projectsToShow.length && (
|
|
|
+ <StyledBadge text={`+${selectedProjects.length - projectsToShow.length}`} />
|
|
|
+ )}
|
|
|
</DropdownTitle>
|
|
|
</PageFilterDropdownButton>
|
|
|
);
|
|
@@ -171,9 +196,12 @@ const TitleContainer = styled('div')`
|
|
|
const DropdownTitle = styled('div')`
|
|
|
width: max-content;
|
|
|
display: flex;
|
|
|
- overflow: hidden;
|
|
|
align-items: center;
|
|
|
flex: 1;
|
|
|
`;
|
|
|
|
|
|
+const StyledBadge = styled(Badge)`
|
|
|
+ flex-shrink: 0;
|
|
|
+`;
|
|
|
+
|
|
|
export default withRouter(ProjectPageFilter);
|