Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions src/api/types/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ export type PermissionGlobalObject =
| "playbook"
| "topology";

type PermissionObjectSelector = {
playbooks?: Selectors[];
connections?: Selectors[];
configs?: Selectors[];
components?: Selectors[];
scopes?: ScopeSelector[];
};

interface Selectors {}

interface ScopeSelector {
namespace?: string;
name: string;
}

export type PermissionTable = {
id: string;
description: string;
Expand All @@ -35,7 +50,7 @@ export type PermissionTable = {

// Resources
object?: PermissionGlobalObject;
object_selector?: Record<string, any>[];
object_selector?: PermissionObjectSelector;
component_id?: string;
canary_id?: string;
config_id?: string;
Expand Down Expand Up @@ -81,12 +96,3 @@ export type PermissionsSummary = PermissionTable & {
connection_object: Pick<Connection, "id" | "name" | "type">;
component_object: Pick<Topology, "id" | "name" | "icon">;
};

type PermissionObjectSelector = {
playbooks: Selectors[];
connections: Selectors[];
configs: Selectors[];
components: Selectors[];
};

interface Selectors {}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import FormikSelectDropdown from "@flanksource-ui/components/Forms/Formik/Formik
import { Switch } from "@flanksource-ui/ui/FormControls/Switch";
import { useFormikContext } from "formik";
import { useState } from "react";
import FormikScopeMultiSelect from "./FormikScopeMultiSelect";

export const permissionObjectList = [
{ label: "Canaries", value: "canaries" },
Expand All @@ -30,18 +31,26 @@ export default function FormikPermissionSelectResourceFields() {
| "Canary"
| "Playbook"
| "Connection"
| "Global" => {
| "Global"
| "Scope" => {
if (values.playbook_id) return "Playbook";
if (values.config_id) return "Catalog";
if (values.component_id) return "Component";
if (values.connection_id) return "Connection";
if (values.canary_id) return "Canary";
if (values.object) return "Global";
if (values.object_selector?.scopes) return "Scope";
return "Catalog";
};

const [switchOption, setSwitchOption] = useState<
"Component" | "Catalog" | "Canary" | "Playbook" | "Connection" | "Global"
| "Component"
| "Catalog"
| "Canary"
| "Playbook"
| "Connection"
| "Global"
| "Scope"
>(getInitialTab());

return (
Expand All @@ -55,7 +64,8 @@ export default function FormikPermissionSelectResourceFields() {
"Component",
"Connection",
"Playbook",
"Global"
"Global",
"Scope"
]}
className="w-auto"
itemsClassName=""
Expand All @@ -69,6 +79,8 @@ export default function FormikPermissionSelectResourceFields() {
setFieldValue("canary_id", undefined);
setFieldValue("component_id", undefined);
setFieldValue("playbook_id", undefined);
setFieldValue("connection_id", undefined);
setFieldValue("object_selector", undefined);
}}
/>
</div>
Expand Down Expand Up @@ -116,6 +128,8 @@ export default function FormikPermissionSelectResourceFields() {
options={permissionObjectList}
/>
)}

{switchOption === "Scope" && <FormikScopeMultiSelect />}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useScopesQuery } from "@flanksource-ui/api/query-hooks/useScopesQuery";
import { useField, useFormikContext } from "formik";
import { useMemo } from "react";
import Select from "react-select";

type ScopeRef = {
namespace?: string;
name: string;
};

type ScopeOption = {
value: string;
label: string;
namespace?: string;
name: string;
};

export default function FormikScopeMultiSelect() {
const { setFieldValue } = useFormikContext<Record<string, any>>();
const [field] = useField<{ scopes?: ScopeRef[] }>({
name: "object_selector"
});

const { data: scopes, isLoading } = useScopesQuery();

const scopeOptions = useMemo(() => {
if (!scopes) return [];
return scopes.map((scope) => ({
value: JSON.stringify({
namespace: scope.namespace,
name: scope.name
}),
label: scope.name,
namespace: scope.namespace,
name: scope.name
}));
}, [scopes]);

const selectedScopes = useMemo(() => {
const scopeRefs = field.value?.scopes || [];
return scopeRefs.map((scopeRef) => ({
value: JSON.stringify(scopeRef),
label: scopeRef.name,
namespace: scopeRef.namespace,
name: scopeRef.name
}));
}, [field.value]);

const formatOptionLabel = (option: ScopeOption) => (
<div className="flex items-center justify-between gap-2">
<span>{option.name}</span>
{option.namespace && (
<span className="text-xs text-gray-500">{option.namespace}</span>
)}
</div>
);

return (
<div className="mt-2 flex flex-col gap-2">
<Select
isMulti
isLoading={isLoading}
className="rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
placeholder="Select..."
options={scopeOptions}
value={selectedScopes}
formatOptionLabel={formatOptionLabel}
onChange={(selectedOptions) => {
const scopeRefs = selectedOptions.map((option) =>
JSON.parse(option.value)
);
setFieldValue("object_selector", { scopes: scopeRefs });
}}
onBlur={field.onBlur}
/>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function PermissionActionDropdown({ isDisabled }: { isDisabled?: boolean }) {
if (values.component_id) return "component";
if (values.connection_id) return "connection";
if (values.canary_id) return "canary";
if (values.object_selector?.scopes) return "global";
if (values.object) return "global";
return undefined;
}, [values]);
Expand Down Expand Up @@ -231,6 +232,7 @@ export default function PermissionForm({
playbook_id: permissionData?.playbook_id,
deny: permissionData?.deny ?? false,
object: permissionData?.object,
object_selector: permissionData?.object_selector,
description: permissionData?.description,
connection_id: permissionData?.connection_id,
created_at: permissionData?.created_at,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,30 @@ import { useFormikContext } from "formik";
import { permissionObjectList } from "./FormikPermissionSelectResourceFields";

export default function PermissionResource() {
const { values } = useFormikContext<Record<string, string>>();
const { values } = useFormikContext<Record<string, any>>();

const componentId = values.component_id;
const playbookId = values.playbook_id;
const configId = values.config_id;
const connectionId = values.connection_id;
const object = values.object;
const objectSelector = values.object_selector;

if (object) {
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{permissionObjectList.find((o) => o.value === object)?.label}</>;
}

if (objectSelector?.scopes) {
const scopeNames = objectSelector.scopes
.map((scope: { namespace?: string; name: string }) =>
scope.namespace ? `${scope.namespace}/${scope.name}` : scope.name
)
.join(", ");
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>Scopes: {scopeNames}</>;
}

return (
<div className="flex flex-row items-center">
{componentId && (
Expand Down
Loading