lint: patch some no-empty-function violations & delete unused code (#6642)

* lint: patch some no-empty-function violations

* docs: update ESLint rules and remove unused loadOwner function in UserAccess component

* refactor: remove getRemoteFile function and associated method from budget file handlers

* chore: disable docstring checks in coderabbit configuration
This commit is contained in:
Matiss Janis Aboltins
2026-01-13 23:05:24 +01:00
committed by GitHub
parent 0c3a515e29
commit b88feb9336
15 changed files with 51 additions and 126 deletions

View File

@@ -10,6 +10,7 @@ reviews:
enabled: false
pre_merge_checks:
docstrings:
mode: off
enabled: false
custom_checks:
- mode: error

View File

@@ -464,16 +464,9 @@
// TODO: enable these
{
"files": [
"packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx",
"packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx",
"packages/desktop-client/src/components/budget/BudgetCategories.tsx",
"packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx",
"packages/desktop-client/src/components/ManageRules.tsx",
"packages/desktop-client/src/components/mobile/budget/ExpenseGroupList.tsx",
"packages/desktop-client/src/components/modals/EditFieldModal.tsx",
"packages/desktop-client/src/components/reports/reports/Calendar.tsx",
"packages/desktop-client/src/components/schedules/ScheduleLink.tsx",
"packages/desktop-client/src/components/ServerContext.tsx",
"packages/desktop-client/src/components/table.tsx"
],
"rules": {

View File

@@ -169,7 +169,7 @@ Custom ESLint rules specific to Actual.
- `no-untranslated-strings`: Enforces i18n usage
- `prefer-trans-over-t`: Prefers Trans component over t() function
- `prefer-logger-over-console`: Enforces using logger instead of console
- `prefer-logger-over-console`: Enforces using logger instead of console in `packages/loot-core/`
- `typography`: Typography rules
- `prefer-if-statement`: Prefers explicit if statements
@@ -328,7 +328,6 @@ Always maintain newlines between import groups.
**Never:**
- Use `console.*` (use logger instead - enforced by ESLint)
- Import from `uuid` without destructuring: use `import { v4 as uuidv4 } from 'uuid'`
- Import colors directly - use theme instead
- Import `@actual-app/web/*` in `loot-core`
@@ -541,7 +540,6 @@ Before committing changes, ensure:
- [ ] `yarn typecheck` passes
- [ ] `yarn lint:fix` has been run
- [ ] Relevant tests pass
- [ ] No new console.\* usage (use logger)
- [ ] User-facing strings are translated
- [ ] Prefer `type` over `interface`
- [ ] Named exports used (not default exports)

View File

@@ -43,8 +43,12 @@ const ServerContext = createContext<ServerContextValue>({
setURL: () => Promise.reject(new Error('ServerContext not initialized')),
refreshLoginMethods: () =>
Promise.reject(new Error('ServerContext not initialized')),
setMultiuserEnabled: () => {},
setLoginMethods: () => {},
setMultiuserEnabled: () => {
throw new Error('ServerContext not initialized');
},
setLoginMethods: () => {
throw new Error('ServerContext not initialized');
},
});
export const useServerURL = () => useContext(ServerContext).url;

View File

@@ -4,8 +4,6 @@ import React, {
useEffect,
useCallback,
useMemo,
type SetStateAction,
type Dispatch,
type CSSProperties,
} from 'react';
import { Trans, useTranslation } from 'react-i18next';
@@ -38,13 +36,9 @@ import { useDispatch } from '@desktop-client/redux';
type ManageUserAccessContentProps = {
isModal: boolean;
setLoading?: Dispatch<SetStateAction<boolean>>;
};
function UserAccessContent({
isModal,
setLoading,
}: ManageUserAccessContentProps) {
function UserAccessContent({ isModal }: ManageUserAccessContentProps) {
const { t } = useTranslation();
const dispatch = useDispatch();
const [allAccess, setAllAccess] = useState([]);
@@ -76,7 +70,6 @@ function UserAccessContent({
);
const loadAccess = useCallback(async () => {
setLoading(true);
const data: Awaited<ReturnType<Handlers['access-get-available-users']>> =
await send('access-get-available-users', cloudFileId as string);
@@ -111,20 +104,7 @@ function UserAccessContent({
setAllAccess(loadedAccess);
return loadedAccess;
}, [cloudFileId, dispatch, setLoading, t]);
const loadOwner = useCallback(async () => {
const file = (await send('get-user-file-info', cloudFileId as string)) ?? {
usersWithAccess: [],
};
const owner = file?.usersWithAccess.filter(user => user.owner);
if (owner.length > 0) {
return owner[0];
}
return null;
}, [cloudFileId]);
}, [cloudFileId, dispatch, t]);
useEffect(() => {
async function loadData() {
@@ -132,8 +112,6 @@ function UserAccessContent({
await loadAccess();
} catch (error) {
console.error('Error loading user access data:', error);
} finally {
setLoading(false);
}
}
@@ -142,7 +120,7 @@ function UserAccessContent({
return () => {
undo.setUndoState('openModal', null);
};
}, [setLoading, loadAccess, loadOwner]);
}, [loadAccess]);
function loadMore() {
setPage(page => page + 1);
@@ -213,7 +191,6 @@ function UserAccessContent({
style={{ width: 16, height: 16 }}
onToggleSave={async () => {
await loadAccess();
setLoading(false);
}}
/>
</View>
@@ -223,14 +200,10 @@ function UserAccessContent({
type ManageUsersProps = {
isModal: boolean;
setLoading?: Dispatch<SetStateAction<boolean>>;
};
export function UserAccess({
isModal,
setLoading = () => {},
}: ManageUsersProps) {
return <UserAccessContent isModal={isModal} setLoading={setLoading} />;
export function UserAccess({ isModal }: ManageUsersProps) {
return <UserAccessContent isModal={isModal} />;
}
type UsersAccessListProps = {

View File

@@ -4,8 +4,6 @@ import {
useEffect,
useCallback,
useMemo,
type SetStateAction,
type Dispatch,
type CSSProperties,
} from 'react';
import { Trans, useTranslation } from 'react-i18next';
@@ -37,7 +35,6 @@ import { signOut } from '@desktop-client/users/usersSlice';
type ManageUserDirectoryContentProps = {
isModal: boolean;
setLoading?: Dispatch<SetStateAction<boolean>>;
};
function useGetUserDirectoryErrors() {
@@ -81,10 +78,7 @@ function useGetUserDirectoryErrors() {
return { getUserDirectoryErrors };
}
function UserDirectoryContent({
isModal,
setLoading,
}: ManageUserDirectoryContentProps) {
function UserDirectoryContent({ isModal }: ManageUserDirectoryContentProps) {
const { t } = useTranslation();
const [allUsers, setAllUsers] = useState([]);
@@ -120,8 +114,6 @@ function UserDirectoryContent({
);
const loadUsers = useCallback(async () => {
setLoading(true);
const loadedUsers = (await send('users-get')) ?? [];
if ('error' in loadedUsers) {
dispatch(
@@ -135,19 +127,16 @@ function UserDirectoryContent({
},
}),
);
setLoading(false);
return;
}
setAllUsers(loadedUsers);
setLoading(false);
return loadedUsers;
}, [dispatch, getUserDirectoryErrors, setLoading, t]);
}, [dispatch, getUserDirectoryErrors, t]);
useEffect(() => {
async function loadData() {
await loadUsers();
setLoading(false);
}
loadData();
@@ -155,14 +144,13 @@ function UserDirectoryContent({
return () => {
undo.setUndoState('openModal', null);
};
}, [setLoading, loadUsers]);
}, [loadUsers]);
function loadMore() {
setPage(page => page + 1);
}
const onDeleteSelected = useCallback(async () => {
setLoading(true);
const res = await send('user-delete-all', [...selectedInst.items]);
const error = res['error'];
@@ -202,15 +190,7 @@ function UserDirectoryContent({
await loadUsers();
selectedInst.dispatch({ type: 'select-none' });
setLoading(false);
}, [
setLoading,
selectedInst,
loadUsers,
dispatch,
t,
getUserDirectoryErrors,
]);
}, [selectedInst, loadUsers, dispatch, t, getUserDirectoryErrors]);
const onEditUser = useCallback(
user => {
@@ -222,14 +202,13 @@ function UserDirectoryContent({
user,
onSave: async () => {
await loadUsers();
setLoading(false);
},
},
},
}),
);
},
[dispatch, loadUsers, setLoading],
[dispatch, loadUsers],
);
function onAddUser() {
@@ -248,7 +227,6 @@ function UserDirectoryContent({
user,
onSave: async () => {
await loadUsers();
setLoading(false);
},
},
},
@@ -370,14 +348,10 @@ function EmptyMessage({ text, style }: EmptyMessageProps) {
type ManageUsersProps = {
isModal: boolean;
setLoading?: Dispatch<SetStateAction<boolean>>;
};
export function UserDirectory({
isModal,
setLoading = () => {},
}: ManageUsersProps) {
return <UserDirectoryContent isModal={isModal} setLoading={setLoading} />;
export function UserDirectory({ isModal }: ManageUsersProps) {
return <UserDirectoryContent isModal={isModal} />;
}
type UsersListProps = {

View File

@@ -282,7 +282,6 @@ export const BudgetCategories = memo<BudgetCategoriesProps>(
}}
editing
onSave={_onSaveCategory}
onDelete={async () => {}}
onHideNewCategory={onHideNewCategory}
onEditName={onEditName!}
/>

View File

@@ -27,16 +27,23 @@ type SidebarCategoryProps = {
categoryGroup?: CategoryGroupEntity;
dragPreview?: boolean;
dragging?: boolean;
editing: boolean;
goalsShown?: boolean;
style?: CSSProperties;
borderColor?: string;
isLast?: boolean;
onEditName: (id: CategoryEntity['id']) => void;
onSave: (category: CategoryEntity) => void;
onDelete: (id: CategoryEntity['id']) => void;
onHideNewCategory?: () => void;
};
} & (
| {
editing: true;
onDelete?: never;
}
| {
editing: boolean;
onDelete: (id: CategoryEntity['id']) => void;
}
);
export function SidebarCategory({
innerRef,

View File

@@ -12,14 +12,14 @@ type BalanceMovementMenuProps = {
categoryId: string;
month: string;
onBudgetAction: (month: string, action: string, arg?: unknown) => void;
onClose?: () => void;
onClose: () => void;
};
export function BalanceMovementMenu({
categoryId,
month,
onBudgetAction,
onClose = () => {},
onClose,
}: BalanceMovementMenuProps) {
const format = useFormat();

View File

@@ -109,7 +109,6 @@ export function EditFieldModal({
value={formatDate(parseISO(today), dateFormat)}
dateFormat={dateFormat}
embedded
onUpdate={() => {}}
onSelect={date => {
onSelect(dayFromDate(parseDate(date, 'yyyy-MM-dd', new Date())));
close();

View File

@@ -149,7 +149,6 @@ export function ScheduleLink({
allowCompleted={false}
filter={filter}
minimal
onAction={() => {}}
onSelect={id => {
onSelect(id);
close();

View File

@@ -45,11 +45,21 @@ type SchedulesTableProps = {
filter: string;
allowCompleted: boolean;
onSelect: (id: ScheduleEntity['id']) => void;
onAction: (actionName: ScheduleItemAction, id: ScheduleEntity['id']) => void;
style: CSSProperties;
minimal?: boolean;
tableStyle?: CSSProperties;
};
} & (
| {
minimal: true;
onAction?: never;
}
| {
minimal?: false;
onAction: (
actionName: ScheduleItemAction,
id: ScheduleEntity['id'],
) => void;
}
);
type CompletedScheduleItem = { id: 'show-completed' };
type SchedulesTableItem = ScheduleEntity | CompletedScheduleItem;

View File

@@ -47,7 +47,6 @@ export type BudgetFileHandlers = {
'unique-budget-name': typeof handleUniqueBudgetName;
'get-budgets': typeof getBudgets;
'get-remote-files': typeof getRemoteFiles;
'get-user-file-info': typeof getUserFileInfo;
'reset-budget-cache': typeof resetBudgetCache;
'upload-budget': typeof uploadBudget;
'download-budget': typeof downloadBudget;
@@ -72,7 +71,6 @@ app.method('validate-budget-name', handleValidateBudgetName);
app.method('unique-budget-name', handleUniqueBudgetName);
app.method('get-budgets', getBudgets);
app.method('get-remote-files', getRemoteFiles);
app.method('get-user-file-info', getUserFileInfo);
app.method('reset-budget-cache', mutator(resetBudgetCache));
app.method('upload-budget', uploadBudget);
app.method('download-budget', downloadBudget);
@@ -140,10 +138,6 @@ async function getRemoteFiles() {
return cloudStorage.listRemoteFiles();
}
async function getUserFileInfo(fileId: string) {
return cloudStorage.getRemoteFile(fileId);
}
async function resetBudgetCache() {
// Recomputing everything will update the cache
await sheet.loadUserBudgets(db);

View File

@@ -402,38 +402,6 @@ export async function listRemoteFiles(): Promise<RemoteFile[]> {
.filter(Boolean);
}
export async function getRemoteFile(
fileId: string,
): Promise<RemoteFile | null> {
const userToken = await asyncStorage.getItem('user-token');
if (!userToken) {
return null;
}
let res;
try {
res = await fetchJSON(getServer().SYNC_SERVER + '/get-user-file-info', {
headers: {
'X-ACTUAL-TOKEN': userToken,
'X-ACTUAL-FILE-ID': fileId,
},
});
} catch (e) {
logger.log('Unexpected error fetching file from server', e);
return null;
}
if (res.status === 'error') {
logger.log('Error fetching file from server', res);
return null;
}
return {
...res.data,
hasKey: encryption.hasKey(res.data.encryptKeyId),
};
}
export async function download(cloudFileId) {
const userToken = await asyncStorage.getItem('user-token');
const syncServer = getServer().SYNC_SERVER;

View File

@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [MatissJanis]
---
lint: patch some no-empty-function violations