Skip to content

Commit

Permalink
feat: add feature to download kubeconfig with instructions on how to …
Browse files Browse the repository at this point in the history
…apply

fixes #2149
  • Loading branch information
mainawycliffe authored and moshloop committed Aug 13, 2024
1 parent 5e5d5ed commit 8d5dfb8
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 13 deletions.
17 changes: 15 additions & 2 deletions src/components/Authentication/Kratos/KratosUserProfileDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -56,6 +61,14 @@ export function KratosUserProfileDropdown() {
</a>
</Menu.Item>
))}
<Menu.Item>
<button
onClick={openKubeConfigModal}
className="block border-0 border-b border-gray-200 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 hover:text-gray-900"
>
Download kubeconfig
</button>
</Menu.Item>
<Menu.Item>
<VersionInfo />
</Menu.Item>
Expand Down
82 changes: 82 additions & 0 deletions src/components/KubeConfig/AddKubeConfigModal.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Modal
title={"Download and install kubeconfig"}
onClose={onClose}
open={isOpen}
bodyClass="flex flex-col w-full flex-1 h-full overflow-y-auto"
helpLink="/installation/saas/agent"
>
<div className="flex flex-1 flex-col gap-4 overflow-y-auto p-4">
<div className="flex flex-col">
<div className="flex w-full flex-col gap-1">
<h4 className="block font-semibold">Instructions</h4>

<StepperList
items={[
<div key="step-1">
<Button
onClick={() => {
window.open(downloadKubeConfigURL, "_blank");
}}
>
<IoMdDownload className="mr-2" />
Download kubeconfig file
</Button>
</div>,
<div className="flex flex-col gap-1" key="step-2">
Apply the kubeconfig file to your kubectl configuration{" "}
<CodeBlock
code={`kubectl --kubeconfig ${kubeConfigFilename} get canaries`}
/>
</div>,
<div key="key-2">
<a
className="text-blue-500 hover:underline"
target="_blank"
href="docs.flanksource.com/reference/kubeconfig"
>
Learn more
</a>{" "}
on how to use the Kubernetes Interface to Mission Control
</div>
]}
/>
</div>
</div>
</div>
<div className="flex flex-row justify-end gap-4 p-4">
<Button text="Close" onClick={onClose} />
</div>
</Modal>
);
}
45 changes: 34 additions & 11 deletions src/components/Users/UserProfile.tsx
Original file line number Diff line number Diff line change
@@ -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" ? (
<div className="flex flex-row gap-2 pr-2">
<OrganizationSwitcher
hidePersonal
createOrganizationMode="modal"
afterSelectOrganizationUrl={`/organizations/orgs-switched`}
afterCreateOrganizationUrl={`/organizations/orgs-switched`}
return (
<>
{authSystem === "clerk" ? (
<div className="flex flex-row gap-2 pr-2">
<OrganizationSwitcher
hidePersonal
createOrganizationMode="modal"
afterSelectOrganizationUrl={`/organizations/orgs-switched`}
afterCreateOrganizationUrl={`/organizations/orgs-switched`}
/>
<UserButton signInUrl="/login">
<UserButton.MenuItems>
<UserButton.Action
label="Download kubeconfig"
labelIcon={<IoMdDownload />}
onClick={() => setIsDownloadKubeConfigModalOpen(true)}
/>
</UserButton.MenuItems>
</UserButton>
</div>
) : (
<KratosUserProfileDropdown
openKubeConfigModal={() => setIsDownloadKubeConfigModalOpen(true)}
/>
)}
<AddKubeConfigModal
isOpen={isDownloadKubeConfigModalOpen}
onClose={() => setIsDownloadKubeConfigModalOpen(false)}
/>
<UserButton signInUrl="/login" />
</div>
) : (
<KratosUserProfileDropdown />
</>
);
}
22 changes: 22 additions & 0 deletions src/ui/StepperList.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Meta, StoryFn } from "@storybook/react";
import StepperList from "./StepperList";

export default {
title: "ui/StepperList",
component: StepperList
} satisfies Meta<typeof StepperList>;

const Template: StoryFn<typeof StepperList> = (args) => (
<StepperList {...args} />
);

export const Variant1 = Template.bind({});
Variant1.args = {
items: [
<div key="step-1">Some list item</div>,
<div className="flex flex-col gap-1" key="step-2">
Some list item
</div>,
<div key="key-2">Some other list item</div>
]
};
38 changes: 38 additions & 0 deletions src/ui/StepperList.tsx
Original file line number Diff line number Diff line change
@@ -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) => (
<div className="flex" key={item?.toString()}>
<div className="mr-4 flex flex-col items-center">
<div className="p-1">
<div className="flex h-7 w-7 items-center justify-center rounded-full border border-gray-200">
<p className="text-blue-900">{index + 1}</p>
</div>
</div>
{index !== items.length - 1 && (
<div className="h-full w-px bg-gray-300"></div>
)}
</div>
<div className="flex flex-1 flex-col gap-2 pb-1 pt-1">
{showStepLabel && (
<div className="font-semi-bold text-gray-900">
Step {index + 1}
</div>
)}
<div className="flex flex-col gap-2 text-gray-600">{item}</div>
</div>
</div>
))}
</>
);
}

0 comments on commit 8d5dfb8

Please sign in to comment.