More lints
This commit is contained in:
@@ -11,7 +11,6 @@ export default [
|
||||
*/
|
||||
"@typescript-eslint/no-unnecessary-condition": "off",
|
||||
/** TODO: Disabled as we migrate, try to prune these again */
|
||||
"@typescript-eslint/no-floating-promises": "off",
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -20,6 +20,7 @@ import { loadCast } from "ente-new/photos/utils/chromecast-sender";
|
||||
import { t } from "i18next";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Trans } from "react-i18next";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
type AlbumCastDialogProps = ModalVisibilityProps & {
|
||||
/** The collection that we want to cast. */
|
||||
@@ -114,7 +115,7 @@ export const AlbumCastDialogContents: React.FC<AlbumCastDialogProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (view == "auto") {
|
||||
loadCast().then(async (cast) => {
|
||||
void loadCast().then(async (cast) => {
|
||||
const instance = cast.framework.CastContext.getInstance();
|
||||
try {
|
||||
await instance.requestSession();
|
||||
@@ -127,29 +128,24 @@ export const AlbumCastDialogContents: React.FC<AlbumCastDialogProps> = ({
|
||||
session.addMessageListener(
|
||||
"urn:x-cast:pair-request",
|
||||
(_, message) => {
|
||||
const data = message;
|
||||
// TODO:
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const obj = JSON.parse(data);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
||||
const code = obj.code;
|
||||
const { code } = CastPairRequest.parse(
|
||||
JSON.parse(message),
|
||||
);
|
||||
|
||||
if (code) {
|
||||
publishCastPayload(`${code}`, collection)
|
||||
.then(() => {
|
||||
setView("choose");
|
||||
onClose();
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
log.error("Error casting to TV", e);
|
||||
setView("auto-cast-error");
|
||||
});
|
||||
}
|
||||
void publishCastPayload(code, collection)
|
||||
.then(() => {
|
||||
setView("choose");
|
||||
onClose();
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
log.error("Error casting to TV", e);
|
||||
setView("auto-cast-error");
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
const collectionID = collection.id;
|
||||
session
|
||||
void session
|
||||
.sendMessage("urn:x-cast:pair-request", { collectionID })
|
||||
.then(() => {
|
||||
log.debug(() => "urn:x-cast:pair-request sent");
|
||||
@@ -252,3 +248,8 @@ export const AlbumCastDialogContents: React.FC<AlbumCastDialogProps> = ({
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Zod schema for the "x-cast:pair-request" payload sent by the cast app.
|
||||
*/
|
||||
const CastPairRequest = z.object({ code: z.string() });
|
||||
|
||||
@@ -627,7 +627,19 @@ const AddParticipantForm: React.FC<AddParticipantFormProps> = ({
|
||||
});
|
||||
|
||||
const resetExistingSelection = () =>
|
||||
formik.setFieldValue("selectedEmails", []);
|
||||
void formik.setFieldValue("selectedEmails", []);
|
||||
|
||||
const createToggleEmail = (email: string) => {
|
||||
return () => {
|
||||
const emails = formik.values.selectedEmails;
|
||||
void formik.setFieldValue(
|
||||
"selectedEmails",
|
||||
emails.includes(email)
|
||||
? emails.filter((e) => e != email)
|
||||
: emails.concat(email),
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
@@ -661,18 +673,7 @@ const AddParticipantForm: React.FC<AddParticipantFormProps> = ({
|
||||
<React.Fragment key={email}>
|
||||
<RowButton
|
||||
fontWeight="regular"
|
||||
onClick={() => {
|
||||
const emails =
|
||||
formik.values.selectedEmails;
|
||||
formik.setFieldValue(
|
||||
"selectedEmails",
|
||||
emails.includes(email)
|
||||
? emails.filter(
|
||||
(e) => e != email,
|
||||
)
|
||||
: emails.concat(email),
|
||||
);
|
||||
}}
|
||||
onClick={createToggleEmail(email)}
|
||||
label={email}
|
||||
startIcon={
|
||||
<Avatar
|
||||
@@ -761,11 +762,11 @@ const ManageEmailShare: React.FC<ManageEmailShareProps> = ({
|
||||
const selectAndManageParticipant = useCallback(
|
||||
(email: string) => {
|
||||
setSelectedParticipant(
|
||||
collection.sharees.find((sharee) => sharee.email === email),
|
||||
collection.sharees.find((sharee) => sharee.email == email),
|
||||
);
|
||||
showManageParticipant();
|
||||
},
|
||||
[showManageParticipant],
|
||||
[collection, showManageParticipant],
|
||||
);
|
||||
|
||||
const handleRootClose = () => {
|
||||
@@ -1120,16 +1121,17 @@ const PublicShare: React.FC<PublicShareProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (publicURL?.url) {
|
||||
appendCollectionKeyToShareURL(publicURL.url, collection.key).then(
|
||||
(url) => setResolvedURL(url),
|
||||
);
|
||||
void appendCollectionKeyToShareURL(
|
||||
publicURL.url,
|
||||
collection.key,
|
||||
).then((url) => setResolvedURL(url));
|
||||
} else {
|
||||
setResolvedURL(undefined);
|
||||
}
|
||||
}, [publicURL]);
|
||||
|
||||
const handleCopyLink = () => {
|
||||
if (resolvedURL) navigator.clipboard.writeText(resolvedURL);
|
||||
if (resolvedURL) void navigator.clipboard.writeText(resolvedURL);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -1475,7 +1477,7 @@ const ManagePublicCollect: React.FC<ManagePublicLinkSettingProps> = ({
|
||||
onUpdate,
|
||||
}) => {
|
||||
const handleFileDownloadSetting = () => {
|
||||
onUpdate({ enableCollect: !publicURL.enableCollect });
|
||||
void onUpdate({ enableCollect: !publicURL.enableCollect });
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -1666,7 +1668,9 @@ const ManageDownloadAccess: React.FC<ManagePublicLinkSettingProps> = ({
|
||||
},
|
||||
});
|
||||
} else {
|
||||
onUpdate({ enableDownload: true });
|
||||
// TODO: Various calls to onUpdate return promises. The UI should
|
||||
// handle the in-progress states where needed.
|
||||
void onUpdate({ enableDownload: true });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ export const DownloadStatusNotifications: React.FC<
|
||||
const createOnClick = (group: SaveGroup) => () => {
|
||||
const electron = globalThis.electron;
|
||||
if (electron && group.downloadDirPath) {
|
||||
electron.openDirectory(group.downloadDirPath);
|
||||
void electron.openDirectory(group.downloadDirPath);
|
||||
} else if (onShowCollectionSummary) {
|
||||
onShowCollectionSummary(
|
||||
group.collectionSummaryID,
|
||||
|
||||
@@ -167,7 +167,7 @@ export const FileListWithViewer: React.FC<FileListWithViewerProps> = ({
|
||||
(editedFile: File, collection: Collection, enteFile: EnteFile) => {
|
||||
uploadManager.prepareForNewUpload();
|
||||
uploadManager.showUploadProgressDialog();
|
||||
uploadManager.uploadFile(editedFile, collection, enteFile);
|
||||
void uploadManager.uploadFile(editedFile, collection, enteFile);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
@@ -265,6 +265,10 @@ const UserDetailsSection: React.FC<UserDetailsSectionProps> = ({
|
||||
isSubscriptionStripe(userDetails.subscription) &&
|
||||
isSubscriptionPastDue(userDetails.subscription)
|
||||
) {
|
||||
// TODO: This makes an API request, so the UI should indicate
|
||||
// the await.
|
||||
//
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
redirectToCustomerPortal();
|
||||
} else {
|
||||
onShowPlanSelector();
|
||||
@@ -337,6 +341,7 @@ const SubscriptionStatus: React.FC<SubscriptionStatusProps> = ({
|
||||
isSubscriptionStripe(userDetails.subscription) &&
|
||||
isSubscriptionPastDue(userDetails.subscription)
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
redirectToCustomerPortal();
|
||||
} else {
|
||||
onShowPlanSelector();
|
||||
@@ -851,16 +856,17 @@ const LanguageSelector = () => {
|
||||
const locale = getLocaleInUse();
|
||||
|
||||
const updateCurrentLocale = (newLocale: SupportedLocale) => {
|
||||
setLocaleInUse(newLocale);
|
||||
// [Note: Changing locale causes a full reload]
|
||||
//
|
||||
// A full reload is needed because we use the global `t` instance
|
||||
// instead of the useTranslation hook.
|
||||
//
|
||||
// We also rely on this behaviour by caching various formatters in
|
||||
// module static variables that not get updated if the i18n.language
|
||||
// changes unless there is a full reload.
|
||||
window.location.reload();
|
||||
void setLocaleInUse(newLocale).then(() => {
|
||||
// [Note: Changing locale causes a full reload]
|
||||
//
|
||||
// A full reload is needed because we use the global `t` instance
|
||||
// instead of the useTranslation hook.
|
||||
//
|
||||
// We also rely on this behaviour by caching various formatters in
|
||||
// module static variables that not get updated if the i18n.language
|
||||
// changes unless there is a full reload.
|
||||
window.location.reload();
|
||||
});
|
||||
};
|
||||
|
||||
const options = supportedLocales.map((locale) => ({
|
||||
@@ -1088,11 +1094,14 @@ const Help: React.FC<NestedSidebarDrawerVisibilityProps> = ({
|
||||
continue: { text: t("view_logs"), action: viewLogs },
|
||||
});
|
||||
|
||||
const viewLogs = () => {
|
||||
const viewLogs = async () => {
|
||||
log.info("Viewing logs");
|
||||
const electron = globalThis.electron;
|
||||
if (electron) electron.openLogDirectory();
|
||||
else saveStringAsFile(savedLogs(), `ente-web-logs-${Date.now()}.txt`);
|
||||
if (electron) {
|
||||
await electron.openLogDirectory();
|
||||
} else {
|
||||
saveStringAsFile(savedLogs(), `ente-web-logs-${Date.now()}.txt`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// TODO: Too many null assertions in this file. The types need reworking.
|
||||
// TODO: Audit this file
|
||||
/* eslint-disable @typescript-eslint/no-misused-promises */
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||
import DiscFullIcon from "@mui/icons-material/DiscFull";
|
||||
import GoogleIcon from "@mui/icons-material/Google";
|
||||
|
||||
@@ -53,7 +53,7 @@ export const WatchFolder: React.FC<ModalVisibilityProps> = ({
|
||||
useModalVisibility();
|
||||
|
||||
useEffect(() => {
|
||||
watcher.getWatches().then((ws) => setWatches(ws));
|
||||
void watcher.getWatches().then((ws) => setWatches(ws));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -87,7 +87,7 @@ export const WatchFolder: React.FC<ModalVisibilityProps> = ({
|
||||
const selectCollectionMappingAndAddWatch = async (path: string) => {
|
||||
const filePaths = await ensureElectron().fs.findFiles(path);
|
||||
if (areAllInSameDirectory(filePaths)) {
|
||||
addWatch(path, "root");
|
||||
await addWatch(path, "root");
|
||||
} else {
|
||||
setSavedFolderPath(path);
|
||||
showMappingChoice();
|
||||
@@ -109,7 +109,7 @@ export const WatchFolder: React.FC<ModalVisibilityProps> = ({
|
||||
|
||||
const handleCollectionMappingSelect = (mapping: CollectionMapping) => {
|
||||
setSavedFolderPath(undefined);
|
||||
addWatch(savedFolderPath!, mapping);
|
||||
void addWatch(savedFolderPath!, mapping);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -89,8 +89,11 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
|
||||
// the user is logged in.
|
||||
|
||||
const handleOpenEnteURL = (url: string) => {
|
||||
if (url.startsWith("ente://app")) router.push(url);
|
||||
else log.info(`Ignoring unhandled open request for URL ${url}`);
|
||||
if (url.startsWith("ente://app")) {
|
||||
void router.push(url);
|
||||
} else {
|
||||
log.info(`Ignoring unhandled open request for URL ${url}`);
|
||||
}
|
||||
};
|
||||
|
||||
const showUpdateDialog = (update: AppUpdate) => {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// TODO: Audit this file (the code here is mostly fine, but needs revisiting
|
||||
// the file it depends on have been audited and their interfaces fixed).
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||
import FileUploadOutlinedIcon from "@mui/icons-material/FileUploadOutlined";
|
||||
import MenuIcon from "@mui/icons-material/Menu";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TODO: Audit this file (too many null assertions)
|
||||
// TODO: Audit this file (too many null assertions + other issues)
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
import AddPhotoAlternateOutlinedIcon from "@mui/icons-material/AddPhotoAlternateOutlined";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import DownloadIcon from "@mui/icons-material/Download";
|
||||
|
||||
@@ -96,7 +96,7 @@ class FolderWatcher {
|
||||
this.upload = upload;
|
||||
this.onTriggerRemotePull = onTriggerRemotePull;
|
||||
this.registerListeners();
|
||||
this.syncWithDisk();
|
||||
this.triggerSyncWithDisk();
|
||||
}
|
||||
|
||||
/** Return `true` if we are currently using the uploader. */
|
||||
@@ -126,7 +126,7 @@ class FolderWatcher {
|
||||
*/
|
||||
resumePausedSync() {
|
||||
this.isPaused = false;
|
||||
this.syncWithDisk();
|
||||
this.triggerSyncWithDisk();
|
||||
}
|
||||
|
||||
/** Return the list of folders we are watching for changes. */
|
||||
@@ -152,7 +152,7 @@ class FolderWatcher {
|
||||
*/
|
||||
async addWatch(folderPath: string, mapping: CollectionMapping) {
|
||||
const watches = await ensureElectron().watch.add(folderPath, mapping);
|
||||
this.syncWithDisk();
|
||||
this.triggerSyncWithDisk();
|
||||
return watches;
|
||||
}
|
||||
|
||||
@@ -165,6 +165,10 @@ class FolderWatcher {
|
||||
return await ensureElectron().watch.remove(folderPath);
|
||||
}
|
||||
|
||||
private triggerSyncWithDisk() {
|
||||
void this.syncWithDisk();
|
||||
}
|
||||
|
||||
private async syncWithDisk() {
|
||||
try {
|
||||
const watches = await this.getWatches();
|
||||
|
||||
Reference in New Issue
Block a user