mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
refactor: unify backend and frontend servers (#3)
* refactor: unify backend and frontend servers * refactor: correct paths for openapi & drizzle * refactor: move api-client to client * fix: drizzle paths * chore: fix linting issues * fix: form reset issue
This commit is contained in:
25
app/utils/clipboard.ts
Normal file
25
app/utils/clipboard.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export async function copyToClipboard(textToCopy: string) {
|
||||
// Navigator clipboard api needs a secure context (https)
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(textToCopy);
|
||||
} else {
|
||||
// Use the 'out of viewport hidden text area' trick
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.value = textToCopy;
|
||||
|
||||
// Move textarea out of the viewport so it's not visible
|
||||
textArea.style.position = "absolute";
|
||||
textArea.style.left = "-999999px";
|
||||
|
||||
document.body.prepend(textArea);
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
document.execCommand("copy");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
textArea.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
14
app/utils/object.ts
Normal file
14
app/utils/object.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export function deepClean<T>(obj: T): T {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(deepClean).filter((v) => v !== undefined && v !== null && v !== "") as T;
|
||||
}
|
||||
|
||||
if (obj && typeof obj === "object") {
|
||||
return Object.entries(obj).reduce((acc, [key, value]) => {
|
||||
const cleaned = deepClean(value);
|
||||
if (cleaned !== undefined && cleaned !== "") acc[key as keyof T] = cleaned;
|
||||
return acc;
|
||||
}, {} as T);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
31
app/utils/utils.ts
Normal file
31
app/utils/utils.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { intervalToDuration } from "date-fns";
|
||||
|
||||
export const getCronExpression = (frequency: string, dailyTime?: string, weeklyDay?: string): string => {
|
||||
if (frequency === "hourly") {
|
||||
return "0 * * * *";
|
||||
}
|
||||
|
||||
if (!dailyTime) {
|
||||
dailyTime = "02:00";
|
||||
}
|
||||
|
||||
const [hours, minutes] = dailyTime.split(":");
|
||||
|
||||
if (frequency === "daily") {
|
||||
return `${minutes} ${hours} * * *`;
|
||||
}
|
||||
|
||||
return `${minutes} ${hours} * * ${weeklyDay ?? "0"}`;
|
||||
};
|
||||
|
||||
export const formatDuration = (seconds: number) => {
|
||||
const duration = intervalToDuration({ start: 0, end: seconds * 1000 });
|
||||
const parts: string[] = [];
|
||||
|
||||
if (duration.days) parts.push(`${duration.days}d`);
|
||||
if (duration.hours) parts.push(`${duration.hours}h`);
|
||||
if (duration.minutes) parts.push(`${duration.minutes}m`);
|
||||
if (duration.seconds || parts.length === 0) parts.push(`${duration.seconds || 0}s`);
|
||||
|
||||
return parts.join(" ");
|
||||
};
|
||||
Reference in New Issue
Block a user