From 3648a6efd477dfcd6fe4e4ce107bfeddfc844c34 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Wed, 18 Jan 2023 06:22:13 +0000 Subject: [PATCH] handle permissions --- .../tabs/{Owners.tsx => Permissions.tsx} | 85 ++++++++++-------- frontend/src/components/build/tabs/Tabs.tsx | 2 +- .../src/components/deployment/Deployment.tsx | 4 +- frontend/src/components/deployment/Header.tsx | 4 +- .../tabs/{config => }/Permissions.tsx | 47 +++++----- .../src/components/deployment/tabs/Tabs.tsx | 2 +- .../deployment/tabs/config/Config.tsx | 2 +- frontend/src/components/home/Tree/Build.tsx | 20 ----- .../src/components/home/Tree/Deployment.tsx | 21 ----- .../tabs/{Owners.tsx => Permissions.tsx} | 90 ++++++++++--------- frontend/src/components/server/tabs/Tabs.tsx | 8 +- .../components/server/tabs/config/Address.tsx | 4 +- .../components/server/tabs/config/Alerts.tsx | 5 +- .../components/server/tabs/config/Config.tsx | 2 +- .../components/server/tabs/config/Enabled.tsx | 3 +- .../components/server/tabs/config/Info.tsx | 3 +- .../server/tabs/config/Networks.tsx | 2 +- .../server/tabs/config/ToNotify.tsx | 49 +++++----- .../src/components/topbar/Search/Search.tsx | 10 +-- frontend/src/state/hooks.ts | 8 +- frontend/src/state/ws.ts | 22 +++++ 21 files changed, 207 insertions(+), 186 deletions(-) rename frontend/src/components/build/tabs/{Owners.tsx => Permissions.tsx} (69%) rename frontend/src/components/deployment/tabs/{config => }/Permissions.tsx (83%) rename frontend/src/components/server/tabs/{Owners.tsx => Permissions.tsx} (67%) diff --git a/frontend/src/components/build/tabs/Owners.tsx b/frontend/src/components/build/tabs/Permissions.tsx similarity index 69% rename from frontend/src/components/build/tabs/Owners.tsx rename to frontend/src/components/build/tabs/Permissions.tsx index 3cdb6ac3c..4f6996d14 100644 --- a/frontend/src/components/build/tabs/Owners.tsx +++ b/frontend/src/components/build/tabs/Permissions.tsx @@ -32,9 +32,9 @@ const PERMISSIONS_OPTIONS = [ PermissionLevel.Update, ]; -const Owners: Component<{}> = (p) => { +const Permissions: Component<{}> = (p) => { const { ws } = useAppState(); - const { build } = useConfig(); + const { build, reset } = useConfig(); const { user } = useUser(); const params = useParams(); const [userSearch, setUserSearch] = createSignal(""); @@ -54,17 +54,22 @@ const Owners: Component<{}> = (p) => { build.permissions![getId(u)] === PermissionLevel.None) ) ); - let unsub = () => {}; + let unsub_permissions = () => {}; createEffect(() => { - unsub(); - unsub = ws.subscribe( - [Operation.ModifyUserPermissions, Operation.ModifyUserEnabled], - () => { - client.list_users().then(setUsers); - } + unsub_permissions(); + unsub_permissions = ws.subscribe([Operation.ModifyUserPermissions], () => + reset() ); }); - onCleanup(() => unsub()); + onCleanup(() => unsub_permissions()); + let unsub_enabled = () => {}; + createEffect(() => { + unsub_enabled(); + unsub_enabled = ws.subscribe([Operation.ModifyUserEnabled], () => + client.list_users().then(setUsers) + ); + }); + onCleanup(() => unsub_enabled()); return ( @@ -137,34 +142,36 @@ const Owners: Component<{}> = (p) => { {u().username} {user_id === getId(user()) && " ( you )"} - - { - client.update_user_permissions_on_target({ - user_id, - permission: permission as PermissionLevel, - target_type: PermissionsTarget.Build, - target_id: params.id, - }); - }} - position="bottom right" - /> - { - client.update_user_permissions_on_target({ - user_id, - permission: PermissionLevel.None, - target_type: PermissionsTarget.Build, - target_id: params.id, - }); - }} - > - remove - - + + + { + client.update_user_permissions_on_target({ + user_id, + permission: permission as PermissionLevel, + target_type: PermissionsTarget.Build, + target_id: params.id, + }); + }} + position="bottom right" + /> + { + client.update_user_permissions_on_target({ + user_id, + permission: PermissionLevel.None, + target_type: PermissionsTarget.Build, + target_id: params.id, + }); + }} + > + remove + + + ); @@ -177,4 +184,4 @@ const Owners: Component<{}> = (p) => { ); }; -export default Owners; +export default Permissions; diff --git a/frontend/src/components/build/tabs/Tabs.tsx b/frontend/src/components/build/tabs/Tabs.tsx index 239e69c25..8916e4e5a 100644 --- a/frontend/src/components/build/tabs/Tabs.tsx +++ b/frontend/src/components/build/tabs/Tabs.tsx @@ -8,7 +8,7 @@ import SimpleTabs from "../../shared/tabs/SimpleTabs"; import { Tab } from "../../shared/tabs/Tabs"; import BuildConfig from "./build-config/BuildConfig"; import GitConfig from "./git-config/GitConfig"; -import Owners from "./Owners"; +import Owners from "./Permissions"; import { ConfigProvider } from "./Provider"; const BuildTabs: Component<{}> = (p) => { diff --git a/frontend/src/components/deployment/Deployment.tsx b/frontend/src/components/deployment/Deployment.tsx index 8869aec5a..36c989942 100644 --- a/frontend/src/components/deployment/Deployment.tsx +++ b/frontend/src/components/deployment/Deployment.tsx @@ -17,7 +17,7 @@ import Updates from "./Updates"; const Deployment2: Component<{}> = (p) => { const { servers, deployments } = useAppState(); - const { isSemiMobile, isMobile } = useAppDimensions(); + const { isSemiMobile } = useAppDimensions(); const params = useParams(); const deployment = () => deployments.get(params.id); const server = () => @@ -42,7 +42,7 @@ const Deployment2: Component<{}> = (p) => {
- + diff --git a/frontend/src/components/deployment/Header.tsx b/frontend/src/components/deployment/Header.tsx index 97dba7cd2..53efdef67 100644 --- a/frontend/src/components/deployment/Header.tsx +++ b/frontend/src/components/deployment/Header.tsx @@ -38,11 +38,11 @@ const Header: Component<{}> = (p) => { class={combineClasses("card shadow")} style={{ position: "relative", - cursor: isSemiMobile() && userCanUpdate() ? "pointer" : undefined, + cursor: isSemiMobile() ? "pointer" : undefined, height: "fit-content", }} onClick={() => { - if (isSemiMobile() && userCanUpdate()) toggleShowUpdates(); + if (isSemiMobile()) toggleShowUpdates(); }} > diff --git a/frontend/src/components/deployment/tabs/config/Permissions.tsx b/frontend/src/components/deployment/tabs/Permissions.tsx similarity index 83% rename from frontend/src/components/deployment/tabs/config/Permissions.tsx rename to frontend/src/components/deployment/tabs/Permissions.tsx index 974653e6f..85f325de9 100644 --- a/frontend/src/components/deployment/tabs/config/Permissions.tsx +++ b/frontend/src/components/deployment/tabs/Permissions.tsx @@ -8,23 +8,23 @@ import { onCleanup, Show, } from "solid-js"; -import { client } from "../../../.."; -import { useAppState } from "../../../../state/StateProvider"; -import { useUser } from "../../../../state/UserProvider"; +import { client } from "../../.."; +import { useAppState } from "../../../state/StateProvider"; +import { useUser } from "../../../state/UserProvider"; import { Operation, PermissionLevel, PermissionsTarget, User, -} from "../../../../types"; -import { combineClasses, getId } from "../../../../util/helpers"; -import ConfirmButton from "../../../shared/ConfirmButton"; -import Input from "../../../shared/Input"; -import Flex from "../../../shared/layout/Flex"; -import Grid from "../../../shared/layout/Grid"; -import Menu from "../../../shared/menu/Menu"; -import Selector from "../../../shared/menu/Selector"; -import { useConfig } from "./Provider"; +} from "../../../types"; +import { combineClasses, getId } from "../../../util/helpers"; +import ConfirmButton from "../../shared/ConfirmButton"; +import Input from "../../shared/Input"; +import Flex from "../../shared/layout/Flex"; +import Grid from "../../shared/layout/Grid"; +import Menu from "../../shared/menu/Menu"; +import Selector from "../../shared/menu/Selector"; +import { useConfig } from "./config/Provider"; const PERMISSIONS_OPTIONS = [ PermissionLevel.Read, @@ -34,7 +34,7 @@ const PERMISSIONS_OPTIONS = [ const Permissions: Component<{}> = (p) => { const { ws } = useAppState(); - const { deployment } = useConfig(); + const { deployment, reset } = useConfig(); const { user } = useUser(); const params = useParams(); const [userSearch, setUserSearch] = createSignal(""); @@ -54,17 +54,22 @@ const Permissions: Component<{}> = (p) => { deployment.permissions![getId(u)] === PermissionLevel.None) ) ); - let unsub = () => {}; + let unsub_permissions = () => {}; createEffect(() => { - unsub(); - unsub = ws.subscribe( - [Operation.ModifyUserPermissions, Operation.ModifyUserEnabled], - () => { - client.list_users().then(setUsers); - } + unsub_permissions(); + unsub_permissions = ws.subscribe([Operation.ModifyUserPermissions], () => + reset() ); }); - onCleanup(() => unsub()); + onCleanup(() => unsub_permissions()); + let unsub_enabled = () => {}; + createEffect(() => { + unsub_enabled(); + unsub_enabled = ws.subscribe([Operation.ModifyUserEnabled], () => + client.list_users().then(setUsers) + ); + }); + onCleanup(() => unsub_enabled()); return ( = () => { diff --git a/frontend/src/components/deployment/tabs/config/Config.tsx b/frontend/src/components/deployment/tabs/config/Config.tsx index 993ec8a1d..f19c6e405 100644 --- a/frontend/src/components/deployment/tabs/config/Config.tsx +++ b/frontend/src/components/deployment/tabs/config/Config.tsx @@ -17,7 +17,7 @@ import { Tab } from "../../../shared/tabs/Tabs"; import RepoMount from "./mount-repo/RepoMount"; import { OnClone, OnPull } from "./mount-repo/OnGit"; import Loading from "../../../shared/loading/Loading"; -import Permissions from "./Permissions"; +import Permissions from "../Permissions"; import { pushNotification, URL } from "../../../.."; import { combineClasses, copyToClipboard, getId } from "../../../../util/helpers"; import { useAppDimensions } from "../../../../state/DimensionProvider"; diff --git a/frontend/src/components/home/Tree/Build.tsx b/frontend/src/components/home/Tree/Build.tsx index 43cabafe3..ab07d4db2 100644 --- a/frontend/src/components/home/Tree/Build.tsx +++ b/frontend/src/components/home/Tree/Build.tsx @@ -1,26 +1,16 @@ import { A } from "@solidjs/router"; import { Component, Show } from "solid-js"; import { useAppState } from "../../../state/StateProvider"; -import { useUser } from "../../../state/UserProvider"; -import { PermissionLevel } from "../../../types"; import { combineClasses, - getId, readableMonitorTimestamp, } from "../../../util/helpers"; -import Icon from "../../shared/Icon"; import Flex from "../../shared/layout/Flex"; -import HoverMenu from "../../shared/menu/HoverMenu"; import s from "../home.module.scss"; const Build: Component<{ id: string }> = (p) => { const { builds } = useAppState(); - const { user } = useUser(); const build = () => builds.get(p.id)!; - const permissionLevel = () => { - const level = build().permissions![getId(user())]; - return level ? level : PermissionLevel.None; - }; const version = () => { return `v${build().version.major}.${build().version.minor}.${ build().version.patch @@ -42,16 +32,6 @@ const Build: Component<{ id: string }> = (p) => {

{build().name}

- - } - content="you are a collaborator" - padding="0.5rem" - position="bottom right" - /> -
{version()}
{lastBuiltAt()}
diff --git a/frontend/src/components/home/Tree/Deployment.tsx b/frontend/src/components/home/Tree/Deployment.tsx index 0a1f56c97..f4a27046e 100644 --- a/frontend/src/components/home/Tree/Deployment.tsx +++ b/frontend/src/components/home/Tree/Deployment.tsx @@ -1,23 +1,14 @@ import { A } from "@solidjs/router"; import { Component, Show } from "solid-js"; import { useAppState } from "../../../state/StateProvider"; -import { useUser } from "../../../state/UserProvider"; -import { PermissionLevel } from "../../../types"; import { combineClasses, deploymentStateClass, getId } from "../../../util/helpers"; import Circle from "../../shared/Circle"; -import Icon from "../../shared/Icon"; import Flex from "../../shared/layout/Flex"; -import HoverMenu from "../../shared/menu/HoverMenu"; import s from "../home.module.scss"; const Deployment: Component<{ id: string }> = (p) => { const { deployments } = useAppState(); - const { user } = useUser(); const deployment = () => deployments.get(p.id)!; - const permissionLevel = () => { - const level = deployment().deployment.permissions![getId(user())]; - return level ? level : PermissionLevel.None; - }; return (
= (p) => { >

{deployment().deployment.name}

- - } - content="you are a collaborator" - padding="0.5rem" - position="bottom center" - /> -
{deployments.status(p.id)}
= (p) => { +const Permissions: Component<{}> = (p) => { const { ws } = useAppState(); - const { server } = useConfig(); + const { server, reset } = useConfig(); const { user } = useUser(); const params = useParams(); const [userSearch, setUserSearch] = createSignal(""); @@ -54,21 +54,29 @@ const Owners: Component<{}> = (p) => { server.permissions![getId(u)] === PermissionLevel.None) ) ); - let unsub = () => {}; + let unsub_permissions = () => {}; createEffect(() => { - unsub(); - unsub = ws.subscribe( - [Operation.ModifyUserPermissions, Operation.ModifyUserEnabled], - () => { - client.list_users().then(setUsers); - } + unsub_permissions(); + unsub_permissions = ws.subscribe([Operation.ModifyUserPermissions], () => + reset() ); }); - onCleanup(() => unsub()); + onCleanup(() => unsub_permissions()); + let unsub_enabled = () => {}; + createEffect(() => { + unsub_enabled(); + unsub_enabled = ws.subscribe([Operation.ModifyUserEnabled], () => + client.list_users().then(setUsers) + ); + }); + onCleanup(() => unsub_enabled()); return ( - + = (p) => { {u().username} {user_id === getId(user()) && " ( you )"} - - { - client.update_user_permissions_on_target({ - user_id, - permission: permission as PermissionLevel, - target_type: PermissionsTarget.Server, - target_id: params.id, - }); - }} - position="bottom right" - /> - { - client.update_user_permissions_on_target({ - user_id, - permission: PermissionLevel.None, - target_type: PermissionsTarget.Server, - target_id: params.id, - }); - }} - > - remove - - + + + { + client.update_user_permissions_on_target({ + user_id, + permission: permission as PermissionLevel, + target_type: PermissionsTarget.Server, + target_id: params.id, + }); + }} + position="bottom right" + /> + { + client.update_user_permissions_on_target({ + user_id, + permission: PermissionLevel.None, + target_type: PermissionsTarget.Server, + target_id: params.id, + }); + }} + > + remove + + + ); @@ -174,4 +184,4 @@ const Owners: Component<{}> = (p) => { ); }; -export default Owners; +export default Permissions; diff --git a/frontend/src/components/server/tabs/Tabs.tsx b/frontend/src/components/server/tabs/Tabs.tsx index f6263caab..1fff1047d 100644 --- a/frontend/src/components/server/tabs/Tabs.tsx +++ b/frontend/src/components/server/tabs/Tabs.tsx @@ -6,7 +6,7 @@ import SimpleTabs from "../../shared/tabs/SimpleTabs"; import { Tab } from "../../shared/tabs/Tabs"; import Config from "./config/Config"; import { ConfigProvider } from "./config/Provider"; -import Owners from "./Owners"; +import Permissions from "./Permissions"; const ServerTabs: Component<{}> = (p) => { const { servers } = useAppState(); @@ -18,7 +18,7 @@ const ServerTabs: Component<{}> = (p) => { = (p) => { element: () => , }, user().admin && { - title: "collaborators", - element: () => , + title: "permissions", + element: () => , }, ].filter((e) => e) as Tab[] } diff --git a/frontend/src/components/server/tabs/config/Address.tsx b/frontend/src/components/server/tabs/config/Address.tsx index 789d3ad59..00a86a7b0 100644 --- a/frontend/src/components/server/tabs/config/Address.tsx +++ b/frontend/src/components/server/tabs/config/Address.tsx @@ -5,17 +5,19 @@ import Flex from "../../../shared/layout/Flex"; import { useConfig } from "./Provider"; const Address: Component<{}> = (p) => { - const { server, setServer } = useConfig(); + const { server, setServer, userCanUpdate } = useConfig(); return (

address

setServer("address", value)} + disabled={!userCanUpdate()} />
); diff --git a/frontend/src/components/server/tabs/config/Alerts.tsx b/frontend/src/components/server/tabs/config/Alerts.tsx index 4e467b1e0..089b48456 100644 --- a/frontend/src/components/server/tabs/config/Alerts.tsx +++ b/frontend/src/components/server/tabs/config/Alerts.tsx @@ -7,7 +7,7 @@ import Grid from "../../../shared/layout/Grid"; import { useConfig } from "./Provider"; const Alerts: Component<{}> = (p) => { - const { server, setServer } = useConfig(); + const { server, setServer, userCanUpdate } = useConfig(); const [alerts, setAlerts] = createStore({ cpu: server.cpu_alert?.toString(), mem: server.mem_alert?.toString(), @@ -32,6 +32,7 @@ const Alerts: Component<{}> = (p) => { } }} style={{ width: "4rem" }} + disabled={!userCanUpdate()} />
%
@@ -51,6 +52,7 @@ const Alerts: Component<{}> = (p) => { } }} style={{ width: "4rem" }} + disabled={!userCanUpdate()} />
%
@@ -70,6 +72,7 @@ const Alerts: Component<{}> = (p) => { } }} style={{ width: "4rem" }} + disabled={!userCanUpdate()} />
%
diff --git a/frontend/src/components/server/tabs/config/Config.tsx b/frontend/src/components/server/tabs/config/Config.tsx index 9ac5ab3bf..ca3b9de13 100644 --- a/frontend/src/components/server/tabs/config/Config.tsx +++ b/frontend/src/components/server/tabs/config/Config.tsx @@ -19,7 +19,7 @@ const Config: Component<{}> = (p) => {
- + {/* */} diff --git a/frontend/src/components/server/tabs/config/Enabled.tsx b/frontend/src/components/server/tabs/config/Enabled.tsx index 7302d3d8a..f3b20fe6e 100644 --- a/frontend/src/components/server/tabs/config/Enabled.tsx +++ b/frontend/src/components/server/tabs/config/Enabled.tsx @@ -4,7 +4,7 @@ import Flex from "../../../shared/layout/Flex"; import { useConfig } from "./Provider"; const Enabled: Component<{}> = (p) => { - const { server, setServer } = useConfig(); + const { server, setServer, userCanUpdate } = useConfig(); return ( = (p) => { diff --git a/frontend/src/components/server/tabs/config/Info.tsx b/frontend/src/components/server/tabs/config/Info.tsx index 25b51eebb..700c1a09e 100644 --- a/frontend/src/components/server/tabs/config/Info.tsx +++ b/frontend/src/components/server/tabs/config/Info.tsx @@ -6,7 +6,7 @@ import Grid from "../../../shared/layout/Grid"; import { useConfig } from "./Provider"; const Info: Component<{}> = (p) => { - const { server, setServer } = useConfig(); + const { server, setServer, userCanUpdate } = useConfig(); return (

info

@@ -15,6 +15,7 @@ const Info: Component<{}> = (p) => { setServer("region", value)} + disabled={!userCanUpdate()} />
{/* diff --git a/frontend/src/components/server/tabs/config/Networks.tsx b/frontend/src/components/server/tabs/config/Networks.tsx index a014e5bc3..9b7f4311d 100644 --- a/frontend/src/components/server/tabs/config/Networks.tsx +++ b/frontend/src/components/server/tabs/config/Networks.tsx @@ -1,5 +1,5 @@ import { Component, createSignal, For } from "solid-js"; -import { pushNotification } from "../../../.."; +import { client, pushNotification } from "../../../.."; import { useAppState } from "../../../../state/StateProvider"; import ConfirmButton from "../../../shared/ConfirmButton"; import Icon from "../../../shared/Icon"; diff --git a/frontend/src/components/server/tabs/config/ToNotify.tsx b/frontend/src/components/server/tabs/config/ToNotify.tsx index fff1b683d..a76426692 100644 --- a/frontend/src/components/server/tabs/config/ToNotify.tsx +++ b/frontend/src/components/server/tabs/config/ToNotify.tsx @@ -7,17 +7,23 @@ import { useConfig } from "./Provider"; import { combineClasses } from "../../../../util/helpers"; const ToNotify: Component<{}> = (p) => { - const { server, setServer } = useConfig(); + const { server, setServer, userCanUpdate } = useConfig(); return (

notify

- + + +
{(user, index) => ( @@ -26,23 +32,26 @@ const ToNotify: Component<{}> = (p) => { placeholder="slack user id" value={user} onEdit={(user) => setServer("to_notify", index(), user)} + disabled={!userCanUpdate()} /> - + + +
)} - -
no slack users to notify
-
+ +
no slack users to notify
+
); }; diff --git a/frontend/src/components/topbar/Search/Search.tsx b/frontend/src/components/topbar/Search/Search.tsx index 9dd6f5c11..4716ede89 100644 --- a/frontend/src/components/topbar/Search/Search.tsx +++ b/frontend/src/components/topbar/Search/Search.tsx @@ -74,16 +74,16 @@ export const Search: Component<{}> = (p) => { const SearchMenu: Component<{ close: () => void }> = (p) => { const { tab, input, search } = useSearchState(); - const { isMobile } = useAppDimensions(); + const { isSemiMobile } = useAppDimensions(); let inputRef: HTMLInputElement | undefined; onMount(() => { - if (isMobile()) { + if (isSemiMobile()) { inputRef?.focus(); } }); return ( <> - + inputRef} class={s.SearchInput} @@ -91,13 +91,13 @@ const SearchMenu: Component<{ close: () => void }> = (p) => { value={search.value()} onEdit={input.onEdit} onKeyDown={input.onKeyDown(inputRef)} - style={{ width: isMobile() ? "100%" : undefined }} + style={{ width: isSemiMobile() ? "100%" : undefined }} /> ( query: () => Promise>, idPath: string[] ) { - const [collection, { mutate }] = createResource(query); + const [collection, { mutate, refetch }] = createResource(query); const add = (item: T) => { mutate((collection: any) => ({ ...collection, @@ -225,10 +225,11 @@ export function useCollection( mutate((collection: any) => filterOutFromObj(collection, [id])); }; const update = (item: T) => { + const id = getNestedEntry(item, idPath); mutate((collection: any) => ({ ...collection, - [getNestedEntry(item, idPath)]: { - ...collection[getNestedEntry(item, idPath)], + [id]: { + ...collection[id], ...item, }, })); @@ -259,5 +260,6 @@ export function useCollection( loaded, filter, filterArray, + refetch, }; } diff --git a/frontend/src/state/ws.ts b/frontend/src/state/ws.ts index 799be972e..40af4c543 100644 --- a/frontend/src/state/ws.ts +++ b/frontend/src/state/ws.ts @@ -183,6 +183,28 @@ async function handleMessage( procedures.update(procedure); } } + + // permissions + else if (update.operation === Operation.ModifyUserPermissions) { + if (update.status === UpdateStatus.Complete) { + if (update.target.type === "Build") { + const build = await client.get_build(update.target.id); + builds.update(build); + } else if (update.target.type === "Deployment") { + const deployment = await client.get_deployment(update.target.id); + deployments.update(deployment); + } else if (update.target.type === "Server") { + const server = await client.get_server(update.target.id); + servers.update(server); + } else if (update.target.type === "Group") { + const group = await client.get_group(update.target.id); + groups.update(group); + } else if (update.target.type === "Procedure") { + const procedure = await client.get_procedure(update.target.id); + procedures.update(procedure); + } + } + } } export default connectToWs;