From 7a196e4315892143c100b9a34183c9638faf21fc Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Sat, 24 May 2025 20:30:46 +0100 Subject: [PATCH 1/8] chore: changing ping pong method --- src/main/services/ws/ws-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/services/ws/ws-client.ts b/src/main/services/ws/ws-client.ts index 632a3107..8a6487de 100644 --- a/src/main/services/ws/ws-client.ts +++ b/src/main/services/ws/ws-client.ts @@ -112,7 +112,7 @@ export class WSClient { private static startHeartbeat() { this.heartbeatInterval = setInterval(() => { if (this.ws && this.ws.readyState === WebSocket.OPEN) { - this.ws.ping(); + this.ws.send("PING"); } }, 15_000); } From 7c425eecccb9f39d96e381629b2b1f1a7c7a5455 Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Fri, 30 May 2025 04:25:35 +0100 Subject: [PATCH 2/8] feat: adding freezing backups logic --- .../cloud-save/toggle-artifact-freeze.ts | 16 +++++++ src/main/events/index.ts | 1 + src/preload/index.ts | 2 + .../context/cloud-sync/cloud-sync.context.tsx | 25 +++++++++++ src/renderer/src/declaration.d.ts | 4 ++ .../cloud-sync-modal/cloud-sync-modal.tsx | 43 ++++++++++++++++--- src/types/index.ts | 1 + 7 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 src/main/events/cloud-save/toggle-artifact-freeze.ts diff --git a/src/main/events/cloud-save/toggle-artifact-freeze.ts b/src/main/events/cloud-save/toggle-artifact-freeze.ts new file mode 100644 index 00000000..d532d459 --- /dev/null +++ b/src/main/events/cloud-save/toggle-artifact-freeze.ts @@ -0,0 +1,16 @@ +import { registerEvent } from "../register-event"; +import { HydraApi } from "@main/services"; + +const toggleArtifactFreeze = async ( + _event: Electron.IpcMainInvokeEvent, + gameArtifactId: string, + freeze: boolean +) => { + if (freeze) { + await HydraApi.put(`/profile/games/artifacts/${gameArtifactId}/freeze`); + } else { + await HydraApi.put(`/profile/games/artifacts/${gameArtifactId}/unfreeze`); + } +}; + +registerEvent("toggleArtifactFreeze", toggleArtifactFreeze); diff --git a/src/main/events/index.ts b/src/main/events/index.ts index ad72163e..94520467 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -86,6 +86,7 @@ import "./cloud-save/get-game-backup-preview"; import "./cloud-save/upload-save-game"; import "./cloud-save/delete-game-artifact"; import "./cloud-save/select-game-backup-path"; +import "./cloud-save/toggle-artifact-freeze"; import "./notifications/publish-new-repacks-notification"; import "./themes/add-custom-theme"; import "./themes/delete-custom-theme"; diff --git a/src/preload/index.ts b/src/preload/index.ts index 6695fa2b..8cf2492d 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -238,6 +238,8 @@ contextBridge.exposeInMainWorld("electron", { downloadOptionTitle: string | null ) => ipcRenderer.invoke("uploadSaveGame", objectId, shop, downloadOptionTitle), + toggleArtifactFreeze: (gameArtifactId: string, freeze: boolean) => + ipcRenderer.invoke("toggleArtifactFreeze", gameArtifactId, freeze), downloadGameArtifact: ( objectId: string, shop: GameShop, diff --git a/src/renderer/src/context/cloud-sync/cloud-sync.context.tsx b/src/renderer/src/context/cloud-sync/cloud-sync.context.tsx index 5671ca56..51b7d332 100644 --- a/src/renderer/src/context/cloud-sync/cloud-sync.context.tsx +++ b/src/renderer/src/context/cloud-sync/cloud-sync.context.tsx @@ -30,9 +30,14 @@ export interface CloudSyncContext { setShowCloudSyncFilesModal: React.Dispatch>; getGameBackupPreview: () => Promise; getGameArtifacts: () => Promise; + toggleArtifactFreeze: ( + gameArtifactId: string, + freeze: boolean + ) => Promise; restoringBackup: boolean; uploadingBackup: boolean; loadingPreview: boolean; + freezingArtifact: boolean; } export const cloudSyncContext = createContext({ @@ -47,10 +52,12 @@ export const cloudSyncContext = createContext({ showCloudSyncFilesModal: false, setShowCloudSyncFilesModal: () => {}, getGameBackupPreview: async () => {}, + toggleArtifactFreeze: async () => {}, getGameArtifacts: async () => {}, restoringBackup: false, uploadingBackup: false, loadingPreview: false, + freezingArtifact: false, }); const { Provider } = cloudSyncContext; @@ -78,6 +85,7 @@ export function CloudSyncContextProvider({ const [uploadingBackup, setUploadingBackup] = useState(false); const [showCloudSyncFilesModal, setShowCloudSyncFilesModal] = useState(false); const [loadingPreview, setLoadingPreview] = useState(false); + const [freezingArtifact, setFreezingArtifact] = useState(false); const { showSuccessToast } = useToast(); @@ -119,6 +127,21 @@ export function CloudSyncContextProvider({ [objectId, shop] ); + const toggleArtifactFreeze = useCallback( + async (gameArtifactId: string, freeze: boolean) => { + setFreezingArtifact(true); + try { + await window.electron.toggleArtifactFreeze(gameArtifactId, freeze); + getGameArtifacts(); + } catch (err) { + logger.error("Failed to toggle artifact freeze", objectId, shop, err); + } finally { + setFreezingArtifact(false); + } + }, + [objectId, shop, getGameArtifacts] + ); + useEffect(() => { const removeUploadCompleteListener = window.electron.onUploadComplete( objectId, @@ -192,6 +215,7 @@ export function CloudSyncContextProvider({ uploadingBackup, showCloudSyncFilesModal, loadingPreview, + freezingArtifact, setShowCloudSyncModal, uploadSaveGame, downloadGameArtifact, @@ -199,6 +223,7 @@ export function CloudSyncContextProvider({ setShowCloudSyncFilesModal, getGameBackupPreview, getGameArtifacts, + toggleArtifactFreeze, }} > {children} diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 7eaa4ee0..a3063591 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -202,6 +202,10 @@ declare global { shop: GameShop, downloadOptionTitle: string | null ) => Promise; + toggleArtifactFreeze: ( + gameArtifactId: string, + freeze: boolean + ) => Promise; downloadGameArtifact: ( objectId: string, shop: GameShop, diff --git a/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.tsx b/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.tsx index bd70aec1..0f6a2a92 100644 --- a/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.tsx +++ b/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.tsx @@ -7,10 +7,13 @@ import { formatBytes } from "@shared"; import { ClockIcon, DeviceDesktopIcon, - HistoryIcon, + DownloadIcon, InfoIcon, + LockIcon, + PencilIcon, SyncIcon, TrashIcon, + UnlockIcon, UploadIcon, } from "@primer/octicons-react"; import { useAppSelector, useDate, useToast } from "@renderer/hooks"; @@ -36,9 +39,11 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { uploadingBackup, restoringBackup, loadingPreview, + freezingArtifact, uploadSaveGame, downloadGameArtifact, deleteGameArtifact, + toggleArtifactFreeze, setShowCloudSyncFilesModal, getGameBackupPreview, } = useContext(cloudSyncContext); @@ -82,6 +87,13 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { downloadGameArtifact(artifactId); }; + const handleFreezeArtifactClick = async (artifactId: string) => { + await toggleArtifactFreeze( + artifactId, + !artifacts.find((artifact) => artifact.id === artifactId)?.isFrozen + ); + }; + useEffect(() => { if (visible) { getGameBackupPreview(); @@ -147,7 +159,8 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { t, ]); - const disableActions = uploadingBackup || restoringBackup || deletingArtifact; + const disableActions = + uploadingBackup || restoringBackup || deletingArtifact || freezingArtifact; const isMissingWinePrefix = window.electron.platform === "linux" && !game?.winePrefixPath; @@ -208,12 +221,14 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
  • -

    +

    + + + {formatBytes(artifact.artifactLengthInBytes)}
    @@ -234,23 +249,37 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
    + +
    + + + {uploadingBackup ? ( + + ) : ( + + )} + {t("create_backup")} + - - +
    +

    {t("backups")}

    + + {artifacts.length} / {backupsPerGameLimit} + +
    -
    -

    {t("backups")}

    - - {artifacts.length} / {backupsPerGameLimit} - -
    + {artifacts.length > 0 ? ( +
      + {artifacts.map((artifact) => ( +
    • +
      +
      + + {formatBytes(artifact.artifactLengthInBytes)} +
      - - - {formatBytes(artifact.artifactLengthInBytes)} + + + {artifact.hostname} + + + + + {artifact.downloadOptionTitle ?? + t("no_download_option_info")} + + + + + {formatDateTime(artifact.createdAt)} +
      - - - {artifact.hostname} - - - - - {artifact.downloadOptionTitle ?? t("no_download_option_info")} - - - - - {formatDateTime(artifact.createdAt)} - - - -
      - - - -
      -
    • - ))} -
    - ) : ( -

    {t("no_backups_created")}

    - )} - +
    + + + +
    +
  • + ))} + + ) : ( +

    {t("no_backups_created")}

    + )} + + ); } diff --git a/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.scss b/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.scss new file mode 100644 index 00000000..a0cf2a80 --- /dev/null +++ b/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.scss @@ -0,0 +1,8 @@ +.cloud-sync-rename-artifact-modal { + &__form-actions { + display: flex; + gap: 8px; + margin-top: 16px; + justify-content: flex-end; + } +} diff --git a/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx b/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx new file mode 100644 index 00000000..3d2690fa --- /dev/null +++ b/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx @@ -0,0 +1,101 @@ +import { useCallback, useContext, useEffect } from "react"; +import { Button, Modal, ModalProps, TextField } from "@renderer/components"; +import { useForm } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import type { GameArtifact } from "@types"; +import { cloudSyncContext } from "@renderer/context"; +import { logger } from "@renderer/logger"; +import * as yup from "yup"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { InferType } from "yup"; +import { useToast } from "@renderer/hooks"; + +import "./cloud-sync-rename-artifact-modal.scss"; + +export interface CloudSyncRenameArtifactModalProps + extends Omit { + artifact: GameArtifact | null; +} + +export function CloudSyncRenameArtifactModal({ + visible, + onClose, + artifact, +}: CloudSyncRenameArtifactModalProps) { + const { t } = useTranslation("game_details"); + + const validationSchema = yup.object({ + label: yup + .string() + .required(t("required_field")) + .max(255, t("max_length_field", { lenght: 255 })), + }); + + const { getGameArtifacts } = useContext(cloudSyncContext); + + const { + register, + handleSubmit, + setValue, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { + label: artifact?.label ?? "", + }, + resolver: yupResolver(validationSchema), + }); + + const { showSuccessToast } = useToast(); + + useEffect(() => { + if (artifact) { + setValue("label", artifact.label ?? ""); + } + }, [artifact, setValue]); + + const onSubmit = useCallback( + async (data: InferType) => { + try { + if (!artifact) return; + + await window.electron.renameGameArtifact(artifact.id, data.label); + await getGameArtifacts(); + + showSuccessToast(t("artifact_renamed")); + + onClose(); + } catch (err) { + logger.error("Failed to rename artifact", err); + } + }, + [artifact, getGameArtifacts, onClose, showSuccessToast, t] + ); + + return ( + +
    + + +
    + + + +
    + +
    + ); +} From 2ebd43d55c747fc72ee98a222fd6b67d3ddcccd8 Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Fri, 30 May 2025 12:29:56 +0100 Subject: [PATCH 4/8] feat: removing test backup --- .../Steam/CODEX/268910/achievements.ini | 73 ------------------- .../Steam/CODEX/268910/leaderboards.ini | 3 - .../Documents/Steam/CODEX/268910/stats.ini | 6 -- 3 files changed, 82 deletions(-) delete mode 100644 C:/users/Public/Documents/Steam/CODEX/268910/achievements.ini delete mode 100644 C:/users/Public/Documents/Steam/CODEX/268910/leaderboards.ini delete mode 100644 C:/users/Public/Documents/Steam/CODEX/268910/stats.ini diff --git a/C:/users/Public/Documents/Steam/CODEX/268910/achievements.ini b/C:/users/Public/Documents/Steam/CODEX/268910/achievements.ini deleted file mode 100644 index 3a1c79d3..00000000 --- a/C:/users/Public/Documents/Steam/CODEX/268910/achievements.ini +++ /dev/null @@ -1,73 +0,0 @@ -[ARankWorldDLC] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740593973 - -[BoughtAllItems] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740592806 - -[CompleteWorldDLC] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740593973 - -[DefeatBoss] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740593973 - -[DefeatBossAsChalice] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740593973 - -[DefeatBossDLCWeapon] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740593973 - -[DefeatSaltbaker] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740595074 - -[DefeatXBossesAsChalice] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740593973 - -[NewGamePlus] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740594289 - -[NoHitsTaken] -Achieved=1 -CurProgress=0 -MaxProgress=0 -UnlockTime=1740593973 - -[SteamAchievements] -00000=BoughtAllItems -00001=CompleteWorldDLC -00002=ARankWorldDLC -00003=NoHitsTaken -00004=DefeatBossDLCWeapon -00005=DefeatBoss -00006=DefeatBossAsChalice -00007=DefeatXBossesAsChalice -00008=NewGamePlus -00009=DefeatSaltbaker -Count=10 - diff --git a/C:/users/Public/Documents/Steam/CODEX/268910/leaderboards.ini b/C:/users/Public/Documents/Steam/CODEX/268910/leaderboards.ini deleted file mode 100644 index 8c93dafd..00000000 --- a/C:/users/Public/Documents/Steam/CODEX/268910/leaderboards.ini +++ /dev/null @@ -1,3 +0,0 @@ -[SteamLeaderboards] -Count=0 - diff --git a/C:/users/Public/Documents/Steam/CODEX/268910/stats.ini b/C:/users/Public/Documents/Steam/CODEX/268910/stats.ini deleted file mode 100644 index 3a99be67..00000000 --- a/C:/users/Public/Documents/Steam/CODEX/268910/stats.ini +++ /dev/null @@ -1,6 +0,0 @@ -[UserStats] -ARanks=25 -BossesDefeatedNormal=17 -HangTime=2.75 -Parries=7 - From 2e2785c33c129d3fe8a363d80618806989f06155 Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Fri, 30 May 2025 12:36:43 +0100 Subject: [PATCH 5/8] fix: fixing duplicate css --- .../game-details/cloud-sync-modal/cloud-sync-modal.scss | 7 ++----- .../cloud-sync-rename-artifact-modal.tsx | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.scss b/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.scss index 451e863c..0d8ee4f0 100644 --- a/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.scss +++ b/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.scss @@ -34,18 +34,15 @@ &__artifact-label { display: flex; align-items: center; - gap: 4px; + gap: 8px; color: globals.$body-color; font-size: 16px; font-weight: 600; text-align: left; + padding: 0; background-color: transparent; border: none; - padding: 0; cursor: pointer; - display: flex; - align-items: center; - gap: 8px; } &__artifacts { diff --git a/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx b/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx index 3d2690fa..53eb79b9 100644 --- a/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx +++ b/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx @@ -21,7 +21,7 @@ export function CloudSyncRenameArtifactModal({ visible, onClose, artifact, -}: CloudSyncRenameArtifactModalProps) { +}: Readonly) { const { t } = useTranslation("game_details"); const validationSchema = yup.object({ From 97a414e77fdba4007148fc981e46172a82cdc5ac Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Fri, 30 May 2025 13:20:21 +0100 Subject: [PATCH 6/8] fix: adding correct binary path --- src/main/services/ludusavi.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/services/ludusavi.ts b/src/main/services/ludusavi.ts index 133f764e..f067b507 100644 --- a/src/main/services/ludusavi.ts +++ b/src/main/services/ludusavi.ts @@ -16,7 +16,10 @@ export class Ludusavi { SystemPath.getPath("userData"), "ludusavi" ); - private static binaryPath = path.join(this.configPath, "ludusavi"); + private static binaryName = + process.platform === "win32" ? "ludusavi.exe" : "ludusavi"; + + private static binaryPath = path.join(this.configPath, this.binaryName); public static async getConfig() { const config = YAML.parse( @@ -40,7 +43,7 @@ export class Ludusavi { public static async copyBinaryToUserData() { if (!fs.existsSync(this.binaryPath)) { fs.cpSync( - path.join(this.ludusaviResourcesPath, "ludusavi"), + path.join(this.ludusaviResourcesPath, this.binaryName), this.binaryPath ); } From 4d950b30fb0dda30accf3e09791e7b9bf18f8ea5 Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Fri, 30 May 2025 14:07:59 +0100 Subject: [PATCH 7/8] feat: adding motion --- package.json | 1 + src/locales/en/translation.json | 4 +- src/locales/pt-BR/translation.json | 4 +- .../context/cloud-sync/cloud-sync.context.tsx | 1 + .../cloud-sync-modal/cloud-sync-modal.tsx | 196 +++++++++--------- yarn.lock | 23 +- 6 files changed, 132 insertions(+), 97 deletions(-) diff --git a/package.json b/package.json index b16e792f..2850454d 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "electron-log": "^5.2.4", "electron-updater": "^6.6.2", "file-type": "^20.5.0", + "framer-motion": "^12.15.0", "i18next": "^23.11.2", "i18next-browser-languagedetector": "^7.2.1", "jsdom": "^24.0.0", diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 4b5f7768..b4427eae 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -217,7 +217,9 @@ "freeze_backup": "Pin it so it's not overwritten by automatic backups", "unfreeze_backup": "Unpin it", "backup_frozen": "Backup pinned", - "backup_unfrozen": "Backup unpinned" + "backup_unfrozen": "Backup unpinned", + "backup_freeze_failed": "Failed to freeze backup", + "backup_freeze_failed_description": "You must leave at least one free slot for automatic backups" }, "activation": { "title": "Activate Hydra", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index 2bd54dac..f6e153c9 100644 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -204,7 +204,9 @@ "freeze_backup": "Fixar para não ser apagado por backups automáticos", "unfreeze_backup": "Remover dos fixados", "backup_frozen": "Backup fixado", - "backup_unfrozen": "Backup removido dos fixados" + "backup_unfrozen": "Backup removido dos fixados", + "backup_freeze_failed": "Falha ao fixar backup", + "backup_freeze_failed_description": "Você deve deixar pelo menos um espaço livre para backups automáticos" }, "activation": { "title": "Ativação", diff --git a/src/renderer/src/context/cloud-sync/cloud-sync.context.tsx b/src/renderer/src/context/cloud-sync/cloud-sync.context.tsx index 51b7d332..f9287a11 100644 --- a/src/renderer/src/context/cloud-sync/cloud-sync.context.tsx +++ b/src/renderer/src/context/cloud-sync/cloud-sync.context.tsx @@ -135,6 +135,7 @@ export function CloudSyncContextProvider({ getGameArtifacts(); } catch (err) { logger.error("Failed to toggle artifact freeze", objectId, shop, err); + throw err; } finally { setFreezingArtifact(false); } diff --git a/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.tsx b/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.tsx index 743bf5b2..e30b244c 100644 --- a/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.tsx +++ b/src/renderer/src/pages/game-details/cloud-sync-modal/cloud-sync-modal.tsx @@ -1,7 +1,6 @@ import { Button, Modal, ModalProps } from "@renderer/components"; import { useContext, useEffect, useMemo, useState } from "react"; import { cloudSyncContext, gameDetailsContext } from "@renderer/context"; - import "./cloud-sync-modal.scss"; import { formatBytes } from "@shared"; import { @@ -22,6 +21,8 @@ import { AxiosProgressEvent } from "axios"; import { formatDownloadProgress } from "@renderer/helpers"; import { CloudSyncRenameArtifactModal } from "../cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal"; import { GameArtifact } from "@types"; +import { motion, AnimatePresence } from "framer-motion"; +import { orderBy } from "lodash-es"; export interface CloudSyncModalProps extends Omit {} @@ -35,7 +36,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { ); const { t } = useTranslation("game_details"); - const { formatDate, formatDateTime } = useDate(); const { @@ -60,10 +60,8 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { const handleDeleteArtifactClick = async (gameArtifactId: string) => { setDeletingArtifact(true); - try { await deleteGameArtifact(gameArtifactId); - showSuccessToast(t("backup_deleted")); } catch (err) { showErrorToast("backup_deletion_failed"); @@ -81,7 +79,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { setBackupDownloadProgress(progressEvent); } ); - return () => { removeBackupDownloadProgressListener(); }; @@ -96,12 +93,14 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { artifactId: string, isFrozen: boolean ) => { - await toggleArtifactFreeze(artifactId, isFrozen); - - if (isFrozen) { - showSuccessToast(t("backup_frozen")); - } else { - showSuccessToast(t("backup_unfrozen")); + try { + await toggleArtifactFreeze(artifactId, isFrozen); + showSuccessToast(isFrozen ? t("backup_frozen") : t("backup_unfrozen")); + } catch (err) { + showErrorToast( + t("backup_freeze_failed"), + t("backup_freeze_failed_description") + ); } }; @@ -123,7 +122,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { ); } - if (restoringBackup) { return ( @@ -136,7 +134,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { ); } - if (loadingPreview) { return ( @@ -145,19 +142,15 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) { ); } - if (artifacts.length >= backupsPerGameLimit) { return t("max_number_of_artifacts_reached"); } - if (!backupPreview) { return t("no_backup_preview"); } - if (artifacts.length === 0) { return t("no_backups"); } - return ""; }, [ uploadingBackup, @@ -194,7 +187,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {

    {gameTitle}

    {backupStateLabel}

    - - {formatBytes(artifact.artifactLengthInBytes)} -
    - - - - {artifact.hostname} - - - - - {artifact.downloadOptionTitle ?? - t("no_download_option_info")} - - - - - {formatDateTime(artifact.createdAt)} - - - -
    - - - -
    - - ))} +
    +
    + + + {formatBytes(artifact.artifactLengthInBytes)} + +
    + + + + {artifact.hostname} + + + + + {artifact.downloadOptionTitle ?? + t("no_download_option_info")} + + + + + {formatDateTime(artifact.createdAt)} + +
    + +
    + + + +
    + + ) + )} + ) : (

    {t("no_backups_created")}

    diff --git a/yarn.lock b/yarn.lock index a745b484..d34598e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5646,6 +5646,15 @@ formdata-polyfill@^4.0.10: dependencies: fetch-blob "^3.1.2" +framer-motion@^12.15.0: + version "12.15.0" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-12.15.0.tgz#6892283fc7967b071f537d6d160ab49e3d5e73ae" + integrity sha512-XKg/LnKExdLGugZrDILV7jZjI599785lDIJZLxMiiIFidCsy0a4R2ZEf+Izm67zyOuJgQYTHOmodi7igQsw3vg== + dependencies: + motion-dom "^12.15.0" + motion-utils "^12.12.1" + tslib "^2.4.0" + fs-extra@^10.0.0, fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -7304,6 +7313,18 @@ module-error@^1.0.1: resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== +motion-dom@^12.15.0: + version "12.15.0" + resolved "https://registry.yarnpkg.com/motion-dom/-/motion-dom-12.15.0.tgz#eca7c9d8c28976b8c920f175f92d5288f5a17785" + integrity sha512-D2ldJgor+2vdcrDtKJw48k3OddXiZN1dDLLWrS8kiHzQdYVruh0IoTwbJBslrnTXIPgFED7PBN2Zbwl7rNqnhA== + dependencies: + motion-utils "^12.12.1" + +motion-utils@^12.12.1: + version "12.12.1" + resolved "https://registry.yarnpkg.com/motion-utils/-/motion-utils-12.12.1.tgz#63e28751325cb9d1cd684f3c273a570022b0010e" + integrity sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w== + ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -9041,7 +9062,7 @@ ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tslib@^2.0.0, tslib@^2.1.0: +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== From 046debffa0bc14c1e20460b584bc2837815f8fd6 Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Fri, 30 May 2025 14:14:39 +0100 Subject: [PATCH 8/8] fix: fixing typo on length --- src/locales/en/translation.json | 2 +- src/locales/pt-BR/translation.json | 2 +- .../cloud-sync-rename-artifact-modal.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index b4427eae..20125efd 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -213,7 +213,7 @@ "artifact_name_placeholder": "Enter a name for the backup", "save_changes": "Save changes", "required_field": "This field is required", - "max_length_field": "This field must be less than {{lenght}} characters", + "max_length_field": "This field must be less than {{length}} characters", "freeze_backup": "Pin it so it's not overwritten by automatic backups", "unfreeze_backup": "Unpin it", "backup_frozen": "Backup pinned", diff --git a/src/locales/pt-BR/translation.json b/src/locales/pt-BR/translation.json index f6e153c9..58796d98 100644 --- a/src/locales/pt-BR/translation.json +++ b/src/locales/pt-BR/translation.json @@ -200,7 +200,7 @@ "artifact_name_placeholder": "Insira um nome para o backup", "save_changes": "Salvar mudanças", "required_field": "Este campo é obrigatório", - "max_length_field": "Este campo deve ter menos de {{lenght}} caracteres", + "max_length_field": "Este campo deve ter menos de {{length}} caracteres", "freeze_backup": "Fixar para não ser apagado por backups automáticos", "unfreeze_backup": "Remover dos fixados", "backup_frozen": "Backup fixado", diff --git a/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx b/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx index 53eb79b9..25525331 100644 --- a/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx +++ b/src/renderer/src/pages/game-details/cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal.tsx @@ -28,7 +28,7 @@ export function CloudSyncRenameArtifactModal({ label: yup .string() .required(t("required_field")) - .max(255, t("max_length_field", { lenght: 255 })), + .max(255, t("max_length_field", { length: 255 })), }); const { getGameArtifacts } = useContext(cloudSyncContext);