mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-09-27 13:33:26 +00:00
Merge remote-tracking branch 'origin/feature/ui/TRA-4192_workspace_management' into origin/ui/TRA-4204_user_managment
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import logo from '../assets/MizuEntLogo.svg';
|
import logo from '../assets/MizuEntLogo.svg';
|
||||||
import './Header.sass';
|
import './Header.sass';
|
||||||
import userImg from '../assets/user-circle.svg';
|
import userImg from '../assets/user-circle.svg';
|
||||||
@@ -12,6 +12,7 @@ import {useSetRecoilState} from "recoil";
|
|||||||
import entPageAtom, {Page} from "../../recoil/entPage";
|
import entPageAtom, {Page} from "../../recoil/entPage";
|
||||||
import {useNavigate} from "react-router-dom";
|
import {useNavigate} from "react-router-dom";
|
||||||
import {RouterRoutes} from "../../helpers/routes";
|
import {RouterRoutes} from "../../helpers/routes";
|
||||||
|
import { SettingsModal } from "../SettingsModal/SettingModal";
|
||||||
|
|
||||||
const api = Api.getInstance();
|
const api = Api.getInstance();
|
||||||
|
|
||||||
@@ -23,6 +24,19 @@ interface EntHeaderProps {
|
|||||||
export const EntHeader: React.FC<EntHeaderProps> = ({isFirstLogin, setIsFirstLogin}) => {
|
export const EntHeader: React.FC<EntHeaderProps> = ({isFirstLogin, setIsFirstLogin}) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(isFirstLogin) {
|
||||||
|
setIsSettingsModalOpen(true)
|
||||||
|
}
|
||||||
|
}, [isFirstLogin])
|
||||||
|
|
||||||
|
const onSettingsModalClose = () => {
|
||||||
|
setIsSettingsModalOpen(false);
|
||||||
|
setIsFirstLogin(false);
|
||||||
|
}
|
||||||
|
|
||||||
return <div className="header">
|
return <div className="header">
|
||||||
<div>
|
<div>
|
||||||
<div className="title">
|
<div className="title">
|
||||||
@@ -33,9 +47,11 @@ export const EntHeader: React.FC<EntHeaderProps> = ({isFirstLogin, setIsFirstLog
|
|||||||
<img className="headerIcon" alt="settings" src={settingImg} style={{marginRight: 25}} onClick={() => navigate(RouterRoutes.SETTINGS)}/>
|
<img className="headerIcon" alt="settings" src={settingImg} style={{marginRight: 25}} onClick={() => navigate(RouterRoutes.SETTINGS)}/>
|
||||||
<ProfileButton/>
|
<ProfileButton/>
|
||||||
</div>
|
</div>
|
||||||
|
<SettingsModal isOpen={isSettingsModalOpen} onClose={onSettingsModalClose} isFirstLogin={isFirstLogin}/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ProfileButton = () => {
|
const ProfileButton = () => {
|
||||||
|
|
||||||
const setEntPage = useSetRecoilState(entPageAtom);
|
const setEntPage = useSetRecoilState(entPageAtom);
|
||||||
|
@@ -49,6 +49,7 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
|
<<<<<<< HEAD
|
||||||
// const workspacesList = [
|
// const workspacesList = [
|
||||||
// {
|
// {
|
||||||
// "id": "f54b18ec-aa15-4b2c-a4d5-8eda17e44c93",
|
// "id": "f54b18ec-aa15-4b2c-a4d5-8eda17e44c93",
|
||||||
@@ -63,6 +64,21 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
const list = await api.getWorkspaces()
|
const list = await api.getWorkspaces()
|
||||||
const workspacesList = list.map((obj) => {return {key:obj.id, value:obj.name,isChecked:false}})
|
const workspacesList = list.map((obj) => {return {key:obj.id, value:obj.name,isChecked:false}})
|
||||||
setWorkspaces(workspacesList)
|
setWorkspaces(workspacesList)
|
||||||
|
=======
|
||||||
|
const workspacesList = [
|
||||||
|
{
|
||||||
|
"id": "f54b18ec-aa15-4b2c-a4d5-8eda17e44c93",
|
||||||
|
"name": "sock-shop"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c7ad9158-d840-46c0-b5ce-2487c013723f",
|
||||||
|
"name": "test"
|
||||||
|
}
|
||||||
|
].map((obj) => {return {key:obj.id, value:obj.name}})
|
||||||
|
//await api.getWorkspaces()
|
||||||
|
setWorkspaces(workspacesList)
|
||||||
|
|
||||||
|
>>>>>>> origin/feature/ui/TRA-4192_workspace_management
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.error("Error finding workspaces")
|
toast.error("Error finding workspaces")
|
||||||
}
|
}
|
||||||
@@ -256,8 +272,8 @@ export const AddUserModal: FC<AddUserModalProps> = ({isOpen, onCloseModal, userD
|
|||||||
<input className={classes.textField + " search-workspace"} placeholder="Search" value={searchValue}
|
<input className={classes.textField + " search-workspace"} placeholder="Search" value={searchValue}
|
||||||
onChange={(event) => setSearchValue(event.target.value)}/>
|
onChange={(event) => setSearchValue(event.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<SelectList valuesListInput={workspaces} tableName={''} multiSelect={false} searchValue={searchValue}
|
<SelectList items={workspaces} tableName={''} multiSelect={false} searchValue={searchValue}
|
||||||
setValues= {workspaceChange} tabelClassName={''}>
|
setCheckedValues={workspaceChange} tabelClassName={''} checkedValues={[]} >
|
||||||
</SelectList>
|
</SelectList>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -4,8 +4,10 @@ import { useCommonStyles } from '../../../helpers/commonStyle';
|
|||||||
import ConfirmationModal from '../../UI/Modals/ConfirmationModal';
|
import ConfirmationModal from '../../UI/Modals/ConfirmationModal';
|
||||||
import SelectList from '../../UI/SelectList';
|
import SelectList from '../../UI/SelectList';
|
||||||
import './AddWorkspaceModal.sass'
|
import './AddWorkspaceModal.sass'
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
export type WorkspaceData = {
|
export type WorkspaceData = {
|
||||||
|
id:string;
|
||||||
name:string;
|
name:string;
|
||||||
namespaces: string[];
|
namespaces: string[];
|
||||||
}
|
}
|
||||||
@@ -13,34 +15,38 @@ export type WorkspaceData = {
|
|||||||
interface AddWorkspaceModalProp {
|
interface AddWorkspaceModalProp {
|
||||||
isOpen : boolean,
|
isOpen : boolean,
|
||||||
onCloseModal: () => void,
|
onCloseModal: () => void,
|
||||||
workspaceData: WorkspaceData,
|
workspaceId: string,
|
||||||
onEdit: boolean
|
onEdit: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const api = Api.getInstance();
|
const api = Api.getInstance();
|
||||||
|
|
||||||
const AddWorkspaceModal: FC<AddWorkspaceModalProp> = ({isOpen,onCloseModal, workspaceData ={}, onEdit}) => {
|
const AddWorkspaceModal: FC<AddWorkspaceModalProp> = ({isOpen,onCloseModal, workspaceId, onEdit}) => {
|
||||||
|
|
||||||
const [workspaceDataModel, setUserData] = useState(workspaceData as WorkspaceData);
|
|
||||||
const [searchValue, setSearchValue] = useState("");
|
const [searchValue, setSearchValue] = useState("");
|
||||||
const classes = useCommonStyles()
|
|
||||||
const [namespaces, setNamespaces] = useState({});
|
const [workspaceName, setWorkspaceName] = useState("");
|
||||||
|
const [checkedNamespacesKeys, setCheckedNamespacesKeys] = useState([]);
|
||||||
|
const [namespaces, setNamespaces] = useState([]);
|
||||||
|
|
||||||
|
const classes = useCommonStyles();
|
||||||
|
|
||||||
const title = onEdit ? "Edit Workspace" : "Add Workspace";
|
const title = onEdit ? "Edit Workspace" : "Add Workspace";
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(!isOpen) return;
|
if(!isOpen) return;
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
|
if(onEdit){
|
||||||
|
const workspace = await api.getSpecificWorkspace(workspaceId);
|
||||||
|
setWorkspaceName(workspace.name);
|
||||||
|
setCheckedNamespacesKeys(workspace.namespaces);
|
||||||
|
}
|
||||||
setSearchValue("");
|
setSearchValue("");
|
||||||
const tapConfig = await api.getTapConfig();
|
const namespaces = await api.getNamespaces();
|
||||||
const namespacesObj = {...tapConfig?.tappedNamespaces}
|
const namespacesMapped = namespaces.map(namespace => {
|
||||||
Object.keys(tapConfig?.tappedNamespaces ?? {}).forEach(namespace => {
|
return {key: namespace, value: namespace}
|
||||||
namespacesObj[namespace] = true;
|
|
||||||
})
|
})
|
||||||
setNamespaces(namespacesObj);
|
setNamespaces(namespacesMapped);
|
||||||
setNamespaces(tapConfig?.tappedNamespaces);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -48,22 +54,69 @@ const AddWorkspaceModal: FC<AddWorkspaceModalProp> = ({isOpen,onCloseModal, work
|
|||||||
})()
|
})()
|
||||||
}, [isOpen])
|
}, [isOpen])
|
||||||
|
|
||||||
const onConfirm = () => {}
|
const onWorkspaceNameChange = (event) => {
|
||||||
|
setWorkspaceName(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isFormValid = () : boolean => {
|
||||||
|
return (workspaceName.length > 0) && (checkedNamespacesKeys.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onConfirm = async () => {
|
||||||
|
try{
|
||||||
|
const workspaceData = {
|
||||||
|
name: workspaceName,
|
||||||
|
namespaces: checkedNamespacesKeys
|
||||||
|
}
|
||||||
|
if(onEdit){
|
||||||
|
await api.editWorkspace(workspaceId, workspaceData);
|
||||||
|
toast.success("Workspace Succesesfully Updated");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
await api.createWorkspace(workspaceData);
|
||||||
|
toast.success("Workspace Succesesfully Created ");
|
||||||
|
}
|
||||||
|
resetForm();
|
||||||
|
onCloseModal();
|
||||||
|
} catch{
|
||||||
|
toast.error("Couldn't Creat The Worksapce");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
onCloseModal();
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
setWorkspaceName("");
|
||||||
|
setCheckedNamespacesKeys([]);
|
||||||
|
setNamespaces([]);
|
||||||
|
}
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<ConfirmationModal isOpen={isOpen} onClose={onCloseModal} onConfirm={onConfirm} title={title}>
|
<ConfirmationModal isOpen={isOpen} onClose={onClose} onConfirm={onConfirm} title={title}>
|
||||||
<h3 className='headline'>DETAILS</h3>
|
<h3 className='comfirmation-modal__sub-section-header'>DETAILS</h3>
|
||||||
|
<div className='comfirmation-modal__sub-section'>
|
||||||
<div>
|
<div>
|
||||||
<input type="text" value={workspaceData?.name ?? ""} className={classes.textField + " workspace__name"} placeholder={"Workspace Name"}
|
<input type="text" value={workspaceName ?? ""} className={classes.textField + " workspace__name"} placeholder={"Workspace Name"}
|
||||||
onChange={(e) => {}}></input>
|
onChange={onWorkspaceNameChange}></input>
|
||||||
</div>
|
</div>
|
||||||
<h3 className='headline'>TAP SETTINGS</h3>
|
</div>
|
||||||
|
<h3 className='comfirmation-modal__sub-section-header'>TAP SETTINGS</h3>
|
||||||
<div className="namespacesSettingsContainer">
|
<div className="namespacesSettingsContainer">
|
||||||
<div>
|
<div>
|
||||||
<input className={classes.textField + " searchNamespace"} placeholder="Search" value={searchValue}
|
<input className={classes.textField + " searchNamespace"} placeholder="Search" value={searchValue}
|
||||||
onChange={(event) => setSearchValue(event.target.value)}/>
|
onChange={(event) => setSearchValue(event.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
<SelectList valuesListInput={namespaces} tableName={"Namespaces"} multiSelect={true} searchValue={searchValue} setValues={setUserData} tabelClassName={undefined}></SelectList>
|
<SelectList items={namespaces}
|
||||||
|
tableName={"Namespaces"}
|
||||||
|
multiSelect={true}
|
||||||
|
checkedValues={checkedNamespacesKeys}
|
||||||
|
searchValue={searchValue}
|
||||||
|
setCheckedValues={setCheckedNamespacesKeys}
|
||||||
|
tabelClassName={undefined}>
|
||||||
|
</SelectList>
|
||||||
</div>
|
</div>
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
</>);
|
</>);
|
||||||
|
@@ -38,7 +38,7 @@ export const InstallPage: React.FC<InstallPageProps> = ({onFirstLogin}) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await api.register(adminUsername, password);
|
await api.setupAdminUser(adminUsername, password);
|
||||||
if (!await api.isAuthenticationNeeded()) {
|
if (!await api.isAuthenticationNeeded()) {
|
||||||
setEntPage(Page.Traffic);
|
setEntPage(Page.Traffic);
|
||||||
onFirstLogin();
|
onFirstLogin();
|
||||||
|
@@ -19,7 +19,8 @@ const api = Api.getInstance();
|
|||||||
export const SettingsModal: React.FC<SettingsModalProps> = ({isOpen, onClose, isFirstLogin}) => {
|
export const SettingsModal: React.FC<SettingsModalProps> = ({isOpen, onClose, isFirstLogin}) => {
|
||||||
|
|
||||||
const classes = useCommonStyles();
|
const classes = useCommonStyles();
|
||||||
const [namespaces, setNamespaces] = useState({});
|
const [namespaces, setNamespaces] = useState([]);
|
||||||
|
const [checkedNamespacesKeys, setCheckedNamespacesKeys] = useState([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [searchValue, setSearchValue] = useState("");
|
const [searchValue, setSearchValue] = useState("");
|
||||||
|
|
||||||
@@ -29,16 +30,21 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({isOpen, onClose, is
|
|||||||
try {
|
try {
|
||||||
setSearchValue("");
|
setSearchValue("");
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const tapConfig = await api.getTapConfig()
|
// const tapConfig = await api.getTapConfig()
|
||||||
if(isFirstLogin) {
|
const namespaces = await api.getNamespaces();
|
||||||
const namespacesObj = {...tapConfig?.tappedNamespaces}
|
const namespacesMapped = namespaces.map(namespace => {
|
||||||
Object.keys(tapConfig?.tappedNamespaces ?? {}).forEach(namespace => {
|
return {key: namespace, value: namespace}
|
||||||
namespacesObj[namespace] = true;
|
|
||||||
})
|
})
|
||||||
setNamespaces(namespacesObj);
|
setNamespaces(namespacesMapped);
|
||||||
} else {
|
// if(isFirstLogin) {
|
||||||
setNamespaces(tapConfig?.tappedNamespaces);
|
// const namespacesObj = {...tapConfig?.tappedNamespaces}
|
||||||
}
|
// Object.keys(tapConfig?.tappedNamespaces ?? {}).forEach(namespace => {
|
||||||
|
// namespacesObj[namespace] = true;
|
||||||
|
// })
|
||||||
|
// setNamespaces(namespacesObj);
|
||||||
|
// } else {
|
||||||
|
// setNamespaces(tapConfig?.tappedNamespaces);
|
||||||
|
// }
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -49,7 +55,11 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({isOpen, onClose, is
|
|||||||
|
|
||||||
const updateTappingSettings = async () => {
|
const updateTappingSettings = async () => {
|
||||||
try {
|
try {
|
||||||
await api.setTapConfig(namespaces);
|
const defaultWorkspace = {
|
||||||
|
name: "default",
|
||||||
|
namespaces: checkedNamespacesKeys
|
||||||
|
}
|
||||||
|
await api.createWorkspace(defaultWorkspace);
|
||||||
onClose();
|
onClose();
|
||||||
toast.success("Saved successfully");
|
toast.success("Saved successfully");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -78,7 +88,7 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({isOpen, onClose, is
|
|||||||
<div style={{padding: 32, paddingBottom: 0}}>
|
<div style={{padding: 32, paddingBottom: 0}}>
|
||||||
<div className="settingsTitle">Tapping Settings</div>
|
<div className="settingsTitle">Tapping Settings</div>
|
||||||
<div className="settingsSubtitle" style={{marginTop: 20}}>
|
<div className="settingsSubtitle" style={{marginTop: 20}}>
|
||||||
Please choose from below the namespaces for tapping, traffic for namespaces selected will be displayed
|
Please choose from below the namespaces for tapping, traffic for namespaces selected will be displayed as default workspace.
|
||||||
</div>
|
</div>
|
||||||
{isLoading ? <div style={{textAlign: "center", padding: 20}}>
|
{isLoading ? <div style={{textAlign: "center", padding: 20}}>
|
||||||
<img alt="spinner" src={spinner} style={{height: 35}}/>
|
<img alt="spinner" src={spinner} style={{height: 35}}/>
|
||||||
@@ -87,7 +97,7 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({isOpen, onClose, is
|
|||||||
<div style={{margin: "10px 0"}}>
|
<div style={{margin: "10px 0"}}>
|
||||||
<input className={classes.textField + " searchNamespace"} placeholder="Search" value={searchValue}
|
<input className={classes.textField + " searchNamespace"} placeholder="Search" value={searchValue}
|
||||||
onChange={(event) => setSearchValue(event.target.value)}/></div>
|
onChange={(event) => setSearchValue(event.target.value)}/></div>
|
||||||
<SelectList valuesListInput={namespaces} tableName={'Namespace'} multiSelect={true} searchValue={searchValue} setValues={setNamespaces} tabelClassName={'namespacesTable'}/>
|
<SelectList items={namespaces} tableName={'Namespace'} multiSelect={true} searchValue={searchValue} setCheckedValues={setCheckedNamespacesKeys} tabelClassName={'namespacesTable'} checkedValues={checkedNamespacesKeys}/>
|
||||||
</div>
|
</div>
|
||||||
</>}
|
</>}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,70 +1,64 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import Checkbox from "./Checkbox"
|
import Checkbox from "./Checkbox"
|
||||||
import Radio from "./Radio";
|
import Radio from "./Radio";
|
||||||
import './style/SelectList.sass';
|
import './style/SelectList.sass';
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
valuesListInput;
|
|
||||||
tableName:string;
|
|
||||||
multiSelect:boolean;
|
|
||||||
searchValue?:string;
|
|
||||||
setValues: (newValues)=> void;
|
|
||||||
tabelClassName
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ValuesListInput = {
|
export type ValuesListInput = {
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
isChecked: boolean;
|
|
||||||
}[]
|
}[]
|
||||||
|
export interface Props {
|
||||||
|
items;
|
||||||
|
tableName:string;
|
||||||
|
checkedValues?:string[];
|
||||||
|
multiSelect:boolean;
|
||||||
|
searchValue?:string;
|
||||||
|
setCheckedValues: (newValues)=> void;
|
||||||
|
tabelClassName
|
||||||
|
}
|
||||||
|
|
||||||
const SelectList: React.FC<Props> = ({valuesListInput ,tableName,multiSelect=true,searchValue="",setValues,tabelClassName}) => {
|
const SelectList: React.FC<Props> = ({items ,tableName,checkedValues=[],multiSelect=true,searchValue="",setCheckedValues,tabelClassName}) => {
|
||||||
const [valuesList, setValuesList] = useState(valuesListInput as ValuesListInput);
|
|
||||||
|
|
||||||
const toggleValues = (checkedKey) => {
|
const filteredValues = useMemo(() => {
|
||||||
|
return items.filter((listValue) => listValue?.value?.includes(searchValue));
|
||||||
|
},[items, searchValue])
|
||||||
|
|
||||||
|
const toggleValue = (checkedKey) => {
|
||||||
if (!multiSelect){
|
if (!multiSelect){
|
||||||
unToggleAll(checkedKey);
|
unToggleAll();
|
||||||
}
|
|
||||||
else {
|
|
||||||
const newValues: ValuesListInput = [...valuesList];
|
|
||||||
newValues.map(item => item.key === checkedKey ? item.isChecked = !item.isChecked : item.isChecked);
|
|
||||||
setValuesList(newValues);
|
|
||||||
setValues(newValues);
|
|
||||||
}
|
}
|
||||||
|
const newCheckedValues = [...checkedValues];
|
||||||
|
let index = newCheckedValues.indexOf(checkedKey);
|
||||||
|
if(index > -1) newCheckedValues.splice(index,1);
|
||||||
|
else newCheckedValues.push(checkedKey);
|
||||||
|
setCheckedValues(newCheckedValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unToggleAll = (checkedKey) => {
|
const unToggleAll = () => {
|
||||||
const list = valuesList.map((obj) => {
|
setCheckedValues([]);
|
||||||
return {...obj, isChecked:checkedKey === obj.key}
|
|
||||||
})
|
|
||||||
setValuesList(list);
|
|
||||||
setValues(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const toggleAll = () => {
|
const toggleAll = () => {
|
||||||
const list = valuesList.map((obj) => {
|
const newCheckedValues = [...checkedValues];
|
||||||
return {...obj, isChecked: true}
|
if(newCheckedValues.length === items.length) setCheckedValues([]);
|
||||||
|
else {
|
||||||
|
items.forEach((obj) => {
|
||||||
|
if(!newCheckedValues.includes(obj.key))
|
||||||
|
newCheckedValues.push(obj.key);
|
||||||
})
|
})
|
||||||
setValuesList(list);
|
setCheckedValues(newCheckedValues);
|
||||||
setValues(list);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tableHead = multiSelect ? <tr style={{borderBottomWidth: "2px"}}>
|
||||||
const tableHead = multiSelect ?
|
<th style={{width: 50}}><Checkbox checked={items.length === checkedValues.length}
|
||||||
<tr style={{borderBottomWidth: "2px"}}>
|
|
||||||
<th style={{width: 50}}><Checkbox checked={valuesList.every(valueTap => valueTap.isChecked === false)}
|
|
||||||
onToggle={toggleAll}/></th>
|
onToggle={toggleAll}/></th>
|
||||||
<th>{tableName}</th>
|
<th>{tableName}</th>
|
||||||
</tr> :
|
</tr> :
|
||||||
<tr style={{borderBottomWidth: "2px",display: !tableName ? "none" : "table"}}>
|
<tr style={{borderBottomWidth: "2px"}}>
|
||||||
<th>{tableName}</th>
|
<th>{tableName}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
const filteredValues = useMemo(() => {
|
|
||||||
return valuesList.filter((listValue) => listValue?.value?.includes(searchValue));
|
|
||||||
},[valuesList, searchValue])
|
|
||||||
|
|
||||||
return <div className={tabelClassName + " select-list-table"}>
|
return <div className={tabelClassName + " select-list-table"}>
|
||||||
<table cellPadding={5} style={{borderCollapse: "collapse"}}>
|
<table cellPadding={5} style={{borderCollapse: "collapse"}}>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -74,8 +68,8 @@ const SelectList: React.FC<Props> = ({valuesListInput ,tableName,multiSelect=tru
|
|||||||
{filteredValues?.map(listValue => {
|
{filteredValues?.map(listValue => {
|
||||||
return <tr key={listValue.key}>
|
return <tr key={listValue.key}>
|
||||||
<td style={{width: 50}}>
|
<td style={{width: 50}}>
|
||||||
{multiSelect && <Checkbox checked={valuesList.find(item => item.key === listValue.key)?.isChecked} onToggle={() => toggleValues(listValue.key)}/>}
|
{multiSelect && <Checkbox checked={checkedValues.includes(listValue.key)} onToggle={() => toggleValue(listValue.key)}/>}
|
||||||
{!multiSelect && <Radio checked={valuesList.find(item => item.key === listValue.key)?.isChecked} onToggle={() => toggleValues(listValue.key)}/>}
|
{!multiSelect && <Radio checked={checkedValues.includes(listValue.key)} onToggle={() => toggleValue(listValue.key)}/>}
|
||||||
</td>
|
</td>
|
||||||
<td>{listValue.value}</td>
|
<td>{listValue.value}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@@ -4,15 +4,6 @@ import {ColsType, FilterableTableAction} from "../UI/FilterableTableAction"
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { UserData,AddUserModal } from "../Modals/AddUserModal/AddUserModal";
|
import { UserData,AddUserModal } from "../Modals/AddUserModal/AddUserModal";
|
||||||
import Api from '../../helpers/api';
|
import Api from '../../helpers/api';
|
||||||
|
|
||||||
import {Snackbar} from "@material-ui/core";
|
|
||||||
import MuiAlert from "@material-ui/lab/Alert";
|
|
||||||
import { Select } from "../UI/Select";
|
|
||||||
import { MenuItem } from "@material-ui/core";
|
|
||||||
import { settings } from "cluster";
|
|
||||||
import { SettingsModal } from "../SettingsModal/SettingModal";
|
|
||||||
import OasModal from "../Modals/OasModal/OasModal";
|
|
||||||
import { apiDefineProperty } from "mobx/dist/internal";
|
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import ConfirmationModal from "../UI/Modals/ConfirmationModal";
|
import ConfirmationModal from "../UI/Modals/ConfirmationModal";
|
||||||
|
|
||||||
|
@@ -1,45 +1,64 @@
|
|||||||
import "../UserSettings/UserSettings.sass"
|
import "../UserSettings/UserSettings.sass"
|
||||||
import {ColsType, FilterableTableAction} from "../UI/FilterableTableAction"
|
import {ColsType, FilterableTableAction} from "../UI/FilterableTableAction"
|
||||||
// import Api from "../../helpers/api"
|
import Api from "../../helpers/api"
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import AddWorkspaceModal, { WorkspaceData } from "../Modals/AddWorkspaceModal/AddWorkspaceModal";
|
import AddWorkspaceModal, { WorkspaceData } from "../Modals/AddWorkspaceModal/AddWorkspaceModal";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import ConfirmationModal from "../UI/Modals/ConfirmationModal";
|
||||||
|
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
|
||||||
// const api = Api.getInstance();
|
const api = Api.getInstance();
|
||||||
|
|
||||||
export const WorkspaceSettings : React.FC<Props> = ({}) => {
|
export const WorkspaceSettings : React.FC<Props> = ({}) => {
|
||||||
|
|
||||||
const [workspacesRows, setWorkspacesRows] = useState([]);
|
const [workspacesRows, setWorkspacesRows] = useState([]);
|
||||||
|
const cols : ColsType[] = [{field : "name",header:"Name"}];
|
||||||
|
|
||||||
const [workspaceData,SetWorkspaceData] = useState({} as WorkspaceData);
|
const [workspaceData,SetWorkspaceData] = useState({} as WorkspaceData);
|
||||||
const [isOpenModal,setIsOpen] = useState(false);
|
const [isOpenModal,setIsOpen] = useState(false);
|
||||||
const [isEditMode,setIsEditMode] = useState(false);
|
const [isEditMode,setIsEditMode] = useState(false);
|
||||||
|
const [isOpenDeleteModal, setIsOpenDeleteModal] = useState(false);
|
||||||
const cols : ColsType[] = [{field : "id",header:"Id"},{field : "name",header:"Name"}];
|
|
||||||
|
|
||||||
const buttonConfig = {onClick: () => {setIsOpen(true); setIsEditMode(false);SetWorkspaceData({} as WorkspaceData)}, text:"Add Workspace"}
|
const buttonConfig = {onClick: () => {setIsOpen(true); setIsEditMode(false);SetWorkspaceData({} as WorkspaceData)}, text:"Add Workspace"}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const workspacesDemo = [{id:"1", name:"Worksapce1"}]
|
const workspaces = await api.getWorkspaces();
|
||||||
setWorkspacesRows(workspacesDemo)
|
setWorkspacesRows(workspaces)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
},[])
|
},[isOpenModal])
|
||||||
|
|
||||||
const filterFuncFactory = (searchQuery: string) => {
|
const filterFuncFactory = (searchQuery: string) => {
|
||||||
return (row) => row.name.toLowerCase().includes(searchQuery.toLowerCase())
|
return (row) => {
|
||||||
|
return row.name.toLowerCase().includes(searchQuery.toLowerCase());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchConfig = { searchPlaceholder: "Search Workspace",filterRows: filterFuncFactory}
|
const searchConfig = { searchPlaceholder: "Search Workspace",filterRows: filterFuncFactory};
|
||||||
|
|
||||||
const onRowDelete = (row) => {
|
const onRowDelete = async (workspace) => {
|
||||||
const filterFunc = filterFuncFactory(row.name)
|
setIsOpenDeleteModal(true);
|
||||||
const newWorkspaceList = workspacesRows.filter(filterFunc)
|
SetWorkspaceData(workspace);
|
||||||
setWorkspacesRows(newWorkspaceList)
|
}
|
||||||
|
|
||||||
|
const onDeleteConfirmation = () => {
|
||||||
|
(async() => {
|
||||||
|
try{
|
||||||
|
const workspaceLeft = workspacesRows.filter(ws => ws.id != workspaceData.id);
|
||||||
|
setWorkspacesRows(workspaceLeft);
|
||||||
|
await api.deleteWorkspace(workspaceData.id);
|
||||||
|
setIsOpenDeleteModal(false);
|
||||||
|
SetWorkspaceData({} as WorkspaceData);
|
||||||
|
toast.success("Workspace Succesesfully Deleted ");
|
||||||
|
} catch {
|
||||||
|
toast.error("Workspace hasn't deleted");
|
||||||
|
}
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
const onRowEdit = (row) => {
|
const onRowEdit = (row) => {
|
||||||
@@ -48,15 +67,17 @@ export const WorkspaceSettings : React.FC<Props> = ({}) => {
|
|||||||
SetWorkspaceData(row);
|
SetWorkspaceData(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<FilterableTableAction onRowEdit={onRowEdit} onRowDelete={onRowDelete} searchConfig={searchConfig}
|
<FilterableTableAction onRowEdit={onRowEdit} onRowDelete={onRowDelete} searchConfig={searchConfig}
|
||||||
buttonConfig={buttonConfig} rows={workspacesRows} cols={cols}>
|
buttonConfig={buttonConfig} rows={workspacesRows} cols={cols}>
|
||||||
</FilterableTableAction>
|
</FilterableTableAction>
|
||||||
<AddWorkspaceModal isOpen={isOpenModal} workspaceData={workspaceData} onEdit={isEditMode} onCloseModal={() => { setIsOpen(false);} } >
|
<AddWorkspaceModal isOpen={isOpenModal} workspaceId={workspaceData.id} onEdit={isEditMode} onCloseModal={() => { setIsOpen(false);} } >
|
||||||
|
|
||||||
|
|
||||||
</AddWorkspaceModal>
|
</AddWorkspaceModal>
|
||||||
|
<ConfirmationModal isOpen={isOpenDeleteModal} onClose={() => setIsOpenDeleteModal(false)}
|
||||||
|
onConfirm={onDeleteConfirmation} confirmButtonText="Delete Workspace" title="Delete Workspace"
|
||||||
|
confirmButtonColor="#DB2156">
|
||||||
|
<p>Are you sure you want to delete this workspace?</p>
|
||||||
|
</ConfirmationModal>
|
||||||
</>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -83,6 +83,31 @@ export default class Api {
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSpecificWorkspace = async(workspaceId) =>{
|
||||||
|
const response = await this.client.get(`/workspace/${workspaceId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
createWorkspace = async(workspaceData) =>{
|
||||||
|
const response = await this.client.post(`/workspace`,workspaceData);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
editWorkspace = async(workspaceId, workspaceData) =>{
|
||||||
|
const response = await this.client.put(`/workspace/${workspaceId}`,workspaceData);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteWorkspace = async(workspaceId) => {
|
||||||
|
const response = await this.client.delete(`/workspace/${workspaceId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
getNamespaces = async() =>{
|
||||||
|
const response = await this.client.get(`/config/namespaces`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
analyzeStatus = async () => {
|
analyzeStatus = async () => {
|
||||||
const response = await this.client.get("/status/analyze");
|
const response = await this.client.get("/status/analyze");
|
||||||
return response.data;
|
return response.data;
|
||||||
@@ -145,7 +170,7 @@ export default class Api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTapConfig = async () => {
|
getTapConfig = async () => {
|
||||||
const response = await this.client.get("/config/tapConfig");
|
const response = await this.client.get("/config/tap");
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,8 +196,29 @@ export default class Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register = async (username, password) => {
|
// register = async (username, password) => {
|
||||||
|
// const form = new FormData();
|
||||||
|
// form.append('username', username);
|
||||||
|
// form.append('password', password);
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// const response = await this.client.post(`/user/register`, form);
|
||||||
|
// this.persistToken(response.data.token);
|
||||||
|
// return response;
|
||||||
|
// } catch (e) {
|
||||||
|
// if (e.response.status === 400) {
|
||||||
|
// const error = {
|
||||||
|
// 'type': FormValidationErrorType,
|
||||||
|
// 'messages': e.response.data
|
||||||
|
// };
|
||||||
|
// throw error;
|
||||||
|
// } else {
|
||||||
|
// throw e;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
setupAdminUser = async (password) => {
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append('password', password);
|
form.append('password', password);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user