From 56df0c0da002f91f55b6ecd557d13ab6b6eaf1f1 Mon Sep 17 00:00:00 2001 From: Maina Wycliffe Date: Wed, 25 Sep 2024 10:31:46 +0300 Subject: [PATCH] feat: add permissions tabs for connection and playbooks Fixes #2246 fix: fix minor issues related to the permissions tab fix: fix failing tests and hard delete permissions fix: don't allow deleting of crd source permissions fix: fix failing test feat: add form for adding permissions in resource and fix form issues Fixes #2246 fix: fix failing build due to removed search layout component --- src/api/services/permissions.ts | 4 +- .../Configs/ConfigLink/ConfigLink.tsx | 9 +- .../Connections/ConnectionFormModal.tsx | 131 ++++++++++++------ .../Forms/PermissionForm.tsx | 66 +++++---- .../Permissions/PermissionsView.tsx | 34 ++++- .../Settings/PlaybookSpecFormModal.tsx | 39 +++++- .../SchemaResourcePage/resourceTypes.tsx | 6 +- src/components/Settings/ResourceTable.tsx | 3 +- src/pages/Settings/ConnectionsPage.tsx | 21 ++- src/pages/Settings/PermissionsPage.tsx | 2 +- 10 files changed, 218 insertions(+), 97 deletions(-) diff --git a/src/api/services/permissions.ts b/src/api/services/permissions.ts index d4ba39174..f19653b96 100644 --- a/src/api/services/permissions.ts +++ b/src/api/services/permissions.ts @@ -92,7 +92,5 @@ export function updatePermission(permission: PermissionTable) { } export function deletePermission(id: string) { - return IncidentCommander.patch(`/permissions?id=eq.${id}`, { - deleted_at: "now()" - }); + return IncidentCommander.delete(`/permissions?id=eq.${id}`); } diff --git a/src/components/Configs/ConfigLink/ConfigLink.tsx b/src/components/Configs/ConfigLink/ConfigLink.tsx index 36ac9d4f4..c27468184 100644 --- a/src/components/Configs/ConfigLink/ConfigLink.tsx +++ b/src/components/Configs/ConfigLink/ConfigLink.tsx @@ -1,6 +1,5 @@ import { getConfigsByID } from "@flanksource-ui/api/services/configs"; import { ConfigIcon } from "@flanksource-ui/ui/Icons/ConfigIcon"; -import TextSkeletonLoader from "@flanksource-ui/ui/SkeletonLoader/TextSkeletonLoader"; import { useQuery } from "@tanstack/react-query"; import clsx from "clsx"; import { HTMLAttributeAnchorTarget } from "react"; @@ -26,7 +25,7 @@ export default function ConfigLink({ showPrimaryIcon = true, showSecondaryIcon = true }: ConfigLinkProps) { - const { data: configFromRequest, isLoading } = useQuery({ + const { data: configFromRequest } = useQuery({ queryKey: ["config", configId, config], queryFn: () => getConfigsByID(configId!), // Only run the query if we have a configId and we don't have a config @@ -35,9 +34,9 @@ export default function ConfigLink({ const data = config || configFromRequest; - if (isLoading) { - return ; - } + // if (isLoading) { + // return ; + // } if (!data) { return null; diff --git a/src/components/Connections/ConnectionFormModal.tsx b/src/components/Connections/ConnectionFormModal.tsx index 8db2a6dd4..66eb9c9b7 100644 --- a/src/components/Connections/ConnectionFormModal.tsx +++ b/src/components/Connections/ConnectionFormModal.tsx @@ -1,6 +1,8 @@ +import { Tab, Tabs } from "@flanksource-ui/ui/Tabs/Tabs"; import React, { useEffect, useState } from "react"; import { Icon } from "../../ui/Icons/Icon"; import { Modal } from "../../ui/Modal"; +import PermissionsView from "../Permissions/PermissionsView"; import ConnectionForm from "./ConnectionForm"; import ConnectionListView from "./ConnectionListView"; import ConnectionSpecEditor from "./ConnectionSpecEditor"; @@ -81,6 +83,8 @@ export default function ConnectionFormModal({ ConnectionType | undefined >(() => connectionTypes.find((item) => item.title === formValue?.type)); + const [activeTab, setActiveTab] = useState<"form" | "permissions">("form"); + useEffect(() => { let connection = connectionTypes.find( (item) => item.value === formValue?.type @@ -93,35 +97,76 @@ export default function ConnectionFormModal({ connectionType; return ( -
- - {typeof connectionType?.icon === "string" ? ( - - ) : ( - connectionType.icon - )} -
- {connectionType.title} Connection Details -
+ + {typeof connectionType?.icon === "string" ? ( + + ) : ( + connectionType.icon + )} +
+ {connectionType.title} Connection Details
- ) : ( -
Select Connection Type
- ) - } - onClose={() => { - setIsOpen(false); - }} - open={isOpen} - bodyClass="flex flex-col w-full flex-1 h-full overflow-y-auto" - helpLink="reference/connections/" - > - {type ? ( +
+ ) : ( +
Select Connection Type
+ ) + } + onClose={() => { + setIsOpen(false); + }} + open={isOpen} + size="full" + bodyClass="flex flex-col w-full flex-1 h-full overflow-y-auto" + helpLink="reference/connections/" + containerClassName="h-full overflow-auto" + > + {type ? ( + formValue?.id ? ( + setActiveTab(label)} + > + + setConnectionType(undefined)} + connectionType={type} + onConnectionSubmit={onConnectionSubmit} + onConnectionDelete={onConnectionDelete} + formValue={formValue} + className={className} + isSubmitting={isSubmitting} + isDeleting={isDeleting} + /> + + + + + + + ) : ( setConnectionType(undefined)} connectionType={type} @@ -132,20 +177,20 @@ export default function ConnectionFormModal({ isSubmitting={isSubmitting} isDeleting={isDeleting} /> - ) : formValue?.id ? ( - setConnectionType(undefined)} - onConnectionSubmit={onConnectionSubmit} - onConnectionDelete={onConnectionDelete} - formValue={formValue} - className={className} - isSubmitting={isSubmitting} - isDeleting={isDeleting} - /> - ) : ( - - )} - - + ) + ) : formValue?.id ? ( + setConnectionType(undefined)} + onConnectionSubmit={onConnectionSubmit} + onConnectionDelete={onConnectionDelete} + formValue={formValue} + className={className} + isSubmitting={isSubmitting} + isDeleting={isDeleting} + /> + ) : ( + + )} + ); } diff --git a/src/components/Permissions/ManagePermissions/Forms/PermissionForm.tsx b/src/components/Permissions/ManagePermissions/Forms/PermissionForm.tsx index e9e5a9429..d788d5553 100644 --- a/src/components/Permissions/ManagePermissions/Forms/PermissionForm.tsx +++ b/src/components/Permissions/ManagePermissions/Forms/PermissionForm.tsx @@ -6,6 +6,7 @@ import { PermissionTable } from "@flanksource-ui/api/types/permissions"; import FormikCheckbox from "@flanksource-ui/components/Forms/Formik/FormikCheckbox"; import FormikTextArea from "@flanksource-ui/components/Forms/Formik/FormikTextArea"; import FormikTextInput from "@flanksource-ui/components/Forms/Formik/FormikTextInput"; +import CanEditResource from "@flanksource-ui/components/Settings/CanEditResource"; import { toastError, toastSuccess @@ -29,7 +30,7 @@ import PermissionsSubjectControls from "./PermissionSubjectControls"; type PermissionFormProps = { onClose: () => void; isOpen: boolean; - data?: PermissionTable; + data?: Partial; }; export default function PermissionForm({ @@ -43,7 +44,8 @@ export default function PermissionForm({ data?.config_id || data?.canary_id || data?.canary_id || - data?.playbook_id + data?.playbook_id || + data?.connection_id ); }, [data]); @@ -107,7 +109,7 @@ export default function PermissionForm({ config_id: data?.config_id, canary_id: data?.canary_id, playbook_id: data?.playbook_id, - deny: data?.deny, + deny: data?.deny ?? false, description: data?.description, connection_id: data?.connection_id, created_at: data?.created_at, @@ -147,34 +149,42 @@ export default function PermissionForm({ - -
- {data?.id && ( - + {data?.id && ( + + )} +
-
+ + + diff --git a/src/components/Permissions/PermissionsView.tsx b/src/components/Permissions/PermissionsView.tsx index 1406fa2a6..557278631 100644 --- a/src/components/Permissions/PermissionsView.tsx +++ b/src/components/Permissions/PermissionsView.tsx @@ -2,10 +2,14 @@ import { fetchPermissions, FetchPermissionsInput } from "@flanksource-ui/api/services/permissions"; -import { PermissionAPIResponse } from "@flanksource-ui/api/types/permissions"; +import { + PermissionAPIResponse, + PermissionTable +} from "@flanksource-ui/api/types/permissions"; import useReactTablePaginationState from "@flanksource-ui/ui/DataTable/Hooks/useReactTablePaginationState"; import { useQuery } from "@tanstack/react-query"; import { useEffect, useState } from "react"; +import { Button } from ".."; import PermissionForm from "./ManagePermissions/Forms/PermissionForm"; import PermissionsTable from "./PermissionsTable"; @@ -13,16 +17,21 @@ type PermissionsViewProps = { permissionRequest: FetchPermissionsInput; setIsLoading?: (isLoading: boolean) => void; hideResourceColumn?: boolean; + newPermissionData?: Partial; + showAddPermission?: boolean; }; export default function PermissionsView({ permissionRequest, setIsLoading = () => {}, - hideResourceColumn = false + hideResourceColumn = false, + newPermissionData, + showAddPermission = false }: PermissionsViewProps) { const [selectedPermission, setSelectedPermission] = useState(); const { pageSize, pageIndex } = useReactTablePaginationState(); + const [isPermissionModalOpen, setIsPermissionModalOpen] = useState(false); const { isLoading, data, refetch } = useQuery({ queryKey: [ @@ -51,6 +60,17 @@ export default function PermissionsView({ return ( <> + {showAddPermission && ( +
+ +
+ )} )} + {showAddPermission && ( + { + setIsPermissionModalOpen(false); + refetch(); + }} + /> + )} ); } diff --git a/src/components/Playbooks/Settings/PlaybookSpecFormModal.tsx b/src/components/Playbooks/Settings/PlaybookSpecFormModal.tsx index 56ed61354..92f49b47a 100644 --- a/src/components/Playbooks/Settings/PlaybookSpecFormModal.tsx +++ b/src/components/Playbooks/Settings/PlaybookSpecFormModal.tsx @@ -1,5 +1,8 @@ import { PlaybookSpec } from "@flanksource-ui/api/types/playbooks"; +import PermissionsView from "@flanksource-ui/components/Permissions/PermissionsView"; import { Modal } from "@flanksource-ui/ui/Modal"; +import { Tab, Tabs } from "@flanksource-ui/ui/Tabs/Tabs"; +import { useState } from "react"; import PlaybookSpecModalTitle from "../PlaybookSpecModalTitle"; import PlaybookSpecsForm from "./PlaybookSpecsForm"; @@ -16,6 +19,8 @@ export default function PlaybookSpecFormModal({ onClose, ...props }: PlaybookSpecFormModalProps) { + const [activeTab, setActiveTab] = useState<"form" | "permissions">("form"); + return ( - + {playbook?.id ? ( + setActiveTab(label)} + > + + + + + + + + + ) : ( + + )} ); } diff --git a/src/components/SchemaResourcePage/resourceTypes.tsx b/src/components/SchemaResourcePage/resourceTypes.tsx index faa8d88b2..b9461a134 100644 --- a/src/components/SchemaResourcePage/resourceTypes.tsx +++ b/src/components/SchemaResourcePage/resourceTypes.tsx @@ -19,7 +19,8 @@ export type SchemaResourceType = { | "Connections" | "Log Backends" | "Notifications" - | "Feature Flags"; + | "Feature Flags" + | "Permissions"; table: | "teams" | "incident_rules" @@ -29,7 +30,8 @@ export type SchemaResourceType = { | "connections" | "logging_backends" | "notifications" - | "properties"; + | "properties" + | "permissions"; api: "incident-commander" | "canary-checker" | "config-db"; featureName: string; resourceName: string; diff --git a/src/components/Settings/ResourceTable.tsx b/src/components/Settings/ResourceTable.tsx index a21aaecbb..ba2cd7bd0 100644 --- a/src/components/Settings/ResourceTable.tsx +++ b/src/components/Settings/ResourceTable.tsx @@ -266,7 +266,8 @@ const permanentlyHiddenColumnsForTableMap: Record< canaries: ["namespace"], config_scrapers: ["schedule", "namespace"], incident_rules: ["schedule", "namespace"], - teams: ["schedule", "namespace"] + teams: ["schedule", "namespace"], + permissions: ["schedule", "namespace"] }; type ResourceTableProps = { diff --git a/src/pages/Settings/ConnectionsPage.tsx b/src/pages/Settings/ConnectionsPage.tsx index e450d926e..f4653e474 100644 --- a/src/pages/Settings/ConnectionsPage.tsx +++ b/src/pages/Settings/ConnectionsPage.tsx @@ -166,18 +166,17 @@ export function ConnectionsPage() { setEditedRow(val); }} /> - - deleteConnection(data)} - isSubmitting={isSubmitting} - isDeleting={isDeleting} - formValue={editedRow} - key={editedRow?.id || "connection-form"} - /> + deleteConnection(data)} + isSubmitting={isSubmitting} + isDeleting={isDeleting} + formValue={editedRow} + key={editedRow?.id || "connection-form"} + /> ); diff --git a/src/pages/Settings/PermissionsPage.tsx b/src/pages/Settings/PermissionsPage.tsx index a6f2ba767..c601e9e95 100644 --- a/src/pages/Settings/PermissionsPage.tsx +++ b/src/pages/Settings/PermissionsPage.tsx @@ -1,4 +1,3 @@ -import { SearchLayout } from "@flanksource-ui/components/Layout/SearchLayout"; import { AuthorizationAccessCheck } from "@flanksource-ui/components/Permissions/AuthorizationAccessCheck"; import AddPermissionButton from "@flanksource-ui/components/Permissions/ManagePermissions/Forms/AddPermissionButton"; import PermissionsView from "@flanksource-ui/components/Permissions/PermissionsView"; @@ -8,6 +7,7 @@ import { BreadcrumbRoot } from "@flanksource-ui/ui/BreadcrumbNav"; import { Head } from "@flanksource-ui/ui/Head"; +import { SearchLayout } from "@flanksource-ui/ui/Layout/SearchLayout"; import { useQueryClient } from "@tanstack/react-query"; import { useState } from "react";