diff --git a/frontend/src/components/resources/resource-sync/pending-or-config.tsx b/frontend/src/components/resources/resource-sync/pending-or-config.tsx index 014a38103..41db17f0c 100644 --- a/frontend/src/components/resources/resource-sync/pending-or-config.tsx +++ b/frontend/src/components/resources/resource-sync/pending-or-config.tsx @@ -54,9 +54,13 @@ export const PendingOrConfig = ({ id }: { id: string }) => {
{pending?.hash && pending.message && ( - - Commit: {pending.hash}: {pending.message} - +
+
Latest Commit
+
|
+
{pending.hash}
+
|
+
{pending.message}
+
)} {pending?.data.type === "Ok" && @@ -103,25 +107,28 @@ const PendingView = ({
{pending.to_create ? ( <> - | +
|
- To Create: {pending.to_create} +
To Create:
+
{pending.to_create}
) : undefined} {pending.to_update ? ( <> - | +
|
- To Update: {pending.to_update} +
To Update:
+
{pending.to_update}
) : undefined} {pending.to_delete ? ( <> - | +
|
- To Delete: {pending.to_delete} +
To Delete:
+
{pending.to_delete}
) : undefined} diff --git a/frontend/src/components/resources/resource-sync/table.tsx b/frontend/src/components/resources/resource-sync/table.tsx index 14c4c2ad9..74b6c9fec 100644 --- a/frontend/src/components/resources/resource-sync/table.tsx +++ b/frontend/src/components/resources/resource-sync/table.tsx @@ -22,6 +22,21 @@ export const ResourceSyncTable = ({ cell: ({ row }) => ( ), + size: 200, + }, + { + accessorKey: "info.repo", + header: ({ column }) => ( + + ), + size: 200, + }, + { + accessorKey: "info.branch", + header: ({ column }) => ( + + ), + size: 200, }, { accessorKey: "info.state", diff --git a/frontend/src/components/sidebar.tsx b/frontend/src/components/sidebar.tsx index e28d5690f..f347b349e 100644 --- a/frontend/src/components/sidebar.tsx +++ b/frontend/src/components/sidebar.tsx @@ -7,10 +7,7 @@ import { Box, Boxes, FolderTree, - Key, - Tag, - User, - Variable, + Settings, } from "lucide-react"; import { Link, useLocation } from "react-router-dom"; import { ResourceComponents } from "./resources"; @@ -18,14 +15,12 @@ import { Separator } from "@ui/separator"; import { ReactNode } from "react"; import { useAtom } from "jotai"; import { homeViewAtom } from "@main"; -import { useUser } from "@lib/hooks"; export const Sidebar = () => { - const user = useUser().data; const [view, setView] = useAtom(homeViewAtom); return ( - + { icon={} /> - } - /> - - } - /> - - {user?.admin && ( - } - /> - )} - } + label="Settings" + to="/settings" + icon={} /> diff --git a/frontend/src/components/topbar.tsx b/frontend/src/components/topbar.tsx index e2a4d6527..a95e566fb 100644 --- a/frontend/src/components/topbar.tsx +++ b/frontend/src/components/topbar.tsx @@ -1,4 +1,4 @@ -import { useRead, useResourceParamType, useUser } from "@lib/hooks"; +import { useRead, useResourceParamType } from "@lib/hooks"; import { ResourceComponents } from "./resources"; import { AlertTriangle, @@ -8,12 +8,10 @@ import { FileQuestion, FolderTree, Home, - Key, SearchX, - Tag, + Settings, User, Users, - Variable, } from "lucide-react"; import { DropdownMenu, @@ -117,8 +115,6 @@ export const Topbar = () => { }; const PrimaryDropdown = () => { - const user = useUser().data; - const type = useResourceParamType(); const Components = type && ResourceComponents[type]; @@ -133,20 +129,15 @@ const PrimaryDropdown = () => { ] : location.pathname === "/" ? [, "Home"] - : location.pathname === "/keys" - ? [, "Api Keys"] - : location.pathname === "/tags" - ? [, "Tags"] - : location.pathname === "/variables" - ? [, "Variables"] + : location.pathname === "/settings" + ? [, "Settings"] : location.pathname === "/alerts" ? [, "Alerts"] : location.pathname === "/updates" ? [, "Updates"] : location.pathname.split("/")[1] === "user-groups" ? [, "User Groups"] - : location.pathname === "/users" || - location.pathname.split("/")[1] === "users" + : location.pathname.split("/")[1] === "users" ? [, "Users"] : [, "Unknown"]; // : [, "Dashboard"]; @@ -199,32 +190,12 @@ const PrimaryDropdown = () => { to="/updates" /> - } - to="/variables" - /> - - } - to="/tags" - /> - - {user?.admin && ( - } - to="/users" - /> - )} - } - to="/keys" + label="Settings" + icon={} + to="/settings" /> diff --git a/frontend/src/pages/settings/index.tsx b/frontend/src/pages/settings/index.tsx new file mode 100644 index 000000000..4340904b2 --- /dev/null +++ b/frontend/src/pages/settings/index.tsx @@ -0,0 +1,57 @@ +import { useLocalStorage, useUser } from "@lib/hooks"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@ui/tabs"; +import { CreateVariable, Variables } from "./variables"; +import { CreateTag, Tags } from "./tags"; +import { UsersPage } from "./users"; +import { CreateKey, Keys } from "./keys"; +import { Page } from "@components/layouts"; +import { useState } from "react"; +import { Input } from "@ui/input"; + +export const Settings = () => { + const user = useUser().data; + const [view, setView] = useLocalStorage("settings-view-v0", "Variables"); + const [search, setSearch] = useState(""); + const currentView = view === "Users" && !user?.admin ? "Variables" : view; + return ( + + +
+ + Variables + Tags + {user?.admin && Users} + Api Keys + + + {currentView === "Variables" && } + {currentView === "Tags" && } + {currentView === "Api Keys" && } + {currentView === "Users" && ( + setSearch(e.target.value)} + className="w-[250px]" + /> + )} +
+ + + + + + + + {user?.admin && ( + + + + )} + + + +
+
+ ); +}; diff --git a/frontend/src/pages/keys.tsx b/frontend/src/pages/settings/keys.tsx similarity index 94% rename from frontend/src/pages/keys.tsx rename to frontend/src/pages/settings/keys.tsx index b348f9564..16ae0e11a 100644 --- a/frontend/src/pages/keys.tsx +++ b/frontend/src/pages/settings/keys.tsx @@ -1,4 +1,3 @@ -import { Page } from "@components/layouts"; import { ConfirmButton, CopyButton } from "@components/util"; import { useInvalidate, useManageUser, useRead, useSetTitle } from "@lib/hooks"; import { @@ -11,7 +10,7 @@ import { } from "@ui/dialog"; import { Button } from "@ui/button"; import { useToast } from "@ui/use-toast"; -import { Trash, PlusCircle, Loader2, Check, Key } from "lucide-react"; +import { Trash, PlusCircle, Loader2, Check } from "lucide-react"; import { useState } from "react"; import { Input } from "@ui/input"; import { @@ -26,22 +25,14 @@ import { KeysTable } from "@components/keys/table"; export const Keys = () => { useSetTitle("Api Keys"); const keys = useRead("ListApiKeys", {}).data ?? []; - return ( - } - actions={} - > - - - ); + return ; }; const ONE_DAY_MS = 1000 * 60 * 60 * 24; type ExpiresOptions = "90 days" | "180 days" | "1 year" | "never"; -const CreateKey = () => { +export const CreateKey = () => { const [open, setOpen] = useState(false); const [name, setName] = useState(""); const [expires, setExpires] = useState("never"); diff --git a/frontend/src/pages/tags.tsx b/frontend/src/pages/settings/tags.tsx similarity index 76% rename from frontend/src/pages/tags.tsx rename to frontend/src/pages/settings/tags.tsx index 065e798f3..f865b4eba 100644 --- a/frontend/src/pages/tags.tsx +++ b/frontend/src/pages/settings/tags.tsx @@ -1,4 +1,3 @@ -import { Page } from "@components/layouts"; import { ConfirmButton } from "@components/util"; import { useInvalidate, useRead, useSetTitle, useWrite } from "@lib/hooks"; import { @@ -12,7 +11,7 @@ import { import { Button } from "@ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@ui/card"; import { useToast } from "@ui/use-toast"; -import { Trash, PlusCircle, Loader2, Check, Tag } from "lucide-react"; +import { Trash, PlusCircle, Loader2, Check } from "lucide-react"; import { useState } from "react"; import { Input } from "@ui/input"; import { UpdateUser } from "@components/updates/details"; @@ -26,43 +25,37 @@ export const Tags = () => { const tags = useRead("ListTags", {}).data; return ( - } - actions={} - > -
- setSearch(e.target.value)} - className="w-[200px] lg:w-[300px]" - /> - tag.name.includes(search)) ?? []} - columns={[ - { - header: "Name", - accessorKey: "name", - }, - { - header: "Owner", - cell: ({ row }) => - row.original.owner ? ( - - ) : ( - "Unknown" - ), - }, - { - header: "Delete", - cell: ({ row }) => , - }, - ]} - /> -
-
+
+ setSearch(e.target.value)} + className="w-[200px] lg:w-[300px]" + /> + tag.name.includes(search)) ?? []} + columns={[ + { + header: "Name", + accessorKey: "name", + }, + { + header: "Owner", + cell: ({ row }) => + row.original.owner ? ( + + ) : ( + "Unknown" + ), + }, + { + header: "Delete", + cell: ({ row }) => , + }, + ]} + /> +
); }; @@ -92,7 +85,7 @@ export const TagCards = () => { ); }; -const CreateTag = () => { +export const CreateTag = () => { const { toast } = useToast(); const [open, setOpen] = useState(false); const [name, setName] = useState(""); @@ -117,7 +110,7 @@ const CreateTag = () => { return ( - diff --git a/frontend/src/pages/users.tsx b/frontend/src/pages/settings/users.tsx similarity index 76% rename from frontend/src/pages/users.tsx rename to frontend/src/pages/settings/users.tsx index 84306e67f..8a13f9843 100644 --- a/frontend/src/pages/users.tsx +++ b/frontend/src/pages/settings/users.tsx @@ -1,33 +1,19 @@ -import { Page, Section } from "@components/layouts"; +import { Section } from "@components/layouts"; import { NewServiceUser, NewUserGroup } from "@components/users/new"; import { UserTable } from "@components/users/table"; import { useRead, useSetTitle } from "@lib/hooks"; import { DataTable } from "@ui/data-table"; -import { Input } from "@ui/input"; import { User, Users } from "lucide-react"; -import { useState } from "react"; import { useNavigate } from "react-router-dom"; -export const UsersPage = () => { +export const UsersPage = ({ search }: { search: string }) => { useSetTitle("Users"); const nav = useNavigate(); const groups = useRead("ListUserGroups", {}).data; const users = useRead("ListUsers", {}).data; - const [search, setSearch] = useState(""); const searchSplit = search.split(" "); return ( - } - actions={ - setSearch(e.target.value)} - className="w-[250px]" - /> - } - > +
{/* User Groups */}
{ } />
- +
); }; diff --git a/frontend/src/pages/variables.tsx b/frontend/src/pages/settings/variables.tsx similarity index 56% rename from frontend/src/pages/variables.tsx rename to frontend/src/pages/settings/variables.tsx index 79e885c32..928b2b137 100644 --- a/frontend/src/pages/variables.tsx +++ b/frontend/src/pages/settings/variables.tsx @@ -1,4 +1,3 @@ -import { Page } from "@components/layouts"; import { ConfirmButton, TextUpdateMenu } from "@components/util"; import { useInvalidate, @@ -20,7 +19,7 @@ import { } from "@ui/dialog"; import { Input } from "@ui/input"; import { useToast } from "@ui/use-toast"; -import { Check, Loader2, PlusCircle, Trash, Variable } from "lucide-react"; +import { Check, Loader2, PlusCircle, Trash } from "lucide-react"; import { useState } from "react"; export const Variables = () => { @@ -51,101 +50,95 @@ export const Variables = () => { }, }); return ( - } - actions={} - > -
- setSearch(e.target.value)} - className="w-[200px] lg:w-[300px]" - /> +
+ setSearch(e.target.value)} + className="w-[200px] lg:w-[300px]" + /> - {/** VARIABLES */} - ( - - ), + {/** VARIABLES */} + ( + + ), + }, + { + accessorKey: "value", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + return ( + { + if (row.original.value === value) { + return; + } + updateValue({ name: row.original.name, value }); + }} + triggerClassName="w-full" + disabled={disabled} + fullWidth + /> + ); }, - { - accessorKey: "value", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - return ( - { - if (row.original.value === value) { - return; - } - updateValue({ name: row.original.name, value }); - }} - triggerClassName="w-full" - disabled={disabled} - fullWidth - /> - ); - }, + }, + { + accessorKey: "description", + header: "Description", + cell: ({ row }) => { + return ( + { + if (row.original.description === description) { + return; + } + updateDescription({ + name: row.original.name, + description, + }); + }} + triggerClassName="w-full" + disabled={disabled} + fullWidth + /> + ); }, - { - accessorKey: "description", - header: "Description", - cell: ({ row }) => { - return ( - { - if (row.original.description === description) { - return; - } - updateDescription({ - name: row.original.name, - description, - }); - }} - triggerClassName="w-full" - disabled={disabled} - fullWidth - /> - ); - }, - }, - { - header: "Delete", - cell: ({ row }) => , - }, - ]} - /> + }, + { + header: "Delete", + cell: ({ row }) => , + }, + ]} + /> - {/** SECRETS */} - {secrets.length && ( -
-
Core Secrets:
- {secrets.map((secret) => ( - {secret} - ))} -
- )} -
- + {/** SECRETS */} + {secrets.length && ( +
+
Core Secrets:
+ {secrets.map((secret) => ( + {secret} + ))} +
+ )} +
); }; -const CreateVariable = () => { +export const CreateVariable = () => { const { toast } = useToast(); const [open, setOpen] = useState(false); const [name, setName] = useState(""); @@ -170,7 +163,7 @@ const CreateVariable = () => { return ( - diff --git a/frontend/src/router.tsx b/frontend/src/router.tsx index 3b966268a..cb40351fc 100644 --- a/frontend/src/router.tsx +++ b/frontend/src/router.tsx @@ -3,12 +3,9 @@ import { useUser } from "@lib/hooks"; import { Login } from "@pages/login"; import { Resource } from "@pages/resource"; import { Resources } from "@pages/resources"; -import { Keys } from "@pages/keys"; import { RouterProvider, createBrowserRouter } from "react-router-dom"; import { Tree } from "@pages/home/tree"; -import { Tags } from "@pages/tags"; import { Updates } from "@pages/updates"; -import { UsersPage } from "@pages/users"; import { AllResources } from "@pages/home/all_resources"; import { UserDisabled } from "@pages/user_disabled"; import { Home } from "@pages/home"; @@ -16,7 +13,7 @@ import { ResourceStats } from "@pages/resource_stats"; import { Alerts } from "@pages/alerts"; import { UserPage } from "@pages/user"; import { UserGroupPage } from "@pages/user-group"; -import { Variables } from "@pages/variables"; +import { Settings } from "@pages/settings"; const ROUTER = createBrowserRouter([ { @@ -24,18 +21,19 @@ const ROUTER = createBrowserRouter([ element: , children: [ { path: "", element: }, - { path: "keys", element: }, - { path: "tags", element: }, + { path: "settings", element: }, + // { path: "keys", element: }, + // { path: "tags", element: }, { path: "tree", element: }, { path: "alerts", element: }, { path: "updates", element: }, - { path: "variables", element: }, + // { path: "variables", element: }, { path: "resources", element: }, { path: "user-groups/:id", element: }, { path: "users", children: [ - { path: "", element: }, + // { path: "", element: }, { path: ":id", element: }, ], },