Files
2024-02-15 17:01:50 +00:00

181 lines
5.0 KiB
TypeScript

import {useState} from 'react';
import {browserHistory} from 'react-router';
import styled from '@emotion/styled';
import debounce from 'lodash/debounce';
import type {SelectOption} from 'sentry/components/compactSelect';
import {CompactSelect} from 'sentry/components/compactSelect';
import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
import {DEFAULT_DEBOUNCE_DURATION} from 'sentry/constants';
import {IconReleases} from 'sentry/icons/iconReleases';
import {t, tn} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {defined} from 'sentry/utils';
import {getFormattedDate} from 'sentry/utils/dates';
import {useLocation} from 'sentry/utils/useLocation';
import {
useReleases,
useReleaseSelection,
} from 'sentry/views/starfish/queries/useReleases';
import {formatVersionAndCenterTruncate} from 'sentry/views/starfish/utils/centerTruncate';
export const PRIMARY_RELEASE_ALIAS = 'R1';
export const SECONDARY_RELEASE_ALIAS = 'R2';
type Props = {
selectorKey: string;
selectorName?: string;
selectorValue?: string;
triggerLabelPrefix?: string;
};
export function ReleaseSelector({selectorKey, selectorValue, triggerLabelPrefix}: Props) {
const [searchTerm, setSearchTerm] = useState<string | undefined>(undefined);
const {data, isLoading} = useReleases(searchTerm);
const {primaryRelease, secondaryRelease} = useReleaseSelection();
const location = useLocation();
const options: SelectOption<string>[] = [];
if (defined(selectorValue)) {
const index = data?.findIndex(({version}) => version === selectorValue);
const selectedRelease = defined(index) ? data?.[index] : undefined;
let selectedReleaseSessionCount: number | undefined = undefined;
let selectedReleaseDateCreated: string | undefined = undefined;
if (defined(selectedRelease)) {
selectedReleaseSessionCount = selectedRelease.count;
selectedReleaseDateCreated = selectedRelease.dateCreated;
}
options.push({
value: selectorValue,
label: selectorValue,
details: (
<LabelDetails
screenCount={selectedReleaseSessionCount}
dateCreated={selectedReleaseDateCreated}
/>
),
});
}
data
?.filter(({version}) => ![primaryRelease, secondaryRelease].includes(version))
.forEach(release => {
const option = {
value: release.version,
label: release.version,
details: (
<LabelDetails screenCount={release.count} dateCreated={release.dateCreated} />
),
};
options.push(option);
});
const triggerLabelContent = selectorValue
? formatVersionAndCenterTruncate(selectorValue, 16)
: selectorValue;
return (
<StyledCompactSelect
triggerProps={{
icon: <IconReleases />,
title: selectorValue,
prefix: triggerLabelPrefix,
}}
triggerLabel={triggerLabelContent}
menuTitle={t('Filter Release')}
loading={isLoading}
searchable
value={selectorValue}
options={[
{
value: '_releases',
label: t('Sorted by date created'),
options,
},
]}
onSearch={debounce(val => {
setSearchTerm(val);
}, DEFAULT_DEBOUNCE_DURATION)}
onChange={newValue => {
browserHistory.push({
...location,
query: {
...location.query,
[selectorKey]: newValue.value,
},
});
}}
onClose={() => {
setSearchTerm(undefined);
}}
/>
);
}
type LabelDetailsProps = {
dateCreated?: string;
screenCount?: number;
};
function LabelDetails(props: LabelDetailsProps) {
return (
<DetailsContainer>
<div>
{defined(props.screenCount)
? tn('%s event', '%s events', props.screenCount)
: t('No screens')}
</div>
<div>
{defined(props.dateCreated)
? getFormattedDate(props.dateCreated, 'MMM D, YYYY')
: null}
</div>
</DetailsContainer>
);
}
export function ReleaseComparisonSelector() {
const {primaryRelease, secondaryRelease} = useReleaseSelection();
return (
<StyledPageSelector condensed>
<ReleaseSelector
selectorKey="primaryRelease"
selectorValue={primaryRelease}
selectorName={t('Release 1')}
key="primaryRelease"
triggerLabelPrefix={PRIMARY_RELEASE_ALIAS}
/>
<ReleaseSelector
selectorKey="secondaryRelease"
selectorName={t('Release 2')}
selectorValue={secondaryRelease}
key="secondaryRelease"
triggerLabelPrefix={SECONDARY_RELEASE_ALIAS}
/>
</StyledPageSelector>
);
}
const StyledCompactSelect = styled(CompactSelect)`
@media (min-width: ${p => p.theme.breakpoints.medium}) {
max-width: 275px;
}
`;
const StyledPageSelector = styled(PageFilterBar)`
& > * {
min-width: 135px;
&:last-child {
min-width: 135px;
}
}
`;
const DetailsContainer = styled('div')`
display: flex;
flex-direction: row;
justify-content: space-between;
gap: ${space(1)};
min-width: 200px;
`;