Skip to content

Commit

Permalink
bug fixing, more types
Browse files Browse the repository at this point in the history
  • Loading branch information
Rampage1xx committed Dec 31, 2020
1 parent 9b27231 commit 2796933
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 114 deletions.
17 changes: 7 additions & 10 deletions web-client/src/components/CreateKubeconfigButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ import React, {useState, useEffect} from 'react'
import {httpClient} from '../services/httpClient'
import {Dialog} from '@reach/dialog'
import Editor from 'react-simple-code-editor'
import {useRbac} from "../hooks/useRbac";
import {ClusterRoleBinding, RoleBinding, useRbac} from "../hooks/useRbac";
import {extractUsersRoles} from "../services/role";
import {User} from "../types";
import {Cluster} from "cluster";

/**
* Extracts the valid kubeconfig namespace values
* @param {array} roleBindings
* @param {array} clusterRoleBindings
* @param {object} user
* @returns {*[]}
*/
function getValidNamespaces(roleBindings, clusterRoleBindings, user) {
function getValidNamespaces(roleBindings: RoleBinding[], clusterRoleBindings: ClusterRoleBinding[], user: User): string[] {
const {extractedPairItems} = extractUsersRoles(roleBindings, clusterRoleBindings, user.name);

const uniqueNamespaces = extractedPairItems.length === 0 ? [] : [...new Set(extractedPairItems.map(i => i.namespaces).flat(1))];
Expand All @@ -30,14 +27,14 @@ function getValidNamespaces(roleBindings, clusterRoleBindings, user) {

export default function CreateKubeconfigButton({user}: { user: User }) {

const [showModal, setShowModal] = useState(false)
const [kubeconfig, setKubeconfig] = useState('')
const [copied, setCopied] = useState(false);
const [showModal, setShowModal] = useState<boolean>(false)
const [kubeconfig, setKubeconfig] = useState<string>('')
const [copied, setCopied] = useState<boolean>(false);
const {clusterRoleBindings, roleBindings} = useRbac()
const validNamespaces = getValidNamespaces(roleBindings, clusterRoleBindings, user);

//b) we generate an array of unique namespaces.
const [chosenNamespace, setChosenNamespace] = useState(validNamespaces[0]);
const [chosenNamespace, setChosenNamespace] = useState<string>(validNamespaces[0]);

useEffect(() => {
// !kubeconfig.includes(chosenNamespace) is needed to remake the API request if the chosenNamespace changed
Expand Down
4 changes: 2 additions & 2 deletions web-client/src/components/NamespaceSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useNamespaceList } from '../hooks/useNamespaceList'
import {Namespace, useNamespaceList} from '../hooks/useNamespaceList'
import React, { useState, useEffect } from 'react'

export default function NamespaceSelect({ onSelect }) {
Expand All @@ -7,7 +7,7 @@ export default function NamespaceSelect({ onSelect }) {

useEffect(() => {
if (namespaceList.length > 0 && !selected) {
setSelected(namespaceList[0])
setSelected(namespaceList[0].metadata.name)
}
}, [namespaceList, selected])

Expand Down
104 changes: 57 additions & 47 deletions web-client/src/components/cluster-rolebindings.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import React, { useCallback, useState, useEffect } from 'react'
import React, {useCallback, useState, useEffect} from 'react'
import uuid from 'uuid'
import {ClusterRoleBinding, RoleBinding as RoleBindingType, useRbac} from '../hooks/useRbac'
import { useUsers } from '../hooks/useUsers'
import { ClusterRoleSelect } from './cluster-role-select'
import {useUsers} from '../hooks/useUsers'
import {ClusterRoleSelect} from './cluster-role-select'
import {httpClient} from '../services/httpClient'

export default () => {
const { refreshRbacData, clusterRoleBindings } = useRbac()
const {refreshRbacData, clusterRoleBindings} = useRbac()
const [
hideSystemCusterRoleBindings,
setHideSystemCusterRoleBindings
] = useState(true)

if (!clusterRoleBindings) return <div>no data</div>

const crbs = hideSystemCusterRoleBindings
? clusterRoleBindings.filter(c => {
return !c.roleRef.name.startsWith('system:')
})
return !c.roleRef.name.startsWith('system:')
})
: clusterRoleBindings

return (
<div>
<div style={{ display: 'flex' }}>
<div style={{display: 'flex'}}>
<div>
<h1 style={{ padding: 20, margin: 30, background: 'aqua' }}>
<h1 style={{padding: 20, margin: 30, background: 'aqua'}}>
cluster rolebindings
</h1>
<NewClusterRoleBindingForm fetchData={refreshRbacData} />
<NewClusterRoleBindingForm fetchData={refreshRbacData}/>
<div>
<label>
hide system clusterRoleBindings (role name starting with
Expand Down Expand Up @@ -56,35 +56,45 @@ export default () => {
)
}

function RoleBinding({ rolebinding: rb, fetchData }: {rolebinding: RoleBindingType | ClusterRoleBinding, fetchData}) {
function RoleBinding({rolebinding: rb, fetchData}: { rolebinding: RoleBindingType | ClusterRoleBinding, fetchData }) {
const [, setShowMore] = useState(false)

async function deleteRoleBinding(e) {
// we check if its a rolebinding
if ("namespace" in rb.metadata) {
await httpClient.post('/api/delete-rolebinding', {
rolebindingName: rb.metadata.name,
namespace: rb.metadata.namespace
})
fetchData()
return
}
//cluster role binding case
await httpClient.post('/api/delete-cluster-rolebinding', {
rolebindingName: rb.metadata.name,
namespace: rb.metadata.namespace
})

fetchData()
}

return (
<div
onMouseEnter={() => setShowMore(true)}
onMouseLeave={() => setShowMore(false)}
style={{ padding: 20, margin: 30, background: 'aqua' }}
style={{padding: 20, margin: 30, background: 'aqua'}}
>
<button onClick={deleteRoleBinding}>delete</button>

<div>name: {rb.metadata.name}</div>
<div>namespace: {rb.metadata.namespace}</div>
<div>namespace: {rb.metadata['namespace'] ?? "global"}</div>
<div>
<div>role: {rb.roleRef.name}</div>
<div>
subjects:
{(rb.subjects || []).map(s => {
return (
<div key={s.name + s.kind}>
<div style={{ paddingLeft: 10 }}>
<div style={{paddingLeft: 10}}>
name: {s.name} ({s.kind})
</div>
</div>
Expand All @@ -98,11 +108,11 @@ function RoleBinding({ rolebinding: rb, fetchData }: {rolebinding: RoleBindingTy
)
}

function NewClusterRoleBindingForm({ fetchData }) {
function NewClusterRoleBindingForm({fetchData}) {
const [roleName, setRoleName] = useState<string>('')
const [subjects, setSubjects] = useState<object[]>([])
const [clusterRolebindingName, setClusterRolebindingName] = useState('')

async function onSubmit(e) {
e.preventDefault()
await httpClient.post('/api/create-cluster-rolebinding', {
Expand All @@ -115,11 +125,11 @@ function NewClusterRoleBindingForm({ fetchData }) {
})
fetchData()
}

return (
<form
onSubmit={onSubmit}
style={{ padding: 20, margin: 30, background: 'aqua' }}
style={{padding: 20, margin: 30, background: 'aqua'}}
>
<h1>new cluster rolebinding</h1>
<div>
Expand All @@ -133,60 +143,60 @@ function NewClusterRoleBindingForm({ fetchData }) {
/>
</label>
</div>

<ClusterRoleSelect onSelected={cr => setRoleName(cr.metadata.name)} />

<ClusterRoleSelect onSelected={cr => setRoleName(cr.metadata.name)}/>
<div>
<h2>subjects</h2>
<SubjectList
subjects={subjects}
setSubjects={setSubjects}
/>
</div>

<button type="submit">submit</button>
</form>
)
}

function SubjectList({ subjects, setSubjects }) {
function SubjectList({subjects, setSubjects}) {
const addSubject = s => setSubjects(state => [...state, s])
const removeSubject = id =>
setSubjects(state => state.filter(sub => sub.id !== id))

const updateSubject = useCallback(s => {
setSubjects(state => {
return state.map(sub => {
if (s.id === sub.id) {
return s
}

return sub
})
})
}, [setSubjects])

const { users } = useUsers()

const {users} = useUsers()
return (
<div style={{ padding: 10, margin: '20px 0', background: 'orange' }}>
<div style={{padding: 10, margin: '20px 0', background: 'orange'}}>
{subjects.map(s => {
return (
<div key={s.id}>
<SubjectItem id={s.id} updateSubject={updateSubject} />
<SubjectItem id={s.id} updateSubject={updateSubject}/>
<button onClick={() => removeSubject(s.id)} type="button">
delete
</button>
<hr />
<hr/>
</div>
)
})}

<div style={{ marginTop: 20 }}>
<div style={{marginTop: 20}}>
<button
type="button"
onClick={() =>
addSubject({ kind: 'User', name: users[0].name, id: uuid.v4() })
addSubject({kind: 'User', name: users[0].name, id: uuid.v4()})
}
>
new
Expand All @@ -196,19 +206,19 @@ function SubjectList({ subjects, setSubjects }) {
)
}

function SubjectItem({ id, updateSubject }) {
function SubjectItem({id, updateSubject}) {
const [kind, setKind] = useState<string>('User')
const [subjectName, setSubjectName] = useState<string>('')
const { users } = useUsers()

const {users} = useUsers()
useEffect(() => {
setSubjectName(users[0].name)
}, [kind, users])

useEffect(() => {
updateSubject({ id, kind, name: subjectName })
updateSubject({id, kind, name: subjectName})
}, [id, kind, subjectName, updateSubject])

return (
<div>
<div>
Expand Down Expand Up @@ -240,7 +250,7 @@ function SubjectItem({ id, updateSubject }) {
</option>
)
})}

</select>
</label>
</div>
Expand Down
22 changes: 16 additions & 6 deletions web-client/src/hooks/useNamespaceList.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import { useState, useEffect } from 'react'
import {useState, useEffect} from 'react'
import {httpClient} from '../services/httpClient'

export function useNamespaceList() {
export interface Namespace {
metadata: {
name: string
};
}

export interface NamespaceProvider {
namespaceList: Namespace[]
}

export function useNamespaceList(): NamespaceProvider {
const [namespaceList, setNamespaceList] = useState([])
useEffect(() => {
let unmounted = false

httpClient.get('/api/list-namespace').then(res => {
if (!unmounted)
setNamespaceList(
Expand All @@ -19,11 +29,11 @@ export function useNamespaceList() {
})
)
})

return () => {
unmounted = true
}
}, [])

return { namespaceList }
return {namespaceList}
}
9 changes: 5 additions & 4 deletions web-client/src/hooks/useRbac.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, {
import {httpClient} from '../services/httpClient'

interface Metadata {

annotations: { [key: string]: string }
creationTimestamp: string
labels: { [key: string]: string }
Expand All @@ -18,7 +19,7 @@ interface Metadata {
uid: string
}

interface MetadataLocalResource extends Metadata {
interface MetadataNamespacedResource extends Metadata {
namespace: string
}

Expand Down Expand Up @@ -63,12 +64,12 @@ export interface ClusterRole {
}

export interface Roles {
metadata: MetadataLocalResource
metadata: MetadataNamespacedResource
rules: Role[]
}

export interface RoleBinding {
metadata: MetadataLocalResource
metadata: MetadataNamespacedResource
roleRef: RoleRef
subjects: Subject[]
}
Expand All @@ -81,7 +82,7 @@ export interface RbacProvider {

/**
* requests the RbacProvider data again
* @type RbacProvider
* @see RbacProvider
*/
refreshRbacData(): void
}
Expand Down
1 change: 0 additions & 1 deletion web-client/src/services/httpClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import axios from 'axios';
/**
* it is possible to customize the url with the env variable REACT_APP_BACKEND_URL.
* Useful for local development.
* @type {AxiosInstance}
*/
const httpClient = axios.create({
url: process.env.REACT_APP_BACKEND_URL ? process.env.REACT_APP_BACKEND_URL : "",
Expand Down
Loading

0 comments on commit 2796933

Please sign in to comment.