|
1 | | -import { ChevronRightIcon } from "@heroicons/react/24/outline"; |
| 1 | +import { |
| 2 | + ArrowTopRightOnSquareIcon, |
| 3 | + ChevronRightIcon, |
| 4 | + ExclamationTriangleIcon, |
| 5 | +} from "@heroicons/react/24/outline"; |
2 | 6 | import { EllipsisHorizontalIcon } from "@heroicons/react/20/solid"; |
3 | 7 | import { |
4 | 8 | Form, |
@@ -92,6 +96,7 @@ import { |
92 | 96 | adminPath, |
93 | 97 | branchesPath, |
94 | 98 | concurrencyPath, |
| 99 | + docsPath, |
95 | 100 | limitsPath, |
96 | 101 | logoutPath, |
97 | 102 | newOrganizationPath, |
@@ -130,9 +135,10 @@ import { |
130 | 135 | import { FreePlanUsage } from "../billing/FreePlanUsage"; |
131 | 136 | import { ConnectionIcon, DevPresencePanel, useDevPresence } from "../DevPresence"; |
132 | 137 | import { AlphaBadge, NewBadge } from "../FeatureBadges"; |
133 | | -import { Button, ButtonContent } from "../primitives/Buttons"; |
| 138 | +import { Button, ButtonContent, LinkButton } from "../primitives/Buttons"; |
134 | 139 | import { Dialog, DialogTrigger } from "../primitives/Dialog"; |
135 | 140 | import { type RenderIcon } from "../primitives/Icon"; |
| 141 | +import { Paragraph } from "../primitives/Paragraph"; |
136 | 142 | import { Badge } from "../primitives/Badge"; |
137 | 143 | import { |
138 | 144 | Popover, |
@@ -320,7 +326,7 @@ type SideMenuUser = Pick< |
320 | 326 | }; |
321 | 327 | export type SideMenuProject = Pick< |
322 | 328 | MatchedProject, |
323 | | - "id" | "name" | "slug" | "version" | "environments" |
| 329 | + "id" | "name" | "slug" | "version" | "environments" | "engine" | "createdAt" |
324 | 330 | >; |
325 | 331 | export type SideMenuEnvironment = MatchedEnvironment; |
326 | 332 |
|
@@ -396,6 +402,7 @@ export function SideMenu({ |
396 | 402 | const { isManagedCloud } = useFeatures(); |
397 | 403 | const featureFlags = useFeatureFlags(); |
398 | 404 | const incidentStatus = useIncidentStatus(); |
| 405 | + const isV3Project = project.engine === "V1"; |
399 | 406 | const favorites = useFavorites(); |
400 | 407 | const [isCustomizeOpen, setCustomizeOpen] = useState(false); |
401 | 408 | // Lives here (not in the dialog): the dialog unmounts on close, which would abort a fetcher it |
@@ -1247,6 +1254,13 @@ export function SideMenu({ |
1247 | 1254 | hasIncident={incidentStatus.hasIncident} |
1248 | 1255 | isManagedCloud={incidentStatus.isManagedCloud} |
1249 | 1256 | /> |
| 1257 | + <V3DeprecationPanel |
| 1258 | + isCollapsed={isCollapsed} |
| 1259 | + isV3={isV3Project} |
| 1260 | + projectCreatedAt={project.createdAt} |
| 1261 | + hasIncident={incidentStatus.hasIncident} |
| 1262 | + isManagedCloud={incidentStatus.isManagedCloud} |
| 1263 | + /> |
1250 | 1264 | <motion.div |
1251 | 1265 | layout |
1252 | 1266 | transition={{ duration: 0.2, ease: "easeInOut" }} |
@@ -1540,6 +1554,100 @@ function SectionHeaderMenu({ onCustomize }: { onCustomize: () => void }) { |
1540 | 1554 | ); |
1541 | 1555 | } |
1542 | 1556 |
|
| 1557 | +function V3DeprecationPanel({ |
| 1558 | + isCollapsed, |
| 1559 | + isV3, |
| 1560 | + projectCreatedAt, |
| 1561 | + hasIncident, |
| 1562 | + isManagedCloud, |
| 1563 | +}: { |
| 1564 | + isCollapsed: boolean; |
| 1565 | + isV3: boolean; |
| 1566 | + projectCreatedAt: Date; |
| 1567 | + hasIncident: boolean; |
| 1568 | + isManagedCloud: boolean; |
| 1569 | +}) { |
| 1570 | + // Only show for projects created before v4 was released |
| 1571 | + const V4_RELEASE_DATE = new Date("2025-09-01"); |
| 1572 | + const isLikelyV3 = isV3 && new Date(projectCreatedAt) < V4_RELEASE_DATE; |
| 1573 | + |
| 1574 | + if (!isManagedCloud || !isLikelyV3 || hasIncident) { |
| 1575 | + return null; |
| 1576 | + } |
| 1577 | + |
| 1578 | + return ( |
| 1579 | + <Popover> |
| 1580 | + <div className="p-1"> |
| 1581 | + <motion.div |
| 1582 | + initial={false} |
| 1583 | + animate={{ |
| 1584 | + height: isCollapsed ? 0 : "auto", |
| 1585 | + opacity: isCollapsed ? 0 : 1, |
| 1586 | + }} |
| 1587 | + transition={{ duration: 0.15 }} |
| 1588 | + className="overflow-hidden" |
| 1589 | + > |
| 1590 | + <V3DeprecationContent /> |
| 1591 | + </motion.div> |
| 1592 | + |
| 1593 | + <motion.div |
| 1594 | + initial={false} |
| 1595 | + animate={{ |
| 1596 | + height: isCollapsed ? "auto" : 0, |
| 1597 | + opacity: isCollapsed ? 1 : 0, |
| 1598 | + }} |
| 1599 | + transition={{ duration: 0.15 }} |
| 1600 | + className="overflow-hidden" |
| 1601 | + > |
| 1602 | + <SimpleTooltip |
| 1603 | + button={ |
| 1604 | + <PopoverTrigger className="flex h-8! w-full items-center justify-center rounded border border-amber-500/30 bg-amber-500/15 transition-colors hover:border-amber-500/50 hover:bg-amber-500/25"> |
| 1605 | + <ExclamationTriangleIcon className="size-5 text-amber-400" /> |
| 1606 | + </PopoverTrigger> |
| 1607 | + } |
| 1608 | + content="v3 is now deprecated" |
| 1609 | + side="right" |
| 1610 | + sideOffset={8} |
| 1611 | + disableHoverableContent |
| 1612 | + asChild |
| 1613 | + /> |
| 1614 | + </motion.div> |
| 1615 | + </div> |
| 1616 | + <PopoverContent side="right" sideOffset={8} align="start" className="w-52 min-w-0! p-0"> |
| 1617 | + <V3DeprecationContent /> |
| 1618 | + </PopoverContent> |
| 1619 | + </Popover> |
| 1620 | + ); |
| 1621 | +} |
| 1622 | + |
| 1623 | +function V3DeprecationContent() { |
| 1624 | + return ( |
| 1625 | + <div className="flex flex-col gap-2 rounded border border-amber-500/30 bg-amber-500/10 p-2 pt-1.5"> |
| 1626 | + <div className="flex items-center gap-1 border-b border-amber-500/30 pb-1"> |
| 1627 | + <ExclamationTriangleIcon className="size-4 text-amber-400" /> |
| 1628 | + <Paragraph variant="small/bright" className="text-amber-300"> |
| 1629 | + v3 is now deprecated |
| 1630 | + </Paragraph> |
| 1631 | + </div> |
| 1632 | + <Paragraph variant="extra-small/bright" className="text-amber-300"> |
| 1633 | + This is a v3 project which is now deprecated so no runs are executing. Upgrade to v4 to |
| 1634 | + resume executing runs in this project. |
| 1635 | + </Paragraph> |
| 1636 | + <LinkButton |
| 1637 | + variant="secondary/small" |
| 1638 | + to={docsPath("/upgrade-to-v4")} |
| 1639 | + target="_blank" |
| 1640 | + fullWidth |
| 1641 | + TrailingIcon={ArrowTopRightOnSquareIcon} |
| 1642 | + trailingIconClassName="text-amber-300" |
| 1643 | + className="border-amber-500/30 bg-amber-500/15 hover:border-amber-500/50! hover:bg-amber-500/25!" |
| 1644 | + > |
| 1645 | + <span className="text-amber-300">Upgrade to v4</span> |
| 1646 | + </LinkButton> |
| 1647 | + </div> |
| 1648 | + ); |
| 1649 | +} |
| 1650 | + |
1543 | 1651 | function OrgSelector({ |
1544 | 1652 | organization, |
1545 | 1653 | organizations, |
|
0 commit comments