-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: create sidebar layout, apply tailwind styles (#8)
- Loading branch information
1 parent
8a7022f
commit ec8096c
Showing
9 changed files
with
235 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,34 @@ | ||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; | ||
import type { PropsWithChildren } from "react"; | ||
|
||
import { Layout } from "./layout"; | ||
import { CurrentNamespaceProvider, NamespaceProvider } from "./namespaces/namespaces"; | ||
import { Pods } from "./pods/pods"; | ||
|
||
const queryClient = new QueryClient(); | ||
|
||
type Provider = ({ children }: PropsWithChildren) => JSX.Element; | ||
|
||
const providers = [NamespaceProvider, CurrentNamespaceProvider]; | ||
|
||
const composeProviders = (providers: Provider[]) => { | ||
return providers.reduce((Prev, Curr) => ({ children }) => ( | ||
<Prev> | ||
<Curr>{children}</Curr> | ||
</Prev> | ||
)); | ||
}; | ||
|
||
const AppProviders = composeProviders(providers); | ||
|
||
export function App() { | ||
return ( | ||
<QueryClientProvider client={queryClient}> | ||
<div className="container"> | ||
<h1>Kube Knots</h1> | ||
|
||
<h2>Pods</h2> | ||
<Pods /> | ||
</div> | ||
<AppProviders> | ||
<Layout> | ||
<Pods /> | ||
</Layout> | ||
</AppProviders> | ||
</QueryClientProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { DocumentMagnifyingGlassIcon } from "@heroicons/react/24/outline"; | ||
import type { PropsWithChildren } from "react"; | ||
|
||
import { NamespaceSelect } from "./namespaces/namespace-select"; | ||
|
||
const navigation = [ | ||
{ name: "Pods", href: "#" }, | ||
{ name: "Jobs", href: "#" }, | ||
]; | ||
|
||
export function Layout({ children }: PropsWithChildren) { | ||
return ( | ||
<div> | ||
<div className="fixed inset-y-0 flex w-40 flex-col bg-gray-200"> | ||
<div className="flex h-16 items-center px-2 font-medium"> | ||
{/* TODO: update logo */} | ||
<DocumentMagnifyingGlassIcon className="mr-2 h-6 w-6" aria-hidden="true" /> | ||
Kube Knots | ||
</div> | ||
|
||
<div className="flex flex-1 flex-col overflow-y-auto"> | ||
<nav className="flex-1 space-y-1 px-2 py-4"> | ||
{navigation.map((item) => ( | ||
<a | ||
key={item.name} | ||
href={item.href} | ||
className="group flex items-center rounded-md p-2 text-sm font-medium text-gray-800 hover:bg-gray-400" | ||
> | ||
{item.name} | ||
</a> | ||
))} | ||
</nav> | ||
</div> | ||
</div> | ||
<div className="flex flex-col pl-40"> | ||
<div className="sticky top-0 z-10 flex h-16 shrink-0 p-2 shadow"> | ||
<NamespaceSelect /> | ||
</div> | ||
|
||
<main className="flex-1"> | ||
<div className="py-6"> | ||
<div className="mx-auto max-w-7xl px-4"> | ||
<div className="py-4">{children}</div> | ||
</div> | ||
</div> | ||
</main> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { Combobox } from "@headlessui/react"; | ||
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid"; | ||
import { useState } from "react"; | ||
|
||
import { useCurrentNamespace, useNamespace } from "./namespaces"; | ||
|
||
export function NamespaceSelect() { | ||
const [query, setQuery] = useState(""); | ||
const { namespace, updateNamespace } = useCurrentNamespace(); | ||
const namespaces = useNamespace(); | ||
|
||
const filteredNamespaces = ["All namespaces"].concat( | ||
namespaces.filter((namespace) => { | ||
return namespace.toLowerCase().includes(query.toLowerCase()); | ||
}) | ||
); | ||
|
||
return ( | ||
<Combobox as="div" value={namespace} onChange={updateNamespace}> | ||
<div className="relative mt-1"> | ||
<Combobox.Input | ||
className="w-full rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 shadow-sm focus:border-slate-500 focus:outline-none focus:ring-1 focus:ring-slate-500" | ||
onChange={(event) => setQuery(event.target.value)} | ||
/> | ||
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none"> | ||
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" /> | ||
</Combobox.Button> | ||
|
||
{filteredNamespaces.length > 0 && ( | ||
<Combobox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none"> | ||
{filteredNamespaces.map((namespace) => ( | ||
<Combobox.Option | ||
key={namespace} | ||
value={namespace} | ||
className={({ active }) => | ||
` | ||
relative cursor-default select-none py-2 pl-3 pr-9 | ||
${active ? "bg-slate-600 text-white" : "text-gray-900"} | ||
` | ||
} | ||
> | ||
{({ active, selected }) => ( | ||
<> | ||
<span | ||
className={`block cursor-pointer truncate ${selected ? "font-semibold" : ""}`} | ||
> | ||
{namespace} | ||
</span> | ||
|
||
{selected && ( | ||
<span | ||
className={` | ||
absolute inset-y-0 right-0 flex items-center pr-4 | ||
${active ? "text-white" : "text-slate-600"} | ||
`} | ||
> | ||
<CheckIcon className="h-5 w-5" aria-hidden="true" /> | ||
</span> | ||
)} | ||
</> | ||
)} | ||
</Combobox.Option> | ||
))} | ||
</Combobox.Options> | ||
)} | ||
</div> | ||
</Combobox> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,44 @@ | ||
import type { V1Namespace } from "@kubernetes/client-node"; | ||
import { useQuery } from "@tanstack/react-query"; | ||
import { invoke } from "@tauri-apps/api"; | ||
import { createContext, PropsWithChildren, useContext, useState } from "react"; | ||
|
||
export function Namespaces({ onChange }: { onChange: (namespace: string) => void }) { | ||
const NamespaceContext = createContext<string[]>([]); | ||
|
||
export const useNamespace = () => useContext(NamespaceContext); | ||
|
||
export function NamespaceProvider({ children }: PropsWithChildren) { | ||
const result = useQuery(["namespaces"], () => { | ||
return invoke<{ items: V1Namespace[] }>("get_namespaces"); | ||
}); | ||
|
||
if (!result.isSuccess) { | ||
return <div>Error</div>; | ||
} | ||
const namespaces = result.data?.items.map((item) => item.metadata?.name ?? ""); | ||
|
||
return <NamespaceContext.Provider value={namespaces ?? []}>{children}</NamespaceContext.Provider>; | ||
} | ||
|
||
const CurrentNamespaceContext = createContext<{ | ||
namespace: string | undefined; | ||
updateNamespace: (ns: string) => void; | ||
}>({ namespace: undefined, updateNamespace: () => null }); | ||
|
||
export const useCurrentNamespace = () => useContext(CurrentNamespaceContext); | ||
|
||
export function CurrentNamespaceProvider({ children }: PropsWithChildren) { | ||
const [namespace, setNamespace] = useState<string | undefined>(); | ||
|
||
const updateNamespace = (ns: string) => { | ||
// TODO: update to a const | ||
if (ns === "All namespaces") { | ||
setNamespace(undefined); | ||
} else { | ||
setNamespace(ns); | ||
} | ||
}; | ||
|
||
return ( | ||
<select name="namespaces" onChange={(e) => onChange(e.target.value)}> | ||
<option>All</option> | ||
{result.data.items.map((item) => ( | ||
<option key={item.metadata?.name} value={item.metadata?.name}> | ||
{item.metadata?.name} | ||
</option> | ||
))} | ||
</select> | ||
<CurrentNamespaceContext.Provider value={{ namespace, updateNamespace }}> | ||
{children} | ||
</CurrentNamespaceContext.Provider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,5 @@ module.exports = { | |
theme: { | ||
extend: {}, | ||
}, | ||
plugins: [], | ||
plugins: [require('@tailwindcss/forms')], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters