Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { cn } from "@/lib/utils";
import { formatCompoundDuration } from "@/lib/utils/metric-formatters";
import { Check, CircleHalfDottedClock, TriangleWarning2 } from "@unkey/icons";
import { Badge, Loading, SettingCard } from "@unkey/ui";
import { GlowIcon } from "../../../../components/glow-icon";

type DeploymentStepProps = {
icon: React.ReactNode;
Expand Down Expand Up @@ -32,28 +33,13 @@ export function DeploymentStep({
<SettingCard
truncateDescription
icon={
<div className="relative w-full h-full">
<div
className={cn(
"absolute inset-[-4px] rounded-[10px] blur-[14px]",
isError
? "bg-linear-to-l from-error-7 to-error-8"
: "bg-linear-to-l from-feature-8 to-info-9",
showGlow ? "animate-pulse opacity-20" : "opacity-0 transition-opacity duration-300",
)}
/>
<div
className={cn(
"w-full h-full rounded-[10px] flex items-center justify-center shrink-0",
isError
? "relative bg-errorA-3 dark:text-error-11 text-error-11"
: showGlow &&
"relative dark:bg-white dark:text-black bg-black text-white shadow-md shadow-black/40",
)}
>
{icon}
</div>
</div>
<GlowIcon
icon={icon}
variant={isError ? "error" : "feature"}
glow={showGlow}
transition
className="w-full h-full"
/>
}
title={
<div className="flex items-center gap-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const RedeployDialog = ({ isOpen, onClose, selectedDeployment }: Redeploy
const redeploy = trpc.deploy.deployment.redeploy.useMutation({
onSuccess: async (data) => {
await queryClient.invalidateQueries({ queryKey: ["deployments", projectId] });
onClose();
router.push(
`/${workspace.slug}/projects/${selectedDeployment.projectId}/deployments/${data.deploymentId}`,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useProjectData } from "../data-provider";
type EnvironmentContextType = {
settings: EnvironmentSettings;
variant: "settings" | "onboarding";
isSaving: boolean;
};

export const EnvironmentContext = createContext<EnvironmentContextType | null>(null);
Expand Down Expand Up @@ -44,7 +45,7 @@ export const EnvironmentSettingsProvider = ({ children }: PropsWithChildren) =>
}

return (
<EnvironmentContext.Provider value={{ settings, variant: "settings" }}>
<EnvironmentContext.Provider value={{ settings, variant: "settings", isSaving: false }}>
{children}
</EnvironmentContext.Provider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { DeploymentSettings } from "./deployment-settings";
import { EnvironmentSettingsProvider } from "./environment-provider";
import { PendingRedeployBanner } from "./pending-redeploy-banner";

export default function SettingsPage() {
return (
Expand All @@ -15,6 +16,7 @@ export default function SettingsPage() {
</div>
<DeploymentSettings />
</div>
<PendingRedeployBanner />
</EnvironmentSettingsProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"use client";

import { useWorkspaceNavigation } from "@/hooks/use-workspace-navigation";
import { queryClient } from "@/lib/collections/client";
import { useSettingsHasSaved } from "@/lib/collections/deploy/environment-settings";
import { trpc } from "@/lib/trpc/client";
import { Hammer2, XMark } from "@unkey/icons";
import { Button, toast } from "@unkey/ui";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { GlowIcon } from "../../components/glow-icon";
import { useProjectData } from "../data-provider";

export function PendingRedeployBanner() {
const [dismissed, setDismissed] = useState(false);
const { project, deployments, projectId } = useProjectData();
const router = useRouter();
const workspace = useWorkspaceNavigation();
const hasSaved = useSettingsHasSaved();
const visible = hasSaved && !dismissed;

const currentDeployment = project?.currentDeploymentId
? deployments.find((d) => d.id === project.currentDeploymentId)
: undefined;

const redeploy = trpc.deploy.deployment.redeploy.useMutation({
onSuccess: async (data) => {
if (!currentDeployment) {
return;
}
await queryClient.invalidateQueries({ queryKey: ["deployments", projectId] });
router.push(
`/${workspace.slug}/projects/${currentDeployment.projectId}/deployments/${data.deploymentId}`,
);
},
onError: (error) => {
toast.error("Redeploy failed", { description: error.message });
},
});

if (!visible || !currentDeployment) {
return null;
}

return (
<div className="fixed top-6 right-6 z-50 animate-fade-slide-in">
<div className="relative flex items-start gap-4 rounded-xl border border-gray-4 bg-gray-1 p-4 shadow-lg w-100">
<button
type="button"
onClick={() => setDismissed(true)}
className="absolute top-3 right-3 text-gray-9 hover:text-gray-11 transition-colors cursor-pointer"
aria-label="Dismiss"
>
<XMark className="size-4" />
</button>

<GlowIcon
icon={<Hammer2 iconSize="sm-medium" className="size-[18px]" />}
className="w-9 h-9 shrink-0"
/>

<div className="flex flex-col gap-3 flex-1 min-w-0">
<div className="flex flex-col gap-1 pr-5">
<span className="text-sm font-semibold text-gray-12 leading-5">Settings changed</span>
<span className="text-xs text-gray-11 leading-4">
Redeploy to apply your latest settings to production.
</span>
</div>
<Button
variant="primary"
size="md"
className="w-full"
disabled={redeploy.isLoading}
loading={redeploy.isLoading}
onClick={() => {
redeploy.mutate({ deploymentId: currentDeployment.id });
}}
>
Redeploy
</Button>
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import type { Domain } from "@/lib/collections";
import { cn } from "@/lib/utils";
import { ChevronDown, Cube, Earth, Link4 } from "@unkey/icons";
import {
Button,
Expand All @@ -17,6 +16,7 @@ import { useProjectData } from "../(overview)/data-provider";
import { useDeployment } from "../(overview)/deployments/[deploymentId]/layout-provider";
import { SettingsGroup } from "../(overview)/settings/components/shared/settings-group";
import { getDomainPriority } from "./domain-priority";
import { GlowIcon } from "./glow-icon";
import { TagBadge } from "./tag-badge";

export function DeploymentDomainsCard({
Expand Down Expand Up @@ -73,28 +73,11 @@ export function DeploymentDomainsCard({
<SettingCard
iconClassName={glow ? "bg-transparent shadow-none dark:ring-0" : undefined}
icon={
glow ? (
<div className="relative w-full h-full">
<div
className={cn(
"absolute inset-[-4px] rounded-[10px] blur-[14px]",
"bg-linear-to-l from-feature-8 to-info-9",
"animate-pulse opacity-20",
)}
/>
<div
className={cn(
"w-full h-full rounded-[10px] flex items-center justify-center shrink-0 relative dark:bg-white dark:text-black bg-black text-white",
)}
>
<Cube iconSize="md-medium" className="size-[18px]" />
</div>
</div>
) : (
<div className="w-full h-full rounded-[10px] flex items-center justify-center shrink-0">
<Cube iconSize="md-medium" className="size-[18px]" />
</div>
)
<GlowIcon
icon={<Cube iconSize="md-medium" className="size-[18px]" />}
glow={glow}
className="w-full h-full"
/>
}
title={project?.name}
description={
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { cn } from "@/lib/utils";
import type { ReactNode } from "react";

type GlowIconProps = {
icon: ReactNode;
variant?: "feature" | "error";
glow?: boolean;
transition?: boolean;
className?: string;
};

export function GlowIcon({
icon,
variant = "feature",
glow = true,
transition = false,
className,
}: GlowIconProps) {
const glowColor =
variant === "error"
? "bg-linear-to-l from-error-7 to-error-8"
: "bg-linear-to-l from-feature-8 to-info-9";

const glowVisible = transition
? glow
? "animate-pulse opacity-20"
: "opacity-0 transition-opacity duration-300"
: glow
? "animate-pulse opacity-20"
: "hidden";

const iconBg =
variant === "error"
? "bg-errorA-3 dark:text-error-11 text-error-11"
: glow
? "dark:bg-white dark:text-black bg-black text-white shadow-md shadow-black/40"
: "";

return (
<div className={cn("relative", className)}>
<div
className={cn("absolute inset-[-4px] rounded-[10px] blur-[14px]", glowColor, glowVisible)}
/>
<div
className={cn(
"relative w-full h-full rounded-[10px] flex items-center justify-center shrink-0",
iconBg,
)}
>
{icon}
</div>
</div>
);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"use client";

import { queryClient } from "@/lib/collections/client";
import { trpc } from "@/lib/trpc/client";
import { Button, toast, useStepWizard } from "@unkey/ui";
import { DeploymentSettings } from "../../../[projectId]/(overview)/settings/deployment-settings";
import { useEnvironmentSettings } from "../../../[projectId]/(overview)/settings/environment-provider";

type ConfigureDeploymentContentProps = {
projectId: string;
onDeploymentCreated: (deploymentId: string) => void;
};

export const ConfigureDeploymentContent = ({
projectId,
onDeploymentCreated,
}: ConfigureDeploymentContentProps) => {
const { next } = useStepWizard();
const { isSaving } = useEnvironmentSettings();

const deploy = trpc.deploy.deployment.create.useMutation({
onSuccess: async (data) => {
await queryClient.invalidateQueries({ queryKey: ["deployments", projectId] });
toast.success("Deployment triggered", {
description: "Your project is being built and deployed",
});
onDeploymentCreated(data.deploymentId);
next();
},
onError: (error) => {
toast.error("Deployment failed", { description: error.message });
},
});

return (
<div className="w-225">
<DeploymentSettings githubReadOnly sections={{ build: true }} />
<div className="flex justify-end mt-6 mb-10 flex-col gap-4">
<Button
type="button"
variant="primary"
size="xlg"
className="rounded-lg"
disabled={deploy.isLoading || isSaving}
loading={deploy.isLoading}
onClick={() => deploy.mutate({ projectId, environmentSlug: "production" })}
>
Deploy
</Button>
<span className="text-gray-10 text-[13px] text-center">
We'll build your image, provision infrastructure, and more.
<br />
</span>
</div>
</div>
);
};
Loading
Loading