fix: resolve follow-up issues from oxlint migration

This commit is contained in:
ephraimduncan
2026-03-06 05:45:16 +00:00
parent ae02169e97
commit 835c55e2ca
68 changed files with 433 additions and 430 deletions
@@ -39,7 +39,7 @@ export function useAnalytics() {
*
* @param eventFlag The event to check against feature flags to determine whether tracking is enabled.
*/
const startSessionRecording = (eventFlag?: string) => {
const startSessionRecording = (_eventFlag?: string) => {
return;
// const isSessionRecordingEnabled = featureFlags.getFlag(FEATURE_FLAG_GLOBAL_SESSION_RECORDING);
// const isSessionRecordingEnabledForEvent = Boolean(eventFlag && featureFlags.getFlag(eventFlag));
@@ -40,7 +40,7 @@ export function useCopyShareLink({ onSuccess, onError }: UseCopyShareLinkOptions
}
onSuccess?.();
} catch (e) {
} catch {
onError?.();
}
};
@@ -14,13 +14,16 @@ export function useCopyToClipboard(): [CopiedValue, CopyFn] {
return false;
}
const isClipboardApiSupported = Boolean(typeof ClipboardItem && navigator.clipboard.write);
const isClipboardApiSupported =
typeof ClipboardItem !== 'undefined' && typeof navigator.clipboard.write === 'function';
// Try to save to clipboard then save it in the state if worked
try {
isClipboardApiSupported
? await handleClipboardApiCopy(text, blobType)
: await handleWriteTextCopy(text);
if (isClipboardApiSupported) {
await handleClipboardApiCopy(text, blobType);
} else {
await handleWriteTextCopy(text);
}
setCopiedText(await text);
return true;
@@ -41,7 +44,7 @@ export function useCopyToClipboard(): [CopiedValue, CopyFn] {
const handleClipboardApiCopy = async (value: CopyValue, blobType = 'text/plain') => {
try {
await navigator.clipboard.write([new ClipboardItem({ [blobType]: value })]);
} catch (e) {
} catch {
// Fallback attempt.
await handleWriteTextCopy(value);
}
@@ -251,7 +251,7 @@ export const useEditorFields = ({
const getFieldByFormId = useCallback(
(formId: string): TLocalField | undefined => {
return localFields.find((field) => field.formId === formId) as TLocalField | undefined;
return localFields.find((field) => field.formId === formId);
},
[localFields],
);
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/consistent-type-assertions */
import { RefObject, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
/**
* Calculate the width and height of a text element.
@@ -276,7 +276,7 @@ export const EnvelopeEditorProvider = ({
[envelope.recipients],
);
const { refetch: reloadEnvelope, isLoading: isReloadingEnvelope } = trpc.envelope.get.useQuery(
const { refetch: reloadEnvelope, isLoading: _isReloadingEnvelope } = trpc.envelope.get.useQuery(
{
envelopeId: envelope.id,
},
@@ -189,7 +189,7 @@ export const EnvelopeRenderProvider = ({
}, [envelope.envelopeItems]);
const recipientIds = useMemo(
() => recipients.map((recipient) => recipient.id).sort(),
() => recipients.map((recipient) => recipient.id).sort((left, right) => left - right),
[recipients],
);
+4 -1
View File
@@ -170,5 +170,8 @@ export const convertToLocalSystemFormat = (
};
export const isValidDateFormat = (dateFormat: unknown): dateFormat is ValidDateFormat => {
return VALID_DATE_FORMAT_VALUES.includes(dateFormat as ValidDateFormat);
return (
typeof dateFormat === 'string' &&
VALID_DATE_FORMAT_VALUES.some((validDateFormat) => validDateFormat === dateFormat)
);
};
+2 -1
View File
@@ -73,4 +73,5 @@ export const SUPPORTED_LANGUAGES: Record<string, SupportedLanguage> = {
} satisfies Record<SupportedLanguageCodes, SupportedLanguage>;
export const isValidLanguageCode = (code: unknown): code is SupportedLanguageCodes =>
SUPPORTED_LANGUAGE_CODES.includes(code as SupportedLanguageCodes);
typeof code === 'string' &&
SUPPORTED_LANGUAGE_CODES.some((languageCode) => languageCode === code);
+5 -5
View File
@@ -91,11 +91,11 @@ export class InngestJobProvider extends BaseJobProvider {
return {
wait: step.sleep,
logger: {
info: ctx.logger.info,
debug: ctx.logger.debug,
error: ctx.logger.error,
warn: ctx.logger.warn,
log: ctx.logger.info,
info: (...args) => ctx.logger.info(...args),
debug: (...args) => ctx.logger.debug(...args),
error: (...args) => ctx.logger.error(...args),
warn: (...args) => ctx.logger.warn(...args),
log: (...args) => ctx.logger.info(...args),
},
runTask: async (cacheKey, callback) => {
const result = await step.run(cacheKey, callback);
@@ -7,7 +7,7 @@ import type { TExecuteWebhookJobDefinition } from './execute-webhook';
export const run = async ({
payload,
io,
io: _io,
}: {
payload: TExecuteWebhookJobDefinition;
io: JobRunIO;
@@ -28,10 +28,11 @@ export const run = async ({
createdAt: new Date().toISOString(),
webhookEndpoint: url,
};
const requestBody: Prisma.InputJsonValue = JSON.parse(JSON.stringify(payloadData));
const response = await fetch(url, {
method: 'POST',
body: JSON.stringify(payloadData),
body: JSON.stringify(requestBody),
headers: {
'Content-Type': 'application/json',
'X-Documenso-Secret': secret ?? '',
@@ -44,7 +45,7 @@ export const run = async ({
try {
responseBody = JSON.parse(body);
} catch (err) {
} catch {
responseBody = body;
}
@@ -53,7 +54,7 @@ export const run = async ({
url,
event,
status: response.ok ? WebhookCallStatus.SUCCESS : WebhookCallStatus.FAILED,
requestBody: payloadData as Prisma.InputJsonValue,
requestBody,
responseCode: response.status,
responseBody,
responseHeaders: Object.fromEntries(response.headers.entries()),
@@ -91,9 +91,13 @@ export const adminFindUnsealedDocuments = async ({
]);
const count = Number(countResult[0]?.count ?? 0);
const formattedData: AdminUnsealedDocument[] = data.map((document) => ({
...document,
id: String(document.id),
}));
return {
data: data as unknown as AdminUnsealedDocument[],
data: formattedData,
count,
currentPage: Math.max(page, 1),
perPage,
@@ -32,7 +32,7 @@ export type TeamInsights = {
export type UserInsights = {
id: number;
name: string;
name: string | null;
email: string;
documentCount: number;
signedDocumentCount: number;
@@ -98,7 +98,7 @@ export async function getOrganisationDetailedInsights({
case 'documents':
return await getDocumentInsights(organisationId, offset, perPage, createdAtFrom);
default:
throw new Error(`Invalid view: ${view}`);
throw new Error('Invalid view');
}
})();
@@ -149,9 +149,14 @@ async function getTeamInsights(
const [teams, countResult] = await Promise.all([teamsQuery.execute(), countQuery.execute()]);
const count = Number(countResult[0]?.count || 0);
const teamInsights: TeamInsights[] = teams.map((team) => ({
...team,
memberCount: Number(team.memberCount),
documentCount: Number(team.documentCount),
}));
return {
teams: teams as TeamInsights[],
teams: teamInsights,
users: [],
documents: [],
totalPages: Math.ceil(Number(count) / perPage),
@@ -208,10 +213,15 @@ async function getUserInsights(
const [users, countResult] = await Promise.all([usersQuery.execute(), countQuery.execute()]);
const count = Number(countResult[0]?.count || 0);
const userInsights: UserInsights[] = users.map((user) => ({
...user,
documentCount: Number(user.documentCount),
signedDocumentCount: Number(user.signedDocumentCount),
}));
return {
teams: [],
users: users as UserInsights[],
users: userInsights,
documents: [],
totalPages: Math.ceil(Number(count) / perPage),
};
@@ -223,18 +233,13 @@ async function getDocumentInsights(
perPage: number,
createdAtFrom: Date | null,
): Promise<OrganisationDetailedInsights> {
let documentsQuery = kyselyPrisma.$kysely
const documentsQuery = kyselyPrisma.$kysely
.selectFrom('Envelope as e')
.innerJoin('Team as t', 'e.teamId', 't.id')
.where('t.organisationId', '=', organisationId)
.where('e.deletedAt', 'is', null)
.where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`);
if (createdAtFrom) {
documentsQuery = documentsQuery.where('e.createdAt', '>=', createdAtFrom);
}
documentsQuery = documentsQuery
.where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`)
.$if(!!createdAtFrom, (qb) => qb.where('e.createdAt', '>=', createdAtFrom!))
.select([
'e.id as id',
'e.title as title',
@@ -247,33 +252,33 @@ async function getDocumentInsights(
.limit(perPage)
.offset(offset);
let countQuery = kyselyPrisma.$kysely
const countQuery = kyselyPrisma.$kysely
.selectFrom('Envelope as e')
.innerJoin('Team as t', 'e.teamId', 't.id')
.where('t.organisationId', '=', organisationId)
.where('e.deletedAt', 'is', null)
.where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`);
if (createdAtFrom) {
countQuery = countQuery.where('e.createdAt', '>=', createdAtFrom);
}
countQuery = countQuery.select(({ fn }) => [fn.countAll().as('count')]);
.where(() => sql`e.type = ${EnvelopeType.DOCUMENT}::"EnvelopeType"`)
.$if(!!createdAtFrom, (qb) => qb.where('e.createdAt', '>=', createdAtFrom!))
.select(sql<number>`count(*)`.as('count'));
const [documents, countResult] = await Promise.all([
documentsQuery.execute(),
countQuery.execute(),
countQuery.executeTakeFirst(),
]);
const count = Number((countResult[0] as { count: number })?.count || 0);
const count = Number(countResult?.count || 0);
const documentInsights: DocumentInsights[] = documents.map((document) => ({
title: document.title,
status: document.status,
createdAt: document.createdAt,
completedAt: document.completedAt,
teamName: document.teamName,
id: String(document.id),
}));
return {
teams: [],
users: [],
documents: documents.map((doc) => ({
...doc,
id: String((doc as { id: number }).id),
})) as DocumentInsights[],
documents: documentInsights,
totalPages: Math.ceil(Number(count) / perPage),
};
}
+1 -1
View File
@@ -47,7 +47,7 @@ export type PdfToImagesOptions = {
export const pdfToImages = async (pdfBytes: Uint8Array, options: PdfToImagesOptions = {}) => {
const { scale = 2 } = options;
const task = await pdfjsLib.getDocument({
const task = pdfjsLib.getDocument({
data: pdfBytes,
CanvasFactory: SkiaCanvasFactory,
});
@@ -4,6 +4,7 @@ import { omit } from 'remeda';
import { prisma } from '@documenso/prisma';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { ZFieldMetaSchema } from '../../types/field-meta';
import {
ZWebhookDocumentSchema,
mapEnvelopeToWebhookDocumentPayload,
@@ -158,7 +159,7 @@ export const duplicateEnvelope = async ({ id, userId, teamId }: DuplicateEnvelop
height: field.height,
customText: '',
inserted: false,
fieldMeta: field.fieldMeta as PrismaJson.FieldMeta,
fieldMeta: field.fieldMeta ? ZFieldMetaSchema.parse(field.fieldMeta) : undefined,
})),
},
},
@@ -25,7 +25,7 @@ export type GetRecipientEnvelopeByTokenOptions = {
export const getEnvelopeForDirectTemplateSigning = async ({
token,
userId,
accessAuth,
accessAuth: _accessAuth,
}: GetRecipientEnvelopeByTokenOptions): Promise<EnvelopeForSigningResponse> => {
if (!token) {
throw new AppError(AppErrorCode.NOT_FOUND, {
@@ -193,12 +193,12 @@ export const updateEnvelope = async ({
isDeepEqual(documentGlobalActionAuth, newGlobalActionAuth);
const isDocumentVisibilitySame =
data.visibility === undefined || data.visibility === envelope.visibility;
const isFolderSame = data.folderId === undefined || data.folderId === envelope.folderId;
const isTemplateTypeSame =
const _isFolderSame = data.folderId === undefined || data.folderId === envelope.folderId;
const _isTemplateTypeSame =
data.templateType === undefined || data.templateType === envelope.templateType;
const isPublicDescriptionSame =
const _isPublicDescriptionSame =
data.publicDescription === undefined || data.publicDescription === envelope.publicDescription;
const isPublicTitleSame =
const _isPublicTitleSame =
data.publicTitle === undefined || data.publicTitle === envelope.publicTitle;
const auditLogs: CreateDocumentAuditLogDataResponse[] = [];
@@ -27,6 +27,7 @@ Konva.Util['createCanvasElement'] = () => {
get: () => node,
});
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return node as unknown as HTMLCanvasElement;
};
@@ -34,6 +35,7 @@ Konva.Util.createImageElement = () => {
const node = new Image();
node.toString = () => '[object HTMLImageElement]';
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return node as unknown as HTMLImageElement;
};
@@ -6,7 +6,7 @@ import { NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../constants/app';
* Adds a rejection stamp to each page of a PDF document.
* The stamp is placed in the center of the page.
*/
export async function addRejectionStampToPdf(pdf: PDF, reason: string): Promise<PDF> {
export async function addRejectionStampToPdf(pdf: PDF, _reason: string): Promise<PDF> {
const pages = pdf.getPages();
const fontBytes = await fetch(`${NEXT_PRIVATE_INTERNAL_WEBAPP_URL()}/fonts/noto-sans.ttf`).then(
@@ -694,10 +694,10 @@ const setTextFieldFontSize = (textField: PDFTextField, font: PDFFont, fontSize:
try {
textField.setFontSize(fontSize);
} catch (err) {
} catch {
let da = textField.acroField.getDefaultAppearance() ?? '';
da += `\n ${setFontAndSize(font.name, fontSize)}`;
da += `\n ${String(setFontAndSize(font.name, fontSize))}`;
textField.acroField.setDefaultAppearance(da);
}
@@ -51,7 +51,7 @@ const parser = new UAParser();
const textMutedForegroundLight = '#929DAE';
const textForeground = '#000';
const textMutedForeground = '#64748B';
const textBase = 10;
const _textBase = 10;
const textSm = 9;
const textXs = 8;
const fontMedium = '500';
@@ -75,13 +75,13 @@ const getDevice = (userAgent?: string | null): string => {
return `${result.os.name} - ${result.browser.name} ${result.browser.version}`;
};
const textMutedForegroundLight = '#929DAE';
const textForeground = '#000';
const _textMutedForegroundLight = '#929DAE';
const _textForeground = '#000';
const textMutedForeground = '#64748B';
const textRejectedRed = '#dc2626';
const textBase = 10;
const textSm = 9;
const textXs = 8;
const _textXs = 8;
const fontMedium = '500';
const columnWidthPercentages = [30, 30, 40];
@@ -33,7 +33,7 @@ export const setAvatarImage = async ({
userId,
target,
bytes,
requestMetadata,
requestMetadata: _requestMetadata,
}: SetAvatarImageOptions) => {
let oldAvatarImageId: string | null = null;
@@ -13,7 +13,7 @@ export const testCredentialsHandler = async (req: Request) => {
return Response.json({
name: result.team?.name ?? result.user.name,
});
} catch (err) {
} catch {
return Response.json(
{
message: 'Internal Server Error',
@@ -99,7 +99,7 @@ export const deleteTeamEmail = async ({ userId, userEmail, teamId }: DeleteTeamE
html,
text,
});
} catch (e) {
} catch {
// Todo: Teams - Alert us.
// We don't want to prevent a user from revoking access because an email could not be sent.
}
@@ -13,7 +13,7 @@ export const deletedServiceAccountEmail = () => {
const { hostname } = new URL(process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000');
return `deleted-account@${hostname}`;
} catch (error) {
} catch {
return LEGACY_DELETED_ACCOUNT_EMAIL;
}
};
@@ -13,7 +13,7 @@ export const legacyServiceAccountEmail = () => {
const { hostname } = new URL(process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000');
return `serviceaccount@${hostname}`;
} catch (error) {
} catch {
return LEGACY_SERVICE_ACCOUNT_EMAIL;
}
};
@@ -545,5 +545,5 @@ export const generateSampleWebhookPayload = (
};
}
throw new Error(`Unsupported event type: ${event}`);
throw new Error('Unsupported event type');
};
@@ -14,7 +14,7 @@ export const validateApiToken = async ({ authorization }: ValidateApiTokenOption
}
return await getApiTokenByToken({ token });
} catch (err) {
} catch {
throw new Error(`Failed to validate API token`);
}
};
-2
View File
@@ -418,5 +418,3 @@ export const ZEnvelopeFieldAndMetaSchema = z.discriminatedUnion('type', [
fieldMeta: ZDropdownFieldMeta.optional().default(FIELD_DROPDOWN_META_DEFAULT_VALUES),
}),
]);
type TEnvelopeFieldAndMeta = z.infer<typeof ZEnvelopeFieldAndMetaSchema>;
@@ -11,7 +11,7 @@ export const MIN_FIELD_WIDTH_PX = 36;
export type FieldToRender = Pick<
Field,
'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted' | 'recipientId'
'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted'
> & {
renderId: string; // A unique ID for the field in the render.
width: number;
@@ -30,7 +30,8 @@ export const renderCheckboxFieldElement = (
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
const checkboxMeta: TCheckboxFieldMeta | null = (field.fieldMeta as TCheckboxFieldMeta) || null;
const checkboxMeta: TCheckboxFieldMeta | null =
field.fieldMeta?.type === 'checkbox' ? field.fieldMeta : null;
const checkboxValues = checkboxMeta?.values || [];
const isFirstRender = !pageLayer.findOne(`#${field.renderId}`);
@@ -131,6 +132,7 @@ export const renderCheckboxFieldElement = (
});
const checkedValues: number[] = field.customText ? parseCheckboxCustomText(field.customText) : [];
const isReadOnly = checkboxMeta?.readOnly ?? false;
checkboxValues.forEach(({ value, checked }, index) => {
const isCheckboxChecked = match(mode)
@@ -138,7 +140,7 @@ export const renderCheckboxFieldElement = (
.with('sign', () => checkedValues.includes(index))
.with('export', () => {
// If it's read-only, check the originally checked state.
if (checkboxMeta.readOnly) {
if (isReadOnly) {
return checked;
}
@@ -54,7 +54,8 @@ export const renderDropdownFieldElement = (
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
const dropdownMeta: TDropdownFieldMeta | null = (field.fieldMeta as TDropdownFieldMeta) || null;
const dropdownMeta: TDropdownFieldMeta | null =
field.fieldMeta?.type === 'dropdown' ? field.fieldMeta : null;
let selectedValue = translations?.[FieldType.DROPDOWN] || 'Select Option';
@@ -28,7 +28,7 @@ export type FieldRenderMode = 'edit' | 'sign' | 'export';
export type FieldToRender = Pick<
Field,
'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted' | 'recipientId'
'envelopeItemId' | 'recipientId' | 'type' | 'page' | 'customText' | 'inserted'
> & {
renderId: string; // A unique ID for the field in the render.
width: number;
@@ -20,12 +20,29 @@ import { calculateFieldPosition } from './field-renderer';
const DEFAULT_TEXT_X_PADDING = 6;
const getGenericTextFieldMeta = (field: FieldToRender): GenericTextFieldTypeMetas | undefined => {
const fieldMeta = field.fieldMeta;
if (
fieldMeta?.type === 'initials' ||
fieldMeta?.type === 'name' ||
fieldMeta?.type === 'email' ||
fieldMeta?.type === 'date' ||
fieldMeta?.type === 'text' ||
fieldMeta?.type === 'number'
) {
return fieldMeta;
}
return undefined;
};
const upsertFieldText = (field: FieldToRender, options: RenderFieldElementOptions): Konva.Text => {
const { pageWidth, pageHeight, mode = 'edit', pageLayer, translations } = options;
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
const fieldMeta = field.fieldMeta as GenericTextFieldTypeMetas | undefined;
const fieldMeta = getGenericTextFieldMeta(field);
const fieldTypeName = translations?.[field.type] || field.type;
@@ -27,7 +27,8 @@ export const renderRadioFieldElement = (
) => {
const { pageWidth, pageHeight, pageLayer, mode, color } = options;
const radioMeta: TRadioFieldMeta | null = (field.fieldMeta as TRadioFieldMeta) || null;
const radioMeta: TRadioFieldMeta | null =
field.fieldMeta?.type === 'radio' ? field.fieldMeta : null;
const radioValues = radioMeta?.values || [];
const isFirstRender = !pageLayer.findOne(`#${field.renderId}`);
@@ -122,6 +123,7 @@ export const renderRadioFieldElement = (
});
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
const isReadOnly = radioMeta?.readOnly ?? false;
radioValues.forEach(({ value, checked }, index) => {
const isRadioValueChecked = match(mode)
@@ -129,7 +131,7 @@ export const renderRadioFieldElement = (
.with('sign', () => index.toString() === field.customText)
.with('export', () => {
// If it's read-only, check the originally checked state.
if (radioMeta.readOnly) {
if (isReadOnly) {
return checked;
}
+1 -1
View File
@@ -13,7 +13,7 @@ export type GetFileOptions = {
*
* - Lucas, 2025-11-04
*/
const getFile = async ({ type, data }: GetFileOptions) => {
const _getFile = async ({ type, data }: GetFileOptions) => {
return await match(type)
.with(DocumentDataType.BYTES, () => getFileFromBytes(data))
.with(DocumentDataType.BYTES_64, () => getFileFromBytes64(data))
+1 -1
View File
@@ -26,7 +26,7 @@ export const getEnvelopeItemPdfUrl = (options: EnvelopeItemPdfUrlOptions) => {
const version = options.version;
return token
? `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/token/${token}/envelopeItem/${id}/download/${version}${presignToken ? `?presignToken=${presignToken}` : ''}`
? `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/token/${token}/envelopeItem/${id}/download/${version}`
: `${NEXT_PUBLIC_WEBAPP_URL()}/api/files/envelope/${envelopeId}/envelopeItem/${id}/download/${version}`;
}
+2 -2
View File
@@ -53,8 +53,8 @@ export const validateFieldsUninserted = (): boolean => {
const innerDiv = element.querySelector('div');
const hasError = innerDiv?.getAttribute('data-error') === 'true';
if (hasError) {
errorElements.push(element as HTMLElement);
if (hasError && element instanceof HTMLElement) {
errorElements.push(element);
} else {
element.removeAttribute('data-error');
}