mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 13:56:16 +00:00
feat: adding backup freezing
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
[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
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[SteamLeaderboards]
|
||||
Count=0
|
||||
|
||||
6
C:/users/Public/Documents/Steam/CODEX/268910/stats.ini
Normal file
6
C:/users/Public/Documents/Steam/CODEX/268910/stats.ini
Normal file
@@ -0,0 +1,6 @@
|
||||
[UserStats]
|
||||
ARanks=25
|
||||
BossesDefeatedNormal=17
|
||||
HangTime=2.75
|
||||
Parries=7
|
||||
|
||||
@@ -205,7 +205,19 @@
|
||||
"create_start_menu_shortcut": "Create Start Menu shortcut",
|
||||
"invalid_wine_prefix_path": "Invalid Wine prefix path",
|
||||
"invalid_wine_prefix_path_description": "The path to the Wine prefix is invalid. Please check the path and try again.",
|
||||
"missing_wine_prefix": "Wine prefix is required to create a backup on Linux"
|
||||
"missing_wine_prefix": "Wine prefix is required to create a backup on Linux",
|
||||
"artifact_renamed": "Backup renamed successfully",
|
||||
"rename_artifact": "Rename Backup",
|
||||
"rename_artifact_description": "Rename the backup to a more descriptive name",
|
||||
"artifact_name_label": "Backup name",
|
||||
"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",
|
||||
"freeze_backup": "Pin it so it's not overwritten by automatic backups",
|
||||
"unfreeze_backup": "Unpin it",
|
||||
"backup_frozen": "Backup pinned",
|
||||
"backup_unfrozen": "Backup unpinned"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Activate Hydra",
|
||||
|
||||
@@ -192,7 +192,19 @@
|
||||
"automatically_extract_downloaded_files": "Extrair automaticamente os arquivos baixados",
|
||||
"create_start_menu_shortcut": "Criar atalho no Menu Iniciar",
|
||||
"invalid_wine_prefix_path": "Caminho do prefixo Wine inválido",
|
||||
"invalid_wine_prefix_path_description": "O caminho para o prefixo Wine é inválido. Por favor, verifique o caminho e tente novamente."
|
||||
"invalid_wine_prefix_path_description": "O caminho para o prefixo Wine é inválido. Por favor, verifique o caminho e tente novamente.",
|
||||
"artifact_renamed": "Backup renomeado com sucesso",
|
||||
"rename_artifact": "Renomear Backup",
|
||||
"rename_artifact_description": "Renomeie o backup para um nome mais descritivo",
|
||||
"artifact_name_label": "Nome do backup",
|
||||
"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",
|
||||
"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"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Ativação",
|
||||
|
||||
14
src/main/events/cloud-save/rename-game-artifact.ts
Normal file
14
src/main/events/cloud-save/rename-game-artifact.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services";
|
||||
|
||||
const renameGameArtifact = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
gameArtifactId: string,
|
||||
label: string
|
||||
) => {
|
||||
await HydraApi.put(`/profile/games/artifacts/${gameArtifactId}`, {
|
||||
label,
|
||||
});
|
||||
};
|
||||
|
||||
registerEvent("renameGameArtifact", renameGameArtifact);
|
||||
@@ -88,6 +88,7 @@ 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 "./cloud-save/rename-game-artifact";
|
||||
import "./notifications/publish-new-repacks-notification";
|
||||
import "./notifications/update-achievement-notification-window";
|
||||
import "./notifications/show-achievement-test-notification";
|
||||
|
||||
@@ -238,6 +238,8 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
ipcRenderer.invoke("uploadSaveGame", objectId, shop, downloadOptionTitle),
|
||||
toggleArtifactFreeze: (gameArtifactId: string, freeze: boolean) =>
|
||||
ipcRenderer.invoke("toggleArtifactFreeze", gameArtifactId, freeze),
|
||||
renameGameArtifact: (gameArtifactId: string, label: string) =>
|
||||
ipcRenderer.invoke("renameGameArtifact", gameArtifactId, label),
|
||||
downloadGameArtifact: (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
|
||||
4
src/renderer/src/declaration.d.ts
vendored
4
src/renderer/src/declaration.d.ts
vendored
@@ -205,6 +205,10 @@ declare global {
|
||||
gameArtifactId: string,
|
||||
freeze: boolean
|
||||
) => Promise<void>;
|
||||
renameGameArtifact: (
|
||||
gameArtifactId: string,
|
||||
label: string
|
||||
) => Promise<void>;
|
||||
downloadGameArtifact: (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
|
||||
@@ -31,6 +31,23 @@
|
||||
gap: globals.$spacing-unit;
|
||||
}
|
||||
|
||||
&__artifact-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: globals.$body-color;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__artifacts {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit;
|
||||
|
||||
@@ -7,19 +7,21 @@ import { formatBytes } from "@shared";
|
||||
import {
|
||||
ClockIcon,
|
||||
DeviceDesktopIcon,
|
||||
DownloadIcon,
|
||||
HistoryIcon,
|
||||
InfoIcon,
|
||||
LockIcon,
|
||||
PencilIcon,
|
||||
PinIcon,
|
||||
PinSlashIcon,
|
||||
SyncIcon,
|
||||
TrashIcon,
|
||||
UnlockIcon,
|
||||
UploadIcon,
|
||||
} from "@primer/octicons-react";
|
||||
import { useAppSelector, useDate, useToast } from "@renderer/hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
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";
|
||||
|
||||
export interface CloudSyncModalProps
|
||||
extends Omit<ModalProps, "children" | "title"> {}
|
||||
@@ -28,6 +30,9 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
const [deletingArtifact, setDeletingArtifact] = useState(false);
|
||||
const [backupDownloadProgress, setBackupDownloadProgress] =
|
||||
useState<AxiosProgressEvent | null>(null);
|
||||
const [artifactToRename, setArtifactToRename] = useState<GameArtifact | null>(
|
||||
null
|
||||
);
|
||||
|
||||
const { t } = useTranslation("game_details");
|
||||
|
||||
@@ -87,11 +92,17 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
downloadGameArtifact(artifactId);
|
||||
};
|
||||
|
||||
const handleFreezeArtifactClick = async (artifactId: string) => {
|
||||
await toggleArtifactFreeze(
|
||||
artifactId,
|
||||
!artifacts.find((artifact) => artifact.id === artifactId)?.isFrozen
|
||||
);
|
||||
const handleFreezeArtifactClick = async (
|
||||
artifactId: string,
|
||||
isFrozen: boolean
|
||||
) => {
|
||||
await toggleArtifactFreeze(artifactId, isFrozen);
|
||||
|
||||
if (isFrozen) {
|
||||
showSuccessToast(t("backup_frozen"));
|
||||
} else {
|
||||
showSuccessToast(t("backup_unfrozen"));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -165,132 +176,147 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
||||
window.electron.platform === "linux" && !game?.winePrefixPath;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
title={t("cloud_save")}
|
||||
description={t("cloud_save_description")}
|
||||
onClose={onClose}
|
||||
large
|
||||
>
|
||||
<div className="cloud-sync-modal__header">
|
||||
<div className="cloud-sync-modal__title-container">
|
||||
<h2>{gameTitle}</h2>
|
||||
<p>{backupStateLabel}</p>
|
||||
<>
|
||||
<CloudSyncRenameArtifactModal
|
||||
visible={!!artifactToRename}
|
||||
onClose={() => setArtifactToRename(null)}
|
||||
artifact={artifactToRename}
|
||||
/>
|
||||
|
||||
<button
|
||||
<Modal
|
||||
visible={visible}
|
||||
title={t("cloud_save")}
|
||||
description={t("cloud_save_description")}
|
||||
onClose={onClose}
|
||||
large
|
||||
>
|
||||
<div className="cloud-sync-modal__header">
|
||||
<div className="cloud-sync-modal__title-container">
|
||||
<h2>{gameTitle}</h2>
|
||||
<p>{backupStateLabel}</p>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="cloud-sync-modal__manage-files-button"
|
||||
onClick={() => setShowCloudSyncFilesModal(true)}
|
||||
disabled={disableActions}
|
||||
>
|
||||
{t("manage_files")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
className="cloud-sync-modal__manage-files-button"
|
||||
onClick={() => setShowCloudSyncFilesModal(true)}
|
||||
disabled={disableActions}
|
||||
onClick={() => uploadSaveGame(lastDownloadedOption?.title ?? null)}
|
||||
tooltip={isMissingWinePrefix ? t("missing_wine_prefix") : undefined}
|
||||
tooltipPlace="left"
|
||||
disabled={
|
||||
disableActions ||
|
||||
!backupPreview?.overall.totalGames ||
|
||||
artifacts.length >= backupsPerGameLimit ||
|
||||
isMissingWinePrefix
|
||||
}
|
||||
>
|
||||
{t("manage_files")}
|
||||
</button>
|
||||
{uploadingBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<UploadIcon />
|
||||
)}
|
||||
{t("create_backup")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => uploadSaveGame(lastDownloadedOption?.title ?? null)}
|
||||
tooltip={isMissingWinePrefix ? t("missing_wine_prefix") : undefined}
|
||||
tooltipPlace="left"
|
||||
disabled={
|
||||
disableActions ||
|
||||
!backupPreview?.overall.totalGames ||
|
||||
artifacts.length >= backupsPerGameLimit ||
|
||||
isMissingWinePrefix
|
||||
}
|
||||
>
|
||||
{uploadingBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<UploadIcon />
|
||||
)}
|
||||
{t("create_backup")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="cloud-sync-modal__backups-header">
|
||||
<h2>{t("backups")}</h2>
|
||||
<small>
|
||||
{artifacts.length} / {backupsPerGameLimit}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div className="cloud-sync-modal__backups-header">
|
||||
<h2>{t("backups")}</h2>
|
||||
<small>
|
||||
{artifacts.length} / {backupsPerGameLimit}
|
||||
</small>
|
||||
</div>
|
||||
{artifacts.length > 0 ? (
|
||||
<ul className="cloud-sync-modal__artifacts">
|
||||
{artifacts.map((artifact) => (
|
||||
<li key={artifact.id} className="cloud-sync-modal__artifact">
|
||||
<div className="cloud-sync-modal__artifact-info">
|
||||
<div className="cloud-sync-modal__artifact-header">
|
||||
<button
|
||||
type="button"
|
||||
className="cloud-sync-modal__artifact-label"
|
||||
onClick={() => setArtifactToRename(artifact)}
|
||||
>
|
||||
{artifact.label ??
|
||||
t("backup_from", {
|
||||
date: formatDate(artifact.createdAt),
|
||||
})}
|
||||
|
||||
{artifacts.length > 0 ? (
|
||||
<ul className="cloud-sync-modal__artifacts">
|
||||
{artifacts.map((artifact) => (
|
||||
<li key={artifact.id} className="cloud-sync-modal__artifact">
|
||||
<div className="cloud-sync-modal__artifact-info">
|
||||
<div className="cloud-sync-modal__artifact-header">
|
||||
<button type="button">
|
||||
{artifact.label ??
|
||||
t("backup_from", {
|
||||
date: formatDate(artifact.createdAt),
|
||||
})}
|
||||
<PencilIcon />
|
||||
</button>
|
||||
<small>{formatBytes(artifact.artifactLengthInBytes)}</small>
|
||||
</div>
|
||||
|
||||
<PencilIcon />
|
||||
</button>
|
||||
<small>{formatBytes(artifact.artifactLengthInBytes)}</small>
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<DeviceDesktopIcon size={14} />
|
||||
{artifact.hostname}
|
||||
</span>
|
||||
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<InfoIcon size={14} />
|
||||
{artifact.downloadOptionTitle ??
|
||||
t("no_download_option_info")}
|
||||
</span>
|
||||
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<ClockIcon size={14} />
|
||||
{formatDateTime(artifact.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<DeviceDesktopIcon size={14} />
|
||||
{artifact.hostname}
|
||||
</span>
|
||||
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<InfoIcon size={14} />
|
||||
{artifact.downloadOptionTitle ?? t("no_download_option_info")}
|
||||
</span>
|
||||
|
||||
<span className="cloud-sync-modal__artifact-meta">
|
||||
<ClockIcon size={14} />
|
||||
{formatDateTime(artifact.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="cloud-sync-modal__artifact-actions">
|
||||
<Button
|
||||
type="button"
|
||||
tooltip={
|
||||
artifact.isFrozen
|
||||
? t("unfreeze_backup")
|
||||
: t("freeze_backup")
|
||||
}
|
||||
theme={artifact.isFrozen ? "danger" : "outline"}
|
||||
onClick={() => handleFreezeArtifactClick(artifact.id)}
|
||||
disabled={disableActions}
|
||||
>
|
||||
{artifact.isFrozen ? <UnlockIcon /> : <LockIcon />}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleBackupInstallClick(artifact.id)}
|
||||
disabled={disableActions}
|
||||
tooltip={t("install_backup")}
|
||||
theme="outline"
|
||||
>
|
||||
{restoringBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<DownloadIcon />
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleDeleteArtifactClick(artifact.id)}
|
||||
theme="danger"
|
||||
disabled={disableActions || artifact.isFrozen}
|
||||
>
|
||||
<TrashIcon />
|
||||
{t("delete_backup")}
|
||||
</Button>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p>{t("no_backups_created")}</p>
|
||||
)}
|
||||
</Modal>
|
||||
<div className="cloud-sync-modal__artifact-actions">
|
||||
<Button
|
||||
type="button"
|
||||
tooltip={
|
||||
artifact.isFrozen
|
||||
? t("unfreeze_backup")
|
||||
: t("freeze_backup")
|
||||
}
|
||||
theme={artifact.isFrozen ? "primary" : "outline"}
|
||||
onClick={() =>
|
||||
handleFreezeArtifactClick(artifact.id, !artifact.isFrozen)
|
||||
}
|
||||
disabled={disableActions}
|
||||
>
|
||||
{artifact.isFrozen ? <PinSlashIcon /> : <PinIcon />}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleBackupInstallClick(artifact.id)}
|
||||
disabled={disableActions}
|
||||
theme="outline"
|
||||
>
|
||||
{restoringBackup ? (
|
||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||
) : (
|
||||
<HistoryIcon />
|
||||
)}
|
||||
{t("install_backup")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleDeleteArtifactClick(artifact.id)}
|
||||
disabled={disableActions || artifact.isFrozen}
|
||||
theme="outline"
|
||||
tooltip={t("delete_backup")}
|
||||
>
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p>{t("no_backups_created")}</p>
|
||||
)}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
.cloud-sync-rename-artifact-modal {
|
||||
&__form-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
@@ -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<ModalProps, "children" | "title"> {
|
||||
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<typeof validationSchema>) => {
|
||||
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 (
|
||||
<Modal
|
||||
visible={visible}
|
||||
title={t("rename_artifact")}
|
||||
description={t("rename_artifact_description")}
|
||||
onClose={onClose}
|
||||
>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<TextField
|
||||
label={t("artifact_name_label")}
|
||||
placeholder={t("artifact_name_placeholder")}
|
||||
{...register("label")}
|
||||
error={errors.label?.message}
|
||||
/>
|
||||
|
||||
<div className="cloud-sync-rename-artifact-modal__form-actions">
|
||||
<Button theme="outline" onClick={onClose}>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
{t("save_changes")}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user