mirror of
https://github.com/netbirdio/dashboard.git
synced 2026-09-23 00:30:43 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2443c6332d | ||
|
|
3b5193ae4e | ||
|
|
cf42dd52fc | ||
|
|
bc6842e5b5 | ||
|
|
a8ed755dda | ||
|
|
a87c06ef52 | ||
|
|
c0130d265c | ||
|
|
63ced3088a | ||
|
|
42b7a15466 | ||
|
|
c88bfa6476 |
No files matched your search
@@ -58,11 +58,12 @@ export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(
|
||||
export NETBIRD_MGMT_GRPC_API_ENDPOINT=${NETBIRD_MGMT_GRPC_API_ENDPOINT}
|
||||
export NETBIRD_HOTJAR_TRACK_ID=${NETBIRD_HOTJAR_TRACK_ID}
|
||||
export NETBIRD_TOKEN_SOURCE=${NETBIRD_TOKEN_SOURCE:-accessToken}
|
||||
export NETBIRD_DRAG_QUERY_PARAMS=${NETBIRD_DRAG_QUERY_PARAMS:-false}
|
||||
|
||||
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
|
||||
|
||||
# replace ENVs in the config
|
||||
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE"
|
||||
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE \$\$NETBIRD_DRAG_QUERY_PARAMS"
|
||||
|
||||
MAIN_JS=$(find /usr/share/nginx/html/static/js/main.*js)
|
||||
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
|
||||
|
||||
+1
-12
@@ -70,16 +70,7 @@ function App() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
borderRadius: 4,
|
||||
colorPrimary: "#1890ff",
|
||||
fontFamily: "Arial"
|
||||
},
|
||||
components: {Badge: {fontSizeSM: 20}},
|
||||
}}
|
||||
>
|
||||
|
||||
<Provider store={store}>
|
||||
{!show && <SecureLoading padding="3em" width={50} height={50}/>}
|
||||
{show &&
|
||||
@@ -124,8 +115,6 @@ function App() {
|
||||
</Layout>
|
||||
}
|
||||
</Provider>
|
||||
|
||||
</ConfigProvider>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ const AccessControlEdit = () => {
|
||||
{ label: "Drop", value: "drop" },
|
||||
];
|
||||
const protocols: SelectProps["options"] = [
|
||||
{ label: "All", value: "all" },
|
||||
{ label: "ALL", value: "all" },
|
||||
{ label: "TCP", value: "tcp" },
|
||||
{ label: "UDP", value: "udp" },
|
||||
{ label: "ICMP", value: "icmp" },
|
||||
@@ -461,6 +461,7 @@ const AccessControlEdit = () => {
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Card bordered={true} style={{ marginBottom: "7px" }}>
|
||||
<div style={{ maxWidth: "550px" }}>
|
||||
<Form
|
||||
@@ -606,6 +607,7 @@ const AccessControlEdit = () => {
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<Row gutter={15}>
|
||||
<Col span={10}>
|
||||
|
||||
@@ -67,7 +67,7 @@ const AccessControlNew = () => {
|
||||
{ label: "Drop", value: "drop" },
|
||||
];
|
||||
const protocols: SelectProps["options"] = [
|
||||
{ label: "All", value: "all" },
|
||||
{ label: "ALL", value: "all" },
|
||||
{ label: "TCP", value: "tcp" },
|
||||
{ label: "UDP", value: "udp" },
|
||||
{ label: "ICMP", value: "icmp" },
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
} from "../store/nameservers/types";
|
||||
import { useGetGroupTagHelpers } from "../utils/groups";
|
||||
import { useGetTokenSilently } from "../utils/token";
|
||||
import { domainValidator } from "../utils/common";
|
||||
|
||||
const { Paragraph, Text } = Typography;
|
||||
|
||||
@@ -272,21 +273,6 @@ const NameServerGroupAdd = () => {
|
||||
setEditDescription(status);
|
||||
};
|
||||
|
||||
const domainRegex =
|
||||
/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/;
|
||||
|
||||
const domainValidator = (_: RuleObject, domain: string) => {
|
||||
if (domainRegex.test(domain)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
setIsPrimary(false);
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
"Please enter a valid domain, e.g. example.com or intra.example.com"
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const nameValidator = (_: RuleObject, value: string) => {
|
||||
const found = nsGroupData.find(
|
||||
(u) => u.name == value && u.id !== formNSGroup.id
|
||||
|
||||
@@ -30,12 +30,14 @@ import {
|
||||
import { useGetGroupTagHelpers } from "../utils/groups";
|
||||
import { useGetTokenSilently } from "../utils/token";
|
||||
import { Container } from "./Container";
|
||||
|
||||
import { domainValidator } from "../utils/common";
|
||||
const { Paragraph, Text } = Typography;
|
||||
|
||||
interface formNSGroup extends NameServerGroup {}
|
||||
|
||||
const NameServerGroupUpdate = () => {
|
||||
const NameServerGroupUpdate = (props: any) => {
|
||||
const { isGroupUpdateView, setShowGroupModal } = props;
|
||||
|
||||
const {
|
||||
blueTagRender,
|
||||
handleChangeTags,
|
||||
@@ -121,6 +123,9 @@ const NameServerGroupUpdate = () => {
|
||||
);
|
||||
setEditName(false);
|
||||
setIsPrimary(false);
|
||||
if (setShowGroupModal) {
|
||||
setShowGroupModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onChange = (changedValues: any) => {
|
||||
@@ -253,21 +258,6 @@ const NameServerGroupUpdate = () => {
|
||||
setEditDescription(status);
|
||||
};
|
||||
|
||||
const domainRegex =
|
||||
/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/;
|
||||
|
||||
const domainValidator = (_: RuleObject, domain: string) => {
|
||||
if (domainRegex.test(domain)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
setIsPrimary(false);
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
"Please enter a valid domain, e.g. example.com or intra.example.com"
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const nameValidator = (_: RuleObject, value: string) => {
|
||||
const found = nsGroupData.find(
|
||||
(u) => u.name == value && u.id !== formNSGroup.id
|
||||
@@ -316,38 +306,38 @@ const NameServerGroupUpdate = () => {
|
||||
<Col span={24} style={{ marginBottom: "15px" }}>
|
||||
<Form.Item name="enabled" label="">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "15px",
|
||||
}}
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<Switch
|
||||
onChange={handleChangeDisabled}
|
||||
defaultChecked={formNSGroup.enabled}
|
||||
size="small"
|
||||
checked={formNSGroup.enabled}
|
||||
onChange={handleChangeDisabled}
|
||||
defaultChecked={formNSGroup.enabled}
|
||||
size="small"
|
||||
checked={formNSGroup.enabled}
|
||||
/>
|
||||
<div>
|
||||
<label
|
||||
style={{
|
||||
color: "rgba(0, 0, 0, 0.88)",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
style={{
|
||||
color: "rgba(0, 0, 0, 0.88)",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
Enabled
|
||||
</label>
|
||||
<Paragraph
|
||||
type={"secondary"}
|
||||
style={{
|
||||
marginTop: "-2",
|
||||
fontWeight: "400",
|
||||
marginBottom: "0",
|
||||
}}
|
||||
type={"secondary"}
|
||||
style={{
|
||||
marginTop: "-2",
|
||||
fontWeight: "400",
|
||||
marginBottom: "0",
|
||||
}}
|
||||
>
|
||||
{formNSGroup.enabled
|
||||
? "Disable this server if you don't want the configuration to apply immediately"
|
||||
: " Enable this server if you want the configuration to apply immediately"}
|
||||
? "Disable this server if you don't want the configuration to apply immediately"
|
||||
: " Enable this server if you want the configuration to apply immediately"}
|
||||
</Paragraph>
|
||||
</div>
|
||||
</div>
|
||||
@@ -568,19 +558,21 @@ const NameServerGroupUpdate = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container style={{ paddingTop: "40px" }}>
|
||||
<Breadcrumb
|
||||
style={{ marginBottom: "25px" }}
|
||||
items={[
|
||||
{
|
||||
title: <a onClick={onBreadcrumbUsersClick}>DNS</a>,
|
||||
},
|
||||
{
|
||||
title: formNSGroup.name,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Card>
|
||||
<Container style={{ paddingTop: `${!isGroupUpdateView ? "40px" : "0"}` }}>
|
||||
{!isGroupUpdateView && (
|
||||
<Breadcrumb
|
||||
style={{ marginBottom: "25px" }}
|
||||
items={[
|
||||
{
|
||||
title: <a onClick={onBreadcrumbUsersClick}>DNS</a>,
|
||||
},
|
||||
{
|
||||
title: formNSGroup.name,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
<Card className={isGroupUpdateView ? "noborderPadding" : ""}>
|
||||
<Form
|
||||
layout="vertical"
|
||||
requiredMark={false}
|
||||
@@ -588,139 +580,148 @@ const NameServerGroupUpdate = () => {
|
||||
onValuesChange={onChange}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col span={24}>
|
||||
<Header
|
||||
style={{
|
||||
border: "none",
|
||||
}}
|
||||
>
|
||||
<Row align="top">
|
||||
<Col flex="auto">
|
||||
{!editName && formNSGroup.id ? (
|
||||
<div
|
||||
className={
|
||||
"access-control input-text ant-drawer-title"
|
||||
}
|
||||
onClick={() => toggleEditName(true)}
|
||||
style={{
|
||||
fontSize: "22px",
|
||||
margin: " 0px 0px 10px",
|
||||
cursor: "pointer",
|
||||
fontWeight: "500",
|
||||
lineHeight: "24px",
|
||||
}}
|
||||
>
|
||||
{formNSGroup.id
|
||||
? formNSGroup.name
|
||||
: "New nameserver group"}
|
||||
</div>
|
||||
) : (
|
||||
<Row>
|
||||
<Col span={8}>
|
||||
<div style={{ lineHeight: "15px" }}>
|
||||
<label
|
||||
style={{
|
||||
color: "rgba(0, 0, 0, 0.88)",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
Name
|
||||
</label>
|
||||
<Form.Item
|
||||
name="name"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message:
|
||||
"Please add an identifier for this nameserver group",
|
||||
whitespace: true,
|
||||
},
|
||||
{
|
||||
validator: nameValidator,
|
||||
},
|
||||
]}
|
||||
style={{
|
||||
marginBottom: "10px",
|
||||
marginTop: "10px",
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
placeholder="e.g. Public DNS"
|
||||
ref={inputNameRef}
|
||||
onPressEnter={() => toggleEditName(false)}
|
||||
onBlur={() => toggleEditName(false)}
|
||||
autoComplete="off"
|
||||
maxLength={40}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{!editDescription ? (
|
||||
<div
|
||||
className={
|
||||
"access-control input-text ant-drawer-subtitle"
|
||||
}
|
||||
style={{ margin: "0 0 39px 0px" }}
|
||||
onClick={() => toggleEditDescription(true)}
|
||||
>
|
||||
{formNSGroup.description &&
|
||||
formNSGroup.description.trim() !== ""
|
||||
? formNSGroup.description
|
||||
: "Add description"}
|
||||
</div>
|
||||
) : (
|
||||
<Row>
|
||||
<Col span={8} style={{ marginBottom: "15px" }}>
|
||||
|
||||
<span className={isGroupUpdateView ? "d-none" : ""}>
|
||||
<Col span={24}>
|
||||
<Header
|
||||
style={{
|
||||
border: "none",
|
||||
}}
|
||||
>
|
||||
<Row align="top">
|
||||
<Col flex="auto">
|
||||
{!editName && formNSGroup.id ? (
|
||||
<div
|
||||
style={{ lineHeight: "15px", marginTop: "24px" }}
|
||||
className={
|
||||
"access-control input-text ant-drawer-title"
|
||||
}
|
||||
onClick={() => toggleEditName(true)}
|
||||
style={{
|
||||
fontSize: "22px",
|
||||
margin: " 0px 0px 10px",
|
||||
cursor: "pointer",
|
||||
fontWeight: "500",
|
||||
lineHeight: "24px",
|
||||
}}
|
||||
>
|
||||
<label
|
||||
style={{
|
||||
color: "rgba(0, 0, 0, 0.88)",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
Description
|
||||
</label>
|
||||
<Form.Item
|
||||
name="description"
|
||||
style={{ marginTop: "8px" }}
|
||||
>
|
||||
<Input
|
||||
placeholder="Add description..."
|
||||
ref={inputDescriptionRef}
|
||||
onPressEnter={() =>
|
||||
toggleEditDescription(false)
|
||||
}
|
||||
onBlur={() => toggleEditDescription(false)}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</Form.Item>
|
||||
{formNSGroup.id
|
||||
? formNSGroup.name
|
||||
: "New nameserver group"}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Header>
|
||||
</Col>
|
||||
) : (
|
||||
<Row>
|
||||
<Col span={8}>
|
||||
<div style={{ lineHeight: "15px" }}>
|
||||
<label
|
||||
style={{
|
||||
color: "rgba(0, 0, 0, 0.88)",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
Name
|
||||
</label>
|
||||
<Form.Item
|
||||
name="name"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message:
|
||||
"Please add an identifier for this nameserver group",
|
||||
whitespace: true,
|
||||
},
|
||||
{
|
||||
validator: nameValidator,
|
||||
},
|
||||
]}
|
||||
style={{
|
||||
marginBottom: "10px",
|
||||
marginTop: "10px",
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
placeholder="e.g. Public DNS"
|
||||
ref={inputNameRef}
|
||||
onPressEnter={() => toggleEditName(false)}
|
||||
onBlur={() => toggleEditName(false)}
|
||||
autoComplete="off"
|
||||
maxLength={40}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{!editDescription ? (
|
||||
<div
|
||||
className={
|
||||
"access-control input-text ant-drawer-subtitle"
|
||||
}
|
||||
style={{ margin: "0 0 39px 0px" }}
|
||||
onClick={() => toggleEditDescription(true)}
|
||||
>
|
||||
{formNSGroup.description &&
|
||||
formNSGroup.description.trim() !== ""
|
||||
? formNSGroup.description
|
||||
: "Add description"}
|
||||
</div>
|
||||
) : (
|
||||
<Row>
|
||||
<Col span={8} style={{ marginBottom: "15px" }}>
|
||||
<div
|
||||
style={{
|
||||
lineHeight: "15px",
|
||||
marginTop: "24px",
|
||||
}}
|
||||
>
|
||||
<label
|
||||
style={{
|
||||
color: "rgba(0, 0, 0, 0.88)",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
Description
|
||||
</label>
|
||||
<Form.Item
|
||||
name="description"
|
||||
style={{ marginTop: "8px" }}
|
||||
>
|
||||
<Input
|
||||
placeholder="Add description..."
|
||||
ref={inputDescriptionRef}
|
||||
onPressEnter={() =>
|
||||
toggleEditDescription(false)
|
||||
}
|
||||
onBlur={() =>
|
||||
toggleEditDescription(false)
|
||||
}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Header>
|
||||
</Col>
|
||||
|
||||
<Col span={24} style={{ marginBottom: "15px" }}>
|
||||
<Form.List
|
||||
name="nameservers"
|
||||
rules={[{ validator: formListValidator }]}
|
||||
>
|
||||
{renderNSList}
|
||||
</Form.List>
|
||||
</Col>
|
||||
<Col span={24} style={{ marginBottom: "15px" }}>
|
||||
<Form.List
|
||||
name="nameservers"
|
||||
rules={[{ validator: formListValidator }]}
|
||||
>
|
||||
{renderNSList}
|
||||
</Form.List>
|
||||
</Col>
|
||||
|
||||
<Col span={24} style={{ marginBottom: "15px" }}>
|
||||
<Form.List name="domains">{renderDomains}</Form.List>
|
||||
</Col>
|
||||
<Col span={24} style={{ marginBottom: "15px" }}>
|
||||
<Form.List name="domains">{renderDomains}</Form.List>
|
||||
</Col>
|
||||
</span>
|
||||
|
||||
<Col span={24} style={{ marginBottom: "15px" }}>
|
||||
<label
|
||||
style={{
|
||||
@@ -764,7 +765,7 @@ const NameServerGroupUpdate = () => {
|
||||
<Space
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "start",
|
||||
justifyContent: `${!isGroupUpdateView ? "start" : "end"}`,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
|
||||
+456
-425
File diff suppressed because it is too large.
Load diff
+125
-105
@@ -38,7 +38,8 @@ const customExpiresFormat = (value: Date): string | null => {
|
||||
return formatDate(value);
|
||||
};
|
||||
|
||||
const SetupKeyNew = () => {
|
||||
const SetupKeyNew = (props: any) => {
|
||||
const { isGroupUpdateView, setShowGroupModal } = props;
|
||||
const {
|
||||
optionRender,
|
||||
blueTagRender,
|
||||
@@ -53,12 +54,12 @@ const SetupKeyNew = () => {
|
||||
const savedSetupKey = useSelector(
|
||||
(state: RootState) => state.setupKey.savedSetupKey
|
||||
);
|
||||
|
||||
|
||||
const groups = useSelector((state: RootState) => state.group.data);
|
||||
|
||||
const [form] = Form.useForm();
|
||||
const [editName, setEditName] = useState(false);
|
||||
const [formSetupKey, setFormSetupKey] = useState({} as FormSetupKey);
|
||||
const [formSetupKey, setFormSetupKey] = useState({} as FormSetupKey);
|
||||
const inputNameRef = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -160,6 +161,9 @@ const SetupKeyNew = () => {
|
||||
);
|
||||
setFormSetupKey({} as FormSetupKey);
|
||||
setVisibleNewSetupKey(false);
|
||||
if (setShowGroupModal) {
|
||||
setShowGroupModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onChange = (data: any) => {
|
||||
@@ -256,28 +260,36 @@ const SetupKeyNew = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Breadcrumb
|
||||
style={{ marginBottom: "25px" }}
|
||||
items={[
|
||||
{
|
||||
title: <a onClick={onBreadcrumbUsersClick}>Setup Keys</a>,
|
||||
},
|
||||
{
|
||||
title: setupKey.name,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Card bordered={true} style={{ marginBottom: "7px", border: "none" }}>
|
||||
{!isGroupUpdateView && (
|
||||
<Breadcrumb
|
||||
style={{ marginBottom: "25px" }}
|
||||
items={[
|
||||
{
|
||||
title: <a onClick={onBreadcrumbUsersClick}>Setup Keys</a>,
|
||||
},
|
||||
{
|
||||
title: setupKey.name,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
<Card
|
||||
bordered={true}
|
||||
className={isGroupUpdateView ? " noborderPadding" : ""}
|
||||
style={{ marginBottom: "7px", border: "none" }}
|
||||
>
|
||||
<div style={{ maxWidth: "800px" }}>
|
||||
<h3
|
||||
style={{
|
||||
fontSize: "22px",
|
||||
fontWeight: "500",
|
||||
marginBottom: "30px",
|
||||
}}
|
||||
>
|
||||
{setupKey.name}
|
||||
</h3>
|
||||
{!isGroupUpdateView && (
|
||||
<h3
|
||||
style={{
|
||||
fontSize: "22px",
|
||||
fontWeight: "500",
|
||||
marginBottom: "30px",
|
||||
}}
|
||||
>
|
||||
{setupKey.name}
|
||||
</h3>
|
||||
)}
|
||||
<Form
|
||||
layout="vertical"
|
||||
requiredMark={false}
|
||||
@@ -287,90 +299,95 @@ const SetupKeyNew = () => {
|
||||
usage_limit: 1,
|
||||
}}
|
||||
>
|
||||
<Row style={{ marginTop: "10px" }}>
|
||||
<Col
|
||||
xs={24}
|
||||
sm={24}
|
||||
md={11}
|
||||
lg={11}
|
||||
xl={11}
|
||||
xxl={11}
|
||||
span={11}
|
||||
style={{ paddingRight: "70px" }}
|
||||
>
|
||||
<Paragraph
|
||||
{!isGroupUpdateView && (
|
||||
<Row style={{ marginTop: "10px" }}>
|
||||
<Col
|
||||
xs={24}
|
||||
sm={24}
|
||||
md={11}
|
||||
lg={11}
|
||||
xl={11}
|
||||
xxl={11}
|
||||
span={11}
|
||||
style={{
|
||||
whiteSpace: "pre-line",
|
||||
fontWeight: "500",
|
||||
margin: 0,
|
||||
paddingRight: "70px",
|
||||
}}
|
||||
>
|
||||
Key
|
||||
<Tag
|
||||
color={`${
|
||||
formSetupKey.state === "valid" ? "green" : "red"
|
||||
}`}
|
||||
<Paragraph
|
||||
style={{
|
||||
marginLeft: "10px",
|
||||
borderRadius: "2px",
|
||||
whiteSpace: "pre-line",
|
||||
fontWeight: "500",
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{formSetupKey.state}
|
||||
</Tag>
|
||||
</Paragraph>
|
||||
<Input
|
||||
style={{ marginTop: "8px" }}
|
||||
disabled
|
||||
value={getFormKey(formSetupKey.key)}
|
||||
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
|
||||
/>
|
||||
</Col>
|
||||
Key
|
||||
<Tag
|
||||
color={`${
|
||||
formSetupKey.state === "valid" ? "green" : "red"
|
||||
}`}
|
||||
style={{
|
||||
marginLeft: "10px",
|
||||
borderRadius: "2px",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
{formSetupKey.state}
|
||||
</Tag>
|
||||
</Paragraph>
|
||||
<Input
|
||||
style={{ marginTop: "8px" }}
|
||||
disabled
|
||||
value={getFormKey(formSetupKey.key)}
|
||||
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
|
||||
<Paragraph
|
||||
style={{
|
||||
whiteSpace: "pre-line",
|
||||
margin: 0,
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
|
||||
<Paragraph
|
||||
style={{
|
||||
whiteSpace: "pre-line",
|
||||
margin: 0,
|
||||
fontWeight: "500",
|
||||
}}
|
||||
></Paragraph>
|
||||
{formSetupKey.type === "one-off" ? "One-off" : "Reusable"},
|
||||
available uses
|
||||
</Paragraph>
|
||||
<Col>
|
||||
<Input
|
||||
disabled
|
||||
value={
|
||||
formSetupKey.type === "reusable" &&
|
||||
formSetupKey.usage_limit === 0
|
||||
? "unlimited"
|
||||
: formSetupKey.usage_limit - formSetupKey.used_times
|
||||
}
|
||||
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
|
||||
style={{ marginTop: "8px" }}
|
||||
/>
|
||||
>
|
||||
<Paragraph
|
||||
style={{
|
||||
whiteSpace: "pre-line",
|
||||
margin: 0,
|
||||
fontWeight: "500",
|
||||
}}
|
||||
></Paragraph>
|
||||
{formSetupKey.type === "one-off" ? "One-off" : "Reusable"},
|
||||
available uses
|
||||
</Paragraph>
|
||||
<Col>
|
||||
<Input
|
||||
disabled
|
||||
value={
|
||||
formSetupKey.type === "reusable" &&
|
||||
formSetupKey.usage_limit === 0
|
||||
? "unlimited"
|
||||
: formSetupKey.usage_limit - formSetupKey.used_times
|
||||
}
|
||||
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
|
||||
style={{ marginTop: "8px" }}
|
||||
/>
|
||||
</Col>
|
||||
</Col>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row style={{ marginTop: "39px" }}>
|
||||
</Row>
|
||||
)}
|
||||
<Row style={{ marginTop: `${isGroupUpdateView ? "0" : "39px"}` }}>
|
||||
<Col
|
||||
xs={24}
|
||||
sm={24}
|
||||
md={11}
|
||||
lg={11}
|
||||
xl={11}
|
||||
xxl={11}
|
||||
span={11}
|
||||
style={{ paddingRight: "70px" }}
|
||||
md={!isGroupUpdateView ? 11 : 24}
|
||||
lg={!isGroupUpdateView ? 11 : 24}
|
||||
xl={!isGroupUpdateView ? 11 : 24}
|
||||
xxl={!isGroupUpdateView ? 11 : 24}
|
||||
span={!isGroupUpdateView ? 11 : 24}
|
||||
style={{
|
||||
paddingRight: `${!isGroupUpdateView ? "70px" : "0"}`,
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
style={{
|
||||
@@ -407,20 +424,23 @@ const SetupKeyNew = () => {
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
|
||||
<Paragraph style={{ margin: 0, fontWeight: "500" }}>
|
||||
Expires
|
||||
</Paragraph>
|
||||
<Row>
|
||||
<Input
|
||||
style={{ marginTop: "8px" }}
|
||||
disabled
|
||||
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
|
||||
value={customExpiresFormat(new Date(formSetupKey.expires))!}
|
||||
/>
|
||||
</Row>
|
||||
</Col>
|
||||
{!isGroupUpdateView && (
|
||||
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
|
||||
<Paragraph style={{ margin: 0, fontWeight: "500" }}>
|
||||
Expires
|
||||
</Paragraph>
|
||||
<Row>
|
||||
<Input
|
||||
style={{ marginTop: "8px" }}
|
||||
disabled
|
||||
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
|
||||
value={
|
||||
customExpiresFormat(new Date(formSetupKey.expires))!
|
||||
}
|
||||
/>
|
||||
</Row>
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
</Form>
|
||||
</div>
|
||||
@@ -428,7 +448,7 @@ const SetupKeyNew = () => {
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "start",
|
||||
justifyContent: `${!isGroupUpdateView ? "start" : "end"}`,
|
||||
padding: 0,
|
||||
gap: "10px",
|
||||
marginTop: "24px",
|
||||
|
||||
@@ -154,7 +154,7 @@ const SetupKeyNew = () => {
|
||||
auto_groups: [] as string[],
|
||||
usage_limit: 0,
|
||||
used_times: 0,
|
||||
expires_in: 0,
|
||||
expires_in: 7,
|
||||
} as SetupKey)
|
||||
);
|
||||
setFormSetupKey({} as FormSetupKey);
|
||||
@@ -220,8 +220,7 @@ const SetupKeyNew = () => {
|
||||
);
|
||||
|
||||
const changesDetected = (): boolean => {
|
||||
console.log("formSetupKey", formSetupKey);
|
||||
return (
|
||||
return (
|
||||
formSetupKey.name == null ||
|
||||
formSetupKey.name !== setupKey.name ||
|
||||
formSetupKey?.usage_limit !== setupKey.usage_limit
|
||||
@@ -229,8 +228,7 @@ const SetupKeyNew = () => {
|
||||
};
|
||||
|
||||
const groupsChanged = (): boolean => {
|
||||
console.log("groupsChanged", formSetupKey);
|
||||
if (
|
||||
if (
|
||||
setupKey &&
|
||||
setupKey?.auto_groups &&
|
||||
formSetupKey?.autoGroupNames &&
|
||||
@@ -346,7 +344,7 @@ const SetupKeyNew = () => {
|
||||
onValuesChange={onChange}
|
||||
initialValues={{
|
||||
usage_limit: 1,
|
||||
expires_in: "7",
|
||||
expires_in: 7,
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
@@ -462,6 +460,13 @@ const SetupKeyNew = () => {
|
||||
<Form.Item
|
||||
name="expires_in"
|
||||
rules={[
|
||||
{
|
||||
type: "number",
|
||||
min: 1,
|
||||
max: 365,
|
||||
message:
|
||||
"The expiration should be set between 1 and 365 days",
|
||||
},
|
||||
{ required: true, message: "Please enter expiration date" },
|
||||
]}
|
||||
>
|
||||
@@ -469,6 +474,7 @@ const SetupKeyNew = () => {
|
||||
placeholder={`2`}
|
||||
type="number"
|
||||
addonAfter=" Days"
|
||||
value={setupKey.expires_in}
|
||||
style={{ width: "160px", marginTop: "5px" }}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -476,7 +482,7 @@ const SetupKeyNew = () => {
|
||||
type={"secondary"}
|
||||
style={{ marginTop: "-18px", marginBottom: 0 }}
|
||||
>
|
||||
Should be between 1 and 180 days
|
||||
Should be between 1 and 365 days
|
||||
</Paragraph>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Modal } from "antd";
|
||||
import SetupKeyNew from "./SetupKeyEdit";
|
||||
export const UpdateKeyGroupModal = (props:any) => {
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
closable={false}
|
||||
open={true}
|
||||
footer={[]}
|
||||
onCancel={() => props.setShowGroupModal(false)}
|
||||
width={450}
|
||||
>
|
||||
<SetupKeyNew
|
||||
isGroupUpdateView={true}
|
||||
setShowGroupModal={props.setShowGroupModal}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Modal } from "antd";
|
||||
import NameServerGroupUpdate from "./NameServerGroupUpdate";
|
||||
export const UpdateNameServerGroupModal = (props:any) => {
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
closable={false}
|
||||
open={true}
|
||||
footer={[]}
|
||||
onCancel={() => props.setShowGroupModal(false)}
|
||||
width={450}
|
||||
>
|
||||
<NameServerGroupUpdate
|
||||
isGroupUpdateView={true}
|
||||
setShowGroupModal={props.setShowGroupModal}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Modal } from "antd";
|
||||
import PeerUpdate from "./PeerUpdate";
|
||||
export const UpdatePeerGroupModal = (props:any) => {
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
closable={false}
|
||||
open={true}
|
||||
footer={[]}
|
||||
onCancel={() => props.setShowGroupModal(false)}
|
||||
width={450}
|
||||
>
|
||||
<PeerUpdate
|
||||
isGroupUpdateView={true}
|
||||
setShowGroupModal={props.setShowGroupModal}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Modal } from "antd";
|
||||
import UserEdit from "./UserEdit";
|
||||
|
||||
export const UpdateUsersGroupModal = (props: any) => {
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
closable={false}
|
||||
open={true}
|
||||
footer={[]}
|
||||
onCancel={() => props.setShowGroupModal(false)}
|
||||
width={450}
|
||||
>
|
||||
{props.showGroupModal && (
|
||||
<UserEdit
|
||||
isGroupUpdateView={true}
|
||||
setShowGroupModal={props.setShowGroupModal}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
+305
-257
File diff suppressed because it is too large.
Load diff
+2
-1
@@ -11,5 +11,6 @@
|
||||
"hotjarTrackID": "$NETBIRD_HOTJAR_TRACK_ID",
|
||||
"redirectURI": "$AUTH_REDIRECT_URI",
|
||||
"silentRedirectURI": "$AUTH_SILENT_REDIRECT_URI",
|
||||
"tokenSource": "$NETBIRD_TOKEN_SOURCE"
|
||||
"tokenSource": "$NETBIRD_TOKEN_SOURCE",
|
||||
"dragQueryParams": "$NETBIRD_DRAG_QUERY_PARAMS"
|
||||
}
|
||||
@@ -39,5 +39,7 @@ export function getConfig() {
|
||||
redirectURI: redirectURI,
|
||||
silentRedirectURI: silentRedirectURI,
|
||||
tokenSource: tokenSource,
|
||||
// drags all the query params to the auth layer specified in the URL when accessing dashboard.
|
||||
dragQueryParams: configJson.dragQueryParams == "true"
|
||||
};
|
||||
}
|
||||
+41
-2
@@ -474,6 +474,45 @@ ul.ant-list-items {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.route-form.edit-form-wrapper .ant-form-item{
|
||||
margin-bottom: 39px;
|
||||
.route-form.edit-form-wrapper .ant-form-item {
|
||||
margin-bottom: 39px;
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
cursor: auto !important;
|
||||
}
|
||||
|
||||
.groupsSelect {
|
||||
max-width: 200px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: 1220px) {
|
||||
.groupsSelect {
|
||||
margin-left: 0;
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.setting-nav {
|
||||
flex-flow: column !important;
|
||||
}
|
||||
|
||||
.setting-nav>div {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.noborderPadding .ant-card-body {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.noborderPadding {
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.d-none{
|
||||
display: none!important;
|
||||
}
|
||||
+44
-4
@@ -10,6 +10,8 @@ import {BrowserRouter} from "react-router-dom";
|
||||
import Loading from "./components/Loading";
|
||||
import LoginError from "./components/LoginError";
|
||||
import {AuthorityConfiguration} from "@axa-fr/react-oidc/dist/vanilla/oidc";
|
||||
import InstallPage from "./views/Install";
|
||||
import {ConfigProvider} from "antd";
|
||||
|
||||
const config = getConfig();
|
||||
|
||||
@@ -17,12 +19,29 @@ const config = getConfig();
|
||||
// is required for doing logout. Therefore, we need to hardcode the config for auth
|
||||
const auth0AuthorityConfig: AuthorityConfiguration = {
|
||||
authorization_endpoint: new URL("authorize", config.authority).href,
|
||||
token_endpoint: new URL("oauth/token", config.authority).href,
|
||||
token_endpoint: new URL("oauth/token", config.authority).href,
|
||||
revocation_endpoint: new URL("oauth/revoke", config.authority).href,
|
||||
end_session_endpoint: new URL("v2/logout", config.authority).href,
|
||||
userinfo_endpoint: new URL("userinfo", config.authority).href,
|
||||
} as AuthorityConfiguration
|
||||
|
||||
const buildExtras = (config: any) => {
|
||||
type Extras = { [key: string]: string }
|
||||
let extras: Extras = {};
|
||||
|
||||
if (config.dragQueryParams) {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
searchParams.forEach((value, key) => {
|
||||
extras[key] = value
|
||||
});
|
||||
}
|
||||
|
||||
if (config.audience) {
|
||||
extras.audience = config.audience
|
||||
}
|
||||
return extras
|
||||
}
|
||||
|
||||
const providerConfig = {
|
||||
authority: config.authority,
|
||||
client_id: config.clientId,
|
||||
@@ -34,7 +53,7 @@ const providerConfig = {
|
||||
// service_worker_relative_url:'/OidcServiceWorker.js',
|
||||
service_worker_only: false,
|
||||
authority_configuration: config.auth0Auth ? auth0AuthorityConfig : undefined,
|
||||
...(config.audience ? {extras: {audience: config.audience}} : null),
|
||||
extras: buildExtras(config),
|
||||
...(config.clientSecret ? {token_request_extras: {client_secret: config.clientSecret}} : null)
|
||||
};
|
||||
|
||||
@@ -44,8 +63,14 @@ const root = ReactDOM.createRoot(
|
||||
|
||||
const loadingComponent = () => <Loading padding="3em" width={50} height={50}/>
|
||||
|
||||
root.render(
|
||||
<OidcProvider
|
||||
const showApp = () => {
|
||||
if (window.location.pathname === "/install") {
|
||||
// We bypass authentication for pages that do not require auth.
|
||||
// E.g., when we just want to show installation steps for public.
|
||||
return <InstallPage/>
|
||||
}
|
||||
|
||||
return <OidcProvider
|
||||
configuration={providerConfig}
|
||||
callbackSuccessComponent={loadingComponent}
|
||||
authenticatingErrorComponent={LoginError}
|
||||
@@ -60,6 +85,21 @@ root.render(
|
||||
<App/>
|
||||
</BrowserRouter>
|
||||
</OidcProvider>
|
||||
}
|
||||
|
||||
root.render(
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
borderRadius: 4,
|
||||
colorPrimary: "#1890ff",
|
||||
fontFamily: "Arial"
|
||||
},
|
||||
components: {Badge: {fontSizeSM: 20}},
|
||||
}}
|
||||
>
|
||||
{showApp()}
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
||||
@@ -74,13 +74,13 @@ export function* setDeleteGroup(action: ReturnType<typeof actions.setDeleteGrou
|
||||
|
||||
export function* deleteGroup(action: ReturnType<typeof actions.deleteGroup.request>): Generator {
|
||||
try {
|
||||
yield call(actions.setDeleteGroup,{
|
||||
yield put(actions.setDeleteGroup({
|
||||
loading: true,
|
||||
success: false,
|
||||
failure: false,
|
||||
error: null,
|
||||
data: null
|
||||
} as DeleteResponse<string | null>)
|
||||
} as DeleteResponse<string | null>))
|
||||
|
||||
const effect = yield call(service.deleteGroup, action.payload);
|
||||
const response = effect as ApiResponse<any>;
|
||||
@@ -93,8 +93,8 @@ export function* deleteGroup(action: ReturnType<typeof actions.deleteGroup.reque
|
||||
data: response.body
|
||||
} as DeleteResponse<string | null>));
|
||||
|
||||
const rules = (yield select(state => state.rule.data)) as Group[]
|
||||
yield put(actions.getGroups.success(rules.filter((p:Group) => p.id !== action.payload.payload)))
|
||||
const groups = (yield select(state => state.group.data)) as Group[]
|
||||
yield put(actions.getGroups.success(groups.filter((p:Group) => p.id !== action.payload.payload)))
|
||||
} catch (err) {
|
||||
yield put(actions.deleteGroup.failure({
|
||||
loading: false,
|
||||
|
||||
+22
-7
@@ -59,22 +59,22 @@ function getFormattedDate(date, preformattedDate = false, hideYear = false) {
|
||||
|
||||
if (minutes < 10) {
|
||||
// Adding leading zero to minutes
|
||||
minutes = `0${ minutes }`;
|
||||
minutes = `0${minutes}`;
|
||||
}
|
||||
|
||||
if (preformattedDate) {
|
||||
// Today
|
||||
// Yesterday
|
||||
return `${ preformattedDate }`;
|
||||
return `${preformattedDate}`;
|
||||
}
|
||||
|
||||
if (hideYear) {
|
||||
// 10. January
|
||||
return `${ day }. ${ month }`;
|
||||
return `${day}. ${month}`;
|
||||
}
|
||||
|
||||
// 10. January 2017.
|
||||
return `${ day }. ${ month } ${ year }`;
|
||||
return `${day}. ${month} ${year}`;
|
||||
}
|
||||
|
||||
export const fullDate = (dateParam) => {
|
||||
@@ -107,11 +107,11 @@ export const timeAgo = (dateParam) => {
|
||||
} else if (seconds < 5) {
|
||||
return 'just now';
|
||||
} else if (seconds < 60) {
|
||||
return `${ seconds } seconds ago`;
|
||||
return `${seconds} seconds ago`;
|
||||
} else if (seconds < 90) {
|
||||
return 'about a minute ago';
|
||||
} else if (minutes < 60) {
|
||||
return `${ minutes } minutes ago`;
|
||||
return `${minutes} minutes ago`;
|
||||
} else if (isToday) {
|
||||
return getFormattedDate(date, 'today'); // Today at 10:20
|
||||
} else if (isYesterday) {
|
||||
@@ -133,4 +133,19 @@ export const isNetBirdHosted = () => {
|
||||
|
||||
export const isLocalDev = () => {
|
||||
return window.location.hostname.includes("localhost")
|
||||
}
|
||||
}
|
||||
|
||||
const domainRegex =
|
||||
/^(?!.*\s)[a-zA-Z0-9](?!.*\s$)(?!.*\.$)(?:(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.){1,126}(?!-)[a-zA-Z0-9-]{1,63}(?<!-)$/;
|
||||
|
||||
export const domainValidator = (_, domain) => {
|
||||
if (domainRegex.test(domain)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
// setIsPrimary(false);
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
"Please enter a valid domain, e.g. example.com or intra.example.com"
|
||||
)
|
||||
);
|
||||
};
|
||||
Loaded 20 of 29 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user