Refactor scripts grid and filter handling for robustness
Improves type safety and normalization in filter, repository, and script status handling across multiple components. Refactors ScriptsGrid for better readability, deduplication, and error messaging, and updates UI markup for consistency. Also adds explicit types for auto-sync settings and ensures string conversion for credential fields.
This commit is contained in:
@@ -67,7 +67,9 @@ export function DownloadedScriptsTab({
|
||||
if (saveFilterEnabled) {
|
||||
const filtersResponse = await fetch("/api/settings/filters");
|
||||
if (filtersResponse.ok) {
|
||||
const filtersData = await filtersResponse.json();
|
||||
const filtersData = (await filtersResponse.json()) as {
|
||||
filters?: Partial<FilterState>;
|
||||
};
|
||||
if (filtersData.filters) {
|
||||
setFilters(mergeFiltersWithDefaults(filtersData.filters));
|
||||
}
|
||||
|
||||
@@ -322,9 +322,9 @@ export function FilterBar({
|
||||
{/* Repository Filter Buttons - Only show if more than one enabled repo */}
|
||||
{enabledRepos.length > 1 &&
|
||||
enabledRepos.map((repo) => {
|
||||
const isSelected = filters.selectedRepositories.includes(
|
||||
repo.url,
|
||||
);
|
||||
const repoUrl = String(repo.url);
|
||||
const isSelected =
|
||||
filters.selectedRepositories.includes(repoUrl);
|
||||
return (
|
||||
<Button
|
||||
key={repo.id}
|
||||
@@ -334,13 +334,13 @@ export function FilterBar({
|
||||
// Remove repository from selection
|
||||
updateFilters({
|
||||
selectedRepositories: currentSelected.filter(
|
||||
(url) => url !== repo.url,
|
||||
(url) => url !== repoUrl,
|
||||
),
|
||||
});
|
||||
} else {
|
||||
// Add repository to selection
|
||||
updateFilters({
|
||||
selectedRepositories: [...currentSelected, repo.url],
|
||||
selectedRepositories: [...currentSelected, repoUrl],
|
||||
});
|
||||
}
|
||||
}}
|
||||
@@ -353,7 +353,7 @@ export function FilterBar({
|
||||
}`}
|
||||
>
|
||||
<GitBranch className="h-4 w-4" />
|
||||
<span>{getRepoName(repo.url)}</span>
|
||||
<span>{getRepoName(repoUrl)}</span>
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -11,6 +11,20 @@ import { api } from "~/trpc/react";
|
||||
import { useAuth } from "./AuthProvider";
|
||||
import { Trash2, ExternalLink } from "lucide-react";
|
||||
|
||||
interface AutoSyncSettings {
|
||||
autoSyncEnabled: boolean;
|
||||
syncIntervalType: "predefined" | "custom";
|
||||
syncIntervalPredefined: string;
|
||||
syncIntervalCron: string;
|
||||
autoDownloadNew: boolean;
|
||||
autoUpdateExisting: boolean;
|
||||
notificationEnabled: boolean;
|
||||
appriseUrls: string[];
|
||||
lastAutoSync: string;
|
||||
lastAutoSyncError: string | null;
|
||||
lastAutoSyncErrorTime: string | null;
|
||||
}
|
||||
|
||||
interface GeneralSettingsModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
@@ -482,7 +496,9 @@ export function GeneralSettingsModal({
|
||||
try {
|
||||
const response = await fetch("/api/settings/auto-sync");
|
||||
if (response.ok) {
|
||||
const data = (await response.json()) as { settings: any };
|
||||
const data = (await response.json()) as {
|
||||
settings: AutoSyncSettings | null;
|
||||
};
|
||||
const settings = data.settings;
|
||||
if (settings) {
|
||||
setAutoSyncEnabled(settings.autoSyncEnabled ?? false);
|
||||
|
||||
@@ -45,10 +45,12 @@ export function PBSCredentialsModal({
|
||||
if (isOpen) {
|
||||
if (credentialData?.success && credentialData.credential) {
|
||||
// Load existing credentials
|
||||
setPbsIp(credentialData.credential.pbs_ip);
|
||||
setPbsDatastore(credentialData.credential.pbs_datastore);
|
||||
setPbsIp(String(credentialData.credential.pbs_ip));
|
||||
setPbsDatastore(String(credentialData.credential.pbs_datastore));
|
||||
setPbsPassword(""); // Don't show password
|
||||
setPbsFingerprint(credentialData.credential.pbs_fingerprint ?? "");
|
||||
setPbsFingerprint(
|
||||
String(credentialData.credential.pbs_fingerprint ?? ""),
|
||||
);
|
||||
} else {
|
||||
// Initialize with storage config values
|
||||
setPbsIp(pbsIpFromStorage ?? "");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,7 @@ export function ServerStoragesModal({
|
||||
const credentialsMap = new Map<string, boolean>();
|
||||
if (allCredentials?.success) {
|
||||
allCredentials.credentials.forEach((c) => {
|
||||
credentialsMap.set(c.storage_name, true);
|
||||
credentialsMap.set(String(c.storage_name), true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -161,8 +161,11 @@ export default function Home() {
|
||||
|
||||
// Secondary: Check install basenames (for edge cases where install script names differ from slugs)
|
||||
const normalizedLocal = normalizeId(local.name);
|
||||
const scriptWithBasenames = script as {
|
||||
install_basenames?: string[];
|
||||
};
|
||||
const matchesInstallBasename =
|
||||
(script as any)?.install_basenames?.some(
|
||||
scriptWithBasenames.install_basenames?.some(
|
||||
(base: string) => normalizeId(base) === normalizedLocal,
|
||||
) ?? false;
|
||||
if (matchesInstallBasename) return true;
|
||||
|
||||
Reference in New Issue
Block a user