spacing and sizing
This commit is contained in:
@@ -3,7 +3,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ChevronDown, Loader2, Play, RefreshCcw, Rocket, Settings, Trash2 } from "lucide-react";
|
import {
|
||||||
|
ChevronDown,
|
||||||
|
Loader2,
|
||||||
|
Play,
|
||||||
|
RefreshCcw,
|
||||||
|
Rocket,
|
||||||
|
Settings,
|
||||||
|
Trash2,
|
||||||
|
} from "lucide-react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -66,29 +74,32 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-40 border-b bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
<header className='sticky top-0 z-40 border-b bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/60'>
|
||||||
<div className="container mx-auto flex max-w-7xl items-center justify-between gap-4 px-4 py-4">
|
<div className='container mx-auto flex max-w-7xl items-center justify-between gap-4 px-4 py-4'>
|
||||||
<Link to="/" className="flex items-center gap-3 hover:opacity-80 transition-opacity">
|
<Link
|
||||||
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-primary text-primary-foreground shadow-sm">
|
to='/'
|
||||||
<Rocket className="h-5 w-5" />
|
className='flex items-center gap-3 hover:opacity-80 transition-opacity'
|
||||||
|
>
|
||||||
|
<div className='flex h-9 w-9 items-center justify-center rounded-lg bg-primary text-primary-foreground shadow-sm'>
|
||||||
|
<Rocket className='h-5 w-5' />
|
||||||
</div>
|
</div>
|
||||||
<div className="leading-tight">
|
<div className='leading-tight'>
|
||||||
<div className="text-sm font-semibold tracking-tight">Job Ops</div>
|
<div className='text-sm font-semibold tracking-tight'>Job Ops</div>
|
||||||
<div className="text-xs text-muted-foreground">Orchestrator</div>
|
<div className='text-xs text-muted-foreground'>Orchestrator</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className='flex flex-wrap items-center gap-1.5'>
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger asChild>
|
<AlertDialogTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant='outline'
|
||||||
size="sm"
|
size='sm'
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
title="Clear all jobs from database"
|
title='Clear all jobs from database'
|
||||||
>
|
>
|
||||||
<Trash2 className="h-4 w-4" />
|
<Trash2 className='h-4 w-4' />
|
||||||
<span className="hidden sm:inline">Clear DB</span>
|
<span className='hidden sm:inline'>Clear DB</span>
|
||||||
</Button>
|
</Button>
|
||||||
</AlertDialogTrigger>
|
</AlertDialogTrigger>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
@@ -108,72 +119,96 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|
||||||
<Button variant="outline" size="sm" onClick={onRefresh} disabled={isLoading}>
|
<Button
|
||||||
<RefreshCcw className="h-4 w-4" />
|
variant='outline'
|
||||||
<span className="hidden sm:inline">Refresh</span>
|
size='sm'
|
||||||
</Button>
|
onClick={onRefresh}
|
||||||
|
disabled={isLoading}
|
||||||
<Button asChild variant="outline" size="sm">
|
>
|
||||||
<Link to="/settings">
|
<RefreshCcw className='h-4 w-4' />
|
||||||
<Settings className="h-4 w-4" />
|
<span className='hidden sm:inline'>Refresh</span>
|
||||||
<span className="hidden sm:inline">Settings</span>
|
|
||||||
</Link>
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
asChild
|
||||||
onClick={onRunPipeline}
|
variant='outline'
|
||||||
disabled={isPipelineRunning}
|
size='sm'
|
||||||
className="rounded-r-none"
|
|
||||||
>
|
>
|
||||||
{isPipelineRunning ? (
|
<Link to='/settings'>
|
||||||
<>
|
<Settings className='h-4 w-4' />
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
<span className='hidden sm:inline'>Settings</span>
|
||||||
Running...
|
</Link>
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Play className="h-4 w-4" />
|
|
||||||
Run Pipeline
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<DropdownMenu>
|
<div>
|
||||||
<DropdownMenuTrigger asChild>
|
<Button
|
||||||
<Button
|
size='sm'
|
||||||
size="sm"
|
onClick={onRunPipeline}
|
||||||
disabled={isPipelineRunning}
|
disabled={isPipelineRunning}
|
||||||
className="rounded-l-none border-l border-primary-foreground/20 px-2"
|
className='rounded-r-none'
|
||||||
aria-label="Select pipeline sources"
|
>
|
||||||
>
|
{isPipelineRunning ? (
|
||||||
<ChevronDown className="h-4 w-4" />
|
<>
|
||||||
</Button>
|
<Loader2 className='h-4 w-4 animate-spin' />
|
||||||
</DropdownMenuTrigger>
|
Running...
|
||||||
<DropdownMenuContent align="end" className="w-56">
|
</>
|
||||||
<DropdownMenuLabel>Sources</DropdownMenuLabel>
|
) : (
|
||||||
<DropdownMenuSeparator />
|
<>
|
||||||
{orderedSources.map((source) => (
|
<Play className='h-4 w-4' />
|
||||||
<DropdownMenuCheckboxItem
|
Run Pipeline
|
||||||
key={source}
|
</>
|
||||||
checked={pipelineSources.includes(source)}
|
)}
|
||||||
onCheckedChange={(checked) => toggleSource(source, Boolean(checked))}
|
</Button>
|
||||||
|
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button
|
||||||
|
size='sm'
|
||||||
|
disabled={isPipelineRunning}
|
||||||
|
className='rounded-l-none border-l border-primary-foreground/20'
|
||||||
|
aria-label='Select pipeline sources'
|
||||||
>
|
>
|
||||||
{sourceLabel[source]}
|
<ChevronDown className='h-4 w-4' />
|
||||||
</DropdownMenuCheckboxItem>
|
</Button>
|
||||||
))}
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuContent
|
||||||
<DropdownMenuItem onSelect={() => onPipelineSourcesChange(orderedSources)}>
|
align='end'
|
||||||
All sources
|
className='w-56'
|
||||||
</DropdownMenuItem>
|
>
|
||||||
<DropdownMenuItem onSelect={() => onPipelineSourcesChange(["gradcracker"])}>
|
<DropdownMenuLabel>Sources</DropdownMenuLabel>
|
||||||
Gradcracker only
|
<DropdownMenuSeparator />
|
||||||
</DropdownMenuItem>
|
{orderedSources.map((source) => (
|
||||||
<DropdownMenuItem onSelect={() => onPipelineSourcesChange(["indeed", "linkedin"])}>
|
<DropdownMenuCheckboxItem
|
||||||
Indeed + LinkedIn only
|
key={source}
|
||||||
</DropdownMenuItem>
|
checked={pipelineSources.includes(source)}
|
||||||
</DropdownMenuContent>
|
onCheckedChange={(checked) =>
|
||||||
</DropdownMenu>
|
toggleSource(source, Boolean(checked))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{sourceLabel[source]}
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
))}
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem
|
||||||
|
onSelect={() => onPipelineSourcesChange(orderedSources)}
|
||||||
|
>
|
||||||
|
All sources
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onSelect={() => onPipelineSourcesChange(["gradcracker"])}
|
||||||
|
>
|
||||||
|
Gradcracker only
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onSelect={() =>
|
||||||
|
onPipelineSourcesChange(["indeed", "linkedin"])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Indeed + LinkedIn only
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -313,8 +313,8 @@ export const JobList: React.FC<JobListProps> = ({
|
|||||||
className="space-y-4"
|
className="space-y-4"
|
||||||
>
|
>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<TabsList className="w-full sm:w-auto">
|
<TabsList className="w-full sm:w-auto h-9">
|
||||||
{tabs.map((tab) => (
|
{tabs.map((tab) => (
|
||||||
<TabsTrigger key={tab.id} value={tab.id} className="flex-1 sm:flex-none">
|
<TabsTrigger key={tab.id} value={tab.id} className="flex-1 sm:flex-none">
|
||||||
{tab.label}
|
{tab.label}
|
||||||
@@ -325,8 +325,8 @@ export const JobList: React.FC<JobListProps> = ({
|
|||||||
))}
|
))}
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<div className="flex items-center justify-between gap-2 sm:justify-end">
|
<div className="flex items-center justify-between gap-1.5 sm:justify-end">
|
||||||
<div className="flex items-center rounded-md border bg-muted/20 p-0.5">
|
<div className="flex items-center rounded-md border bg-muted/20 p-0.5 h-9">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -367,7 +367,7 @@ export const JobList: React.FC<JobListProps> = ({
|
|||||||
<div className="flex flex-wrap items-center gap-2 self-start sm:self-auto">
|
<div className="flex flex-wrap items-center gap-2 self-start sm:self-auto">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant="outline" size="sm">
|
<Button variant="outline" size="sm" className="h-9">
|
||||||
<ArrowUpDown className="h-4 w-4" />
|
<ArrowUpDown className="h-4 w-4" />
|
||||||
<span className="hidden sm:inline">
|
<span className="hidden sm:inline">
|
||||||
Sort: {sortLabels[sort.key]} {sort.direction === "asc" ? "↑" : "↓"}
|
Sort: {sortLabels[sort.key]} {sort.direction === "asc" ? "↑" : "↓"}
|
||||||
|
|||||||
Reference in New Issue
Block a user