Compare commits

..
9 Commits
Author SHA1 Message Date
pascal-fischer 2613948cdf Fix OS display format for iOS (#297)
* fix OS format function to properly show iOS

* bring back windows check
2023-11-13 22:30:50 +08:00
pascal-fischer dc95d8bfd1 disallow routing through ios devices (#295) 2023-11-11 13:20:39 +01:00
Bethuel Mmbaga f49c28f550 Add integration activity events target to Activity view as system setting (#293) 2023-11-08 13:51:57 +03:00
Maycon Santos 2fc7b73ea0 Fix/blank page on empty policy groups (#292)
validate null sources and destinations fields
2023-11-01 11:56:12 +01:00
pascal-fischer a9354d3c87 removed disabled option from setup key filter switch (#291) 2023-10-27 20:06:42 +02:00
Sarooj bukhariandbraginini e0ae7d068a add search domains enabled to namespace (#288)
---------

Co-authored-by: braginini <bangvalo@gmail.com>
2023-10-20 09:33:44 +02:00
Sarooj bukhariandbraginini ddd812e9a0 Add a refresh button to the table views (#287)
Co-authored-by: braginini <bangvalo@gmail.com>
2023-10-15 19:04:05 +02:00
Sarooj bukhariandbraginini 2d55d0736f Add referesh button to the peers table (#286)
Co-authored-by: braginini <bangvalo@gmail.com>
2023-10-12 18:38:59 +02:00
Sarooj bukhari 8febc26f1f fix update distribution groups bug (#284) 2023-10-04 20:07:02 +02:00
19 changed files with 775 additions and 355 deletions

No files matched your search

+55 -1
View File
@@ -73,6 +73,7 @@ const NameServerGroupAdd = () => {
const inputNameRef = useRef<any>(null);
const inputDescriptionRef = useRef<any>(null);
const [selectCustom, setSelectCustom] = useState(false);
const [matchDomains, setMatchDomains] = useState(0);
useEffect(() => {
if (editName)
@@ -87,7 +88,6 @@ const NameServerGroupAdd = () => {
cursor: "end",
});
}, [editDescription]);
useEffect(() => {
if (!nsGroup) return;
@@ -117,6 +117,7 @@ const NameServerGroupAdd = () => {
nameservers: [] as NameServer[],
groups: [],
enabled: false,
search_domains_enabled: false,
} as NameServerGroup)
);
setEditName(false);
@@ -156,6 +157,7 @@ const NameServerGroupAdd = () => {
],
groups: [],
enabled: true,
search_domains_enabled: false,
},
{
name: cloudflareChoice,
@@ -176,6 +178,7 @@ const NameServerGroupAdd = () => {
],
groups: [],
enabled: true,
search_domains_enabled: false,
},
{
name: quad9Choice,
@@ -196,6 +199,7 @@ const NameServerGroupAdd = () => {
],
groups: [],
enabled: true,
search_domains_enabled: false,
},
];
@@ -262,6 +266,8 @@ const NameServerGroupAdd = () => {
groups: existingGroups,
groupsToCreate: newGroups,
enabled: values.enabled,
search_domains_enabled:
matchDomains > 0 ? formNSGroup.search_domains_enabled : false,
} as NameServerGroupToSave;
};
@@ -462,6 +468,7 @@ const NameServerGroupAdd = () => {
</Col>
</Space>
</Row>
{setMatchDomains(fields.length)}
{fields.map((field, index) => {
return (
<Row key={index} style={{ marginBottom: "5px" }}>
@@ -522,6 +529,13 @@ const NameServerGroupAdd = () => {
});
};
const handleChangeMarkDomain = (checked: boolean) => {
setFormNSGroup({
...formNSGroup,
search_domains_enabled: checked,
});
};
return (
<>
{nsGroup && (
@@ -701,6 +715,46 @@ const NameServerGroupAdd = () => {
<Col span={24}>
<Form.List name="domains">{renderDomains}</Form.List>
</Col>
{matchDomains > 0 && (
<Col span={24}>
<Form.Item name="search_domains_enabled" label="">
<div
style={{
display: "flex",
gap: "15px",
}}
>
<Switch
onChange={handleChangeMarkDomain}
size="small"
/>
<div>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
}}
>
Mark match domains as search domains
</label>
<Paragraph
type={"secondary"}
style={{
marginTop: "-2",
fontWeight: "400",
marginBottom: "0",
}}
>
E.g., "peer.example.com" will be accessible with
"peer"
</Paragraph>
</div>
</div>
</Form.Item>
</Col>
)}
<Col span={24}>
<label
style={{
File diff suppressed because it is too large. Load diff
+1
View File
@@ -197,6 +197,7 @@ const PeerUpdate = (props: any) => {
os !== "" &&
!os.toLowerCase().startsWith("darwin") &&
!os.toLowerCase().startsWith("windows") &&
!os.toLowerCase().startsWith("ios") &&
!os.toLowerCase().startsWith("android")
);
};
+1
View File
@@ -151,6 +151,7 @@ const RouteAddNew = (selectedPeer: any) => {
!os.toLowerCase().startsWith("darwin") &&
!os.toLowerCase().startsWith("windows") &&
!os.toLowerCase().startsWith("android") &&
!os.toLowerCase().startsWith("ios") &&
route &&
!routes
.filter((r) => r.network_id === route.network_id)
+1
View File
@@ -100,6 +100,7 @@ const RoutePeerUpdate = () => {
!os.toLowerCase().startsWith("darwin") &&
!os.toLowerCase().startsWith("windows") &&
!os.toLowerCase().startsWith("android") &&
!os.toLowerCase().startsWith("ios") &&
route &&
!routes
.filter((r) => r.network_id === route.network_id)
+1
View File
@@ -96,6 +96,7 @@ const RouteAddNew = () => {
!os.toLowerCase().startsWith("darwin") &&
!os.toLowerCase().startsWith("windows") &&
!os.toLowerCase().startsWith("android") &&
!os.toLowerCase().startsWith("ios") &&
route &&
!routes
.filter((r) => r.network_id === route.network_id)
+3 -2
View File
@@ -69,8 +69,9 @@ export function* saveNameServerGroup(action: ReturnType<typeof actions.saveNameS
nameservers: nameserverGroupToSave.nameservers,
groups: newGroups,
enabled: nameserverGroupToSave.enabled,
} as NameServerGroup
}
search_domains_enabled: nameserverGroupToSave.search_domains_enabled,
} as NameServerGroup,
};
let effect
if (!nameserverGroupToSave.id) {
+1
View File
@@ -7,6 +7,7 @@ export interface NameServerGroup {
nameservers: NameServer[];
groups: string[];
enabled: boolean;
search_domains_enabled: boolean;
}
export interface NameServer {
+1 -1
View File
@@ -109,7 +109,7 @@ export function* saveRoute(
network: routeToSave.network,
network_id: routeToSave.network_id,
peer: routeToSave.peer,
peer_groups: newPeerGroups,
peer_groups: newPeerGroups.length ? newPeerGroups : null,
groups: newGroups,
} as Route,
};
+6 -2
View File
@@ -8,8 +8,12 @@ export const formatOS = (os) => {
if (os.startsWith("Darwin")) {
return os.replace("Darwin", "MacOS");
}
// capitalize first letter
os = os.charAt(0).toUpperCase() + os.slice(1);
if (!os.startsWith("iOS")) {
// capitalize first letter
os = os.charAt(0).toUpperCase() + os.slice(1);
}
return os;
};
+45 -3
View File
@@ -21,6 +21,7 @@ import {
Tooltip,
Typography,
} from "antd";
import { ReloadOutlined } from "@ant-design/icons";
import { Container } from "../components/Container";
import { useDispatch, useSelector } from "react-redux";
import { storeFilterState, getFilterState } from "../utils/filterState";
@@ -72,7 +73,7 @@ export const AccessControl = () => {
const { onChangePageSize, pageSizeOptions, pageSize } = usePageSizeHelpers();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
const policies = useSelector((state: RootState) => state.policy.data);
const failed = useSelector((state: RootState) => state.policy.failed);
const loading = useSelector((state: RootState) => state.policy.loading);
@@ -84,6 +85,7 @@ export const AccessControl = () => {
);
const [showTutorial, setShowTutorial] = useState(true);
const [isRefreshButtonDisabled, setIsRefreshButtonDisabled] = useState(false);
const [textToSearch, setTextToSearch] = useState("");
const [optionAllEnable, setOptionAllEnable] = useState("all");
const [currentPage, setCurrentPage] = useState(1);
@@ -184,6 +186,26 @@ export const AccessControl = () => {
);
}, []);
const fetchData = async () => {
setIsRefreshButtonDisabled(true);
dispatch(
policyActions.getPolicies.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
groupActions.getGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
await new Promise((resolve) => setTimeout(resolve, 5000)).then(() =>
setIsRefreshButtonDisabled(false)
);
};
useEffect(() => {
if (failed) {
setShowTutorial(false);
@@ -298,7 +320,11 @@ export const AccessControl = () => {
setPolicyToAction(record as PolicyDataTable);
confirm({
icon: <ExclamationCircleOutlined />,
title: <span data-testid="confirm-delete-modal-title" className="font-500">Delete rule {record.name}</span>,
title: (
<span data-testid="confirm-delete-modal-title" className="font-500">
Delete rule {record.name}
</span>
),
width: 500,
content: (
<Space direction="vertical" size="small">
@@ -420,7 +446,6 @@ export const AccessControl = () => {
);
};
const toggleModalGroups = (
title: string,
groups: Group[] | string[] | null,
@@ -643,6 +668,7 @@ export const AccessControl = () => {
disabled={showTutorial}
/>
<Select
style={{ marginRight: "10px" }}
value={pageSize.toString()}
options={pageSizeOptions}
onChange={(value) => {
@@ -652,6 +678,22 @@ export const AccessControl = () => {
disabled={showTutorial}
/>
</Space>
<Tooltip
title={
isRefreshButtonDisabled
? "You can refresh it again in 5 seconds"
: "Refresh"
}
>
<Button
onClick={fetchData}
disabled={isRefreshButtonDisabled}
style={{ marginLeft: "5px", color: "#1890ff" }}
>
<ReloadOutlined />
</Button>
</Tooltip>
</Col>
{!showTutorial && (
<Col
+38 -1
View File
@@ -14,6 +14,7 @@ import {
Space,
Table,
Typography,
Tooltip,
} from "antd";
import { Event } from "../store/event/types";
import { filter } from "lodash";
@@ -23,7 +24,7 @@ import { useOidcUser } from "@axa-fr/react-oidc";
import { capitalize, formatDateTime } from "../utils/common";
import { User } from "../store/user/types";
import { usePageSizeHelpers } from "../utils/pageSize";
import { QuestionCircleFilled } from "@ant-design/icons";
import { ReloadOutlined } from "@ant-design/icons";
import { storeFilterState, getFilterState } from "../utils/filterState";
const { Title, Paragraph, Text } = Typography;
@@ -44,6 +45,7 @@ export const Activity = () => {
const setupKeys = useSelector((state: RootState) => state.setupKey.data);
const [textToSearch, setTextToSearch] = useState("");
const [isRefreshButtonDisabled, setIsRefreshButtonDisabled] = useState(false);
const [dataTable, setDataTable] = useState([] as EventDataTable[]);
const transformDataTable = (d: Event[]): EventDataTable[] => {
@@ -58,6 +60,21 @@ export const Activity = () => {
})
);
}, []);
const fetchData = async() => {
setIsRefreshButtonDisabled(true);
dispatch(
eventActions.getEvents.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
await new Promise((resolve) => setTimeout(resolve, 5000)).then(() =>
setIsRefreshButtonDisabled(false)
);
};
// useEffect(() => {
// setDataTable(transformDataTable(events));
// }, [events]);
@@ -356,6 +373,9 @@ export const Activity = () => {
case "account.setting.peer.login.expiration.enable":
case "account.setting.peer.login.expiration.disable":
case "account.setting.peer.login.expiration.update":
case "integration.create":
case "integration.update":
case "integration.delete":
return renderMultiRowSpan("", "System setting");
case "personal.access.token.create":
case "personal.access.token.delete":
@@ -427,6 +447,7 @@ export const Activity = () => {
<Col xs={24} sm={24} md={11} lg={11} xl={11} xxl={11} span={11}>
<Space size="middle">
<Select
style={{ marginRight: "10px" }}
value={pageSize.toString()}
options={pageSizeOptions}
onChange={(value) => {
@@ -435,6 +456,22 @@ export const Activity = () => {
className="select-rows-per-page-en"
/>
</Space>
<Tooltip
title={
isRefreshButtonDisabled
? "You can refresh it again in 5 seconds"
: "Refresh"
}
>
<Button
onClick={fetchData}
disabled={isRefreshButtonDisabled}
style={{ marginLeft: "5px", color: "#1890ff" }}
>
<ReloadOutlined />
</Button>
</Tooltip>
</Col>
</Row>
{failed && (
+41 -1
View File
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "typesafe-actions";
import { actions as nsGroupActions } from "../store/nameservers";
import { Container } from "../components/Container";
import {
Alert,
Button,
@@ -21,8 +20,10 @@ import {
Table,
Tag,
Typography,
Tooltip,
} from "antd";
import { filter } from "lodash";
import { ReloadOutlined } from "@ant-design/icons";
import tableSpin from "../components/Spin";
import { storeFilterState, getFilterState } from "../utils/filterState";
import { useGetTokenSilently } from "../utils/token";
@@ -77,6 +78,7 @@ export const Nameservers = () => {
);
const [textToSearch, setTextToSearch] = useState("");
const [isRefreshButtonDisabled, setIsRefreshButtonDisabled] = useState(false);
const [optionAllEnable, setOptionAllEnable] = useState("all");
const [dataTable, setDataTable] = useState([] as NameserverGroupDataTable[]);
const [showTutorial, setShowTutorial] = useState(false);
@@ -151,6 +153,7 @@ export const Nameservers = () => {
nameservers: nsGroup.nameservers,
groups: nsGroup.groups,
enabled: nsGroup.enabled,
search_domains_enabled: nsGroup.search_domains_enabled,
} as NameServerGroup)
);
};
@@ -166,6 +169,7 @@ export const Nameservers = () => {
nameservers: nsGroup.nameservers,
groups: nsGroup.groups,
enabled: nsGroup.enabled,
search_domains_enabled: nsGroup.search_domains_enabled,
} as NameServerGroup)
);
setShowGroupModal(true);
@@ -192,6 +196,26 @@ export const Nameservers = () => {
);
}, []);
const fetchData = async () => {
setIsRefreshButtonDisabled(true);
dispatch(
nsGroupActions.getNameServerGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
groupActions.getGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
await new Promise((resolve) => setTimeout(resolve, 5000)).then(() =>
setIsRefreshButtonDisabled(false)
);
};
const onChangeAllEnabled = ({ target: { value } }: RadioChangeEvent) => {
setOptionAllEnable(value);
storeFilterState("nameServerFilter", "quickFilter", value);
@@ -554,6 +578,22 @@ export const Nameservers = () => {
className="select-rows-per-page-en"
disabled={showTutorial}
/>
<Tooltip
title={
isRefreshButtonDisabled
? "You can refresh it again in 5 seconds"
: "Refresh"
}
>
<Button
onClick={fetchData}
disabled={isRefreshButtonDisabled}
style={{ color: "#1890ff" }}
>
<ReloadOutlined />
</Button>
</Tooltip>
</Space>
</Col>
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
+51 -7
View File
@@ -94,6 +94,7 @@ export const Peers = () => {
const [groupPopupVisible, setGroupPopupVisible] = useState("");
const [showTutorial, setShowTutorial] = useState(false);
const [hadFirstRun, setHadFirstRun] = useState(true);
const [isRefreshButtonDisabled, setIsRefreshButtonDisabled] = useState(false);
const [confirmModal, confirmModalContextHolder] = Modal.useModal();
const optionsOnOff = [
@@ -182,6 +183,33 @@ export const Peers = () => {
);
};
const fetchData = async () => {
setIsRefreshButtonDisabled(true);
dispatch(
userActions.getUsers.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
peerActions.getPeers.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
groupActions.getGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
await new Promise((resolve) => setTimeout(resolve, 5000)).then(() =>
setIsRefreshButtonDisabled(false)
);
};
useEffect(() => {
getLocalItem<boolean>(StorageKey.hadFirstRun).then((f) =>
setHadFirstRun(f === null ? false : f)
@@ -666,11 +694,11 @@ export const Peers = () => {
<Col
xs={24}
sm={24}
md={11}
lg={11}
xl={11}
xxl={11}
span={11}
md={12}
lg={12}
xl={12}
xxl={12}
span={12}
>
<Space size="middle" style={{ marginRight: "15px" }}>
<Radio.Group
@@ -691,10 +719,10 @@ export const Peers = () => {
className="select-rows-per-page-en"
/>
</Space>
{isAdmin && (
<Select
mode="tags"
style={{ marginRight: "10px" }}
placeholder="Filter by groups"
tagRender={blueTagRender}
// dropdownRender={dropDownRender}
@@ -714,8 +742,24 @@ export const Peers = () => {
))}
</Select>
)}
<Tooltip
title={
isRefreshButtonDisabled
? "You can refresh it again in 5 seconds"
: "Refresh"
}
>
<Button
onClick={fetchData}
disabled={isRefreshButtonDisabled}
style={{ marginLeft: "5px", color: "#1890ff" }}
>
<ReloadOutlined />
</Button>
</Tooltip>
</Col>
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Col xs={24} sm={24} md={4} lg={4} xl={4} xxl={4} span={4}>
<Row justify="end">
<Col>
{!showTutorial && (
+119 -31
View File
@@ -41,7 +41,7 @@ import { usePageSizeHelpers } from "../utils/pageSize";
import AddServiceUserPopup from "../components/popups/AddServiceUserPopup";
import InviteUserPopup from "../components/popups/InviteUserPopup";
import { Peer, PeerDataTable } from "../store/peer/types";
import { ExclamationCircleOutlined, MinusOutlined } from "@ant-design/icons";
import { ExclamationCircleOutlined, ReloadOutlined } from "@ant-design/icons";
import { actions as peerActions } from "../store/peer";
import { useOidcUser } from "@axa-fr/react-oidc";
import { storeFilterState, getFilterState } from "../utils/filterState";
@@ -79,6 +79,7 @@ export const RegularUsers = () => {
null as UserDataTable | null
);
const [textToSearch, setTextToSearch] = useState("");
const [isRefreshButtonDisabled, setIsRefreshButtonDisabled] = useState(false);
const [dataTable, setDataTable] = useState([] as UserDataTable[]);
const [confirmModal, confirmModalContextHolder] = Modal.useModal();
@@ -166,6 +167,31 @@ export const RegularUsers = () => {
);
}, [savedUser]);
const fetchData = async () => {
setIsRefreshButtonDisabled(true);
dispatch(
userActions.getUsers.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
userActions.getRegularUsers.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
groupActions.getGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
await new Promise((resolve) => setTimeout(resolve, 5000)).then(() =>
setIsRefreshButtonDisabled(false)
);
};
useEffect(() => {
if (!loading && groups.length && users) {
const searchText = getFilterState("userFilter", "search");
@@ -396,7 +422,7 @@ export const RegularUsers = () => {
icon: <ExclamationCircleOutlined />,
title: (
<span className="font-500">
Are you sure you want to block {user.name? user.name : user.id}?
Are you sure you want to block {user.name ? user.name : user.id}?
</span>
),
width: 600,
@@ -450,12 +476,18 @@ export const RegularUsers = () => {
const handleDeleteUser = (user: UserDataTable) => {
confirmModal.confirm({
icon: <ExclamationCircleOutlined />,
title: <span className="font-500">Are you sure you want to delete {user.name? user.name : user.id}?</span>,
title: (
<span className="font-500">
Are you sure you want to delete {user.name ? user.name : user.id}?
</span>
),
width: 500,
content: (
<Space direction="vertical" size="small">
<Paragraph>
Deleting this user will remove their devices and remove dashboard access.</Paragraph>
Deleting this user will remove their devices and remove dashboard
access.
</Paragraph>
</Space>
),
onOk() {
@@ -510,6 +542,7 @@ export const RegularUsers = () => {
<Col xs={24} sm={24} md={11} lg={11} xl={11} xxl={11} span={11}>
<Space size="middle">
<Select
style={{ marginRight: "10px" }}
value={pageSize.toString()}
options={pageSizeOptions}
onChange={(value) => {
@@ -518,6 +551,21 @@ export const RegularUsers = () => {
className="select-rows-per-page-en"
/>
</Space>
<Tooltip
title={
isRefreshButtonDisabled
? "You can refresh it again in 5 seconds"
: "Refresh"
}
>
<Button
onClick={fetchData}
disabled={isRefreshButtonDisabled}
style={{ marginLeft: "5px", color: "#1890ff" }}
>
<ReloadOutlined />
</Button>
</Tooltip>
</Col>
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
{(isNetBirdHosted() || isLocalDev()) && (
@@ -583,47 +631,87 @@ export const RegularUsers = () => {
if ((record as User).is_current) {
return (
<>
<div>
{btn}
<Tag color="blue">me</Tag>
</div>
{(isNetBirdHosted() || isLocalDev()) && ((record as User).last_login && <Text type={"secondary"} style={{paddingLeft: "15px"}}>Last login: {String(timeAgo((record as User).last_login))}</Text>)}
</>
<>
<div>
{btn}
<Tag color="blue">me</Tag>
</div>
{(isNetBirdHosted() || isLocalDev()) &&
(record as User).last_login && (
<Text
type={"secondary"}
style={{ paddingLeft: "15px" }}
>
Last login:{" "}
{String(timeAgo((record as User).last_login))}
</Text>
)}
</>
);
}
if ((record as User).status === "invited") {
return (
<>
<div>
{btn}
<Tag color="gold">invited</Tag>
</div>
{(isNetBirdHosted() || isLocalDev()) && ((record as User).last_login && <Text type={"secondary"} style={{paddingLeft: "15px", paddingTop: "0px"}}>Last login: {String(timeAgo((record as User).last_login))}</Text>)}
</>
<>
<div>
{btn}
<Tag color="gold">invited</Tag>
</div>
{(isNetBirdHosted() || isLocalDev()) &&
(record as User).last_login && (
<Text
type={"secondary"}
style={{
paddingLeft: "15px",
paddingTop: "0px",
}}
>
Last login:{" "}
{String(timeAgo((record as User).last_login))}
</Text>
)}
</>
);
}
if ((record as User).status === "blocked") {
return (
<>
<div>
{btn}
<Tag color="red">blocked</Tag>
</div>
{(isNetBirdHosted() || isLocalDev()) && ((record as User).last_login && <Text type={"secondary"} style={{paddingLeft: "15px"}}>Last login: {String(timeAgo((record as User).last_login))}</Text>)}
</>
<>
<div>
{btn}
<Tag color="red">blocked</Tag>
</div>
{(isNetBirdHosted() || isLocalDev()) &&
(record as User).last_login && (
<Text
type={"secondary"}
style={{ paddingLeft: "15px" }}
>
Last login:{" "}
{String(timeAgo((record as User).last_login))}
</Text>
)}
</>
);
}
return (
<>
<div>
{btn}
</div>
{(isNetBirdHosted() || isLocalDev()) && ((record as User).last_login && <Text type={"secondary"} style={{paddingLeft: "15px", paddingTop: "0px"}}>Last login: {String(timeAgo((record as User).last_login))}</Text>)}
</>
<>
<div>{btn}</div>
{(isNetBirdHosted() || isLocalDev()) &&
(record as User).last_login && (
<Text
type={"secondary"}
style={{
paddingLeft: "15px",
paddingTop: "0px",
}}
>
Last login:{" "}
{String(timeAgo((record as User).last_login))}
</Text>
)}
</>
);
}}
/>
+39
View File
@@ -34,6 +34,7 @@ import {
EllipsisOutlined,
ExclamationCircleOutlined,
ExclamationCircleFilled,
ReloadOutlined,
} from "@ant-design/icons";
import { storeFilterState, getFilterState } from "../utils/filterState";
import RouteAddNew from "../components/RouteAddNew";
@@ -89,6 +90,7 @@ export const Routes = () => {
(state: RootState) => state.route.setupEditRouteVisible
);
const [showTutorial, setShowTutorial] = useState(true);
const [isRefreshButtonDisabled, setIsRefreshButtonDisabled] = useState(false);
const [textToSearch, setTextToSearch] = useState("");
const [optionAllEnable, setOptionAllEnable] = useState("enabled");
const [dataTable, setDataTable] = useState([] as RouteDataTable[]);
@@ -184,8 +186,29 @@ export const Routes = () => {
payload: null,
})
);
}, []);
const fetchData = async() => {
setIsRefreshButtonDisabled(true);
dispatch(
peerActions.getPeers.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
groupActions.getGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
await new Promise((resolve) => setTimeout(resolve, 5000)).then(() =>
setIsRefreshButtonDisabled(false)
);
};
const filterGroupedDataTable = (
routes: GroupedDataTable[],
searchText: string
@@ -861,6 +884,7 @@ export const Routes = () => {
>
<Space size="middle">
<Radio.Group
style={{ marginRight: "10px" }}
options={optionsAllEnabled}
onChange={onChangeAllEnabled}
value={optionAllEnable}
@@ -869,6 +893,21 @@ export const Routes = () => {
disabled={showTutorial}
/>
</Space>
<Tooltip
title={
isRefreshButtonDisabled
? "You can refresh it again in 5 seconds"
: "Refresh"
}
>
<Button
onClick={fetchData}
disabled={isRefreshButtonDisabled}
style={{ marginLeft: "5px", color: "#1890ff" }}
>
<ReloadOutlined />
</Button>
</Tooltip>
</Col>
{!showTutorial && (
<Col
+51 -10
View File
@@ -17,11 +17,13 @@ import {
Table,
Tag,
Typography,
Tooltip,
} from "antd";
import { User } from "../store/user/types";
import { filter } from "lodash";
import tableSpin from "../components/Spin";
import { useGetTokenSilently } from "../utils/token";
import { ReloadOutlined } from "@ant-design/icons";
import { actions as groupActions } from "../store/group";
import { capitalize, isLocalDev, isNetBirdHosted } from "../utils/common";
import { usePageSizeHelpers } from "../utils/pageSize";
@@ -53,6 +55,7 @@ export const ServiceUsers = () => {
);
const savedUser = useSelector((state: RootState) => state.user.savedUser);
const deletedUser = useSelector((state: RootState) => state.user.deletedUser);
const [isRefreshButtonDisabled, setIsRefreshButtonDisabled] = useState(false);
const [showTutorial, setShowTutorial] = useState(false);
const [confirmModal, confirmModalContextHolder] = Modal.useModal();
@@ -78,18 +81,42 @@ export const ServiceUsers = () => {
);
}, [savedUser, deletedUser]);
const fetchData = async () => {
setIsRefreshButtonDisabled(true);
dispatch(
userActions.getUsers.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
userActions.getServiceUsers.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
groupActions.getGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
await new Promise((resolve) => setTimeout(resolve, 5000)).then(() =>
setIsRefreshButtonDisabled(false)
);
};
// useEffect(() => {
// setDataTable(transformDataTable(users));
// }, [users, groups]);
useEffect(() => {
if (users.length > 0) {
setShowTutorial(false);
} else {
setShowTutorial(true);
}
// setDataTable(transformDataTable(filterDataTable()));
}, [users]);
useEffect(() => {
if (users.length > 0) {
setShowTutorial(false);
} else {
setShowTutorial(true);
}
// setDataTable(transformDataTable(filterDataTable()));
}, [users]);
useEffect(() => {
if (!loading && groups.length) {
@@ -227,8 +254,6 @@ export const ServiceUsers = () => {
});
};
return (
<>
{!user && (
@@ -289,6 +314,7 @@ export const ServiceUsers = () => {
>
<Space size="middle">
<Select
style={{ marginRight: "10px" }}
value={pageSize.toString()}
options={pageSizeOptions}
onChange={(value) => {
@@ -298,6 +324,21 @@ export const ServiceUsers = () => {
disabled={showTutorial}
/>
</Space>
<Tooltip
title={
isRefreshButtonDisabled
? "You can refresh it again in 5 seconds"
: "Refresh"
}
>
<Button
onClick={fetchData}
disabled={isRefreshButtonDisabled}
style={{ marginLeft: "5px", color: "#1890ff" }}
>
<ReloadOutlined />
</Button>
</Tooltip>
</Col>
{!showTutorial && (
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
+14 -11
View File
@@ -305,17 +305,20 @@ export const Settings = () => {
const createSingleArrayForPolicy: any = [];
policies.map((aControl: any) => {
const cSingleAccessArray = aControl.allGroups ? aControl.allGroups : [];
aControl.rules[0].destinations.forEach((destination: any) => {
if (cSingleAccessArray.indexOf(destination.id) === -1) {
cSingleAccessArray.push(destination.id);
}
});
aControl.rules[0].sources.forEach((source: any) => {
if (cSingleAccessArray.indexOf(source.id) === -1) {
cSingleAccessArray.push(source.id);
}
});
if (aControl.rules[0].destinations) {
aControl.rules[0].destinations.forEach((destination: any) => {
if (cSingleAccessArray.indexOf(destination.id) === -1) {
cSingleAccessArray.push(destination.id);
}
});
}
if (aControl.rules[0].sources) {
aControl.rules[0].sources.forEach((source: any) => {
if (cSingleAccessArray.indexOf(source.id) === -1) {
cSingleAccessArray.push(source.id);
}
});
}
aControl["cSingleAccessArray"] = cSingleAccessArray;
createSingleArrayForPolicy.push(aControl);
+39 -1
View File
@@ -3,6 +3,7 @@ import { useDispatch, useSelector } from "react-redux";
import { RootState } from "typesafe-actions";
import { actions as setupKeyActions } from "../store/setup-key";
import { Container } from "../components/Container";
import { ReloadOutlined } from "@ant-design/icons";
import {
Alert,
Button,
@@ -51,6 +52,7 @@ export const SetupKeys = () => {
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
const [showGroupModal, setShowGroupModal] = useState(false);
const [isRefreshButtonDisabled, setIsRefreshButtonDisabled] = useState(false);
const setupKeys = useSelector((state: RootState) => state.setupKey.data);
const failed = useSelector((state: RootState) => state.setupKey.failed);
@@ -109,6 +111,26 @@ export const SetupKeys = () => {
);
}, []);
const fetchData = async () => {
setIsRefreshButtonDisabled(true);
dispatch(
setupKeyActions.getSetupKeys.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
dispatch(
groupActions.getGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
await new Promise((resolve) => setTimeout(resolve, 5000)).then(() =>
setIsRefreshButtonDisabled(false)
);
};
useEffect(() => {
setDataTable(transformDataTable(filterDataTable("")));
}, [textToSearch, optionValidAll]);
@@ -472,9 +494,9 @@ export const SetupKeys = () => {
value={optionValidAll}
optionType="button"
buttonStyle="solid"
disabled={!dataTable?.length}
/>
<Select
style={{ marginRight: "10px" }}
disabled={!dataTable?.length}
value={pageSize.toString()}
options={pageSizeOptions}
@@ -484,6 +506,22 @@ export const SetupKeys = () => {
className="select-rows-per-page-en"
/>
</Space>
<Tooltip
title={
isRefreshButtonDisabled
? "You can refresh it again in 5 seconds"
: "Refresh"
}
>
<Button
onClick={fetchData}
disabled={isRefreshButtonDisabled}
style={{ marginLeft: "5px", color: "#1890ff" }}
>
<ReloadOutlined />
</Button>
</Tooltip>
</Col>
{dataTable.length ? (
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>