|
@@ -8,6 +8,8 @@ import useQueryBasedSorting from 'sentry/components/feedback/table/useQueryBased
|
|
import GridEditable, {GridColumnOrder} from 'sentry/components/gridEditable';
|
|
import GridEditable, {GridColumnOrder} from 'sentry/components/gridEditable';
|
|
import Link from 'sentry/components/links/link';
|
|
import Link from 'sentry/components/links/link';
|
|
import TextOverflow from 'sentry/components/textOverflow';
|
|
import TextOverflow from 'sentry/components/textOverflow';
|
|
|
|
+import {IconCursorArrow} from 'sentry/icons';
|
|
|
|
+import {space} from 'sentry/styles/space';
|
|
import {Organization} from 'sentry/types';
|
|
import {Organization} from 'sentry/types';
|
|
import useOrganization from 'sentry/utils/useOrganization';
|
|
import useOrganization from 'sentry/utils/useOrganization';
|
|
import {normalizeUrl} from 'sentry/utils/withDomainRequired';
|
|
import {normalizeUrl} from 'sentry/utils/withDomainRequired';
|
|
@@ -25,27 +27,28 @@ export function getAriaLabel(str: string) {
|
|
return pre.substring(0, pre.lastIndexOf('"]'));
|
|
return pre.substring(0, pre.lastIndexOf('"]'));
|
|
}
|
|
}
|
|
|
|
|
|
-export function hydratedSelectorData(data, clickType): DeadRageSelectorItem[] {
|
|
|
|
- return data
|
|
|
|
- .filter(d => d[clickType] > 0)
|
|
|
|
- .map(d => {
|
|
|
|
- return {
|
|
|
|
- [clickType]: d[clickType],
|
|
|
|
- dom_element: d.dom_element,
|
|
|
|
- element: d.dom_element.split(/[#.]+/)[0],
|
|
|
|
- aria_label: getAriaLabel(d.dom_element),
|
|
|
|
- };
|
|
|
|
- });
|
|
|
|
|
|
+export function hydratedSelectorData(data, clickType?): DeadRageSelectorItem[] {
|
|
|
|
+ return data.map(d => ({
|
|
|
|
+ ...(clickType
|
|
|
|
+ ? {[clickType]: d[clickType]}
|
|
|
|
+ : {
|
|
|
|
+ count_dead_clicks: d.count_dead_clicks,
|
|
|
|
+ count_rage_clicks: d.count_rage_clicks,
|
|
|
|
+ }),
|
|
|
|
+ dom_element: d.dom_element,
|
|
|
|
+ element: d.dom_element.split(/[#.]+/)[0],
|
|
|
|
+ aria_label: getAriaLabel(d.dom_element),
|
|
|
|
+ }));
|
|
}
|
|
}
|
|
|
|
|
|
interface Props {
|
|
interface Props {
|
|
- clickCountColumn: {key: string; name: string};
|
|
|
|
|
|
+ clickCountColumns: {key: string; name: string}[];
|
|
|
|
+ clickCountSortable: boolean;
|
|
data: DeadRageSelectorItem[];
|
|
data: DeadRageSelectorItem[];
|
|
isError: boolean;
|
|
isError: boolean;
|
|
isLoading: boolean;
|
|
isLoading: boolean;
|
|
location: Location<any>;
|
|
location: Location<any>;
|
|
customHandleResize?: () => void;
|
|
customHandleResize?: () => void;
|
|
- headerButtons?: ReactNode;
|
|
|
|
title?: ReactNode;
|
|
title?: ReactNode;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -56,24 +59,24 @@ const BASE_COLUMNS: GridColumnOrder<string>[] = [
|
|
];
|
|
];
|
|
|
|
|
|
export default function SelectorTable({
|
|
export default function SelectorTable({
|
|
- clickCountColumn,
|
|
|
|
|
|
+ clickCountColumns,
|
|
data,
|
|
data,
|
|
isError,
|
|
isError,
|
|
isLoading,
|
|
isLoading,
|
|
location,
|
|
location,
|
|
title,
|
|
title,
|
|
- headerButtons,
|
|
|
|
customHandleResize,
|
|
customHandleResize,
|
|
|
|
+ clickCountSortable,
|
|
}: Props) {
|
|
}: Props) {
|
|
const organization = useOrganization();
|
|
const organization = useOrganization();
|
|
|
|
|
|
const {currentSort, makeSortLinkGenerator} = useQueryBasedSorting({
|
|
const {currentSort, makeSortLinkGenerator} = useQueryBasedSorting({
|
|
- defaultSort: {field: clickCountColumn.key, kind: 'desc'},
|
|
|
|
|
|
+ defaultSort: {field: clickCountColumns[0].key, kind: 'desc'},
|
|
location,
|
|
location,
|
|
});
|
|
});
|
|
|
|
|
|
const {columns, handleResizeColumn} = useQueryBasedColumnResize({
|
|
const {columns, handleResizeColumn} = useQueryBasedColumnResize({
|
|
- columns: BASE_COLUMNS.concat(clickCountColumn),
|
|
|
|
|
|
+ columns: BASE_COLUMNS.concat(clickCountColumns),
|
|
location,
|
|
location,
|
|
});
|
|
});
|
|
|
|
|
|
@@ -84,9 +87,9 @@ export default function SelectorTable({
|
|
makeSortLinkGenerator,
|
|
makeSortLinkGenerator,
|
|
onClick: () => {},
|
|
onClick: () => {},
|
|
rightAlignedColumns: [],
|
|
rightAlignedColumns: [],
|
|
- sortableColumns: [],
|
|
|
|
|
|
+ sortableColumns: clickCountSortable ? clickCountColumns : [],
|
|
}),
|
|
}),
|
|
- [currentSort, makeSortLinkGenerator]
|
|
|
|
|
|
+ [currentSort, makeSortLinkGenerator, clickCountColumns, clickCountSortable]
|
|
);
|
|
);
|
|
|
|
|
|
const renderBodyCell = useCallback(
|
|
const renderBodyCell = useCallback(
|
|
@@ -124,7 +127,6 @@ export default function SelectorTable({
|
|
}}
|
|
}}
|
|
location={location as Location<any>}
|
|
location={location as Location<any>}
|
|
title={title}
|
|
title={title}
|
|
- headerButtons={() => headerButtons}
|
|
|
|
/>
|
|
/>
|
|
);
|
|
);
|
|
}
|
|
}
|
|
@@ -149,10 +151,24 @@ function SelectorLink({
|
|
|
|
|
|
function renderSimpleBodyCell<T>(column: GridColumnOrder<string>, dataRow: T) {
|
|
function renderSimpleBodyCell<T>(column: GridColumnOrder<string>, dataRow: T) {
|
|
if (column.key === 'count_dead_clicks') {
|
|
if (column.key === 'count_dead_clicks') {
|
|
- return <DeadClickCount>{dataRow[column.key]}</DeadClickCount>;
|
|
|
|
|
|
+ return (
|
|
|
|
+ <DeadClickCount>
|
|
|
|
+ <IconContainer>
|
|
|
|
+ <IconCursorArrow size="xs" />
|
|
|
|
+ </IconContainer>
|
|
|
|
+ {dataRow[column.key]}
|
|
|
|
+ </DeadClickCount>
|
|
|
|
+ );
|
|
}
|
|
}
|
|
if (column.key === 'count_rage_clicks') {
|
|
if (column.key === 'count_rage_clicks') {
|
|
- return <RageClickCount>{dataRow[column.key]}</RageClickCount>;
|
|
|
|
|
|
+ return (
|
|
|
|
+ <RageClickCount>
|
|
|
|
+ <IconContainer>
|
|
|
|
+ <IconCursorArrow size="xs" />
|
|
|
|
+ </IconContainer>
|
|
|
|
+ {dataRow[column.key]}
|
|
|
|
+ </RageClickCount>
|
|
|
|
+ );
|
|
}
|
|
}
|
|
return <TextOverflow>{dataRow[column.key]}</TextOverflow>;
|
|
return <TextOverflow>{dataRow[column.key]}</TextOverflow>;
|
|
}
|
|
}
|
|
@@ -164,3 +180,7 @@ const DeadClickCount = styled(TextOverflow)`
|
|
const RageClickCount = styled(TextOverflow)`
|
|
const RageClickCount = styled(TextOverflow)`
|
|
color: ${p => p.theme.red300};
|
|
color: ${p => p.theme.red300};
|
|
`;
|
|
`;
|
|
|
|
+
|
|
|
|
+const IconContainer = styled('span')`
|
|
|
|
+ margin-right: ${space(1)};
|
|
|
|
+`;
|