Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1393,4 +1393,12 @@ export default typescript.config([
'boundaries/dependencies': 'off',
},
},
{
name: 'files/scraps',
files: ['static/app/components/core/**/*.{js,mjs,ts,jsx,tsx}'],
ignores: ['**/*.spec.{js,mjs,ts,jsx,tsx}'],
rules: {
'@typescript-eslint/no-non-null-assertion': 'error',
},
},
]);
2 changes: 2 additions & 0 deletions static/app/components/core/avatar/avatarList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ export function AvatarList({

if (numCollapsedAvatars === 1) {
if (visibleTeamAvatars.length < teams.length) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
visibleTeamAvatars.unshift(teams[teams.length - 1]!);
} else if (visibleUserAvatars.length < users.length) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
visibleUserAvatars.unshift(users[users.length - 1]!);
}
numCollapsedAvatars = 0;
Expand Down
2 changes: 2 additions & 0 deletions static/app/components/core/avatar/useAvatar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,10 @@ function getInitials(name: string | undefined): Tagged<string, '__avatar'> {

// Use Array.from as slicing and substring() work on ucs2 segments which
// results in only getting half of any 4+ byte character.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
let initials = Array.from(words[0]!)[0]!;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
let initials = Array.from(words[0]!)[0]!;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
let initials = Array.from(words[0] ?? '')[0] ?? '';

if (words.length > 1) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
initials += Array.from(words[words.length - 1]!)[0]!;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
initials += Array.from(words[words.length - 1]!)[0]!;
initials += Array.from(words[words.length - 1] ?? '')[0] ?? '';

}
return initials.toUpperCase() as Tagged<string, '__avatar'>;
Expand Down
24 changes: 17 additions & 7 deletions static/app/components/core/avatarButton/avatarButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useTheme, type Theme} from '@emotion/react';
import styled from '@emotion/styled';
import {useQuery} from '@tanstack/react-query';
import {skipToken, useQuery} from '@tanstack/react-query';
import color from 'color';

import type {BaseAvatarProps} from '@sentry/scraps/avatar';
Expand Down Expand Up @@ -32,8 +32,10 @@ export function AvatarButton({avatar, size: explicitSize, ...props}: AvatarButto

const {data: imageResult} = useQuery({
queryKey: ['avatar-button-chonk', imageUrl, theme.type],
queryFn: () => resolveImageAvatarColors(imageUrl!, theme.type),
enabled: !!imageUrl && avatarDefinition.type === 'image',
queryFn:
imageUrl && avatarDefinition.type === 'image'
? () => resolveImageAvatarColors(imageUrl, theme.type)
: skipToken,
staleTime: Infinity,
});

Expand Down Expand Up @@ -133,6 +135,7 @@ const StyledAvatarButton = styled(Button)<{chonk: string | undefined}>`
// Returns 'fill' when the image covers the full frame edge-to-edge, 'padded' otherwise.
// Each edge check returns 'padded' when every pixel on that edge is transparent (alpha < 128).
// Pixel (col, row) has its alpha channel at (row * 12 + col) * 4 + 3 in a 12×12 RGBA canvas.
/* eslint-disable @typescript-eslint/no-non-null-assertion */
function shouldPadImage(data: Uint8ClampedArray): 'fill' | 'padded' {
// oxfmt-ignore
if (!(data[3]!>=128 || data[51]!>=128 || data[99]!>=128 ||
Expand All @@ -159,6 +162,7 @@ function shouldPadImage(data: Uint8ClampedArray): 'fill' | 'padded' {

return 'fill';
}
/* eslint-enable @typescript-eslint/no-non-null-assertion */

function readPixels(img: HTMLImageElement): Uint8ClampedArray | null {
const SAMPLE_SIZE = 12;
Expand Down Expand Up @@ -200,18 +204,24 @@ function sampleAvatarColor(
const style = shouldPadImage(data);

// Accumulate two sets: chromatic pixels (saturation ≥ 0.15) and all opaque pixels.
// oxfmt-ignore
let cr = 0, cg = 0, cb = 0, ccount = 0;
// oxfmt-ignore
let ar = 0, ag = 0, ab = 0, acount = 0;
let cr = 0,
cg = 0,
cb = 0,
ccount = 0;
let ar = 0,
ag = 0,
ab = 0,
acount = 0;

for (let i = 0; i < data.length; i += 4) {
/* eslint-disable @typescript-eslint/no-non-null-assertion */
if (data[i + 3]! < 128) continue;

const r = data[i]!,
g = data[i + 1]!,
b = data[i + 2]!;

/* eslint-enable @typescript-eslint/no-non-null-assertion */
// accumulate all pixels
ar += r;
ag += g;
Expand Down
4 changes: 2 additions & 2 deletions static/app/components/core/compactSelect/control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -504,13 +504,13 @@ export function Control({
ref={menuRef}
width={menuWidth ?? menuFullWidth}
height={menuHeight}
minWidth={menuMinWidth ?? overlayProps.style!.minWidth}
minWidth={menuMinWidth ?? overlayProps.style?.minWidth}
maxWidth={
overlayProps.style?.maxWidth
? `calc(${withUnits(overlayProps.style.maxWidth)} * 0.9)`
: undefined
}
maxHeight={overlayProps.style!.maxHeight}
maxHeight={overlayProps.style?.maxHeight}
maxHeightProp={maxMenuHeight}
data-menu-has-header={!!menuTitle || clearable}
data-menu-has-search={searchEnabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ function GridList({
ref={ref}
>
{virtualizer.items.map(row => {
const item = listItems[row.index]!;
const item = listItems[row.index];
if (!item) return null;
if (item.type === 'section') {
return (
<GridListSection
Expand Down
1 change: 1 addition & 0 deletions static/app/components/core/compactSelect/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export function List<Value extends SelectKey>({
disallowEmptySelection: !clearable,
allowDuplicateSelectionEvents: true,
onSelectionChange: selection => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const selectedOption = getSelectedOptions(items, selection)[0]!;
onChange?.(selectedOption);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@ export function ListBox<T extends ObjectLike>({
>
{overlayIsOpen &&
virtualizer.items.map(row => {
const item = listItems[row.index]!;
const item = listItems[row.index];
if (!item) return null;
if (item.type === 'section') {
return (
<ListBoxSection
Expand Down
25 changes: 14 additions & 11 deletions static/app/components/core/compactSelect/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,13 @@ export function getHiddenOptions<Value extends SelectKey>(
//
// Then, limit the number of remaining options to `limit`
//
let threshold = [Infinity, Infinity];
let threshold: [number, number] = [Infinity, Infinity];
let accumulator = 0;
let currentIndex = 0;

while (currentIndex < orderedRemainingItems.length) {
const item = orderedRemainingItems[currentIndex]!;
const delta = 'options' in item ? item.options.length : 1;
const item = orderedRemainingItems[currentIndex];
const delta = item && 'options' in item ? item.options.length : 1;

if (accumulator + delta > limit) {
threshold = [currentIndex, limit - accumulator];
Expand All @@ -233,15 +233,18 @@ export function getHiddenOptions<Value extends SelectKey>(
currentIndex += 1;
}

for (let i = threshold[0]!; i < orderedRemainingItems.length; i++) {
const item = orderedRemainingItems[i]!;
if ('options' in item) {
const startingIndex = i === threshold[0] ? threshold[1]! : 0;
for (let j = startingIndex; j < item.options.length; j++) {
hiddenOptionsSet.add(item.options[j]!.key);
for (let i = threshold[0]; i < orderedRemainingItems.length; i++) {
const item = orderedRemainingItems[i];
if (item) {
if ('options' in item) {
const startingIndex = i === threshold[0] ? threshold[1] : 0;
for (let j = startingIndex; j < item.options.length; j++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
hiddenOptionsSet.add(item.options[j]!.key);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (let j = startingIndex; j < item.options.length; j++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
hiddenOptionsSet.add(item.options[j]!.key);
}
for (const option of item.options.slice(startingIndex)) {
hiddenOptionsSet.add(option.key);
}

} else {
hiddenOptionsSet.add(item.key);
}
} else {
hiddenOptionsSet.add(item.key);
}
}

Expand Down
2 changes: 1 addition & 1 deletion static/app/components/core/form/field/baseField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ function useFocusRestore(ref: React.RefObject<HTMLElement | null>) {
}

function onBlur() {
if (el!.hasAttribute('disabled')) {
if (el?.hasAttribute('disabled')) {
hadFocusRef.current = true;
}
}
Expand Down
Loading
Loading