Re-Organsied options

This commit is contained in:
Arunavo Ray
2025-06-15 12:35:26 +05:30
parent 7456fe3fae
commit 0cdb386f56
3 changed files with 464 additions and 145 deletions

View File

@@ -3,8 +3,6 @@ import { GitHubConfigForm } from './GitHubConfigForm';
import { GiteaConfigForm } from './GiteaConfigForm';
import { ScheduleConfigForm } from './ScheduleConfigForm';
import { DatabaseCleanupConfigForm } from './DatabaseCleanupConfigForm';
import { MirrorOptionsForm } from './MirrorOptionsForm';
import { AdvancedOptionsForm } from './AdvancedOptionsForm';
import type {
ConfigApiResponse,
GiteaConfig,
@@ -540,62 +538,52 @@ export function ConfigTabs() {
</div>
{/* Content section - Grid layout */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* GitHub & Gitea connections */}
<div className="border rounded-lg p-4">
<div className="flex justify-between items-center mb-4">
<Skeleton className="h-6 w-40" />
<Skeleton className="h-9 w-32" />
</div>
<div className="space-y-4">
<Skeleton className="h-20 w-full" />
<Skeleton className="h-20 w-full" />
<Skeleton className="h-32 w-full" />
</div>
</div>
<div className="border rounded-lg p-4">
<div className="flex justify-between items-center mb-4">
<Skeleton className="h-6 w-40" />
<Skeleton className="h-9 w-32" />
</div>
<div className="space-y-4">
<Skeleton className="h-20 w-full" />
<Skeleton className="h-20 w-full" />
<Skeleton className="h-20 w-full" />
<Skeleton className="h-20 w-full" />
</div>
</div>
{/* Schedule & Database Cleanup */}
<div className="border rounded-lg p-4">
<div className="space-y-4">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-16 w-full" />
<Skeleton className="h-8 w-32" />
</div>
</div>
<div className="border rounded-lg p-4">
<div className="space-y-4">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-16 w-full" />
<Skeleton className="h-8 w-32" />
</div>
</div>
</div>
{/* Mirror Options & Advanced - Full width sections */}
<div className="space-y-4">
<div className="border rounded-lg p-4">
<Skeleton className="h-8 w-48 mb-4" />
<div className="space-y-4">
<Skeleton className="h-16 w-full" />
<Skeleton className="h-24 w-full" />
{/* GitHub & Gitea connections - Side by side */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="border rounded-lg p-4">
<div className="flex justify-between items-center mb-4">
<Skeleton className="h-6 w-40" />
<Skeleton className="h-9 w-32" />
</div>
<div className="space-y-4">
<Skeleton className="h-20 w-full" />
<Skeleton className="h-20 w-full" />
<Skeleton className="h-1 w-full" />
<Skeleton className="h-32 w-full" />
<Skeleton className="h-48 w-full" />
<Skeleton className="h-32 w-full" />
</div>
</div>
<div className="border rounded-lg p-4">
<div className="flex justify-between items-center mb-4">
<Skeleton className="h-6 w-40" />
<Skeleton className="h-9 w-32" />
</div>
<div className="space-y-4">
<Skeleton className="h-20 w-full" />
<Skeleton className="h-20 w-full" />
<Skeleton className="h-20 w-full" />
<Skeleton className="h-64 w-full" />
</div>
</div>
</div>
<div className="border rounded-lg p-4">
<Skeleton className="h-8 w-48 mb-4" />
<div className="space-y-4">
<Skeleton className="h-16 w-full" />
{/* Schedule & Database Cleanup - Side by side */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="border rounded-lg p-4">
<div className="space-y-4">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-16 w-full" />
<Skeleton className="h-8 w-32" />
</div>
</div>
<div className="border rounded-lg p-4">
<div className="space-y-4">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-16 w-full" />
<Skeleton className="h-8 w-32" />
</div>
</div>
</div>
</div>
@@ -662,7 +650,29 @@ export function ConfigTabs() {
: update,
}))
}
mirrorOptions={config.mirrorOptions}
setMirrorOptions={update =>
setConfig(prev => ({
...prev,
mirrorOptions:
typeof update === 'function'
? update(prev.mirrorOptions)
: update,
}))
}
advancedOptions={config.advancedOptions}
setAdvancedOptions={update =>
setConfig(prev => ({
...prev,
advancedOptions:
typeof update === 'function'
? update(prev.advancedOptions)
: update,
}))
}
onAutoSave={autoSaveGitHubConfig}
onMirrorOptionsAutoSave={autoSaveMirrorOptions}
onAdvancedOptionsAutoSave={autoSaveAdvancedOptions}
isAutoSaving={isAutoSavingGitHub}
/>
<GiteaConfigForm
@@ -682,24 +692,6 @@ export function ConfigTabs() {
/>
</div>
{/* Mirror Options - Full width */}
<div>
<MirrorOptionsForm
config={config.mirrorOptions}
setConfig={update =>
setConfig(prev => ({
...prev,
mirrorOptions:
typeof update === 'function'
? update(prev.mirrorOptions)
: update,
}))
}
onAutoSave={autoSaveMirrorOptions}
isAutoSaving={isAutoSavingMirrorOptions}
/>
</div>
{/* Schedule & Database Cleanup - Side by side */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<ScheduleConfigForm
@@ -731,24 +723,6 @@ export function ConfigTabs() {
isAutoSaving={isAutoSavingCleanup}
/>
</div>
{/* Advanced options - Full width */}
<div>
<AdvancedOptionsForm
config={config.advancedOptions}
setConfig={update =>
setConfig(prev => ({
...prev,
advancedOptions:
typeof update === 'function'
? update(prev.advancedOptions)
: update,
}))
}
onAutoSave={autoSaveAdvancedOptions}
isAutoSaving={isAutoSavingAdvancedOptions}
/>
</div>
</div>
</div>
);

View File

@@ -8,7 +8,7 @@ import {
CardTitle,
} from "@/components/ui/card";
import { githubApi } from "@/lib/api";
import type { GitHubConfig } from "@/types/config";
import type { GitHubConfig, MirrorOptions, AdvancedOptions } from "@/types/config";
import { Input } from "../ui/input";
import { Checkbox } from "../ui/checkbox";
import { toast } from "sonner";
@@ -16,15 +16,34 @@ import { AlertTriangle } from "lucide-react";
import { Alert, AlertDescription } from "../ui/alert";
import { Info } from "lucide-react";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
import { GitHubMirrorSettings } from "./GitHubMirrorSettings";
import { Separator } from "../ui/separator";
interface GitHubConfigFormProps {
config: GitHubConfig;
setConfig: React.Dispatch<React.SetStateAction<GitHubConfig>>;
mirrorOptions: MirrorOptions;
setMirrorOptions: React.Dispatch<React.SetStateAction<MirrorOptions>>;
advancedOptions: AdvancedOptions;
setAdvancedOptions: React.Dispatch<React.SetStateAction<AdvancedOptions>>;
onAutoSave?: (githubConfig: GitHubConfig) => Promise<void>;
onMirrorOptionsAutoSave?: (mirrorOptions: MirrorOptions) => Promise<void>;
onAdvancedOptionsAutoSave?: (advancedOptions: AdvancedOptions) => Promise<void>;
isAutoSaving?: boolean;
}
export function GitHubConfigForm({ config, setConfig, onAutoSave, isAutoSaving }: GitHubConfigFormProps) {
export function GitHubConfigForm({
config,
setConfig,
mirrorOptions,
setMirrorOptions,
advancedOptions,
setAdvancedOptions,
onAutoSave,
onMirrorOptionsAutoSave,
onAdvancedOptionsAutoSave,
isAutoSaving
}: GitHubConfigFormProps) {
const [isLoading, setIsLoading] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -125,59 +144,25 @@ export function GitHubConfigForm({ config, setConfig, onAutoSave, isAutoSaving }
</p>
</div>
<div className="space-y-4">
<h4 className="text-sm font-medium text-foreground">Repository Access</h4>
<Separator />
<div className="space-y-3">
<div className="flex items-center">
<Checkbox
id="private-repositories"
name="privateRepositories"
checked={config.privateRepositories}
onCheckedChange={(checked) =>
handleChange({
target: {
name: "privateRepositories",
type: "checkbox",
checked: Boolean(checked),
value: "",
},
} as React.ChangeEvent<HTMLInputElement>)
}
/>
<label
htmlFor="private-repositories"
className="ml-2 block text-sm select-none"
>
Include private repos
</label>
</div>
<div className="flex items-center">
<Checkbox
id="mirror-starred"
name="mirrorStarred"
checked={config.mirrorStarred}
onCheckedChange={(checked) =>
handleChange({
target: {
name: "mirrorStarred",
type: "checkbox",
checked: Boolean(checked),
value: "",
},
} as React.ChangeEvent<HTMLInputElement>)
}
/>
<label
htmlFor="mirror-starred"
className="ml-2 block text-sm select-none"
>
Mirror starred repos
</label>
</div>
</div>
</div>
<GitHubMirrorSettings
githubConfig={config}
mirrorOptions={mirrorOptions}
advancedOptions={advancedOptions}
onGitHubConfigChange={(newConfig) => {
setConfig(newConfig);
if (onAutoSave) onAutoSave(newConfig);
}}
onMirrorOptionsChange={(newOptions) => {
setMirrorOptions(newOptions);
if (onMirrorOptionsAutoSave) onMirrorOptionsAutoSave(newOptions);
}}
onAdvancedOptionsChange={(newOptions) => {
setAdvancedOptions(newOptions);
if (onAdvancedOptionsAutoSave) onAdvancedOptionsAutoSave(newOptions);
}}
/>
</CardContent>
<CardFooter className="flex-col items-start">

View File

@@ -0,0 +1,360 @@
import React from "react";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import { Badge } from "@/components/ui/badge";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
Info,
GitBranch,
Star,
Building2,
Lock,
Archive,
GitPullRequest,
Tag,
FileText,
MessageSquare,
Target,
BookOpen,
GitFork
} from "lucide-react";
import type { GitHubConfig, MirrorOptions, AdvancedOptions } from "@/types/config";
import { cn } from "@/lib/utils";
interface GitHubMirrorSettingsProps {
githubConfig: GitHubConfig;
mirrorOptions: MirrorOptions;
advancedOptions: AdvancedOptions;
onGitHubConfigChange: (config: GitHubConfig) => void;
onMirrorOptionsChange: (options: MirrorOptions) => void;
onAdvancedOptionsChange: (options: AdvancedOptions) => void;
}
export function GitHubMirrorSettings({
githubConfig,
mirrorOptions,
advancedOptions,
onGitHubConfigChange,
onMirrorOptionsChange,
onAdvancedOptionsChange,
}: GitHubMirrorSettingsProps) {
const handleGitHubChange = (field: keyof GitHubConfig, value: boolean) => {
onGitHubConfigChange({ ...githubConfig, [field]: value });
};
const handleMirrorChange = (field: keyof MirrorOptions, value: boolean) => {
onMirrorOptionsChange({ ...mirrorOptions, [field]: value });
};
const handleMetadataComponentChange = (component: keyof MirrorOptions['metadataComponents'], value: boolean) => {
onMirrorOptionsChange({
...mirrorOptions,
metadataComponents: {
...mirrorOptions.metadataComponents,
[component]: value,
},
});
};
const handleAdvancedChange = (field: keyof AdvancedOptions, value: boolean) => {
onAdvancedOptionsChange({ ...advancedOptions, [field]: value });
};
// When metadata is disabled, all components should be disabled
const isMetadataEnabled = mirrorOptions.mirrorMetadata;
return (
<div className="space-y-6">
{/* Repository Selection Section */}
<div className="space-y-4">
<div>
<h4 className="text-sm font-medium mb-3 flex items-center gap-2">
<GitBranch className="h-4 w-4" />
Repository Selection
</h4>
<p className="text-xs text-muted-foreground mb-4">
Choose which repositories to include in mirroring
</p>
</div>
<div className="space-y-3">
<div className="flex items-start space-x-3">
<Checkbox
id="private-repos"
checked={githubConfig.privateRepositories}
onCheckedChange={(checked) => handleGitHubChange('privateRepositories', !!checked)}
/>
<div className="space-y-0.5 flex-1">
<Label
htmlFor="private-repos"
className="text-sm font-normal cursor-pointer flex items-center gap-2"
>
<Lock className="h-3.5 w-3.5" />
Include private repositories
</Label>
<p className="text-xs text-muted-foreground">
Mirror your private repositories (requires appropriate token permissions)
</p>
</div>
</div>
<div className="flex items-start space-x-3">
<Checkbox
id="starred-repos"
checked={githubConfig.mirrorStarred}
onCheckedChange={(checked) => handleGitHubChange('mirrorStarred', !!checked)}
/>
<div className="space-y-0.5 flex-1">
<Label
htmlFor="starred-repos"
className="text-sm font-normal cursor-pointer flex items-center gap-2"
>
<Star className="h-3.5 w-3.5" />
Mirror starred repositories
</Label>
<p className="text-xs text-muted-foreground">
Include repositories you've starred on GitHub
</p>
</div>
</div>
</div>
</div>
<Separator />
{/* Content & Data Section */}
<div className="space-y-4">
<div>
<h4 className="text-sm font-medium mb-3 flex items-center gap-2">
<Archive className="h-4 w-4" />
Content & Data
</h4>
<p className="text-xs text-muted-foreground mb-4">
Select what content to mirror from each repository
</p>
</div>
<div className="space-y-3">
{/* Code is always mirrored - shown as info */}
<div className="flex items-center gap-3 p-3 bg-muted/50 dark:bg-muted/20 rounded-md">
<GitBranch className="h-4 w-4 text-muted-foreground" />
<div className="flex-1">
<p className="text-sm">Source code & branches</p>
<p className="text-xs text-muted-foreground">Always included</p>
</div>
<Badge variant="secondary" className="text-xs">Default</Badge>
</div>
<div className="flex items-start space-x-3">
<Checkbox
id="mirror-releases"
checked={mirrorOptions.mirrorReleases}
onCheckedChange={(checked) => handleMirrorChange('mirrorReleases', !!checked)}
/>
<div className="space-y-0.5 flex-1">
<Label
htmlFor="mirror-releases"
className="text-sm font-normal cursor-pointer flex items-center gap-2"
>
<Tag className="h-3.5 w-3.5" />
Releases & Tags
</Label>
<p className="text-xs text-muted-foreground">
Include GitHub releases, tags, and associated assets
</p>
</div>
</div>
<div className="space-y-3">
<div className="flex items-start space-x-3">
<Checkbox
id="mirror-metadata"
checked={mirrorOptions.mirrorMetadata}
onCheckedChange={(checked) => handleMirrorChange('mirrorMetadata', !!checked)}
/>
<div className="space-y-0.5 flex-1">
<Label
htmlFor="mirror-metadata"
className="text-sm font-normal cursor-pointer flex items-center gap-2"
>
<FileText className="h-3.5 w-3.5" />
Repository Metadata
</Label>
<p className="text-xs text-muted-foreground">
Mirror issues, pull requests, and other repository data
</p>
</div>
</div>
{/* Metadata sub-options */}
{mirrorOptions.mirrorMetadata && (
<div className="ml-7 space-y-2 p-3 bg-muted/30 dark:bg-muted/10 rounded-md">
<div className="grid grid-cols-2 gap-3">
<div className="flex items-center space-x-2">
<Checkbox
id="metadata-issues"
checked={mirrorOptions.metadataComponents.issues}
onCheckedChange={(checked) => handleMetadataComponentChange('issues', !!checked)}
disabled={!isMetadataEnabled}
/>
<Label
htmlFor="metadata-issues"
className="text-sm font-normal cursor-pointer flex items-center gap-1.5"
>
<MessageSquare className="h-3 w-3" />
Issues
</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="metadata-prs"
checked={mirrorOptions.metadataComponents.pullRequests}
onCheckedChange={(checked) => handleMetadataComponentChange('pullRequests', !!checked)}
disabled={!isMetadataEnabled}
/>
<Label
htmlFor="metadata-prs"
className="text-sm font-normal cursor-pointer flex items-center gap-1.5"
>
<GitPullRequest className="h-3 w-3" />
Pull Requests
</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="metadata-labels"
checked={mirrorOptions.metadataComponents.labels}
onCheckedChange={(checked) => handleMetadataComponentChange('labels', !!checked)}
disabled={!isMetadataEnabled}
/>
<Label
htmlFor="metadata-labels"
className="text-sm font-normal cursor-pointer flex items-center gap-1.5"
>
<Tag className="h-3 w-3" />
Labels
</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="metadata-milestones"
checked={mirrorOptions.metadataComponents.milestones}
onCheckedChange={(checked) => handleMetadataComponentChange('milestones', !!checked)}
disabled={!isMetadataEnabled}
/>
<Label
htmlFor="metadata-milestones"
className="text-sm font-normal cursor-pointer flex items-center gap-1.5"
>
<Target className="h-3 w-3" />
Milestones
</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="metadata-wiki"
checked={mirrorOptions.metadataComponents.wiki}
onCheckedChange={(checked) => handleMetadataComponentChange('wiki', !!checked)}
disabled={!isMetadataEnabled}
/>
<Label
htmlFor="metadata-wiki"
className="text-sm font-normal cursor-pointer flex items-center gap-1.5"
>
<BookOpen className="h-3 w-3" />
Wiki
</Label>
</div>
</div>
</div>
)}
</div>
</div>
</div>
<Separator />
{/* Filtering & Behavior Section */}
<div className="space-y-4">
<div>
<h4 className="text-sm font-medium mb-3 flex items-center gap-2">
<Building2 className="h-4 w-4" />
Filtering & Behavior
</h4>
<p className="text-xs text-muted-foreground mb-4">
Fine-tune what gets excluded from mirroring
</p>
</div>
<div className="space-y-3">
<div className="flex items-start space-x-3">
<Checkbox
id="skip-forks"
checked={advancedOptions.skipForks}
onCheckedChange={(checked) => handleAdvancedChange('skipForks', !!checked)}
/>
<div className="space-y-0.5 flex-1">
<Label
htmlFor="skip-forks"
className="text-sm font-normal cursor-pointer flex items-center gap-2"
>
<GitFork className="h-3.5 w-3.5" />
Skip forked repositories
</Label>
<p className="text-xs text-muted-foreground">
Exclude repositories that are forks of other projects
</p>
</div>
</div>
{githubConfig.mirrorStarred && (
<div className="flex items-start space-x-3">
<Checkbox
id="skip-starred-metadata"
checked={advancedOptions.skipStarredIssues}
onCheckedChange={(checked) => handleAdvancedChange('skipStarredIssues', !!checked)}
/>
<div className="space-y-0.5 flex-1">
<Label
htmlFor="skip-starred-metadata"
className="text-sm font-normal cursor-pointer flex items-center gap-2"
>
<Star className="h-3.5 w-3.5" />
Lightweight starred repository mirroring
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<Info className="h-3 w-3 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent side="right" className="max-w-xs">
<p className="text-xs">
When enabled, starred repositories will only mirror code,
skipping issues, PRs, and other metadata to reduce storage
and improve performance.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</Label>
<p className="text-xs text-muted-foreground">
Only mirror code from starred repos, skip issues and metadata
</p>
</div>
</div>
)}
</div>
</div>
</div>
);
}