mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-22 14:10:45 -06:00
Compare commits
17 Commits
docs/custo
...
version-fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
435dbf2261 | ||
|
|
df74510756 | ||
|
|
57135d167b | ||
|
|
916e47c55d | ||
|
|
5faccf1063 | ||
|
|
ebbc5abd3c | ||
|
|
ad445d1915 | ||
|
|
756d0c84af | ||
|
|
8f6b356870 | ||
|
|
e0ba9cb998 | ||
|
|
c6f1e9e7d5 | ||
|
|
f025a70d20 | ||
|
|
ba1e478d68 | ||
|
|
8e57082376 | ||
|
|
2681d03e15 | ||
|
|
72e023c530 | ||
|
|
7088f9bd26 |
@@ -2,8 +2,9 @@
|
||||
|
||||
import { z } from "zod";
|
||||
import { deleteActionClass, getActionClass, updateActionClass } from "@formbricks/lib/actionClass/service";
|
||||
import { authenticatedActionClient } from "@formbricks/lib/actionClient";
|
||||
import { actionClient, authenticatedActionClient } from "@formbricks/lib/actionClient";
|
||||
import { checkAuthorization } from "@formbricks/lib/actionClient/utils";
|
||||
import { cache } from "@formbricks/lib/cache";
|
||||
import { getOrganizationIdFromActionClassId } from "@formbricks/lib/organization/utils";
|
||||
import { getSurveysByActionClassId } from "@formbricks/lib/survey/service";
|
||||
import { ZActionClassInput } from "@formbricks/types/action-classes";
|
||||
@@ -72,3 +73,33 @@ export const getActiveInactiveSurveysAction = authenticatedActionClient
|
||||
};
|
||||
return response;
|
||||
});
|
||||
|
||||
const getLatestStableFbRelease = async (): Promise<string | null> =>
|
||||
cache(
|
||||
async () => {
|
||||
try {
|
||||
const res = await fetch("https://api.github.com/repos/formbricks/formbricks/releases");
|
||||
const releases = await res.json();
|
||||
|
||||
if (Array.isArray(releases)) {
|
||||
const latestStableReleaseTag = releases.filter((release) => !release.prerelease)?.[0]
|
||||
?.tag_name as string;
|
||||
if (latestStableReleaseTag) {
|
||||
return latestStableReleaseTag;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
["latest-fb-release"],
|
||||
{
|
||||
revalidate: 60 * 60 * 24, // 24 hours
|
||||
}
|
||||
)();
|
||||
|
||||
export const getLatestStableFbReleaseAction = actionClient.action(async () => {
|
||||
return await getLatestStableFbRelease();
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { getLatestStableFbReleaseAction } from "@/app/(app)/environments/[environmentId]/actions/actions";
|
||||
import { NavigationLink } from "@/app/(app)/environments/[environmentId]/components/NavigationLink";
|
||||
import { formbricksLogout } from "@/app/lib/formbricks";
|
||||
import FBLogo from "@/images/formbricks-wordmark.svg";
|
||||
@@ -20,6 +21,7 @@ import {
|
||||
PanelLeftCloseIcon,
|
||||
PanelLeftOpenIcon,
|
||||
PlusIcon,
|
||||
RocketIcon,
|
||||
UserCircleIcon,
|
||||
UserIcon,
|
||||
UsersIcon,
|
||||
@@ -54,6 +56,7 @@ import {
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@formbricks/ui/DropdownMenu";
|
||||
import { version } from "../../../../../package.json";
|
||||
|
||||
interface NavigationProps {
|
||||
environment: TEnvironment;
|
||||
@@ -61,9 +64,9 @@ interface NavigationProps {
|
||||
user: TUser;
|
||||
organization: TOrganization;
|
||||
products: TProduct[];
|
||||
isFormbricksCloud: boolean;
|
||||
membershipRole?: TMembershipRole;
|
||||
isMultiOrgEnabled: boolean;
|
||||
isFormbricksCloud?: boolean;
|
||||
membershipRole?: TMembershipRole;
|
||||
}
|
||||
|
||||
export const MainNavigation = ({
|
||||
@@ -72,9 +75,9 @@ export const MainNavigation = ({
|
||||
organization,
|
||||
user,
|
||||
products,
|
||||
isFormbricksCloud,
|
||||
membershipRole,
|
||||
isMultiOrgEnabled,
|
||||
isFormbricksCloud = true,
|
||||
membershipRole,
|
||||
}: NavigationProps) => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
@@ -84,6 +87,7 @@ export const MainNavigation = ({
|
||||
const [showCreateOrganizationModal, setShowCreateOrganizationModal] = useState(false);
|
||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||
const [isTextVisible, setIsTextVisible] = useState(true);
|
||||
const [latestVersion, setLatestVersion] = useState("");
|
||||
|
||||
const product = products.find((product) => product.id === environment.productId);
|
||||
const { isAdmin, isOwner, isViewer } = getAccessFlags(membershipRole);
|
||||
@@ -248,6 +252,21 @@ export const MainNavigation = ({
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
async function loadReleases() {
|
||||
const res = await getLatestStableFbReleaseAction();
|
||||
if (res?.data) {
|
||||
const latestVersionTag = res.data;
|
||||
const currentVersionTag = `v${version}`;
|
||||
|
||||
if (currentVersionTag !== latestVersionTag) {
|
||||
setLatestVersion(latestVersionTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isOwnerOrAdmin) loadReleases();
|
||||
}, [isOwnerOrAdmin]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{product && (
|
||||
@@ -305,8 +324,22 @@ export const MainNavigation = ({
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Product Switch */}
|
||||
<div>
|
||||
{/* New Version Available */}
|
||||
{!isCollapsed && isOwnerOrAdmin && latestVersion && !isFormbricksCloud && (
|
||||
<Link
|
||||
href="https://github.com/formbricks/formbricks/releases"
|
||||
target="_blank"
|
||||
className="m-2 flex items-center space-x-4 rounded-lg border border-slate-200 bg-slate-100 p-2 text-sm text-slate-800 hover:border-slate-300 hover:bg-slate-200">
|
||||
<p className="flex items-center justify-center gap-x-2 text-xs">
|
||||
<RocketIcon strokeWidth={1.5} className="mx-1 h-6 w-6 text-slate-900" />
|
||||
Formbricks {latestVersion} is here. Upgrade now!
|
||||
</p>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
asChild
|
||||
|
||||
Reference in New Issue
Block a user