From 65fb281a643f82e6862718bd9665cbfff04a8620 Mon Sep 17 00:00:00 2001 From: silentrald Date: Wed, 11 Dec 2024 22:28:07 +0800 Subject: [PATCH] [feat] added blacklist for shared folders * change BasicModal data to handle cascading modals better --- assets/jsons/translations/en.json | 8 ++ .../modal/basic-modal.component.tsx | 30 +++- .../share-folders-modal.component.tsx | 130 +++++++++++++----- .../config/default-configuration.config.ts | 16 +++ .../pages/settings-page.component.tsx | 8 +- 5 files changed, 148 insertions(+), 44 deletions(-) diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index 12ff1c77..afc81289 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -601,6 +601,10 @@ "ENOSPC": "The disk is full, make some space and try again.", "UNKNOWN_ERROR": "An unknown error has occurred while linking the folder." } + }, + "adding-error": { + "title": "Adding shared folder failed", + "msg": "You can't add \"{folder}\" to shared folders" } }, "create-launch-shortcut": { @@ -805,6 +809,10 @@ "link-all": "Link all" } }, + "adding-shared-folder": { + "title": "Adding Shared Folder", + "description": "Are you sure you want to add \"{folder}\" to shared folder?" + }, "create-launch-shortcut": { "title": "Create a shortcut", "desc": "Creating a shortcut will allow you to start Beat Saber with the chosen options without going through BSManager.", diff --git a/src/renderer/components/modal/basic-modal.component.tsx b/src/renderer/components/modal/basic-modal.component.tsx index 0e68ab16..d1acbce0 100644 --- a/src/renderer/components/modal/basic-modal.component.tsx +++ b/src/renderer/components/modal/basic-modal.component.tsx @@ -1,7 +1,7 @@ import { BsmButton, BsmButtonType } from "renderer/components/shared/bsm-button.component"; import { BsmImage } from "renderer/components/shared/bsm-image.component"; import { cn } from "renderer/helpers/css-class.helpers"; -import { useTranslation } from "renderer/hooks/use-translation.hook"; +import { useTranslationV2 } from "renderer/hooks/use-translation.hook"; import { ModalComponent, ModalExitCode } from "renderer/services/modale.service"; type BasicModalOptions = { @@ -12,7 +12,11 @@ type BasicModalOptions = { id: string; text: string; type: BsmButtonType, - isCancel?: boolean; + /** + * true - ModalExitCode.COMPLETED + * undefined/false - ModalExitCode.CANCELED + */ + onClick?: () => boolean; }[]; buttonsLayout?: "row" | "column"; }; @@ -21,20 +25,32 @@ export const BasicModal: ModalComponent { - const t = useTranslation(); + const t = useTranslationV2(); const handleClick = (button: BasicModalOptions["buttons"][0]) => { - resolver({ exitCode: button.isCancel ? ModalExitCode.CANCELED : ModalExitCode.COMPLETED, data: button.id }); + resolver({ + exitCode: button.onClick?.() + ? ModalExitCode.COMPLETED + : ModalExitCode.CANCELED, + data: button.id + }); } return (
-

{t(title)}

+

{t.text(title)}

- { body &&

{t(body)}

} + { body &&

{t.text(body)}

}
{buttons.map(button => ( - handleClick(button)} withBar={false} text={button.text} /> + handleClick(button)} + withBar={false} + text={button.text} + /> ))}
diff --git a/src/renderer/components/modal/modal-types/share-folders-modal.component.tsx b/src/renderer/components/modal/modal-types/share-folders-modal.component.tsx index b685a3fe..b5cd56f3 100644 --- a/src/renderer/components/modal/modal-types/share-folders-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/share-folders-modal.component.tsx @@ -6,30 +6,32 @@ import { BsmButton } from "renderer/components/shared/bsm-button.component"; import { useObservable } from "renderer/hooks/use-observable.hook"; import { useService } from "renderer/hooks/use-service.hook"; import { useThemeColor } from "renderer/hooks/use-theme-color.hook"; -import { useTranslation } from "renderer/hooks/use-translation.hook"; +import { useTranslationV2 } from "renderer/hooks/use-translation.hook"; import { BSVersionManagerService } from "renderer/services/bs-version-manager.service"; import { ConfigurationService } from "renderer/services/configuration.service"; import { IpcService } from "renderer/services/ipc.service"; -import { ModalComponent } from "renderer/services/modale.service"; +import { ModalComponent, ModalService } from "renderer/services/modale.service"; import { FolderLinkState, VersionFolderLinkerService, VersionLinkerActionType } from "renderer/services/version-folder-linker.service"; import { lastValueFrom } from "rxjs"; import { BSVersion } from "shared/bs-version.interface"; +import { SHARED_FOLDER_BLACKLIST } from "renderer/config/default-configuration.config"; +import { NotificationService } from "renderer/services/notification.service"; +import { BasicModal } from "../basic-modal.component"; +import BeatConflict from "../../../../../assets/images/apngs/beat-conflict.png"; -export const ShareFoldersModal: ModalComponent = ({ options: {data} }) => { - const SHARED_FOLDERS_KEY = "default-shared-folders"; +const SHARED_FOLDERS_KEY = "default-shared-folders"; +export const ShareFoldersModal: ModalComponent = ({ options: { data: version } }) => { const config = useService(ConfigurationService); - const ipc = useService(IpcService); const linker = useService(VersionFolderLinkerService); - const versionManager = useService(BSVersionManagerService); - const t = useTranslation(); + const t = useTranslationV2(); const [folders, setFolders] = useState(Array.from(new Set([...config.get(SHARED_FOLDERS_KEY)]).values())); useEffect(() => { linker - .getLinkedFolders(data, { relative: true }) + .getLinkedFolders(version, { relative: true }) .toPromise() .then(linkedFolders => { setFolders(prev => Array.from(new Set([...prev, ...linkedFolders]).values())); @@ -45,42 +47,24 @@ export const ShareFoldersModal: ModalComponent = ({ options: {d config.set(SHARED_FOLDERS_KEY, folders); }, [folders]); - const addFolder = async () => { - const versionPath = await lastValueFrom(versionManager.getVersionPath(data)); - const folder = await lastValueFrom(ipc.sendV2("choose-folder", { - defaultPath: versionPath - })); - - if (!folder || folder.canceled || !folder.filePaths?.length) { - return; - } - - const relativeFolder = await lastValueFrom(ipc.sendV2("full-version-path-to-relative", { version: data, fullPath: folder.filePaths[0] })); - - if (folders.includes(relativeFolder)) { - return; - } - - setFolders(pre => [...pre, relativeFolder]); - }; const removeFolder = (index: number) => { setFolders(prev => prev.filter((_, i) => i !== index)); }; const linkAll = () => { - folders.forEach(relativeFolder => linker.linkVersionFolder({ version: data, relativeFolder, type: VersionLinkerActionType.Link })); + folders.forEach(relativeFolder => linker.linkVersionFolder({ version, relativeFolder, type: VersionLinkerActionType.Link })); }; return (
-

{t("modals.shared-folders.title")}

-

{t("modals.shared-folders.description")}

+

{t.text("modals.shared-folders.title")}

+

{t.text("modals.shared-folders.description")}

    {folders.map((folder, index) => ( { removeFolder(index); @@ -89,13 +73,93 @@ export const ShareFoldersModal: ModalComponent = ({ options: {d ))}
- +
); }; +function AddFolderButton({ + version, + folders, + setFolders, +}: Readonly<{ + version: BSVersion; + folders: string[]; + setFolders: (value: string[]) => void; +}>) { + const config = useService(ConfigurationService); + const ipc = useService(IpcService); + const versionManager = useService(BSVersionManagerService); + const notification = useService(NotificationService); + const modal = useService(ModalService); + + const t = useTranslationV2(); + + const addFolder = async () => { + const versionPath = await lastValueFrom(versionManager.getVersionPath(version)); + const folder = await lastValueFrom(ipc.sendV2("choose-folder", { + defaultPath: versionPath + })); + + if (!folder || folder.canceled || !folder.filePaths?.length) { + return; + } + + const relativeFolder = await lastValueFrom(ipc.sendV2("full-version-path-to-relative", { version, fullPath: folder.filePaths[0] })); + if (folders.includes(relativeFolder)) { + return; + } + + if (SHARED_FOLDER_BLACKLIST.error.includes(relativeFolder)) { + notification.notifyError({ + title: "notifications.shared-folder.adding-error.title", + desc: t.text("notifications.shared-folder.adding-error.msg", { + folder: relativeFolder + }), + }); + return; + } + + if (SHARED_FOLDER_BLACKLIST.warn.includes(relativeFolder)) { + await modal.openModal(BasicModal, { data: { + title: "modals.adding-shared-folder.title", + body: t.text("modals.adding-shared-folder.description", { + folder: relativeFolder + }), + image: BeatConflict, + buttons: [ + { id: "cancel", text: "misc.cancel", type: "cancel" }, + { + id: "confirm", text: "misc.confirm", type: "primary", + onClick() { + config.set(SHARED_FOLDERS_KEY, [...folders, relativeFolder]); + return true; + }, + } + ] + }}); + return; + } + + setFolders([...folders, relativeFolder]); + }; + + return ; +} + // -------- FOLDER ITEM -------- type FolderProps = { @@ -107,7 +171,7 @@ type FolderProps = { const FolderItem = ({ version, relativeFolder, onDelete }: FolderProps) => { const linker = useService(VersionFolderLinkerService); - const t = useTranslation(); + const t = useTranslationV2(); const color = useThemeColor("first-color"); const state = useObservable(() => linker.$folderLinkedState(version, relativeFolder), FolderLinkState.Unlinked, [version, relativeFolder]); @@ -139,7 +203,7 @@ const FolderItem = ({ version, relativeFolder, onDelete }: FolderProps) => { {name}
- + true }, ] }}); @@ -275,8 +275,8 @@ export function SettingsPage() { body: "pages.settings.advanced.use-symlinks.modal.body", image: BeatConflict, buttons: [ - { id: "cancel", text: "misc.cancel", type: "cancel", isCancel: true }, - { id: "confirm", text: "pages.settings.advanced.use-symlinks.modal.confirm-btn", type: "error" } + { id: "cancel", text: "misc.cancel", type: "cancel" }, + { id: "confirm", text: "pages.settings.advanced.use-symlinks.modal.confirm-btn", type: "error", onClick: () => true } ] }});