Merge pull request #30703 from overleaf/ae-prettier

Upgrade Prettier to v3.7.4

GitOrigin-RevId: 0f4434019bc7d12f2d5b7ecbb833ee20570d0706
This commit is contained in:
Alf Eaton
2026-01-16 09:56:07 +00:00
committed by Copybot
parent 3f19aaa58e
commit 03a3518aae
36 changed files with 144 additions and 137 deletions
@@ -3,7 +3,8 @@ module.exports = {
type: 'problem', type: 'problem',
fixable: null, fixable: null,
docs: { docs: {
description: 'Require loadingLabel prop when isLoading is specified on OLButton', description:
'Require loadingLabel prop when isLoading is specified on OLButton',
}, },
schema: [], schema: [],
}, },
@@ -11,10 +12,7 @@ module.exports = {
return { return {
'JSXOpeningElement[name.name="OLButton"]'(node) { 'JSXOpeningElement[name.name="OLButton"]'(node) {
const attributes = new Map( const attributes = new Map(
node.attributes.map(attr => [ node.attributes.map(attr => [attr.name?.name, attr])
attr.name?.name,
attr
])
) )
const isLoadingAttr = attributes.get('isLoading') const isLoadingAttr = attributes.get('isLoading')
@@ -26,12 +24,13 @@ module.exports = {
if ( if (
!isLoadingValue || !isLoadingValue ||
(isLoadingValue.type === 'JSXExpressionContainer' && (isLoadingValue.type === 'JSXExpressionContainer' &&
isLoadingValue.expression.type === 'Literal' && isLoadingValue.expression.type === 'Literal' &&
isLoadingValue.expression.value === true) isLoadingValue.expression.value === true)
) { ) {
context.report({ context.report({
node: isLoadingAttr, node: isLoadingAttr,
message: 'Button with isLoading prop must also specify loadingLabel', message:
'Button with isLoading prop must also specify loadingLabel',
}) })
} else if ( } else if (
isLoadingValue.type === 'JSXExpressionContainer' && isLoadingValue.type === 'JSXExpressionContainer' &&
@@ -39,7 +38,8 @@ module.exports = {
) { ) {
context.report({ context.report({
node: isLoadingAttr, node: isLoadingAttr,
message: 'Button with isLoading prop must also specify loadingLabel', message:
'Button with isLoading prop must also specify loadingLabel',
}) })
} }
} }
@@ -1,5 +1,5 @@
const path = require('node:path'); const path = require('node:path')
const fs = require('node:fs'); const fs = require('node:fs')
module.exports = { module.exports = {
meta: { meta: {
@@ -14,26 +14,39 @@ module.exports = {
hasSuggestions: true, hasSuggestions: true,
schema: [], schema: [],
messages: { messages: {
unresolvablePath: 'The path "{{pathValue}}" in vi.doMock() cannot be resolved relative to the current file.', unresolvablePath:
notAStringLiteral: 'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.', 'The path "{{pathValue}}" in vi.doMock() cannot be resolved relative to the current file.',
notAStringLiteral:
'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.',
noArguments: 'vi.doMock() called with no arguments.', noArguments: 'vi.doMock() called with no arguments.',
}, },
}, },
create(context) { create(context) {
const currentFilePath = context.getFilename(); const currentFilePath = context.getFilename()
// ESLint can sometimes pass <text> or <input> for snippets not in a file // ESLint can sometimes pass <text> or <input> for snippets not in a file
if (currentFilePath === '<text>' || currentFilePath === '<input>') { if (currentFilePath === '<text>' || currentFilePath === '<input>') {
return {} return {}
} }
const currentDirectory = path.dirname(currentFilePath); const currentDirectory = path.dirname(currentFilePath)
function canResolve(modulePath) { function canResolve(modulePath) {
try { try {
require.resolve(path.resolve(currentDirectory, modulePath)); require.resolve(path.resolve(currentDirectory, modulePath))
return true; return true
} catch (e) { } catch (e) {
const absolutePath = path.resolve(currentDirectory, modulePath); const absolutePath = path.resolve(currentDirectory, modulePath)
const extensions = ['', '.js', '.mjs', '.ts', '.jsx', '.tsx', '.json', '.node', '/index.js', '/index.ts']; // Add common extensions const extensions = [
'',
'.js',
'.mjs',
'.ts',
'.jsx',
'.tsx',
'.json',
'.node',
'/index.js',
'/index.ts',
] // Add common extensions
for (const ext of extensions) { for (const ext of extensions) {
if (fs.existsSync(absolutePath + ext)) { if (fs.existsSync(absolutePath + ext)) {
return true return true
@@ -63,9 +76,14 @@ module.exports = {
const firstArg = node.arguments[0] const firstArg = node.arguments[0]
let pathValue = firstArg.value let pathValue = firstArg.value
if (firstArg.type !== 'Literal' || typeof firstArg.value !== 'string') { if (
firstArg.type !== 'Literal' ||
typeof firstArg.value !== 'string'
) {
if (firstArg.type === 'Identifier') { if (firstArg.type === 'Identifier') {
const variable = context.getScope().variables.find(v => v.name === firstArg.name); const variable = context
.getScope()
.variables.find(v => v.name === firstArg.name)
if ( if (
variable && variable &&
variable.defs.length > 0 && variable.defs.length > 0 &&
@@ -80,15 +98,13 @@ module.exports = {
// If the first argument was a variable that didn't resolve then we can't auto-fix it // If the first argument was a variable that didn't resolve then we can't auto-fix it
} }
} }
context.report({ context.report({
node: firstArg, node: firstArg,
messageId: 'notAStringLiteral', messageId: 'notAStringLiteral',
}) })
return return
} }
if (!pathValue.startsWith('.')) { if (!pathValue.startsWith('.')) {
return return
} }
@@ -97,12 +113,13 @@ module.exports = {
const mjsPath = pathValue.replace('.js', '.mjs') const mjsPath = pathValue.replace('.js', '.mjs')
const additionalReportOptions = {} const additionalReportOptions = {}
if (canResolve(mjsPath)) { if (canResolve(mjsPath)) {
additionalReportOptions.fix = (fixer) => fixer.replaceText(firstArg, `'${mjsPath}'`) additionalReportOptions.fix = fixer =>
fixer.replaceText(firstArg, `'${mjsPath}'`)
additionalReportOptions.suggest = [ additionalReportOptions.suggest = [
{ {
desc: `Replace with "${pathValue.replace('.js', '.mjs')}"`, desc: `Replace with "${pathValue.replace('.js', '.mjs')}"`,
fix: (fixer) => fixer.replaceText(firstArg, `'${mjsPath}'`), fix: fixer => fixer.replaceText(firstArg, `'${mjsPath}'`),
} },
] ]
} }
context.report({ context.report({
@@ -111,11 +128,11 @@ module.exports = {
data: { data: {
pathValue, pathValue,
}, },
...additionalReportOptions ...additionalReportOptions,
}) })
} }
} }
}, },
} }
}, },
}; }
+25 -18
View File
@@ -136,26 +136,33 @@ ruleTester.run('domock-require-valid-path', viDoMockValidPath, {
valid: [ valid: [
{ {
code: 'vi.doMock("./require-vi-doMock-valid-path.js")', code: 'vi.doMock("./require-vi-doMock-valid-path.js")',
filename: __filename filename: __filename,
}, },
{ {
code: 'const filename = "./require-vi-doMock-valid-path.js"; vi.doMock(filename);', code: 'const filename = "./require-vi-doMock-valid-path.js"; vi.doMock(filename);',
filename: __filename filename: __filename,
} },
],
invalid: [
{
code: "vi.doMock('./require-vi-doMock-valid-path2')",
filename: __filename,
errors: [
{
message:
'The path "./require-vi-doMock-valid-path2" in vi.doMock() cannot be resolved relative to the current file.',
},
],
},
{
code: 'const filename = "./require-vi-doMock-valid-path2.js"; vi.doMock(filename);',
filename: __filename,
errors: [
{
message:
'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.',
},
],
},
], ],
invalid: [{
code: "vi.doMock('./require-vi-doMock-valid-path2')",
filename: __filename,
errors: [
{
message: 'The path "./require-vi-doMock-valid-path2" in vi.doMock() cannot be resolved relative to the current file.'}
]
}, {
code: 'const filename = "./require-vi-doMock-valid-path2.js"; vi.doMock(filename);',
filename: __filename,
errors: [
{
message: 'The first argument of vi.doMock() must be (or resolve to) a string literal representing a path.'}
]
}]
}) })
+4 -4
View File
@@ -59,7 +59,7 @@
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^6.0.0", "eslint-plugin-promise": "^6.0.0",
"eslint-plugin-unicorn": "^56.0.0", "eslint-plugin-unicorn": "^56.0.0",
"prettier": "3.6.2", "prettier": "3.7.4",
"prettier-plugin-groovy": "0.2.1", "prettier-plugin-groovy": "0.2.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
}, },
@@ -44023,9 +44023,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.6.2", "version": "3.7.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
+1 -1
View File
@@ -23,7 +23,7 @@
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^6.0.0", "eslint-plugin-promise": "^6.0.0",
"eslint-plugin-unicorn": "^56.0.0", "eslint-plugin-unicorn": "^56.0.0",
"prettier": "3.6.2", "prettier": "3.7.4",
"prettier-plugin-groovy": "0.2.1", "prettier-plugin-groovy": "0.2.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
}, },
@@ -70,9 +70,8 @@ async function cleanupBackup() {
// The backupPersistor refuses to delete short prefixes. Use a low-level S3 persistor. // The backupPersistor refuses to delete short prefixes. Use a low-level S3 persistor.
if (!s3PersistorForBackupCleanup) { if (!s3PersistorForBackupCleanup) {
const { backupPersistor } = await import( const { backupPersistor } =
'../../../../../storage/lib/backupPersistor.mjs' await import('../../../../../storage/lib/backupPersistor.mjs')
)
s3PersistorForBackupCleanup = new S3Persistor(backupPersistor.settings) s3PersistorForBackupCleanup = new S3Persistor(backupPersistor.settings)
} }
await Promise.all( await Promise.all(
@@ -393,9 +393,7 @@ const AuthenticationController = {
const middleware = async (req, res, next) => { const middleware = async (req, res, next) => {
const Oauth2Server = ( const Oauth2Server = (
await import( await import('../../../../modules/oauth2-server/app/src/Oauth2Server.mjs')
'../../../../modules/oauth2-server/app/src/Oauth2Server.mjs'
)
).default ).default
const request = new Oauth2Server.Request(req) const request = new Oauth2Server.Request(req)
@@ -6,7 +6,8 @@ import Errors from '../Errors/Errors.js'
export class InvalidEmailError extends Errors.BackwardCompatibleError {} export class InvalidEmailError extends Errors.BackwardCompatibleError {}
export class InvalidPasswordError extends Errors.BackwardCompatibleError {} export class InvalidPasswordError extends Errors.BackwardCompatibleError {}
export class ParallelLoginError extends Errors.BackwardCompatibleError {} export class ParallelLoginError extends Errors.BackwardCompatibleError {}
export class PasswordMustBeDifferentError extends Errors.BackwardCompatibleError {} export class PasswordMustBeDifferentError
extends Errors.BackwardCompatibleError {}
export class PasswordReusedError extends Errors.BackwardCompatibleError {} export class PasswordReusedError extends Errors.BackwardCompatibleError {}
export function handleAuthenticateErrors(error, req) { export function handleAuthenticateErrors(error, req) {
@@ -876,12 +876,12 @@ function _matchesFilters(project, tags, filters) {
function _hasActiveFilter(filters) { function _hasActiveFilter(filters) {
return Boolean( return Boolean(
filters.ownedByUser || filters.ownedByUser ||
filters.sharedWithUser || filters.sharedWithUser ||
filters.archived || filters.archived ||
filters.trashed || filters.trashed ||
filters.tag === null || filters.tag === null ||
filters.tag?.length || filters.tag?.length ||
filters.search?.length filters.search?.length
) )
} }
@@ -31,9 +31,7 @@ export function isStandaloneAiAddOnPlanCode(planCode) {
export function subscriptionChangeIsAiAssistUpgrade(subscriptionChange) { export function subscriptionChangeIsAiAssistUpgrade(subscriptionChange) {
return Boolean( return Boolean(
isStandaloneAiAddOnPlanCode(subscriptionChange.nextPlanCode) || isStandaloneAiAddOnPlanCode(subscriptionChange.nextPlanCode) ||
subscriptionChange.nextAddOns?.some( subscriptionChange.nextAddOns?.some(addOn => addOn.code === AI_ADD_ON_CODE)
addOn => addOn.code === AI_ADD_ON_CODE
)
) )
} }
@@ -6,7 +6,7 @@ export function isProfessionalPlan(planCode) {
// only identify "modern" professional group plans as eligible, and do not include legacy plans // only identify "modern" professional group plans as eligible, and do not include legacy plans
return Boolean( return Boolean(
planCode?.includes('professional') && planCode?.includes('professional') &&
FeaturesHelper.getMatchedFeatureSet(plan?.features) === 'professional' FeaturesHelper.getMatchedFeatureSet(plan?.features) === 'professional'
) )
} }
@@ -171,7 +171,7 @@ const SubscriptionLocator = {
return Boolean( return Boolean(
(subscription?.planCode && (subscription?.planCode &&
isStandaloneAiAddOnPlanCode(subscription?.planCode)) || isStandaloneAiAddOnPlanCode(subscription?.planCode)) ||
subscription?.addOns?.some(addOn => addOn.addOnCode === AI_ADD_ON_CODE) subscription?.addOns?.some(addOn => addOn.addOnCode === AI_ADD_ON_CODE)
) )
}, },
@@ -59,9 +59,9 @@ async function manageGroupMembers(req, res, next) {
const canUseAddSeatsFeature = Boolean( const canUseAddSeatsFeature = Boolean(
plan?.canUseFlexibleLicensing && plan?.canUseFlexibleLicensing &&
isAdmin && isAdmin &&
recurlySubscription && recurlySubscription &&
!recurlySubscription.pendingChange !recurlySubscription.pendingChange
) )
res.render('user_membership/group-members-react', { res.render('user_membership/group-members-react', {
@@ -85,7 +85,7 @@ const Features = {
case 'link-url': case 'link-url':
return Boolean( return Boolean(
_.get(Settings, ['apis', 'linkedUrlProxy', 'url']) && _.get(Settings, ['apis', 'linkedUrlProxy', 'url']) &&
Settings.enabledLinkedFileTypes.includes('url') Settings.enabledLinkedFileTypes.includes('url')
) )
case 'support': case 'support':
return supportModuleAvailable return supportModuleAvailable
@@ -32,9 +32,9 @@ export function cookieBannerRequired() {
const exposedSettings = getMeta('ol-ExposedSettings') const exposedSettings = getMeta('ol-ExposedSettings')
return Boolean( return Boolean(
exposedSettings.gaToken || exposedSettings.gaToken ||
exposedSettings.gaTokenV4 || exposedSettings.gaTokenV4 ||
exposedSettings.propensityId || exposedSettings.propensityId ||
exposedSettings.hotjarId exposedSettings.hotjarId
) )
} }
@@ -14,9 +14,8 @@ const FileViewPdf: FC<{
const handleContainer = useCallback( const handleContainer = useCallback(
async (element: HTMLDivElement | null) => { async (element: HTMLDivElement | null) => {
if (element) { if (element) {
const { loadPdfDocumentFromUrl } = await import( const { loadPdfDocumentFromUrl } =
'@/features/pdf-preview/util/pdf-js' await import('@/features/pdf-preview/util/pdf-js')
)
// bail out if loading PDF.js took too long // bail out if loading PDF.js took too long
if (!mountedRef.current) { if (!mountedRef.current) {
@@ -42,8 +42,7 @@ export interface GotoOffsetOptions {
} }
interface OpenDocOptions interface OpenDocOptions
extends Partial<GotoLineOptions>, extends Partial<GotoLineOptions>, Partial<GotoOffsetOptions> {
Partial<GotoOffsetOptions> {
gotoOffset?: number gotoOffset?: number
forceReopen?: boolean forceReopen?: boolean
keepCurrentView?: boolean keepCurrentView?: boolean
@@ -13,18 +13,15 @@ interface BaseFileTreeFindResult<T> {
index: number index: number
} }
export interface FileTreeFolderFindResult export interface FileTreeFolderFindResult extends BaseFileTreeFindResult<Folder> {
extends BaseFileTreeFindResult<Folder> {
type: 'folder' type: 'folder'
} }
export interface FileTreeDocumentFindResult export interface FileTreeDocumentFindResult extends BaseFileTreeFindResult<Doc> {
extends BaseFileTreeFindResult<Doc> {
type: 'doc' type: 'doc'
} }
export interface FileTreeFileRefFindResult export interface FileTreeFileRefFindResult extends BaseFileTreeFindResult<FileRef> {
extends BaseFileTreeFindResult<FileRef> {
type: 'fileRef' type: 'fileRef'
} }
@@ -144,9 +144,9 @@ export function ManageTagModal({
onClick={() => runUpdateTag(tag._id)} onClick={() => runUpdateTag(tag._id)}
disabled={Boolean( disabled={Boolean(
isUpdateLoading || isUpdateLoading ||
isDeleteLoading || isDeleteLoading ||
!newTagName?.length || !newTagName?.length ||
(newTagName === tag?.name && selectedColor === getTagColor(tag)) (newTagName === tag?.name && selectedColor === getTagColor(tag))
)} )}
isLoading={isUpdateLoading} isLoading={isUpdateLoading}
loadingLabel={t('saving')} loadingLabel={t('saving')}
@@ -86,8 +86,8 @@ function MakePrimary({
const isConfirmDisabled = Boolean( const isConfirmDisabled = Boolean(
!userEmailData.confirmedAt || !userEmailData.confirmedAt ||
state.isLoading || state.isLoading ||
inReconfirmNotificationPeriod(userEmailData) inReconfirmNotificationPeriod(userEmailData)
) )
return ( return (
@@ -23,7 +23,7 @@ type EmailsRowProps = {
function EmailsRow({ userEmailData, primary }: EmailsRowProps) { function EmailsRow({ userEmailData, primary }: EmailsRowProps) {
const hasSSOAffiliation = Boolean( const hasSSOAffiliation = Boolean(
userEmailData.affiliation && userEmailData.affiliation &&
ssoAvailableForInstitution(userEmailData.affiliation.institution) ssoAvailableForInstitution(userEmailData.affiliation.institution)
) )
return ( return (
@@ -45,7 +45,7 @@ export default function ShareModalBody() {
members?.some(member => members?.some(member =>
['readAndWrite', 'review'].includes(member.privileges) ['readAndWrite', 'review'].includes(member.privileges)
) && ) &&
members?.some(member => member.pendingEditor || member.pendingReviewer) members?.some(member => member.pendingEditor || member.pendingReviewer)
) )
}, [members]) }, [members])
@@ -1,7 +1,6 @@
import { forwardRef, useImperativeHandle, useLayoutEffect, useRef } from 'react' import { forwardRef, useImperativeHandle, useLayoutEffect, useRef } from 'react'
interface CellInputProps interface CellInputProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
value: string value: string
} }
@@ -61,8 +61,8 @@ interface AdjacentMatchResult extends MatchResult {
const matchedAdjacent = (match: MatchResult): match is AdjacentMatchResult => const matchedAdjacent = (match: MatchResult): match is AdjacentMatchResult =>
Boolean( Boolean(
match.matched && match.matched &&
match.end && match.end &&
(match.start.to === match.end.from || match.end.to === match.start.from) (match.start.to === match.end.from || match.end.to === match.start.from)
) )
/** /**
@@ -922,7 +922,7 @@ export const atomicDecorations = (options: Options) => {
) )
const centered = Boolean( const centered = Boolean(
environmentNode && environmentNode &&
centeringNodeForEnvironment(environmentNode) centeringNodeForEnvironment(environmentNode)
) )
const figureData = environmentNode const figureData = environmentNode
? parseFigureData(environmentNode, state) ? parseFigureData(environmentNode, state)
@@ -241,9 +241,8 @@ export class GraphicsWidget extends WidgetType {
} }
async renderPDF(view: EditorView, canvas: HTMLCanvasElement, url: string) { async renderPDF(view: EditorView, canvas: HTMLCanvasElement, url: string) {
const { loadPdfDocumentFromUrl } = await import( const { loadPdfDocumentFromUrl } =
'@/features/pdf-preview/util/pdf-js' await import('@/features/pdf-preview/util/pdf-js')
)
// bail out if loading PDF.js took too long // bail out if loading PDF.js took too long
if (this.destroyed) { if (this.destroyed) {
@@ -271,7 +271,6 @@ function rectanglesForRange(
for ( for (
let pos = Math.max(r.from, start), endPos = Math.min(r.to, end); let pos = Math.max(r.from, start), endPos = Math.min(r.to, end);
; ;
) { ) {
const docLine = view.state.doc.lineAt(pos) const docLine = view.state.doc.lineAt(pos)
for (const span of view.bidiSpans(docLine)) { for (const span of view.bidiSpans(docLine)) {
@@ -85,8 +85,8 @@ export function ActiveSubscription({
const hasPendingPause = Boolean( const hasPendingPause = Boolean(
subscription.payment.state === 'active' && subscription.payment.state === 'active' &&
subscription.payment.remainingPauseCycles && subscription.payment.remainingPauseCycles &&
subscription.payment.remainingPauseCycles > 0 subscription.payment.remainingPauseCycles > 0
) )
const isLegacyPlan = const isLegacyPlan =
@@ -129,17 +129,17 @@ export function SubscriptionDashboardProvider({
const hasDisplayedSubscription = Boolean( const hasDisplayedSubscription = Boolean(
institutionMemberships?.length > 0 || institutionMemberships?.length > 0 ||
personalSubscription || personalSubscription ||
memberGroupSubscriptions?.length > 0 || memberGroupSubscriptions?.length > 0 ||
managedGroupSubscriptions?.length > 0 || managedGroupSubscriptions?.length > 0 ||
managedInstitutions?.length > 0 || managedInstitutions?.length > 0 ||
managedPublishers?.length > 0 managedPublishers?.length > 0
) )
const hasValidActiveSubscription = Boolean( const hasValidActiveSubscription = Boolean(
['active', 'canceled'].includes(personalSubscription?.payment?.state) || ['active', 'canceled'].includes(personalSubscription?.payment?.state) ||
institutionMemberships?.length > 0 || institutionMemberships?.length > 0 ||
memberGroupSubscriptions?.length > 0 memberGroupSubscriptions?.length > 0
) )
const getFormattedRenewalDate = useCallback(() => { const getFormattedRenewalDate = useCallback(() => {
@@ -58,10 +58,10 @@ const isPropensityNetworkError = (err: ErrorEvent) => {
const breadcrumbUrl = errorBreadcrumbs[0]?.data?.url const breadcrumbUrl = errorBreadcrumbs[0]?.data?.url
return Boolean( return Boolean(
breadcrumbUrl && breadcrumbUrl &&
[ [
'https://analytics.propensity.com/', 'https://analytics.propensity.com/',
'https://analytics.propensity-abm.com/', 'https://analytics.propensity-abm.com/',
].some(url => breadcrumbUrl.startsWith(url)) ].some(url => breadcrumbUrl.startsWith(url))
) )
} }
@@ -2,8 +2,10 @@ import ReCAPTCHA from 'react-google-recaptcha'
import getMeta from '@/utils/meta' import getMeta from '@/utils/meta'
import { ExposedSettings } from '../../../../types/exposed-settings' import { ExposedSettings } from '../../../../types/exposed-settings'
interface ReCaptcha2Props interface ReCaptcha2Props extends Pick<
extends Pick<React.ComponentProps<typeof ReCAPTCHA>, 'onChange'> { React.ComponentProps<typeof ReCAPTCHA>,
'onChange'
> {
page: keyof ExposedSettings['recaptchaDisabled'] page: keyof ExposedSettings['recaptchaDisabled']
recaptchaRef: React.LegacyRef<ReCAPTCHA> recaptchaRef: React.LegacyRef<ReCAPTCHA>
} }
@@ -84,7 +84,7 @@ export const EditorProvider: FC<React.PropsWithChildren> = ({ children }) => {
() => { () => {
return Boolean( return Boolean(
featureUsage?.aiErrorAssistant && featureUsage?.aiErrorAssistant &&
featureUsage?.aiErrorAssistant.remainingUsage > 0 featureUsage?.aiErrorAssistant.remainingUsage > 0
) )
} }
) )
@@ -29,9 +29,7 @@ describe('EmailChangeHelper', function () {
) )
EmailChangeHelpers = ( EmailChangeHelpers = (
await import( await import('../../../../app/src/Features/Analytics/EmailChangeHelper.mjs')
'../../../../app/src/Features/Analytics/EmailChangeHelper.mjs'
)
).default ).default
}) })
@@ -46,8 +46,7 @@ export interface NotificationTPDSFileLimit extends NotificationBase {
} }
} }
export interface NotificationDropboxDuplicateProjectNames export interface NotificationDropboxDuplicateProjectNames extends NotificationBase {
extends NotificationBase {
templateKey: Extract< templateKey: Extract<
TemplateKey, TemplateKey,
'notification_dropbox_duplicate_project_names' 'notification_dropbox_duplicate_project_names'
@@ -57,8 +56,7 @@ export interface NotificationDropboxDuplicateProjectNames
} }
} }
interface NotificationDropboxUnlinkedDueToLapsedReconfirmation interface NotificationDropboxUnlinkedDueToLapsedReconfirmation extends NotificationBase {
extends NotificationBase {
templateKey: Extract< templateKey: Extract<
TemplateKey, TemplateKey,
'notification_dropbox_unlinked_due_to_lapsed_reconfirmation' 'notification_dropbox_unlinked_due_to_lapsed_reconfirmation'
@@ -55,8 +55,7 @@ interface AddOn {
// Extending the default interface as it lacks the `items` prop // Extending the default interface as it lacks the `items` prop
export interface SubscriptionPricingInstanceCustom export interface SubscriptionPricingInstanceCustom
extends SubscriptionPricingInstance, extends SubscriptionPricingInstance, SubscriptionPricingState {
SubscriptionPricingState {
id: string id: string
items: { items: {
addons: AddOn[] addons: AddOn[]
@@ -10,16 +10,14 @@ export interface ReviewPanelCommentThreadBase {
submitting?: boolean // angular specific (to be made into a local state) submitting?: boolean // angular specific (to be made into a local state)
} }
interface ReviewPanelUnresolvedCommentThread interface ReviewPanelUnresolvedCommentThread extends ReviewPanelCommentThreadBase {
extends ReviewPanelCommentThreadBase {
resolved?: never resolved?: never
resolved_at?: never resolved_at?: never
resolved_by_user_id?: never resolved_by_user_id?: never
resolved_by_user?: never resolved_by_user?: never
} }
export interface ReviewPanelResolvedCommentThread export interface ReviewPanelResolvedCommentThread extends ReviewPanelCommentThreadBase {
extends ReviewPanelCommentThreadBase {
resolved: boolean resolved: boolean
resolved_at: DateString resolved_at: DateString
resolved_by_user_id: UserId resolved_by_user_id: UserId