mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 02:10:12 -06:00
Compare commits
17 Commits
admin-emai
...
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 { z } from "zod";
|
||||||
import { deleteActionClass, getActionClass, updateActionClass } from "@formbricks/lib/actionClass/service";
|
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 { checkAuthorization } from "@formbricks/lib/actionClient/utils";
|
||||||
|
import { cache } from "@formbricks/lib/cache";
|
||||||
import { getOrganizationIdFromActionClassId } from "@formbricks/lib/organization/utils";
|
import { getOrganizationIdFromActionClassId } from "@formbricks/lib/organization/utils";
|
||||||
import { getSurveysByActionClassId } from "@formbricks/lib/survey/service";
|
import { getSurveysByActionClassId } from "@formbricks/lib/survey/service";
|
||||||
import { ZActionClassInput } from "@formbricks/types/action-classes";
|
import { ZActionClassInput } from "@formbricks/types/action-classes";
|
||||||
@@ -72,3 +73,33 @@ export const getActiveInactiveSurveysAction = authenticatedActionClient
|
|||||||
};
|
};
|
||||||
return response;
|
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";
|
"use client";
|
||||||
|
|
||||||
|
import { getLatestStableFbReleaseAction } from "@/app/(app)/environments/[environmentId]/actions/actions";
|
||||||
import { NavigationLink } from "@/app/(app)/environments/[environmentId]/components/NavigationLink";
|
import { NavigationLink } from "@/app/(app)/environments/[environmentId]/components/NavigationLink";
|
||||||
import { formbricksLogout } from "@/app/lib/formbricks";
|
import { formbricksLogout } from "@/app/lib/formbricks";
|
||||||
import FBLogo from "@/images/formbricks-wordmark.svg";
|
import FBLogo from "@/images/formbricks-wordmark.svg";
|
||||||
@@ -20,6 +21,7 @@ import {
|
|||||||
PanelLeftCloseIcon,
|
PanelLeftCloseIcon,
|
||||||
PanelLeftOpenIcon,
|
PanelLeftOpenIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
|
RocketIcon,
|
||||||
UserCircleIcon,
|
UserCircleIcon,
|
||||||
UserIcon,
|
UserIcon,
|
||||||
UsersIcon,
|
UsersIcon,
|
||||||
@@ -54,6 +56,7 @@ import {
|
|||||||
DropdownMenuSubTrigger,
|
DropdownMenuSubTrigger,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@formbricks/ui/DropdownMenu";
|
} from "@formbricks/ui/DropdownMenu";
|
||||||
|
import { version } from "../../../../../package.json";
|
||||||
|
|
||||||
interface NavigationProps {
|
interface NavigationProps {
|
||||||
environment: TEnvironment;
|
environment: TEnvironment;
|
||||||
@@ -61,9 +64,9 @@ interface NavigationProps {
|
|||||||
user: TUser;
|
user: TUser;
|
||||||
organization: TOrganization;
|
organization: TOrganization;
|
||||||
products: TProduct[];
|
products: TProduct[];
|
||||||
isFormbricksCloud: boolean;
|
|
||||||
membershipRole?: TMembershipRole;
|
|
||||||
isMultiOrgEnabled: boolean;
|
isMultiOrgEnabled: boolean;
|
||||||
|
isFormbricksCloud?: boolean;
|
||||||
|
membershipRole?: TMembershipRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MainNavigation = ({
|
export const MainNavigation = ({
|
||||||
@@ -72,9 +75,9 @@ export const MainNavigation = ({
|
|||||||
organization,
|
organization,
|
||||||
user,
|
user,
|
||||||
products,
|
products,
|
||||||
isFormbricksCloud,
|
|
||||||
membershipRole,
|
|
||||||
isMultiOrgEnabled,
|
isMultiOrgEnabled,
|
||||||
|
isFormbricksCloud = true,
|
||||||
|
membershipRole,
|
||||||
}: NavigationProps) => {
|
}: NavigationProps) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
@@ -84,6 +87,7 @@ export const MainNavigation = ({
|
|||||||
const [showCreateOrganizationModal, setShowCreateOrganizationModal] = useState(false);
|
const [showCreateOrganizationModal, setShowCreateOrganizationModal] = useState(false);
|
||||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||||
const [isTextVisible, setIsTextVisible] = useState(true);
|
const [isTextVisible, setIsTextVisible] = useState(true);
|
||||||
|
const [latestVersion, setLatestVersion] = useState("");
|
||||||
|
|
||||||
const product = products.find((product) => product.id === environment.productId);
|
const product = products.find((product) => product.id === environment.productId);
|
||||||
const { isAdmin, isOwner, isViewer } = getAccessFlags(membershipRole);
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
{product && (
|
{product && (
|
||||||
@@ -305,8 +324,22 @@ export const MainNavigation = ({
|
|||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Product Switch */}
|
{/* Product Switch */}
|
||||||
<div>
|
<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>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger
|
<DropdownMenuTrigger
|
||||||
asChild
|
asChild
|
||||||
|
|||||||
Reference in New Issue
Block a user