diff --git a/cyclops-ui/src/components/k8s-resources/ClusterRole.tsx b/cyclops-ui/src/components/k8s-resources/ClusterRole.tsx new file mode 100644 index 00000000..4909f8cf --- /dev/null +++ b/cyclops-ui/src/components/k8s-resources/ClusterRole.tsx @@ -0,0 +1,156 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { Col, Divider, Row, Alert, Table, Tag } from "antd"; +import axios from "axios"; +import { mapResponseError } from "../../utils/api/errors"; +import { isStreamingEnabled } from "../../utils/api/common"; + +interface Props { + name: string; +} + +interface Rule { + verbs?: string[]; + apiGroups?: string[]; + resources?: string[]; + nonResourceURLs?: string[]; +} + +interface ClusterRoleData { + rules: Rule[]; +} + +const ClusterRole = ({ name }: Props) => { + const [clusterRole, setClusterRole] = useState({ + rules: [], + }); + + const [error, setError] = useState({ + message: "", + description: "", + }); + + const fetchClusterRole = useCallback(() => { + axios + .get(`/api/resources`, { + params: { + group: `rbac.authorization.k8s.io`, + version: `v1`, + kind: `ClusterRole`, + name: name, + }, + }) + .then((res) => { + setClusterRole({ + rules: res.data.rules || [], + }); + }) + .catch((error) => { + setError(mapResponseError(error)); + }); + }, [name]); + + useEffect(() => { + fetchClusterRole(); + + const interval = setInterval(() => fetchClusterRole(), 15000); + return () => { + clearInterval(interval); + }; + }, [fetchClusterRole]); + + const columns = [ + { + title: "Verbs", + dataIndex: "verbs", + key: "verbs", + render: (verbs?: string[]) => ( + <> + {verbs?.map((verb) => ( + + {verb} + + ))} + + ), + }, + { + title: "API Groups", + dataIndex: "apiGroups", + key: "apiGroups", + render: (apiGroups?: string[]) => ( + <> + {apiGroups?.map((group) => ( + + {group || "*"} + + ))} + + ), + }, + { + title: "Resources", + dataIndex: "resources", + key: "resources", + render: (resources?: string[]) => ( + <> + {resources?.map((resource) => ( + + {resource} + + ))} + + ), + }, + ]; + + if (clusterRole.rules.some((rule) => rule.nonResourceURLs)) { + columns.push({ + title: "Non resource URLs", + dataIndex: "nonResourceURLs", + key: "nonResourceURLs", + render: (nonResourceURLs?: string[]) => ( + <> + {nonResourceURLs?.map((url) => ( + + {url} + + ))} + + ), + }); + } + + return ( +
+ {error.message.length !== 0 && ( + { + setError({ + message: "", + description: "", + }); + }} + style={{ marginBottom: "20px" }} + /> + )} + + Rules + + + + + + + + ); +}; + +export default ClusterRole; diff --git a/cyclops-ui/src/components/k8s-resources/ResourceList/ResourceList.tsx b/cyclops-ui/src/components/k8s-resources/ResourceList/ResourceList.tsx index 15ee2328..dcea7f49 100644 --- a/cyclops-ui/src/components/k8s-resources/ResourceList/ResourceList.tsx +++ b/cyclops-ui/src/components/k8s-resources/ResourceList/ResourceList.tsx @@ -27,6 +27,7 @@ import DaemonSet from "../DaemonSet"; import StatefulSet from "../StatefulSet"; import Pod from "../Pod"; import Service from "../Service"; +import ClusterRole from "../ClusterRole"; import ConfigMap from "../ConfigMap"; import PersistentVolumeClaim from "../PersistentVolumeClaim"; import Secret from "../Secret"; @@ -329,6 +330,9 @@ const ResourceList = ({ ); break; + case "ClusterRole": + resourceDetails = ; + break; } let deletedWarning =

;