fix: use nullish coalescing

This commit is contained in:
Julian Sommer
2026-03-24 10:20:11 +10:00
parent 3467e0cf22
commit 30b08ca984
26 changed files with 43 additions and 32 deletions
@@ -39,7 +39,6 @@
"promise/prefer-await-to-callbacks": "off",
"react-perf/jsx-no-new-function-as-prop": "off",
"typescript/no-confusing-void-expression": "off",
"typescript/prefer-nullish-coalescing": "off",
"typescript/return-await": "off",
"typescript/no-floating-promises": "off",
"typescript/strict-boolean-expressions": "off",
@@ -11,6 +11,7 @@ export function DetailRow({
<div>
<dt className="text-sm text-muted-foreground">{label}</dt>
<dd className="mt-1 font-mono text-sm">
{/* oxlint-disable-next-line typescript/prefer-nullish-coalescing */}
{value || <span className="text-muted-foreground">—</span>}
</dd>
</div>
@@ -117,6 +117,7 @@ export function useCreateInstance() {
KeyName: params.keyName,
MinCount: params.count,
MaxCount: params.count,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
SubnetId: params.subnetId || undefined,
})
return getEc2Client().send(command)
@@ -232,6 +233,7 @@ export function useCreateSnapshot() {
mutationFn: (params: CreateSnapshotFormData) => {
const command = new CreateSnapshotCommand({
VolumeId: params.volumeId,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
Description: params.description || undefined,
})
return getEc2Client().send(command)
@@ -264,6 +266,7 @@ export function useCopySnapshot() {
const command = new CopySnapshotCommand({
SourceSnapshotId: params.sourceSnapshotId,
SourceRegion: params.sourceRegion,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
Description: params.description || undefined,
})
return getEc2Client().send(command)
@@ -281,6 +284,7 @@ export function useAttachVolume() {
const command = new AttachVolumeCommand({
VolumeId: params.volumeId,
InstanceId: params.instanceId,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
Device: params.device || undefined,
})
return getEc2Client().send(command)
@@ -298,6 +302,7 @@ export function useDetachVolume() {
mutationFn: (params: DetachVolumeFormData) => {
const command = new DetachVolumeCommand({
VolumeId: params.volumeId,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
InstanceId: params.instanceId || undefined,
Force: params.force,
})
@@ -347,6 +352,7 @@ export function useCreateImage() {
const command = new CreateImageCommand({
InstanceId: params.instanceId,
Name: params.name,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
Description: params.description || undefined,
})
return getEc2Client().send(command)
@@ -402,6 +408,7 @@ export function useCreateSubnet() {
const command = new CreateSubnetCommand({
VpcId: params.vpcId,
CidrBlock: params.cidrBlock,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
AvailabilityZone: params.availabilityZone || undefined,
})
return getEc2Client().send(command)
@@ -26,6 +26,7 @@ export function useCreateUser() {
mutationFn: (params: CreateUserFormData) => {
const command = new CreateUserCommand({
UserName: params.userName,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
Path: params.path || undefined,
})
return getIamClient().send(command)
@@ -101,6 +102,7 @@ export function useCreatePolicy() {
mutationFn: (params: CreatePolicyFormData) => {
const command = new CreatePolicyCommand({
PolicyName: params.policyName,
// oxlint-disable-next-line typescript/prefer-nullish-coalescing
Description: params.description || undefined,
PolicyDocument: params.policyDocument,
})
@@ -24,7 +24,7 @@ export const Route = createFileRoute("/_auth/ec2/(images)/describe-images/")({
function Images() {
const { data } = useSuspenseQuery(ec2ImagesQueryOptions)
const images = data.Images || []
const images = data.Images ?? []
return (
<>
@@ -247,11 +247,13 @@ function InstanceDetail() {
</DetailCard>
{/* Network & Security */}
{/* oxlint-disable typescript/prefer-nullish-coalescing */}
{(instance.PrivateIpAddress ||
instance.PublicIpAddress ||
instance.VpcId ||
instance.SubnetId ||
(instance.SecurityGroups && instance.SecurityGroups.length > 0)) && (
/* oxlint-enable typescript/prefer-nullish-coalescing */
<DetailCard>
<DetailCard.Header>Network & Security</DetailCard.Header>
<DetailCard.Content>
@@ -38,8 +38,8 @@ function Ec2() {
const instances = (
data.Reservations?.flatMap(
(reservation: Reservation) => reservation.Instances || [],
) || []
(reservation: Reservation) => reservation.Instances ?? [],
) ?? []
).toSorted((a, b) => {
const pa = statePriority[a.State?.Name ?? ""] ?? 6
const pb = statePriority[b.State?.Name ?? ""] ?? 6
@@ -60,7 +60,7 @@ function CreateInstance() {
for (const type of instanceTypesData.InstanceTypes ?? []) {
const typeName = type.InstanceType
if (typeName) {
instanceTypeCounts[typeName] = (instanceTypeCounts[typeName] || 0) + 1
instanceTypeCounts[typeName] = (instanceTypeCounts[typeName] ?? 0) + 1
}
}
@@ -151,7 +151,7 @@ function CreateInstance() {
>
<SelectValue>
{selectedImage
? `${selectedImage.Name || "Unnamed"} (${selectedImage.Architecture})`
? `${selectedImage.Name ?? "Unnamed"} (${selectedImage.Architecture})`
: ""}
</SelectValue>
</SelectTrigger>
@@ -161,7 +161,7 @@ function CreateInstance() {
key={image.ImageId}
value={image.ImageId ?? ""}
>
{image.Name || "Unnamed"} ({image.Architecture})
{image.Name ?? "Unnamed"} ({image.Architecture})
</SelectItem>
))}
</SelectContent>
@@ -106,7 +106,7 @@ function KeyPairDetail() {
{keyPair.Tags.map((tag) => (
<DetailRow
key={tag.Key}
label={tag.Key || ""}
label={tag.Key ?? ""}
value={tag.Value}
/>
))}
@@ -24,7 +24,7 @@ export const Route = createFileRoute("/_auth/ec2/(key)/describe-key-pairs/")({
function KeyPairs() {
const { data } = useSuspenseQuery(ec2KeyPairsQueryOptions)
const keyPairs = (data.KeyPairs || []).toSorted((a, b) => {
const keyPairs = (data.KeyPairs ?? []).toSorted((a, b) => {
const nameA = a.KeyName?.toLowerCase() ?? ""
const nameB = b.KeyName?.toLowerCase() ?? ""
return nameA.localeCompare(nameB)
@@ -27,7 +27,7 @@ export const Route = createFileRoute(
function Snapshots() {
const { data } = useSuspenseQuery(ec2SnapshotsQueryOptions)
const snapshots = data.Snapshots || []
const snapshots = data.Snapshots ?? []
return (
<>
@@ -152,7 +152,7 @@ function CreateSubnet() {
onValueChange={(value) =>
field.onChange(value === "none" ? "" : value)
}
value={field.value || "none"}
value={field.value ?? "none"}
>
<SelectTrigger className="w-full" id="availabilityZone">
<SelectValue />
@@ -26,7 +26,7 @@ export const Route = createFileRoute("/_auth/ec2/(subnet)/describe-subnets/")({
function Subnets() {
const { data } = useSuspenseQuery(ec2SubnetsQueryOptions)
const subnets = data.Subnets || []
const subnets = data.Subnets ?? []
return (
<>
@@ -113,7 +113,7 @@ function VolumeDetail() {
try {
await detachMutation.mutateAsync({
volumeId: id,
instanceId: instanceId || undefined,
instanceId: instanceId ?? undefined,
force: detachForce || undefined,
})
closeDialog()
@@ -25,7 +25,7 @@ export const Route = createFileRoute("/_auth/ec2/(volumes)/describe-volumes/")({
function Volumes() {
const { data } = useSuspenseQuery(ec2VolumesQueryOptions)
const volumes = data.Volumes || []
const volumes = data.Volumes ?? []
return (
<>
@@ -26,7 +26,7 @@ export const Route = createFileRoute("/_auth/ec2/(vpc)/describe-vpcs/")({
function Vpcs() {
const { data } = useSuspenseQuery(ec2VpcsQueryOptions)
const vpcs = data.Vpcs || []
const vpcs = data.Vpcs ?? []
return (
<>
@@ -47,7 +47,7 @@ export function AmiDetails({
label="Virtualization Type"
value={image.VirtualizationType}
/>
<DetailRow label="Platform" value={image.Platform || "Linux"} />
<DetailRow label="Platform" value={image.Platform ?? "Linux"} />
<DetailRow label="Platform Details" value={image.PlatformDetails} />
<DetailRow label="Image Type" value={image.ImageType} />
<DetailRow label="Root Device Type" value={image.RootDeviceType} />
@@ -27,7 +27,7 @@ export function InstanceActions({ instanceId, state }: InstanceActionsProps) {
const rebootMutation = useRebootInstance()
const terminateMutation = useTerminateInstance()
const isTransitioning = TRANSITIONING_STATES.has(state || "")
const isTransitioning = TRANSITIONING_STATES.has(state ?? "")
if (isTransitioning && state !== "terminated") {
return (
@@ -117,7 +117,7 @@ function PolicyDetail() {
<DetailRow label="Policy ID" value={policy.PolicyId} />
<DetailRow label="ARN" value={policy.Arn} />
<DetailRow label="Path" value={policy.Path} />
<DetailRow label="Description" value={policy.Description || "-"} />
<DetailRow label="Description" value={policy.Description ?? "-"} />
<DetailRow
label="Created"
value={formatDateTime(policy.CreateDate)}
@@ -21,7 +21,7 @@ export const Route = createFileRoute("/_auth/iam/(policies)/list-policies/")({
function Policies() {
const { data } = useSuspenseQuery(iamPoliciesQueryOptions)
const policies = (data.Policies || []).toSorted((a, b) => {
const policies = (data.Policies ?? []).toSorted((a, b) => {
const nameA = a.PolicyName?.toLowerCase() ?? ""
const nameB = b.PolicyName?.toLowerCase() ?? ""
return nameA.localeCompare(nameB)
@@ -84,9 +84,9 @@ function UserDetail() {
)
const user = userData.User
const accessKeys = accessKeysData.AccessKeyMetadata || []
const attachedPolicies = attachedPoliciesData.AttachedPolicies || []
const allPolicies = allPoliciesData.Policies || []
const accessKeys = accessKeysData.AccessKeyMetadata ?? []
const attachedPolicies = attachedPoliciesData.AttachedPolicies ?? []
const allPolicies = allPoliciesData.Policies ?? []
const attachedArns = new Set(attachedPolicies.map((p) => p.PolicyArn))
const availablePolicies = allPolicies.filter(
@@ -21,7 +21,7 @@ export const Route = createFileRoute("/_auth/iam/(users)/list-users/")({
function Users() {
const { data } = useSuspenseQuery(iamUsersQueryOptions)
const users = (data.Users || []).toSorted((a, b) => {
const users = (data.Users ?? []).toSorted((a, b) => {
const nameA = a.UserName?.toLowerCase() ?? ""
const nameB = b.UserName?.toLowerCase() ?? ""
return nameA.localeCompare(nameB)
@@ -85,7 +85,7 @@ export function ObjectListItem({
</div>
<div className="flex items-center gap-3">
<div className="text-sm text-muted-foreground">
{formatSize(object.Size || 0)}
{formatSize(object.Size ?? 0)}
</div>
<button
className="rounded-md p-2 transition-colors hover:bg-accent"
@@ -18,13 +18,13 @@ import { UploadButton } from "@/routes/_auth/s3/-components/upload-button"
export const Route = createFileRoute("/_auth/s3/ls/$bucket/$")({
loader: async ({ context, params }) => {
const prefix = ensureTrailingSlash(params._splat || "")
const prefix = ensureTrailingSlash(params._splat ?? "")
await context.queryClient.ensureQueryData(
s3BucketObjectsQueryOptions(params.bucket, prefix),
)
},
head: ({ params }) => {
const path = buildFullS3Key(params._splat || "", `${params.bucket}/`)
const path = buildFullS3Key(params._splat ?? "", `${params.bucket}/`)
return {
meta: [
{
@@ -39,13 +39,13 @@ export const Route = createFileRoute("/_auth/s3/ls/$bucket/$")({
function BucketObjectsWithPrefix() {
const { bucket, _splat } = Route.useParams()
const prefix = ensureTrailingSlash(_splat || "")
const prefix = ensureTrailingSlash(_splat ?? "")
const { data } = useSuspenseQuery(s3BucketObjectsQueryOptions(bucket, prefix))
const uploadMutation = useUploadObject()
const objects = data.Contents || []
const commonPrefixes = data.CommonPrefixes || []
const objects = data.Contents ?? []
const commonPrefixes = data.CommonPrefixes ?? []
// Build breadcrumb navigation
const pathParts = prefix.split("/").filter(Boolean)
@@ -33,8 +33,8 @@ function BucketObjects() {
const { data } = useSuspenseQuery(s3BucketObjectsQueryOptions(bucketName))
const uploadMutation = useUploadObject()
const objects = data.Contents || []
const commonPrefixes = data.CommonPrefixes || []
const objects = data.Contents ?? []
const commonPrefixes = data.CommonPrefixes ?? []
return (
<>
@@ -25,7 +25,7 @@ export const Route = createFileRoute("/_auth/s3/ls/")({
function Buckets() {
const { data } = useSuspenseQuery(s3BucketsQueryOptions)
const buckets = data.Buckets || []
const buckets = data.Buckets ?? []
return (
<>