diff --git a/src/components/Authentication/Kratos/KratosUserProfileDropdown.tsx b/src/components/Authentication/Kratos/KratosUserProfileDropdown.tsx
index 081fe09e8..553792f7f 100644
--- a/src/components/Authentication/Kratos/KratosUserProfileDropdown.tsx
+++ b/src/components/Authentication/Kratos/KratosUserProfileDropdown.tsx
@@ -6,9 +6,14 @@ import { ClickableSvg } from "../../../ui/ClickableSvg/ClickableSvg";
import { VersionInfo } from "../../VersionInfo/VersionInfo";
import KratosLogoutButton from "./KratosLogoutButton";
-export function KratosUserProfileDropdown() {
- const { user } = useUser();
+type UserProfileDropdownProps = {
+ openKubeConfigModal: () => void;
+};
+export function KratosUserProfileDropdown({
+ openKubeConfigModal
+}: UserProfileDropdownProps) {
+ const { user } = useUser();
const userNavigation = [{ name: "Your Profile", href: "/profile-settings" }];
return (
@@ -56,6 +61,14 @@ export function KratosUserProfileDropdown() {
))}
+
+
+
diff --git a/src/components/KubeConfig/AddKubeConfigModal.tsx b/src/components/KubeConfig/AddKubeConfigModal.tsx
new file mode 100644
index 000000000..07c468fe8
--- /dev/null
+++ b/src/components/KubeConfig/AddKubeConfigModal.tsx
@@ -0,0 +1,82 @@
+import { useUser } from "@flanksource-ui/context";
+import { Button } from "@flanksource-ui/ui/Buttons/Button";
+import CodeBlock from "@flanksource-ui/ui/Code/CodeBlock";
+import { Modal } from "@flanksource-ui/ui/Modal";
+import StepperList from "@flanksource-ui/ui/StepperList";
+import { useMemo } from "react";
+import { IoMdDownload } from "react-icons/io";
+
+const downloadKubeConfigURL = `/api/kubeconfig`;
+
+type AddKubeConfigModalProps = {
+ isOpen: boolean;
+ onClose: () => void;
+};
+
+export default function AddKubeConfigModal({
+ isOpen,
+ onClose
+}: AddKubeConfigModalProps) {
+ const { backendUrl } = useUser();
+
+ const kubeConfigFilename = useMemo(
+ () =>
+ backendUrl
+ ?.replaceAll("https://", "")
+ .replaceAll(".flanksource.com", "")
+ .replaceAll("/", "") + "-kubeconfig.yaml",
+ [backendUrl]
+ );
+
+ return (
+
+
+
+
+
Instructions
+
+
+
+ ,
+
+ Apply the kubeconfig file to your kubectl configuration{" "}
+
+
,
+
+
+ Learn more
+ {" "}
+ on how to use the Kubernetes Interface to Mission Control
+
+ ]}
+ />
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/Users/UserProfile.tsx b/src/components/Users/UserProfile.tsx
index 2238c6994..e61172b44 100644
--- a/src/components/Users/UserProfile.tsx
+++ b/src/components/Users/UserProfile.tsx
@@ -1,21 +1,44 @@
import { OrganizationSwitcher, UserButton } from "@clerk/nextjs";
+import { useState } from "react";
+import { IoMdDownload } from "react-icons/io";
import { KratosUserProfileDropdown } from "../Authentication/Kratos/KratosUserProfileDropdown";
import useDetermineAuthSystem from "../Authentication/useDetermineAuthSystem";
+import AddKubeConfigModal from "../KubeConfig/AddKubeConfigModal";
export function UserProfileDropdown() {
const authSystem = useDetermineAuthSystem();
+ const [isDownloadKubeConfigModalOpen, setIsDownloadKubeConfigModalOpen] =
+ useState(false);
- return authSystem === "clerk" ? (
-
-
+ {authSystem === "clerk" ? (
+
+
+
+
+ }
+ onClick={() => setIsDownloadKubeConfigModalOpen(true)}
+ />
+
+
+
+ ) : (
+ setIsDownloadKubeConfigModalOpen(true)}
+ />
+ )}
+ setIsDownloadKubeConfigModalOpen(false)}
/>
-
-
- ) : (
-
+ >
);
}
diff --git a/src/ui/StepperList.stories.tsx b/src/ui/StepperList.stories.tsx
new file mode 100644
index 000000000..f40b146ef
--- /dev/null
+++ b/src/ui/StepperList.stories.tsx
@@ -0,0 +1,22 @@
+import { Meta, StoryFn } from "@storybook/react";
+import StepperList from "./StepperList";
+
+export default {
+ title: "ui/StepperList",
+ component: StepperList
+} satisfies Meta;
+
+const Template: StoryFn = (args) => (
+
+);
+
+export const Variant1 = Template.bind({});
+Variant1.args = {
+ items: [
+ Some list item
,
+
+ Some list item
+
,
+ Some other list item
+ ]
+};
diff --git a/src/ui/StepperList.tsx b/src/ui/StepperList.tsx
new file mode 100644
index 000000000..c7858518f
--- /dev/null
+++ b/src/ui/StepperList.tsx
@@ -0,0 +1,38 @@
+import React from "react";
+
+type StepperListProps = {
+ items: React.ReactNode[];
+ showStepLabel?: boolean;
+};
+
+export default function StepperList({
+ items,
+ showStepLabel = false
+}: StepperListProps) {
+ return (
+ <>
+ {items.map((item, index) => (
+
+
+
+ {index !== items.length - 1 && (
+
+ )}
+
+
+ {showStepLabel && (
+
+ Step {index + 1}
+
+ )}
+
{item}
+
+
+ ))}
+ >
+ );
+}