mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
Refactor Response and FilePicker components for improved readability and consistency
This commit is contained in:
@@ -57,7 +57,7 @@ export default class Response {
|
||||
const oneUptimeResponse: OneUptimeResponse = res as OneUptimeResponse;
|
||||
|
||||
if (headers) {
|
||||
Response.setNoCacheHeaders(oneUptimeResponse);
|
||||
Response.setNoCacheHeaders(oneUptimeResponse);
|
||||
for (const key in headers) {
|
||||
oneUptimeResponse.set(key, headers[key]?.toString() || "");
|
||||
}
|
||||
|
||||
@@ -54,31 +54,34 @@ const FilePicker: FunctionComponent<ComponentProps> = (
|
||||
const [uploadStatuses, setUploadStatuses] = useState<Array<UploadStatus>>([]);
|
||||
|
||||
const addUploadStatus = (status: UploadStatus): void => {
|
||||
setUploadStatuses((current: Array<UploadStatus>) => [
|
||||
...current,
|
||||
status,
|
||||
]);
|
||||
setUploadStatuses((current: Array<UploadStatus>) => {
|
||||
return [...current, status];
|
||||
});
|
||||
};
|
||||
|
||||
const updateUploadStatus = (
|
||||
id: string,
|
||||
updates: Partial<UploadStatus>,
|
||||
): void => {
|
||||
setUploadStatuses((current: Array<UploadStatus>) =>
|
||||
current.map((upload: UploadStatus) =>
|
||||
upload.id === id
|
||||
setUploadStatuses((current: Array<UploadStatus>) => {
|
||||
return current.map((upload: UploadStatus) => {
|
||||
return upload.id === id
|
||||
? {
|
||||
...upload,
|
||||
...updates,
|
||||
}
|
||||
: upload,
|
||||
),
|
||||
);
|
||||
: upload;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const updateUploadProgress = (id: string, total?: number, loaded?: number): void => {
|
||||
setUploadStatuses((current: Array<UploadStatus>) =>
|
||||
current.map((upload: UploadStatus) => {
|
||||
const updateUploadProgress = (
|
||||
id: string,
|
||||
total?: number,
|
||||
loaded?: number,
|
||||
): void => {
|
||||
setUploadStatuses((current: Array<UploadStatus>) => {
|
||||
return current.map((upload: UploadStatus) => {
|
||||
if (upload.id !== id || upload.status === "error") {
|
||||
return upload;
|
||||
}
|
||||
@@ -91,16 +94,19 @@ const FilePicker: FunctionComponent<ComponentProps> = (
|
||||
|
||||
return {
|
||||
...upload,
|
||||
progress: progressFromEvent !== null ? progressFromEvent : fallbackProgress,
|
||||
progress:
|
||||
progressFromEvent !== null ? progressFromEvent : fallbackProgress,
|
||||
};
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const removeUploadStatus = (id: string): void => {
|
||||
setUploadStatuses((current: Array<UploadStatus>) =>
|
||||
current.filter((upload: UploadStatus) => upload.id !== id),
|
||||
);
|
||||
setUploadStatuses((current: Array<UploadStatus>) => {
|
||||
return current.filter((upload: UploadStatus) => {
|
||||
return upload.id !== id;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -157,8 +163,12 @@ const FilePicker: FunctionComponent<ComponentProps> = (
|
||||
maxSize: MAX_FILE_SIZE_BYTES,
|
||||
onDropRejected: (fileRejections) => {
|
||||
const oversizedFiles: Array<string> = fileRejections
|
||||
.filter((rejection) => rejection.file.size > MAX_FILE_SIZE_BYTES)
|
||||
.map((rejection) => rejection.file.name);
|
||||
.filter((rejection) => {
|
||||
return rejection.file.size > MAX_FILE_SIZE_BYTES;
|
||||
})
|
||||
.map((rejection) => {
|
||||
return rejection.file.name;
|
||||
});
|
||||
|
||||
if (oversizedFiles.length > 0) {
|
||||
setError(buildFileSizeError(oversizedFiles));
|
||||
@@ -361,7 +371,9 @@ const FilePicker: FunctionComponent<ComponentProps> = (
|
||||
};
|
||||
|
||||
const hasActiveUploads: boolean = uploadStatuses.some(
|
||||
(upload: UploadStatus) => upload.status === "uploading",
|
||||
(upload: UploadStatus) => {
|
||||
return upload.status === "uploading";
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -437,16 +449,23 @@ const FilePicker: FunctionComponent<ComponentProps> = (
|
||||
];
|
||||
return enumKey?.toUpperCase() || "";
|
||||
})
|
||||
.filter((item: string | undefined, pos: number, array: Array<string | undefined>) => {
|
||||
return array.indexOf(item) === pos;
|
||||
})
|
||||
.filter(
|
||||
(
|
||||
item: string | undefined,
|
||||
pos: number,
|
||||
array: Array<string | undefined>,
|
||||
) => {
|
||||
return array.indexOf(item) === pos;
|
||||
},
|
||||
)
|
||||
.join(", ")}
|
||||
{props.mimeTypes && props.mimeTypes?.length > 0 && <span>.</span>} Max 10MB each.
|
||||
{props.mimeTypes && props.mimeTypes?.length > 0 && (
|
||||
<span>.</span>
|
||||
)}{" "}
|
||||
Max 10MB each.
|
||||
</p>
|
||||
{error && (
|
||||
<p className="text-xs text-red-500 font-medium">
|
||||
{error}
|
||||
</p>
|
||||
<p className="text-xs text-red-500 font-medium">{error}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -460,49 +479,51 @@ const FilePicker: FunctionComponent<ComponentProps> = (
|
||||
{hasActiveUploads ? "Uploading files" : "Upload status"}
|
||||
</p>
|
||||
<div className="space-y-2">
|
||||
{uploadStatuses.map((upload: UploadStatus) => (
|
||||
<div
|
||||
key={upload.id}
|
||||
className={`rounded border px-3 py-2 ${upload.status === "error" ? "border-red-200 bg-red-50" : "border-gray-200 bg-white"}`}
|
||||
>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<p className="font-medium text-gray-800 truncate">
|
||||
{upload.name}
|
||||
</p>
|
||||
<span
|
||||
className={`text-xs ${upload.status === "error" ? "text-red-600" : "text-gray-500"}`}
|
||||
>
|
||||
{upload.status === "error"
|
||||
? "Failed"
|
||||
: `${upload.progress}%`}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-2 h-2 rounded bg-gray-200 overflow-hidden">
|
||||
<div
|
||||
className={`h-full transition-all duration-300 ${upload.status === "error" ? "bg-red-400" : "bg-indigo-500"}`}
|
||||
style={{ width: `${Math.min(upload.progress, 100)}%` }}
|
||||
></div>
|
||||
</div>
|
||||
{upload.status === "error" && upload.errorMessage && (
|
||||
<p className="mt-2 text-xs text-red-600 text-left">
|
||||
{upload.errorMessage}
|
||||
</p>
|
||||
)}
|
||||
{upload.status === "error" && (
|
||||
<div className="mt-2 text-right">
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs font-medium text-gray-600 hover:text-gray-800"
|
||||
onClick={() => {
|
||||
removeUploadStatus(upload.id);
|
||||
}}
|
||||
{uploadStatuses.map((upload: UploadStatus) => {
|
||||
return (
|
||||
<div
|
||||
key={upload.id}
|
||||
className={`rounded border px-3 py-2 ${upload.status === "error" ? "border-red-200 bg-red-50" : "border-gray-200 bg-white"}`}
|
||||
>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<p className="font-medium text-gray-800 truncate">
|
||||
{upload.name}
|
||||
</p>
|
||||
<span
|
||||
className={`text-xs ${upload.status === "error" ? "text-red-600" : "text-gray-500"}`}
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
{upload.status === "error"
|
||||
? "Failed"
|
||||
: `${upload.progress}%`}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className="mt-2 h-2 rounded bg-gray-200 overflow-hidden">
|
||||
<div
|
||||
className={`h-full transition-all duration-300 ${upload.status === "error" ? "bg-red-400" : "bg-indigo-500"}`}
|
||||
style={{ width: `${Math.min(upload.progress, 100)}%` }}
|
||||
></div>
|
||||
</div>
|
||||
{upload.status === "error" && upload.errorMessage && (
|
||||
<p className="mt-2 text-xs text-red-600 text-left">
|
||||
{upload.errorMessage}
|
||||
</p>
|
||||
)}
|
||||
{upload.status === "error" && (
|
||||
<div className="mt-2 text-right">
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs font-medium text-gray-600 hover:text-gray-800"
|
||||
onClick={() => {
|
||||
removeUploadStatus(upload.id);
|
||||
}}
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -10,8 +10,6 @@ import Field from "./Types/Field";
|
||||
import FieldType from "../Types/FieldType";
|
||||
import { FormStep } from "./Types/FormStep";
|
||||
import HorizontalRule from "../HorizontalRule/HorizontalRule";
|
||||
import Icon from "../Icon/Icon";
|
||||
import IconProp from "../../../Types/Icon/IconProp";
|
||||
|
||||
type SummaryElementFn<T extends GenericObject> = (
|
||||
item: FormValues<T>,
|
||||
@@ -113,7 +111,11 @@ const getFileSummaryElement: <T extends GenericObject>(
|
||||
const formValuesRecord: Record<string, unknown> =
|
||||
(item as Record<string, unknown>) || {};
|
||||
|
||||
const value: FileSummaryItem | Array<FileSummaryItem | string> | string | null =
|
||||
const value:
|
||||
| FileSummaryItem
|
||||
| Array<FileSummaryItem | string>
|
||||
| string
|
||||
| null =
|
||||
(formValuesRecord[fieldName] as
|
||||
| FileSummaryItem
|
||||
| Array<FileSummaryItem | string>
|
||||
@@ -138,26 +140,18 @@ const getFileSummaryElement: <T extends GenericObject>(
|
||||
|
||||
const displayName: string = formatFileName(fileObject, index);
|
||||
const subtitle: string | undefined = getFileSubtitle(fileObject);
|
||||
const accessLabel: string | undefined =
|
||||
getAccessLabel(fileObject);
|
||||
const accessLabel: string | undefined = getAccessLabel(fileObject);
|
||||
|
||||
const key: string =
|
||||
fileObject._id || `${displayName}-${index}`;
|
||||
const key: string = fileObject._id || `${displayName}-${index}`;
|
||||
|
||||
return (
|
||||
<li
|
||||
key={key}
|
||||
className="flex items-center gap-3 px-3 py-2"
|
||||
>
|
||||
|
||||
<li key={key} className="flex items-center gap-3 px-3 py-2">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-sm font-medium text-gray-900">
|
||||
{displayName}
|
||||
</p>
|
||||
{subtitle && (
|
||||
<p className="truncate text-xs text-gray-500">
|
||||
{subtitle}
|
||||
</p>
|
||||
<p className="truncate text-xs text-gray-500">{subtitle}</p>
|
||||
)}
|
||||
</div>
|
||||
{accessLabel && (
|
||||
@@ -213,7 +207,8 @@ const FormSummary: <T extends GenericObject>(
|
||||
field.fieldType || FormFieldSchemaType.Text,
|
||||
),
|
||||
description: field.description || "",
|
||||
getElement: (field.getSummaryElement || defaultSummaryElement) as any,
|
||||
getElement: (field.getSummaryElement ||
|
||||
defaultSummaryElement) as any,
|
||||
sideLink: field.sideLink,
|
||||
key: (Object.keys(field.field || {})[0]?.toString() ||
|
||||
"") as keyof T,
|
||||
|
||||
@@ -394,10 +394,7 @@ const ModelForm: <TBaseModel extends BaseModel>(
|
||||
if (isModelArray) {
|
||||
(item as any)[key] = idArray;
|
||||
}
|
||||
} else if (
|
||||
(item as any)[key] &&
|
||||
typeof (item as any)[key] === "object"
|
||||
) {
|
||||
} else if ((item as any)[key] && typeof (item as any)[key] === "object") {
|
||||
if (isFileColumn) {
|
||||
(item as any)[key] = BaseModel.fromJSON(
|
||||
(item as any)[key] as JSONObject,
|
||||
@@ -407,9 +404,9 @@ const ModelForm: <TBaseModel extends BaseModel>(
|
||||
}
|
||||
|
||||
if (!((item as any)[key] instanceof FileModel)) {
|
||||
const id: string | undefined = (
|
||||
(item as any)[key] as JSONObject
|
||||
)["_id"] as string | undefined;
|
||||
const id: string | undefined = ((item as any)[key] as JSONObject)[
|
||||
"_id"
|
||||
] as string | undefined;
|
||||
|
||||
if (id) {
|
||||
(item as any)[key] = id;
|
||||
|
||||
Reference in New Issue
Block a user