refactor(logo): improve flow for managing logo

This commit is contained in:
Carlos Valente
2026-08-01 14:06:45 +02:00
parent 19fc887d6f
commit 55cf0efa64
4 changed files with 31 additions and 20 deletions
@@ -69,6 +69,9 @@ export default function ProjectData() {
} catch (error) { } catch (error) {
const message = maybeAxiosError(error); const message = maybeAxiosError(error);
setError('logo', { message }); setError('logo', { message });
} finally {
// Allow selecting the same local file again after an upload attempt.
event.target.value = '';
} }
}; };
@@ -153,14 +156,21 @@ export default function ProjectData() {
{watch('logo') ? ( {watch('logo') ? (
<> <>
<img src={`${projectLogoPath}/${watch('logo')}`} /> <img src={`${projectLogoPath}/${watch('logo')}`} />
<Button <div className={style.logoActions}>
variant='subtle-destructive' <Button disabled={isSubmitting} onClick={handleClickUpload} type='button'>
disabled={isSubmitting || !watch('logo')} <IoDownloadOutline />
onClick={handleDeleteLogo} Replace logo
> </Button>
<IoTrash /> <Button
Delete variant='subtle-destructive'
</Button> disabled={isSubmitting || !watch('logo')}
onClick={handleDeleteLogo}
type='button'
>
<IoTrash />
Delete
</Button>
</div>
</> </>
) : ( ) : (
<Button disabled={isSubmitting} onClick={handleClickUpload} type='button'> <Button disabled={isSubmitting} onClick={handleClickUpload} type='button'>
@@ -15,6 +15,11 @@
} }
} }
.logoActions {
display: flex;
gap: 0.5rem;
}
.customDataItem { .customDataItem {
width: 100%; width: 100%;
display: flex; display: flex;
@@ -16,19 +16,13 @@ export function getProjectData(): Readonly<ProjectData> {
/** /**
* Patches the current project data * Patches the current project data
* Handles deleting the local logo if the logo has been removed
*/ */
export async function editCurrentProjectData(newData: Partial<ProjectData>) { export async function editCurrentProjectData(newData: Partial<ProjectData>) {
const currentProjectData = getDataProvider().getProjectData(); const currentProjectData = getDataProvider().getProjectData();
const updatedProjectData = await getDataProvider().setProjectData(newData); const updatedProjectData = await getDataProvider().setProjectData(newData);
// Delete the old logo if the logo has been removed if (currentProjectData.logo && currentProjectData.logo !== updatedProjectData.logo) {
if (!updatedProjectData.logo && currentProjectData.logo) { deleteFile(join(publicDir.logoDir, currentProjectData.logo));
const filePath = join(publicDir.logoDir, currentProjectData.logo);
deleteFile(filePath).catch((_error) => {
/** we do not handle this error */
});
} }
// Notify the websocket clients to refetch the project data // Notify the websocket clients to refetch the project data
@@ -3,6 +3,7 @@ import { readFile, stat } from 'fs/promises';
import { extname, join } from 'path'; import { extname, join } from 'path';
import { DatabaseModel, MaybeString, ProjectFile } from 'ontime-types'; import { DatabaseModel, MaybeString, ProjectFile } from 'ontime-types';
import { generateId } from 'ontime-utils';
import { publicDir } from '../../setup/index.js'; import { publicDir } from '../../setup/index.js';
import { dockerSafeRename, getFilesFromFolder, removeFileExtension } from '../../utils/fileManagement.js'; import { dockerSafeRename, getFilesFromFolder, removeFileExtension } from '../../utils/fileManagement.js';
@@ -20,15 +21,16 @@ export async function handleProjectUploaded(filePath: string, name: string) {
/** /**
* Handles the upload of a logo image * Handles the upload of a logo image
* @throws if the file already exits * Each upload gets a unique filename so logos cannot conflict across projects.
* @param filePath * @param filePath
* @param name * @param name
* @returns * @returns the generated filename
*/ */
export async function handleImageUpload(filePath: string, name: string): Promise<string> { export async function handleImageUpload(filePath: string, name: string): Promise<string> {
const newFilePath = join(publicDir.logoDir, name); const filename = `${generateId()}${extname(name)}`;
const newFilePath = join(publicDir.logoDir, filename);
await dockerSafeRename(filePath, newFilePath); await dockerSafeRename(filePath, newFilePath);
return name; return filename;
} }
/** /**