feat(web): responsive page padding and stacking page headers
This commit is contained in:
@@ -49,7 +49,7 @@ export default function AuditPage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6">
|
||||
<h1 className="text-2xl font-bold text-text-primary">Audit Log</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">
|
||||
|
||||
@@ -227,7 +227,7 @@ export default function KeyDetailPage() {
|
||||
|
||||
if (error || !key) {
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="rounded-lg border border-danger/30 bg-danger/10 p-4 text-danger">
|
||||
Key not found or failed to load.
|
||||
</div>
|
||||
@@ -239,7 +239,7 @@ export default function KeyDetailPage() {
|
||||
const assignedServerIds = activeAssignments.map((a) => a.server_id);
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
{showAssign && (
|
||||
<AssignModal
|
||||
keyId={keyId}
|
||||
|
||||
@@ -106,10 +106,10 @@ export default function KeysPage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
{showUpload && <UploadKeyModal onClose={() => setShowUpload(false)} />}
|
||||
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-text-primary">SSH Keys</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">
|
||||
|
||||
@@ -37,14 +37,14 @@ export default function EditMonitorPage() {
|
||||
|
||||
if (!monitor) {
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="rounded-lg border border-danger/30 bg-danger/10 p-4 text-danger">Monitor not found.</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<Link href={`/monitors/${monitorId}`} className="text-sm text-text-secondary hover:text-text-primary">
|
||||
← {monitor.name}
|
||||
</Link>
|
||||
|
||||
@@ -86,7 +86,7 @@ export default function MonitorDetailPage() {
|
||||
|
||||
if (!monitor) {
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="rounded-lg border border-danger/30 bg-danger/10 p-4 text-danger">Monitor not found.</div>
|
||||
</div>
|
||||
);
|
||||
@@ -96,7 +96,7 @@ export default function MonitorDetailPage() {
|
||||
const last24 = all.slice(-24);
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6 flex items-start justify-between">
|
||||
<div>
|
||||
<Link href="/monitors" className="text-sm text-text-secondary hover:text-text-primary">
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function NewMonitorPage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<Link href="/monitors" className="text-sm text-text-secondary hover:text-text-primary">
|
||||
← Monitors
|
||||
</Link>
|
||||
|
||||
@@ -31,8 +31,8 @@ export default function MonitorsPage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-text-primary">Monitors</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">Service uptime and latency checks.</p>
|
||||
|
||||
@@ -241,14 +241,14 @@ export default function SecretGroupPage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
{showYaml && <YamlModal group={group} onClose={() => setShowYaml(false)} />}
|
||||
|
||||
<Link href="/secrets" className="mb-4 inline-flex items-center gap-1 text-sm text-text-secondary hover:text-text-primary">
|
||||
← Back to secrets
|
||||
</Link>
|
||||
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h1 className="font-mono text-2xl font-bold text-text-primary">{group}</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">
|
||||
|
||||
@@ -99,10 +99,10 @@ export default function SecretsPage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
{showNew && <NewGroupModal onClose={() => setShowNew(false)} />}
|
||||
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-text-primary">Secrets</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">
|
||||
|
||||
@@ -158,7 +158,7 @@ export default function ServerConsolePage() {
|
||||
|
||||
if (!server) {
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="rounded-lg border border-danger/30 bg-danger/10 p-4 text-danger">Server not found or failed to load.</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -372,14 +372,14 @@ export default function ServerDetailPage() {
|
||||
|
||||
if (error || !server) {
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="rounded-lg border border-danger/30 bg-danger/10 p-4 text-danger">Server not found or failed to load.</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
{showGenerateModal && <GenerateKeyModal onClose={() => setShowGenerateModal(false)} onSubmit={(opts) => generateKey(opts)} isPending={isGenerating} />}
|
||||
{showUpdatesModal && server.available_updates && (
|
||||
<UpdatesModal updates={server.available_updates} onClose={() => setShowUpdatesModal(false)} onApply={() => applyUpdates()} isApplying={isApplying} applySuccess={applySuccess} />
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function NewServerPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6">
|
||||
<h1 className="text-2xl font-bold text-text-primary">Add Server</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">
|
||||
|
||||
@@ -71,8 +71,8 @@ export default function ServersPage() {
|
||||
const latestVersion = latestVersionData?.version;
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-text-primary">Servers</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">
|
||||
|
||||
@@ -237,7 +237,7 @@ export default function LicensePage() {
|
||||
|
||||
if (!license) {
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<Card className="max-w-lg">
|
||||
<h1 className="text-base font-bold text-text-primary">Licence unavailable</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">The licence state could not be read. Reload the page, and check the server logs if it keeps failing.</p>
|
||||
@@ -253,7 +253,7 @@ export default function LicensePage() {
|
||||
const hqUrl = process.env.NEXT_PUBLIC_HQ_URL ?? "";
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mx-auto max-w-5xl space-y-10">
|
||||
<div>
|
||||
<h1 className="text-2xl font-extrabold tracking-[-0.03em] text-text-primary">Licence</h1>
|
||||
|
||||
@@ -149,8 +149,8 @@ export default function NotificationSettingsPage() {
|
||||
const { data: channels, isLoading } = useQuery({ queryKey: ["channels"], queryFn: () => api.listChannels() });
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<Link href="/monitors" className="text-sm text-text-secondary hover:text-text-primary">
|
||||
← Monitors
|
||||
|
||||
@@ -160,7 +160,7 @@ export default function SettingsPage() {
|
||||
|
||||
if (!isAdmin) {
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<Card className="max-w-lg">
|
||||
<h1 className="text-base font-bold text-text-primary">You don't have access</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">Settings are available to owners and admins only. Ask an administrator if you need access.</p>
|
||||
@@ -178,7 +178,7 @@ export default function SettingsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-2xl font-extrabold tracking-[-0.03em] text-text-primary">Settings</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">
|
||||
|
||||
@@ -91,7 +91,7 @@ export default function StepsPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6 flex items-center gap-3">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-text-primary">Steps</h1>
|
||||
|
||||
@@ -130,7 +130,7 @@ export default function WorkflowBuilder() {
|
||||
}, [lastSaved]);
|
||||
|
||||
if (!wf) {
|
||||
return <div className="p-8 text-text-secondary">Loading…</div>;
|
||||
return <div className="p-4 text-text-secondary sm:p-6 lg:p-8">Loading…</div>;
|
||||
}
|
||||
|
||||
const libById = (sid?: string) => (sid ? library?.find((l) => l.step_id === sid) : undefined);
|
||||
|
||||
@@ -326,7 +326,7 @@ export default function RunDetail() {
|
||||
};
|
||||
|
||||
if (isLoading || !run) {
|
||||
return <div className="p-8 text-text-secondary">Loading…</div>;
|
||||
return <div className="p-4 text-text-secondary sm:p-6 lg:p-8">Loading…</div>;
|
||||
}
|
||||
|
||||
const totalSteps = run.server_runs.reduce((n, s) => n + s.steps.length, 0);
|
||||
@@ -340,7 +340,7 @@ export default function RunDetail() {
|
||||
const ago = fmtDuration(now - startMs);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-[1180px] p-8 pb-16">
|
||||
<div className="mx-auto max-w-[1180px] p-4 pb-16 sm:p-6 lg:p-8">
|
||||
{/* identity bar */}
|
||||
<div className="flex flex-wrap items-start justify-between gap-6">
|
||||
<div>
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function WorkflowRunsPage() {
|
||||
const { data: runs, isLoading, error } = useQuery({ queryKey: ["runs", id], queryFn: () => api.listRuns(id) });
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6">
|
||||
<Link href={`/workflows/${id}`} className="text-sm text-text-secondary hover:text-text-primary">
|
||||
← Back to builder
|
||||
|
||||
@@ -28,8 +28,8 @@ export default function WorkflowsPage() {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-text-primary">Workflows</h1>
|
||||
<p className="mt-1 text-sm text-text-secondary">
|
||||
|
||||
Reference in New Issue
Block a user