Compare commits

..
18 Commits
Author SHA1 Message Date
Bethuel 899f56acdc fix: remove any trailing / in auth authority (#201) 2023-06-07 15:35:20 +02:00
braginini dc2760d5ff Fix elements alignment for the ACLs view 2023-06-06 15:07:51 +02:00
Sarooj bukhariandSarooj Bukhari 5ae4fd31f1 Udpate acceess control table layout (#199)
Co-authored-by: Sarooj Bukhari <120650489+saroojbukhari2022@users.noreply.github.com>
2023-06-06 14:31:18 +02:00
braginini 54d9d7c768 Remove peer view header 2023-06-05 18:44:18 +02:00
braginini 3a73781fca Merge remote-tracking branch 'origin/main' 2023-06-05 18:10:21 +02:00
braginini f3c5d4df6a Fix color scheme for disabled fields 2023-06-05 18:07:28 +02:00
Bethuel b4c9135c58 support authentication with client_secret (#198) 2023-06-05 18:02:43 +02:00
Sarooj bukhari a280d9c67c Update peers layout and add routes component on peers edit (#196) 2023-06-05 15:22:03 +02:00
Misha Bragin 5caf06b086 Decrease length of the hidden setup key prefix (#195) 2023-06-02 11:06:05 +02:00
braginini 95af1c4e32 lower case of the Create key button 2023-06-02 10:53:47 +02:00
Sarooj bukhari d247e7f3ed Change edit key on group from popup to page (#194) 2023-06-01 16:51:51 +02:00
Sarooj bukhari 391e534253 Show setupkey once on creation (#191) 2023-06-01 12:08:58 +02:00
Sarooj bukhari a7f64d4a15 Update setup key edit layout (#190)
https://github.com/netbirdio/dashboard/issues/187
2023-06-01 09:49:10 +02:00
Givi Khojanashvili 53ed514803 ACL to firewall rules (#163)
ACL based on the firewall rules
2023-06-01 10:06:08 +04:00
pascal-fischer 6cadce1598 Add pkg installer to MacOS popup (#188) 2023-05-30 19:05:29 +02:00
pascal-fischer c03d4b8a4b Fix peers views in safari 2023-05-30 13:42:29 +02:00
dependabot[bot] bc1053fbb4 Bump json5 from 1.0.1 to 1.0.2 (#124) 2023-05-29 13:58:20 +02:00
dependabot[bot] d154bfb799 Bump webpack from 5.74.0 to 5.76.1 (#148) 2023-05-29 13:57:48 +02:00
31 changed files with 5955 additions and 3451 deletions

No files matched your search

+2 -1
View File
@@ -43,6 +43,7 @@ fi
export AUTH_AUTHORITY=${AUTH_AUTHORITY:-https://$AUTH0_DOMAIN}
export AUTH_CLIENT_ID=${AUTH_CLIENT_ID:-$AUTH0_CLIENT_ID}
export AUTH_CLIENT_SECRET=${AUTH_CLIENT_SECRET}
export AUTH_AUDIENCE=${AUTH_AUDIENCE:-$AUTH0_AUDIENCE}
export AUTH_REDIRECT_URI=${AUTH_REDIRECT_URI}
export AUTH_SILENT_REDIRECT_URI=${AUTH_SILENT_REDIRECT_URI}
@@ -57,7 +58,7 @@ export NETBIRD_TOKEN_SOURCE=${NETBIRD_TOKEN_SOURCE:-accessToken}
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
# replace ENVs in the config
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$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"
MAIN_JS=$(find /usr/share/nginx/html/static/js/main.*js)
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
+18 -18
View File
@@ -10395,9 +10395,9 @@
}
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"bin": {
"json5": "lib/cli.js"
},
@@ -15701,9 +15701,9 @@
}
},
"node_modules/tsconfig-paths/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dependencies": {
"minimist": "^1.2.0"
},
@@ -16110,9 +16110,9 @@
}
},
"node_modules/webpack": {
"version": "5.74.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
"integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
"version": "5.76.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
"integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
"dependencies": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51",
@@ -24411,9 +24411,9 @@
}
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
},
"jsonfile": {
"version": "6.1.0",
@@ -28108,9 +28108,9 @@
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"requires": {
"minimist": "^1.2.0"
}
@@ -28411,9 +28411,9 @@
"integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
},
"webpack": {
"version": "5.74.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz",
"integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==",
"version": "5.76.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
"integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
"requires": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51",
+2 -2
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="29.435" height="7.636" viewBox="0 0 29.435 7.636">
<path id="direct_bi" d="M3.64,8.158-.178,4.34,3.64.522,4.3,1.17l-2.7,2.7h25.89l-2.7-2.7.656-.648L29.257,4.34,27.213,6.384,25.439,8.158,24.783,7.5l2.7-2.693H1.595L4.3,7.5Z" transform="translate(0.178 -0.522)" fill="#1e429f"/>
<svg width="39" height="6" viewBox="0 0 39 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.451731 2.66267C0.315048 2.79935 0.315048 3.02096 0.451731 3.15764L2.67912 5.38503C2.8158 5.52171 3.03741 5.52171 3.17409 5.38503C3.31078 5.24835 3.31078 5.02674 3.17409 4.89006L1.19419 2.91016L3.17409 0.930257C3.31078 0.793574 3.31078 0.571966 3.17409 0.435282C3.03741 0.298599 2.8158 0.298599 2.67912 0.435282L0.451731 2.66267ZM38.3807 3.15764C38.5174 3.02096 38.5174 2.79935 38.3807 2.66267L36.1533 0.435282C36.0166 0.298599 35.795 0.298599 35.6583 0.435282C35.5216 0.571966 35.5216 0.793574 35.6583 0.930257L37.6382 2.91016L35.6583 4.89006C35.5216 5.02674 35.5216 5.24835 35.6583 5.38503C35.795 5.52171 36.0166 5.52171 36.1533 5.38503L38.3807 3.15764ZM0.699219 3.26016H38.1332V2.56016H0.699219V3.26016Z" fill="#03543F"/>
</svg>

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 837 B

+2 -2
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="29.497" height="7.636" viewBox="0 0 29.497 7.636">
<path id="direct_out" d="M26.589,8l-.656-.656,2.7-2.693H.91V3.713H28.635l-2.7-2.7.656-.648,3.818,3.818Z" transform="translate(-0.91 -0.364)" fill="#03543f"/>
<svg width="39" height="6" viewBox="0 0 39 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.3807 3.15764C38.5174 3.02096 38.5174 2.79935 38.3807 2.66267L36.1533 0.435282C36.0166 0.298599 35.795 0.298599 35.6583 0.435282C35.5216 0.571966 35.5216 0.793574 35.6583 0.930257L37.6382 2.91016L35.6583 4.89006C35.5216 5.02674 35.5216 5.24835 35.6583 5.38503C35.795 5.52171 36.0166 5.52171 36.1533 5.38503L38.3807 3.15764ZM0.699219 3.26016H38.1332V2.56016H0.699219V3.26016Z" fill="#1E429F"/>
</svg>

Before

Width:  |  Height:  |  Size: 265 B

After

Width:  |  Height:  |  Size: 506 B

File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -49,7 +49,7 @@ export const AddPeerPopup: React.FC<Props> = ({
},
{
key: "3",
label: <span><AppleFilled/>macOS</span>,
label: <span><AppleFilled/>MacOS</span>,
children: <MacTab/>,
},
{
@@ -1,12 +1,14 @@
import React, {useState} from 'react';
import {Button, Typography} from "antd";
import {Button, Divider, Row, Tooltip, Typography} from "antd";
import TabSteps from "./TabSteps";
import {StepCommand} from "./types"
import {formatNetBirdUP} from "./common"
import {Collapse} from "antd";
import SyntaxHighlighter from "react-syntax-highlighter";
const { Panel } = Collapse;
import {QuestionCircleOutlined} from "@ant-design/icons";
const {Panel} = Collapse;
const {Text} = Typography;
@@ -15,10 +17,28 @@ export const LinuxTab = () => {
const [quickSteps, setQuickSteps] = useState([
{
key: 1,
title: 'Download and run installer:',
title: (
<Row>
<Text>Download and run MacOS installer: </Text>
<Tooltip title={
<text>If you don't know what chip your Mac has, you can find out by clicking on the Apple logo
in the top left corner of your screen and selecting 'About This Mac'. For more information
click <a href="https://support.apple.com/en-us/HT211814" target="_blank">here</a></text>
}
className={"ant-form-item-tooltip"}>
<QuestionCircleOutlined
style={{color: "rgba(0, 0, 0, 0.45)", cursor: "help", marginLeft: "3px"}}/>
</Tooltip>
</Row>
),
commands: (
<Button style={{marginTop: "5px"}} type="primary" href="https://pkgs.netbird.io/windows/x64"
target="_blank">Download NetBird</Button>
<Row style={{paddingTop: "5px"}}>
<Button style={{marginRight: "10px"}} type="primary" href="https://pkgs.netbird.io/macos/amd64">Download
for Intel</Button>
<Button style={{marginRight: "10px"}} type="default" href="https://pkgs.netbird.io/macos/arm64">Download
for M1 & M2</Button>
</Row>
),
copied: false
} as StepCommand,
@@ -78,35 +98,38 @@ export const LinuxTab = () => {
showCopyButton: true
} as StepCommand
])
return (
<div style={{marginTop: 10}}>
<Text style={{fontWeight: "bold"}}>
Install with one command
Install on MacOS
</Text>
<div style={{fontSize: ".85em", marginTop: 5, marginBottom: 25}}>
<SyntaxHighlighter language="bash">
curl -fsSL https://pkgs.netbird.io/install.sh | sh
</SyntaxHighlighter>
</div>
<Text style={{fontWeight: "bold"}}>
Or install manually with HomeBrew
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</div>
/*<div style={{marginTop: 5}}>
<div style={{marginTop: 5, marginBottom: 5}}>
<TabSteps stepsItems={quickSteps}/>
</div>*/
/*<div style={{marginTop: 10}}>
<Text style={{fontWeight: "bold"}}>
Install on macOS with Homebrew
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</div>*/
<div style={{marginTop: 0}}/>
{/*<Divider style={{marginTop: "5px"}} />*/}
<Collapse bordered={false} style={{backgroundColor: "unset"}}>
<Panel className="CustomPopupCollapse" header={<Text strong={true}>Or install via command line</Text>}
key="1">
<div style={{marginLeft: "25px"}}>
<Text style={{fontWeight: "bold"}}>
Install with one command
</Text>
<div style={{fontSize: ".85em", marginTop: 5, marginBottom: 25}}>
<SyntaxHighlighter language="bash">
curl -fsSL https://pkgs.netbird.io/install.sh | sh
</SyntaxHighlighter>
</div>
<Text style={{fontWeight: "bold"}}>
Or install manually with HomeBrew
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</div>
</Panel>
</Collapse>
</div>
)
}
+1
View File
@@ -2,6 +2,7 @@
"auth0Auth": "$USE_AUTH0",
"authAuthority": "$AUTH_AUTHORITY",
"authClientId": "$AUTH_CLIENT_ID",
"authClientSecret": "$AUTH_CLIENT_SECRET",
"authScopesSupported": "$AUTH_SUPPORTED_SCOPES",
"authAudience": "$AUTH_AUDIENCE",
+2 -1
View File
@@ -28,8 +28,9 @@ export function getConfig() {
return {
auth0Auth: configJson.auth0Auth == "true", //due to substitution we can't use boolean in the config
authority: configJson.authAuthority,
authority: configJson.authAuthority.replace(/\/+$/, ''),
clientId: configJson.authClientId,
clientSecret: configJson.authClientSecret,
scopesSupported: configJson.authScopesSupported,
apiOrigin: configJson.apiOrigin,
grpcApiOrigin: configJson.grpcApiOrigin,
+38 -9
View File
@@ -5,6 +5,7 @@ body {
background-color: #f0f2f5;
}
.ant-layout-header {
background: #fff;
padding: 0;
@@ -23,12 +24,12 @@ body {
border: none;
}
.ant-menu-horizontal > .ant-menu-item a {
.ant-menu-horizontal>.ant-menu-item a {
color: rgba(107, 114, 128, 1);
font-weight: 500;
}
.ant-menu-horizontal > .ant-menu-item-selected a {
.ant-menu-horizontal>.ant-menu-item-selected a {
color: rgba(17, 24, 39, 1);
}
@@ -47,23 +48,25 @@ body {
flex-wrap: wrap;
align-items: flex-start;
}
.space-align-block {
flex: none;
margin: 8px 4px;
padding: 4px;
border: none;
}
.space-align-block .mock-block {
display: inline-block;
padding: 32px 8px 16px;
background: rgba(150, 150, 150, 0.2);
}
.bg-indigo-600{
.bg-indigo-600 {
background-color: rgb(79, 70, 229);
}
.card-table-no-placeholder .ant-table-placeholder{
.card-table-no-placeholder .ant-table-placeholder {
display: none;
}
@@ -75,9 +78,10 @@ body {
height: 200px;
}
.card-table .ant-table-ping-left:not(.ant-table-has-fix-left) .ant-table-container::before {
.card-table .ant-table-ping-left:not(.ant-table-has-fix-left) .ant-table-container::before {
box-shadow: none;
}
.card-table .ant-table-ping-right:not(.ant-table-has-fix-right) .ant-table-container::after {
box-shadow: none;
}
@@ -119,15 +123,17 @@ body {
margin: 24px 0;
}
.ant-steps-item-icon{
.ant-steps-item-icon {
background: #EBEBEB !important;
border-color: #EBEBEB !important;
}
.ant-steps-icon-dot{
.ant-steps-icon-dot {
background: #EBEBEB !important;
border-color: #EBEBEB !important;
}
.ant-steps-icon {
.ant-steps-icon {
background: #EBEBEB !important;
border: none;
color: black !important;
@@ -145,10 +151,33 @@ td.non-highlighted-table-column {
background-color: #FFFFFF !important;
}
.ant-table-tbody > tr.ant-table-row:hover > td {
.ant-table-tbody>tr.ant-table-row:hover>td {
background: #FAFAFA !important;
}
.ant-table-thead .ant-table-cell {
font-weight: normal !important;
}
.CustomPopupCollapse .ant-collapse-content-box,
.CustomPopupCollapse .ant-collapse-header {
padding-left: 0 !important;
padding-top: 0 !important;
}
.system-info-panel .ant-collapse-header {
padding: 0 !important;
}
.system-info-panel .ant-collapse-content-box {
padding-left: 0 !important;
padding-right: 0 !important;
}
.peers-form .ant-layout-header {
line-height: 25px;
height: auto;
min-height: auto;
padding-bottom: 15px;
cursor: pointer;
}
+2 -1
View File
@@ -34,7 +34,8 @@ 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)
...(config.audience ? {extras: {audience: config.audience}} : null),
...(config.clientSecret ? {token_request_extras: {client_secret: config.clientSecret}} : null)
};
const root = ReactDOM.createRoot(
+3 -1
View File
@@ -5,6 +5,7 @@ import { composeWithDevTools } from 'redux-devtools-extension';
import { sagas as peerSagas } from './peer';
import { sagas as setupKeySagas } from './setup-key';
import { sagas as userSagas } from './user';
import { sagas as policySagas } from './policy';
import { sagas as ruleSagas } from './rule';
import { sagas as groupSagas } from './group';
import { sagas as routeSagas } from './route';
@@ -28,6 +29,7 @@ sagaMiddleware.run(peerSagas);
sagaMiddleware.run(setupKeySagas);
sagaMiddleware.run(userSagas);
sagaMiddleware.run(ruleSagas);
sagaMiddleware.run(policySagas);
sagaMiddleware.run(groupSagas);
sagaMiddleware.run(routeSagas);
sagaMiddleware.run(nameserverGroupSagas);
@@ -36,4 +38,4 @@ sagaMiddleware.run(dnsSettingsSagas);
sagaMiddleware.run(accountSagas);
sagaMiddleware.run(personalAccessTokenSagas);
export { apiClient, rootReducer, store };
export { apiClient, rootReducer, store };
+34
View File
@@ -0,0 +1,34 @@
import { ActionType, createAction, createAsyncAction } from 'typesafe-actions';
import { Policy, PolicyToSave } from './types';
import { ApiError, CreateResponse, DeleteResponse, RequestPayload } from '../../services/api-client/types';
const actions = {
getPolicies: createAsyncAction(
'GET_POLICIES_REQUEST',
'GET_POLICIES_SUCCESS',
'GET_POLICIES_FAILURE',
)<RequestPayload<null>, Policy[], ApiError>(),
savePolicy: createAsyncAction(
'SAVE_POLICY_REQUEST',
'SAVE_POLICY_SUCCESS',
'SAVE_POLICY_FAILURE',
)<RequestPayload<PolicyToSave>, CreateResponse<Policy | null>, CreateResponse<Policy | null>>(),
setSavedPolicy: createAction('SET_CREATE_POLICY')<CreateResponse<Policy | null>>(),
resetSavedPolicy: createAction('RESET_CREATE_POLICY')<null>(),
deletePolicy: createAsyncAction(
'DELETE_POLICY_REQUEST',
'DELETE_POLICY_SUCCESS',
'DELETE_POLICY_FAILURE'
)<RequestPayload<string>, DeleteResponse<string | null>, DeleteResponse<string | null>>(),
setDeletedPolicy: createAction('SET_DELETED_POLICY')<DeleteResponse<string | null>>(),
resetDeletedPolicy: createAction('RESET_DELETED_POLICY')<null>(),
removePolicy: createAction('REMOVE_POLICY')<string>(),
setPolicy: createAction('SET_POLICY')<Policy>(),
setSetupNewPolicyVisible: createAction('SET_SETUP_NEW_POLICY_VISIBLE')<boolean>()
};
export type ActionTypes = ActionType<typeof actions>;
export default actions;
+7
View File
@@ -0,0 +1,7 @@
import actions, { ActionTypes as _actionTypes } from './actions';
import reducer from './reducer';
import sagas from './sagas';
export type ActionTypes = _actionTypes;
export { actions, reducer, sagas };
+89
View File
@@ -0,0 +1,89 @@
import { createReducer } from 'typesafe-actions';
import { combineReducers } from 'redux';
import { Policy } from './types';
import actions, { ActionTypes } from './actions';
import { ApiError, DeleteResponse, CreateResponse } from "../../services/api-client/types";
type StateType = Readonly<{
data: Policy[] | null;
policy: Policy | null;
loading: boolean;
failed: ApiError | null;
saving: boolean;
deletePolicy: DeleteResponse<string | null>;
savedPolicy: CreateResponse<Policy | null>;
setupNewPolicyVisible: boolean
}>;
const initialState: StateType = {
data: [],
policy: null,
loading: false,
failed: null,
saving: false,
deletePolicy: <DeleteResponse<string | null>>{
loading: false,
success: false,
failure: false,
error: null,
data: null
},
savedPolicy: <CreateResponse<Policy | null>>{
loading: false,
success: false,
failure: false,
error: null,
data: null
},
setupNewPolicyVisible: false
};
const data = createReducer<Policy[], ActionTypes>(initialState.data as Policy[])
.handleAction(actions.getPolicies.success, (_, action) => action.payload)
.handleAction(actions.getPolicies.failure, () => []);
const policy = createReducer<Policy, ActionTypes>(initialState.policy as Policy)
.handleAction(actions.setPolicy, (store, action) => action.payload);
const loading = createReducer<boolean, ActionTypes>(initialState.loading)
.handleAction(actions.getPolicies.request, () => true)
.handleAction(actions.getPolicies.success, () => false)
.handleAction(actions.getPolicies.failure, () => false);
const failed = createReducer<ApiError | null, ActionTypes>(initialState.failed)
.handleAction(actions.getPolicies.request, () => null)
.handleAction(actions.getPolicies.success, () => null)
.handleAction(actions.getPolicies.failure, (store, action) => action.payload);
const saving = createReducer<boolean, ActionTypes>(initialState.saving)
.handleAction(actions.getPolicies.request, () => true)
.handleAction(actions.getPolicies.success, () => false)
.handleAction(actions.getPolicies.failure, () => false);
const deletedPolicy = createReducer<DeleteResponse<string | null>, ActionTypes>(initialState.deletePolicy)
.handleAction(actions.deletePolicy.request, () => initialState.deletePolicy)
.handleAction(actions.deletePolicy.success, (store, action) => action.payload)
.handleAction(actions.deletePolicy.failure, (store, action) => action.payload)
.handleAction(actions.setDeletedPolicy, (store, action) => action.payload)
.handleAction(actions.resetDeletedPolicy, () => initialState.deletePolicy)
const savedPolicy = createReducer<CreateResponse<Policy | null>, ActionTypes>(initialState.savedPolicy)
.handleAction(actions.savePolicy.request, () => initialState.savedPolicy)
.handleAction(actions.savePolicy.success, (store, action) => action.payload)
.handleAction(actions.savePolicy.failure, (store, action) => action.payload)
.handleAction(actions.setSavedPolicy, (store, action) => action.payload)
.handleAction(actions.resetSavedPolicy, () => initialState.savedPolicy)
const setupNewPolicyVisible = createReducer<boolean, ActionTypes>(initialState.setupNewPolicyVisible)
.handleAction(actions.setSetupNewPolicyVisible, (store, action) => action.payload)
export default combineReducers({
data,
policy,
loading,
failed,
saving,
deletedPolicy,
savedPolicy,
setupNewPolicyVisible
});
+223
View File
@@ -0,0 +1,223 @@
import { all, call, put, select, takeLatest } from "redux-saga/effects";
import {
ApiError,
ApiResponse,
CreateResponse,
DeleteResponse,
} from "../../services/api-client/types";
import { Policy, PolicyRule } from "./types";
import service from "./service";
import serviceGroup from "../group/service";
import actions from "./actions";
import { actions as groupActions } from "../group";
import { Group } from "../group/types";
export function* getPolicies(
action: ReturnType<typeof actions.getPolicies.request>
): Generator {
try {
yield put(
actions.setDeletedPolicy({
loading: false,
success: false,
failure: false,
error: null,
data: null,
} as DeleteResponse<string | null>)
);
const effect = yield call(service.getPolicies, action.payload);
const response = effect as ApiResponse<Policy[]>;
yield put(actions.getPolicies.success(response.body));
} catch (err) {
yield put(actions.getPolicies.failure(err as ApiError));
}
}
export function* setCreatedPolicy(
action: ReturnType<typeof actions.setSavedPolicy>
): Generator {
yield put(actions.setSavedPolicy(action.payload));
}
function getNewGroupIds(dataString: string[], responses: Group[]): string[] {
return responses
.filter((r) => dataString.includes(r.name))
.map((r) => r.id || "");
}
export function* savePolicy(
action: ReturnType<typeof actions.savePolicy.request>
): Generator {
try {
yield put(
actions.setSavedPolicy({
loading: true,
success: false,
failure: false,
error: null,
data: null,
} as CreateResponse<Policy | null>)
);
const policyToSave = action.payload.payload;
const groupsToSave = policyToSave.groupsToSave
? policyToSave.groupsToSave
: [];
const responsesGroup = yield all(
groupsToSave.map((g) =>
call(serviceGroup.createGroup, {
getAccessTokenSilently: action.payload.getAccessTokenSilently,
payload: { name: g },
})
)
);
const resGroups = (responsesGroup as ApiResponse<Policy>[])
.filter((r) => r.statusCode === 200)
.map((r) => r.body as Group);
const currentGroups = [
...((yield select((state) => state.group.data)) as Policy[]),
];
const newGroups = [...currentGroups, ...resGroups];
yield put(groupActions.getGroups.success(newGroups));
const newSources = getNewGroupIds(
policyToSave.sourcesNoId ? policyToSave.sourcesNoId : [],
resGroups
);
const newDestinations = getNewGroupIds(
policyToSave.destinationsNoId ? policyToSave.destinationsNoId : [],
resGroups
);
const payloadToSave = {
getAccessTokenSilently: action.payload.getAccessTokenSilently,
payload: {
name: policyToSave.name,
description: policyToSave.description,
enabled: policyToSave.enabled,
query: policyToSave.query,
} as Policy,
};
if (policyToSave.rules.length > 0) {
payloadToSave.payload.rules = [];
}
policyToSave.rules.forEach((r) => {
payloadToSave.payload.rules.push({
name: r.name,
description: r.description,
enabled: r.enabled,
sources: [...(r.sources as string[]), ...newSources],
destinations: [...(r.destinations as string[]), ...newDestinations],
bidirectional: r.bidirectional,
protocol: r.protocol,
ports: r.ports,
action: r.action,
} as PolicyRule);
});
let effect;
if (!policyToSave.id) {
effect = yield call(service.createPolicy, payloadToSave);
} else {
payloadToSave.payload.id = policyToSave.id;
effect = yield call(service.editPolicy, payloadToSave);
}
const response = effect as ApiResponse<Policy>;
yield put(
actions.savePolicy.success({
loading: false,
success: true,
failure: false,
error: null,
data: response.body,
} as CreateResponse<Policy | null>)
);
yield put(
groupActions.getGroups.request({
getAccessTokenSilently: action.payload.getAccessTokenSilently,
payload: null,
})
);
yield put(
actions.getPolicies.request({
getAccessTokenSilently: action.payload.getAccessTokenSilently,
payload: null,
})
);
} catch (err) {
yield put(
actions.savePolicy.failure({
loading: false,
success: false,
failure: true,
error: err as ApiError,
data: null,
} as CreateResponse<Policy | null>)
);
}
}
export function* setDeletePolicy(
action: ReturnType<typeof actions.setDeletedPolicy>
): Generator {
yield put(actions.setDeletedPolicy(action.payload));
}
export function* deletePolicy(
action: ReturnType<typeof actions.deletePolicy.request>
): Generator {
try {
yield call(actions.setDeletedPolicy, {
loading: true,
success: false,
failure: false,
error: null,
data: null,
} as DeleteResponse<string | null>);
const effect = yield call(service.deletedPolicy, action.payload);
const response = effect as ApiResponse<any>;
yield put(
actions.deletePolicy.success({
loading: false,
success: true,
failure: false,
error: null,
data: response.body,
} as DeleteResponse<string | null>)
);
const policies = (yield select((state) => state.policy.data)) as Policy[];
yield put(
actions.getPolicies.success(
policies.filter((p: Policy) => p.id !== action.payload.payload)
)
);
} catch (err) {
yield put(
actions.deletePolicy.failure({
loading: false,
success: false,
failure: false,
error: err as ApiError,
data: null,
} as DeleteResponse<string | null>)
);
}
}
export default function* sagas(): Generator {
yield all([
takeLatest(actions.getPolicies.request, getPolicies),
takeLatest(actions.savePolicy.request, savePolicy),
takeLatest(actions.deletePolicy.request, deletePolicy),
]);
}
Loaded 20 of 31 files, more files were not shown because too many files have changed in this diff. Show more