|
@@ -3,18 +3,20 @@ import {components, MultiValueProps} from 'react-select';
|
|
|
import styled from '@emotion/styled';
|
|
|
|
|
|
import {fetchTagValues} from 'sentry/actionCreators/tags';
|
|
|
+import Count from 'sentry/components/count';
|
|
|
import SelectField from 'sentry/components/forms/selectField';
|
|
|
import {t} from 'sentry/locale';
|
|
|
-import {Organization, Project} from 'sentry/types';
|
|
|
+import {Organization, Project, TagValue as IssueTagValue} from 'sentry/types';
|
|
|
import {SamplingInnerName} from 'sentry/types/sampling';
|
|
|
import useApi from 'sentry/utils/useApi';
|
|
|
|
|
|
import {TruncatedLabel} from './truncatedLabel';
|
|
|
import {formatCreateTagLabel, getMatchFieldPlaceholder} from './utils';
|
|
|
|
|
|
-type Tag = {
|
|
|
- value: string;
|
|
|
-};
|
|
|
+type TagValue = Pick<
|
|
|
+ IssueTagValue,
|
|
|
+ 'key' | 'name' | 'value' | 'count' | 'lastSeen' | 'firstSeen'
|
|
|
+>;
|
|
|
|
|
|
export interface TagValueAutocompleteProps {
|
|
|
category:
|
|
@@ -37,7 +39,7 @@ function TagValueAutocomplete({
|
|
|
tagKey,
|
|
|
}: TagValueAutocompleteProps) {
|
|
|
const api = useApi();
|
|
|
- const [tagValues, setTagValues] = useState<Tag[]>([]);
|
|
|
+ const [tagValues, setTagValues] = useState<TagValue[]>([]);
|
|
|
|
|
|
function getAriaLabel() {
|
|
|
switch (category) {
|
|
@@ -63,7 +65,9 @@ function TagValueAutocomplete({
|
|
|
null,
|
|
|
[projectId],
|
|
|
null,
|
|
|
- true
|
|
|
+ true,
|
|
|
+ undefined,
|
|
|
+ '-count'
|
|
|
);
|
|
|
setTagValues(response);
|
|
|
} catch {
|
|
@@ -77,20 +81,28 @@ function TagValueAutocomplete({
|
|
|
|
|
|
// react-select doesn't seem to work very well when its value contains
|
|
|
// a created item that isn't listed in the options
|
|
|
- const createdOptions: Tag[] = !value
|
|
|
+ const createdOptions: TagValue[] = !value
|
|
|
? []
|
|
|
: value
|
|
|
.split('\n')
|
|
|
.filter(v => !tagValues.some(tagValue => tagValue.value === v))
|
|
|
- .map(v => ({value: v}));
|
|
|
+ .map(v => ({
|
|
|
+ value: v,
|
|
|
+ name: v,
|
|
|
+ key: tagKey,
|
|
|
+ count: 0,
|
|
|
+ firstSeen: '',
|
|
|
+ lastSeen: '',
|
|
|
+ }));
|
|
|
|
|
|
return (
|
|
|
<StyledSelectField
|
|
|
name="match"
|
|
|
aria-label={getAriaLabel()}
|
|
|
- options={[...createdOptions, ...tagValues].map(tagValue => ({
|
|
|
+ options={[...tagValues, ...createdOptions].map(tagValue => ({
|
|
|
value: tagValue.value,
|
|
|
label: <TruncatedLabel value={tagValue.value} />,
|
|
|
+ trailingItems: <StyledCount value={tagValue.count} />,
|
|
|
}))}
|
|
|
value={value?.split('\n')}
|
|
|
onChange={newValue => {
|
|
@@ -133,4 +145,8 @@ const StyledSelectField = styled(SelectField)`
|
|
|
width: 100%;
|
|
|
`;
|
|
|
|
|
|
+const StyledCount = styled(Count)`
|
|
|
+ color: ${p => p.theme.subText};
|
|
|
+`;
|
|
|
+
|
|
|
export {TagValueAutocomplete};
|