mirror of
https://github.com/netbirdio/dashboard.git
synced 2026-09-23 00:30:43 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a29dac01c | ||
|
|
444e9ec44a | ||
|
|
dff0313f82 | ||
|
|
11fbfb336a | ||
|
|
4a0ae8f27d | ||
|
|
9a72d8b0c4 | ||
|
|
8e038cf242 |
No files matched your search
@@ -52,11 +52,12 @@ export AUTH_SUPPORTED_SCOPES=${AUTH_SUPPORTED_SCOPES:-openid profile email api o
|
||||
export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//')
|
||||
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}
|
||||
|
||||
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"
|
||||
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"
|
||||
|
||||
MAIN_JS=$(find /usr/share/nginx/html/static/js/main.*js)
|
||||
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
|
||||
|
||||
+6
-5
@@ -16,7 +16,7 @@ import SetupKeys from "./views/SetupKeys";
|
||||
import AccessControl from "./views/AccessControl";
|
||||
import Users from "./views/Users";
|
||||
import FooterComponent from "./components/FooterComponent";
|
||||
import {useGetAccessTokenSilently} from "./utils/token";
|
||||
import {useGetTokenSilently, useTokenSource} from "./utils/token";
|
||||
import {User} from "./store/user/types";
|
||||
import {SecureLoading} from "./components/Loading";
|
||||
import DNS from "./views/DNS";
|
||||
@@ -29,8 +29,9 @@ const {Header, Content} = Layout;
|
||||
function App() {
|
||||
const run = useRef(false)
|
||||
const [show, setShow] = useState(false)
|
||||
const {getAccessTokenSilently} = useGetAccessTokenSilently();
|
||||
const {hotjarTrackID} = getConfig();
|
||||
const {hotjarTrackID,tokenSource} = getConfig();
|
||||
useTokenSource(tokenSource)
|
||||
const {getTokenSilently} = useGetTokenSilently();
|
||||
// @ts-ignore
|
||||
if (hotjarTrackID && window._DATADOG_SYNTHETICS_BROWSER === undefined) {
|
||||
hotjar.initialize(hotjarTrackID, 6);
|
||||
@@ -55,7 +56,7 @@ function App() {
|
||||
useEffect(() => {
|
||||
if (!run.current) {
|
||||
run.current = true
|
||||
apiClient.request<User[]>('GET', `/api/users`, {getAccessTokenSilently: getAccessTokenSilently})
|
||||
apiClient.request<User[]>('GET', `/api/users`, {getAccessTokenSilently: getTokenSilently})
|
||||
.then(() => {
|
||||
setShow(true)
|
||||
})
|
||||
@@ -65,7 +66,7 @@ function App() {
|
||||
})
|
||||
}
|
||||
|
||||
}, [getAccessTokenSilently])
|
||||
}, [getTokenSilently])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -23,7 +23,7 @@ import {Rule, RuleToSave} from "../store/rule/types";
|
||||
import {uniq} from "lodash"
|
||||
import {Header} from "antd/es/layout/layout";
|
||||
import {RuleObject} from "antd/lib/form";
|
||||
import {useGetAccessTokenSilently} from "../utils/token";
|
||||
import {useGetTokenSilently} from "../utils/token";
|
||||
|
||||
const {Paragraph} = Typography;
|
||||
const {Option} = Select;
|
||||
@@ -34,7 +34,7 @@ interface FormRule extends Rule {
|
||||
}
|
||||
|
||||
const AccessControlNew = () => {
|
||||
const {getAccessTokenSilently} = useGetAccessTokenSilently()
|
||||
const {getTokenSilently} = useGetTokenSilently()
|
||||
const dispatch = useDispatch()
|
||||
const setupNewRuleVisible = useSelector((state: RootState) => state.rule.setupNewRuleVisible)
|
||||
const groups = useSelector((state: RootState) => state.group.data)
|
||||
@@ -103,7 +103,7 @@ const AccessControlNew = () => {
|
||||
.then((values) => {
|
||||
const ruleToSave = createRuleToSave()
|
||||
dispatch(ruleActions.saveRule.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: ruleToSave
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -32,7 +32,7 @@ import {RuleObject} from "antd/lib/form";
|
||||
import cidrRegex from 'cidr-regex';
|
||||
import {NameServer, NameServerGroup, NameServerGroupToSave} from "../store/nameservers/types";
|
||||
import {useGetGroupTagHelpers} from "../utils/groups"
|
||||
import {useGetAccessTokenSilently} from "../utils/token";
|
||||
import {useGetTokenSilently} from "../utils/token";
|
||||
|
||||
const {Paragraph} = Typography;
|
||||
|
||||
@@ -51,7 +51,7 @@ const NameServerGroupUpdate = () => {
|
||||
selectValidator
|
||||
} = useGetGroupTagHelpers()
|
||||
const dispatch = useDispatch()
|
||||
const {getAccessTokenSilently} = useGetAccessTokenSilently()
|
||||
const {getTokenSilently} = useGetTokenSilently()
|
||||
const {Option} = Select;
|
||||
const nsGroup = useSelector((state: RootState) => state.nameserverGroup.nameserverGroup)
|
||||
const setupNewNameServerGroupVisible = useSelector((state: RootState) => state.nameserverGroup.setupNewNameServerGroupVisible)
|
||||
@@ -220,7 +220,7 @@ const NameServerGroupUpdate = () => {
|
||||
.then((values) => {
|
||||
const nsGroupToSave = createNSGroupToSave(values as NameServerGroup)
|
||||
dispatch(nsGroupActions.saveNameServerGroup.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: nsGroupToSave
|
||||
}))
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {User} from "../store/user/types";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import {RootState} from "typesafe-actions";
|
||||
import {actions as userActions} from "../store/user";
|
||||
import {useGetAccessTokenSilently} from "../utils/token";
|
||||
import {useGetTokenSilently} from "../utils/token";
|
||||
|
||||
const {useBreakpoint} = Grid;
|
||||
|
||||
@@ -19,7 +19,7 @@ const Navbar = () => {
|
||||
let location = useLocation();
|
||||
const config = getConfig();
|
||||
const { logout } = useOidc();
|
||||
const {getAccessTokenSilently} = useGetAccessTokenSilently()
|
||||
const {getTokenSilently} = useGetTokenSilently()
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const {oidcUser} = useOidcUser();
|
||||
@@ -47,7 +47,7 @@ const Navbar = () => {
|
||||
const userEmailKey = 'user-email'
|
||||
const userLogoutKey = 'user-logout'
|
||||
const userDividerKey = 'user-divider'
|
||||
const adminOnlyTabs = ["/setup-keys", "/acls", "/routes", "/dns", "/activity", "/settings"]
|
||||
const adminOnlyTabs = ["/setup-keys", "/acls", "/routes", "/dns", "/activity"]
|
||||
const [menuItems, setMenuItems] = useState(items)
|
||||
const logoutWithRedirect = () =>
|
||||
logout("/", {client_id: config.clientId});
|
||||
@@ -80,7 +80,7 @@ const Navbar = () => {
|
||||
window.location.pathname !== '/peers' &&
|
||||
window.location.pathname !== '/users') {
|
||||
setIsRefreshingUserState(true)
|
||||
dispatch(userActions.getUsers.request({getAccessTokenSilently: getAccessTokenSilently, payload: null}))
|
||||
dispatch(userActions.getUsers.request({getAccessTokenSilently: getTokenSilently, payload: null}))
|
||||
return
|
||||
}
|
||||
if (users.length === 0 && isRefreshingUserState) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {FormPeer, Peer, PeerGroupsToSave} from "../store/peer/types";
|
||||
import {Group, GroupPeer} from "../store/group/types";
|
||||
import {CloseOutlined, EditOutlined} from "@ant-design/icons";
|
||||
import {RuleObject} from 'antd/lib/form';
|
||||
import {useGetAccessTokenSilently} from "../utils/token";
|
||||
import {useGetTokenSilently} from "../utils/token";
|
||||
import {timeAgo} from "../utils/common";
|
||||
|
||||
const {Paragraph} = Typography;
|
||||
@@ -19,7 +19,7 @@ const punycode = require('punycode/')
|
||||
|
||||
const PeerUpdate = () => {
|
||||
|
||||
const {getAccessTokenSilently} = useGetAccessTokenSilently()
|
||||
const {getTokenSilently} = useGetTokenSilently()
|
||||
const dispatch = useDispatch()
|
||||
const groups = useSelector((state: RootState) => state.group.data)
|
||||
const users = useSelector((state: RootState) => state.user.data)
|
||||
@@ -191,6 +191,7 @@ const PeerUpdate = () => {
|
||||
setCallingPeerAPI(false)
|
||||
setCallingPeerAPI(false)
|
||||
setSubmitRunning(false)
|
||||
setEstimatedName("")
|
||||
}
|
||||
|
||||
const noUpdateToGroups = (): Boolean => {
|
||||
@@ -250,14 +251,14 @@ const PeerUpdate = () => {
|
||||
const peerUpdate = createPeerToSave()
|
||||
setCallingPeerAPI(true)
|
||||
dispatch(peerActions.updatePeer.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: peerUpdate
|
||||
}))
|
||||
}
|
||||
if (!noUpdateToGroups()) {
|
||||
setCallingGroupAPI(true)
|
||||
dispatch(peerActions.saveGroups.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: peerGroupsToSave
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
routePeerSeparator,
|
||||
transformGroupedDataTable
|
||||
} from '../utils/routes'
|
||||
import {useGetAccessTokenSilently} from "../utils/token";
|
||||
import {useGetTokenSilently} from "../utils/token";
|
||||
import {useGetGroupTagHelpers} from "../utils/groups";
|
||||
|
||||
const {Paragraph} = Typography;
|
||||
@@ -50,7 +50,7 @@ const RouteUpdate = () => {
|
||||
selectValidator
|
||||
} = useGetGroupTagHelpers()
|
||||
const {Option} = Select;
|
||||
const {getAccessTokenSilently} = useGetAccessTokenSilently()
|
||||
const {getTokenSilently} = useGetTokenSilently()
|
||||
const dispatch = useDispatch()
|
||||
const setupNewRouteVisible = useSelector((state: RootState) => state.route.setupNewRouteVisible)
|
||||
const setupNewRouteHA = useSelector((state: RootState) => state.route.setupNewRouteHA)
|
||||
@@ -163,7 +163,7 @@ const RouteUpdate = () => {
|
||||
if (!setupNewRouteHA || formRoute.peer != '') {
|
||||
const routeToSave = createRouteToSave(formRoute)
|
||||
dispatch(routeActions.saveRoute.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: routeToSave
|
||||
}))
|
||||
} else {
|
||||
@@ -180,7 +180,7 @@ const RouteUpdate = () => {
|
||||
}
|
||||
const routeToSave = createRouteToSave(updateRoute)
|
||||
dispatch(routeActions.saveRoute.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: routeToSave
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -27,7 +27,7 @@ import {checkExpiresIn, formatDate, timeAgo} from "../utils/common";
|
||||
import {RuleObject} from "antd/lib/form";
|
||||
import {CustomTagProps} from "rc-select/lib/BaseSelect";
|
||||
import {Group} from "../store/group/types";
|
||||
import {useGetAccessTokenSilently} from "../utils/token";
|
||||
import {useGetTokenSilently} from "../utils/token";
|
||||
import ExpiresInInput, {expiresInToSeconds, ExpiresInValue} from "../views/ExpiresInInput";
|
||||
import moment from "moment";
|
||||
|
||||
@@ -54,7 +54,7 @@ const customLastUsedFormat: DatePickerProps['format'] = value => {
|
||||
}
|
||||
|
||||
const SetupKeyNew = () => {
|
||||
const {getAccessTokenSilently} = useGetAccessTokenSilently()
|
||||
const {getTokenSilently} = useGetTokenSilently()
|
||||
const dispatch = useDispatch()
|
||||
const setupNewKeyVisible = useSelector((state: RootState) => state.setupKey.setupNewKeyVisible)
|
||||
const setupKey = useSelector((state: RootState) => state.setupKey.setupKey)
|
||||
@@ -127,7 +127,7 @@ const SetupKeyNew = () => {
|
||||
.then((values) => {
|
||||
let setupKeyToSave = createSetupKeyToSave()
|
||||
dispatch(setupKeyActions.saveSetupKey.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: setupKeyToSave
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -9,7 +9,7 @@ import {FormUser, User, UserToSave} from "../store/user/types";
|
||||
import {RuleObject} from "antd/lib/form";
|
||||
import {CustomTagProps} from "rc-select/lib/BaseSelect";
|
||||
import {actions as userActions} from "../store/user";
|
||||
import {useGetAccessTokenSilently} from "../utils/token";
|
||||
import {useGetTokenSilently} from "../utils/token";
|
||||
import {useOidcUser} from "@axa-fr/react-oidc";
|
||||
|
||||
const {Paragraph} = Typography;
|
||||
@@ -20,7 +20,7 @@ const {Option} = Select;
|
||||
|
||||
const UserUpdate = () => {
|
||||
const {oidcUser} = useOidcUser();
|
||||
const {getAccessTokenSilently} = useGetAccessTokenSilently()
|
||||
const {getTokenSilently} = useGetTokenSilently()
|
||||
const dispatch = useDispatch()
|
||||
const user = useSelector((state: RootState) => state.user.user)
|
||||
const savedUser = useSelector((state: RootState) => state.user.savedUser)
|
||||
@@ -193,7 +193,7 @@ const UserUpdate = () => {
|
||||
okType: 'danger',
|
||||
onOk() {
|
||||
dispatch(userActions.saveUser.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: userToSave
|
||||
}))
|
||||
},
|
||||
@@ -215,7 +215,7 @@ const UserUpdate = () => {
|
||||
showConfirmChangeRole(userToSave)
|
||||
} else {
|
||||
dispatch(userActions.saveUser.request({
|
||||
getAccessTokenSilently: getAccessTokenSilently,
|
||||
getAccessTokenSilently: getTokenSilently,
|
||||
payload: userToSave
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export const AddPeerPopup: React.FC<Props> = ({
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
key: "1",
|
||||
label: <span><Icon component={LinuxSVG}/>Ubuntu</span>,
|
||||
label: <span><Icon component={LinuxSVG}/>Linux</span>,
|
||||
children: <UbuntuTab/>,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ 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;
|
||||
|
||||
const {Text} = Typography;
|
||||
@@ -79,31 +80,33 @@ export const LinuxTab = () => {
|
||||
])
|
||||
|
||||
return (
|
||||
/*<div style={{marginTop: 10}}>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Text style={{fontWeight: "bold"}}>
|
||||
Install on macOS
|
||||
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={quickSteps}/>
|
||||
<TabSteps stepsItems={steps}/>
|
||||
</div>
|
||||
<Collapse style={{marginLeft: -15}} bordered={false}>
|
||||
<Panel header={<Text style={{fontWeight: "bold"}}>
|
||||
Or install manually with Homebrew
|
||||
</Text>} key="1">
|
||||
<div style={{marginTop: 5}}>
|
||||
<TabSteps stepsItems={steps}/>
|
||||
</div>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
</div>*/
|
||||
<div style={{marginTop: 10}}>
|
||||
</div>
|
||||
/*<div style={{marginTop: 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>*/
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -45,19 +45,16 @@ export const UbuntuTab = () => {
|
||||
|
||||
return (
|
||||
<div style={{marginTop: 10}}>
|
||||
{/*<Text style={{fontWeight: "bold"}}>
|
||||
<Text style={{fontWeight: "bold"}}>
|
||||
Install with one command
|
||||
</Text>
|
||||
<div style={{fontSize: ".85em", marginTop: 5, marginBottom: 25}}>
|
||||
<SyntaxHighlighter language="bash">
|
||||
curl -fsSL https://netbird.io/install.sh | sh
|
||||
curl -fsSL https://pkgs.netbird.io/install.sh | sh
|
||||
</SyntaxHighlighter>
|
||||
</div>*/}
|
||||
{/*<Text style={{fontWeight: "bold"}}>*/}
|
||||
{/* Or install manually*/}
|
||||
{/*</Text>*/}
|
||||
</div>
|
||||
<Text style={{fontWeight: "bold"}}>
|
||||
Install on Ubuntu
|
||||
Or install manually on Ubuntu
|
||||
</Text>
|
||||
<div style={{marginTop: 5}}>
|
||||
<TabSteps stepsItems={steps}/>
|
||||
|
||||
+2
-1
@@ -9,5 +9,6 @@
|
||||
"grpcApiOrigin": "$NETBIRD_MGMT_GRPC_API_ENDPOINT",
|
||||
"hotjarTrackID": "$NETBIRD_HOTJAR_TRACK_ID",
|
||||
"redirectURI": "$AUTH_REDIRECT_URI",
|
||||
"silentRedirectURI": "$AUTH_SILENT_REDIRECT_URI"
|
||||
"silentRedirectURI": "$AUTH_SILENT_REDIRECT_URI",
|
||||
"tokenSource": "$NETBIRD_TOKEN_SOURCE"
|
||||
}
|
||||
+7
-1
@@ -9,7 +9,7 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
|
||||
const defaultRedirectURI = '/#callback';
|
||||
const defaultSilentRedirectURI = '/#silent-callback'
|
||||
|
||||
const defaultTokenSource = "accessToken"
|
||||
export function getConfig() {
|
||||
let redirectURI = defaultRedirectURI
|
||||
if (configJson.redirectURI) {
|
||||
@@ -21,6 +21,11 @@ export function getConfig() {
|
||||
silentRedirectURI = configJson.silentRedirectURI
|
||||
}
|
||||
|
||||
let tokenSource = defaultTokenSource
|
||||
if (configJson.tokenSource) {
|
||||
tokenSource = configJson.tokenSource
|
||||
}
|
||||
|
||||
return {
|
||||
auth0Auth: configJson.auth0Auth == "true", //due to substitution we can't use boolean in the config
|
||||
authority: configJson.authAuthority,
|
||||
@@ -32,5 +37,6 @@ export function getConfig() {
|
||||
hotjarTrackID: configJson.hotjarTrackID,
|
||||
redirectURI: redirectURI,
|
||||
silentRedirectURI: silentRedirectURI,
|
||||
tokenSource: tokenSource,
|
||||
};
|
||||
}
|
||||
@@ -139,4 +139,8 @@ body {
|
||||
|
||||
.ant-steps-item-tail {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ant-table-thead .ant-table-cell {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { sagas as nameserverGroupSagas } from './nameservers';
|
||||
import { sagas as eventSagas } from './event';
|
||||
import { sagas as dnsSettingsSagas } from './dns-settings';
|
||||
import { sagas as accountSagas } from './account';
|
||||
import { sagas as personalAccessTokenSagas } from './personal-access-token';
|
||||
|
||||
import rootReducer from './root-reducer';
|
||||
import { apiClient } from '../services/api-client';
|
||||
@@ -33,5 +34,6 @@ sagaMiddleware.run(nameserverGroupSagas);
|
||||
sagaMiddleware.run(eventSagas);
|
||||
sagaMiddleware.run(dnsSettingsSagas);
|
||||
sagaMiddleware.run(accountSagas);
|
||||
sagaMiddleware.run(personalAccessTokenSagas);
|
||||
|
||||
export { apiClient, rootReducer, store };
|
||||
@@ -0,0 +1,39 @@
|
||||
import { ActionType, createAction, createAsyncAction } from 'typesafe-actions';
|
||||
import {PersonalAccessToken, PersonalAccessTokenCreate, PersonalAccessTokenGenerated, SpecificPAT} from './types';
|
||||
import {
|
||||
ApiError,
|
||||
CreateResponse,
|
||||
DeleteResponse,
|
||||
RequestPayload
|
||||
} from '../../services/api-client/types';
|
||||
|
||||
const actions = {
|
||||
getPersonalAccessTokens: createAsyncAction(
|
||||
'GET_PERSONAL_ACCESS_TOKEN_REQUEST',
|
||||
'GET_PERSONAL_ACCESS_TOKEN_SUCCESS',
|
||||
'GET_PERSONAL_ACCESS_TOKEN_FAILURE',
|
||||
)<RequestPayload<string>, PersonalAccessToken[], ApiError>(),
|
||||
|
||||
savePersonalAccessToken: createAsyncAction(
|
||||
'SAVE_PERSONAL_ACCESS_TOKEN_REQUEST',
|
||||
'SAVE_PERSONAL_ACCESS_TOKEN_SUCCESS',
|
||||
'SAVE_PERSONAL_ACCESS_TOKEN_FAILURE',
|
||||
)<RequestPayload<PersonalAccessTokenCreate>, CreateResponse<PersonalAccessTokenGenerated | null>, CreateResponse<PersonalAccessTokenGenerated | null>>(),
|
||||
setSavedPersonalAccessToken: createAction('SET_PERSONAL_ACCESS_TOKEN_KEY')<CreateResponse<PersonalAccessTokenGenerated | null>>(),
|
||||
resetSavedPersonalAccessToken: createAction('RESET_PERSONAL_ACCESS_TOKEN_KEY')<null>(),
|
||||
|
||||
deletePersonalAccessToken: createAsyncAction(
|
||||
'DELETE_PERSONAL_ACCESS_TOKEN_REQUEST',
|
||||
'DELETE_PERSONAL_ACCESS_TOKEN_SUCCESS',
|
||||
'DELETE_PERSONAL_ACCESS_TOKEN_FAILURE'
|
||||
)<RequestPayload<SpecificPAT>, DeleteResponse<string | null>, DeleteResponse<string | null>>(),
|
||||
setDeletePersonalAccessToken: createAction('SET_DELETE_PERSONAL_ACCESS_TOKEN')<DeleteResponse<string | null>>(),
|
||||
resetDeletedPersonalAccessToken: createAction('RESET_DELETE_PERSONAL_ACCESS_TOKEN')<null>(),
|
||||
|
||||
removePersonalAccessToken: createAction('REMOVE_PERSONAL_ACCESS_TOKEN')<string>(),
|
||||
setPersonalAccessToken: createAction('SET_SETUP_KEY')<PersonalAccessTokenCreate>(),
|
||||
setNewPersonalAccessTokenVisible: createAction('SET_NEW_PERSONAL_ACCESS_TOKEN_VISIBLE')<boolean>()
|
||||
};
|
||||
|
||||
export type ActionTypes = ActionType<typeof actions>;
|
||||
export default actions;
|
||||
@@ -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 };
|
||||
@@ -0,0 +1,97 @@
|
||||
import { createReducer } from 'typesafe-actions';
|
||||
import { combineReducers } from 'redux';
|
||||
import actions, { ActionTypes } from './actions';
|
||||
import {ApiError, DeleteResponse, CreateResponse, ChangeResponse} from "../../services/api-client/types";
|
||||
import {PersonalAccessToken, PersonalAccessTokenCreate, PersonalAccessTokenGenerated} from "./types";
|
||||
|
||||
type StateType = Readonly<{
|
||||
data: PersonalAccessToken[] | null;
|
||||
personalAccessToken: PersonalAccessTokenCreate | null;
|
||||
loading: boolean;
|
||||
failed: ApiError | null;
|
||||
saving: boolean;
|
||||
deletedPersonalAccessToken: DeleteResponse<string | null>;
|
||||
revokedPersonalAccessToken: ChangeResponse<string | null>;
|
||||
savedPersonalAccessToken: CreateResponse<PersonalAccessTokenGenerated | null>;
|
||||
newPersonalAccessTokenVisible: boolean
|
||||
}>;
|
||||
|
||||
const initialState: StateType = {
|
||||
data: [],
|
||||
personalAccessToken: null,
|
||||
loading: false,
|
||||
failed: null,
|
||||
saving: false,
|
||||
deletedPersonalAccessToken: <DeleteResponse<string | null>>{
|
||||
loading: false,
|
||||
success: false,
|
||||
failure: false,
|
||||
error: null,
|
||||
data : null
|
||||
},
|
||||
revokedPersonalAccessToken: <ChangeResponse<string | null>>{
|
||||
loading: false,
|
||||
success: false,
|
||||
failure: false,
|
||||
error: null,
|
||||
data : null
|
||||
},
|
||||
savedPersonalAccessToken: <CreateResponse<PersonalAccessTokenGenerated | null>>{
|
||||
loading: false,
|
||||
success: false,
|
||||
failure: false,
|
||||
error: null,
|
||||
data : null
|
||||
},
|
||||
newPersonalAccessTokenVisible: false
|
||||
};
|
||||
|
||||
const data = createReducer<PersonalAccessToken[], ActionTypes>(initialState.data as PersonalAccessToken[])
|
||||
.handleAction(actions.getPersonalAccessTokens.success,(_, action) => action.payload)
|
||||
.handleAction(actions.getPersonalAccessTokens.failure, () => []);
|
||||
|
||||
const personalAccessToken = createReducer<PersonalAccessTokenCreate, ActionTypes>(initialState.personalAccessToken as PersonalAccessTokenCreate)
|
||||
.handleAction(actions.setPersonalAccessToken, (store, action) => action.payload);
|
||||
|
||||
const loading = createReducer<boolean, ActionTypes>(initialState.loading)
|
||||
.handleAction(actions.getPersonalAccessTokens.request, () => true)
|
||||
.handleAction(actions.getPersonalAccessTokens.success, () => false)
|
||||
.handleAction(actions.getPersonalAccessTokens.failure, () => false);
|
||||
|
||||
const failed = createReducer<ApiError | null, ActionTypes>(initialState.failed)
|
||||
.handleAction(actions.getPersonalAccessTokens.request, () => null)
|
||||
.handleAction(actions.getPersonalAccessTokens.success, () => null)
|
||||
.handleAction(actions.getPersonalAccessTokens.failure, (store, action) => action.payload);
|
||||
|
||||
const saving = createReducer<boolean, ActionTypes>(initialState.saving)
|
||||
.handleAction(actions.getPersonalAccessTokens.request, () => true)
|
||||
.handleAction(actions.getPersonalAccessTokens.success, () => false)
|
||||
.handleAction(actions.getPersonalAccessTokens.failure, () => false);
|
||||
|
||||
const deletedPersonalAccessToken = createReducer<DeleteResponse<string | null>, ActionTypes>(initialState.deletedPersonalAccessToken)
|
||||
.handleAction(actions.deletePersonalAccessToken.request, () => initialState.deletedPersonalAccessToken)
|
||||
.handleAction(actions.deletePersonalAccessToken.success, (store, action) => action.payload)
|
||||
.handleAction(actions.deletePersonalAccessToken.failure, (store, action) => action.payload)
|
||||
.handleAction(actions.setDeletePersonalAccessToken, (store, action) => action.payload)
|
||||
.handleAction(actions.resetDeletedPersonalAccessToken, (store, action) => initialState.deletedPersonalAccessToken);
|
||||
|
||||
const savedPersonalAccessToken = createReducer<CreateResponse<PersonalAccessTokenGenerated | null>, ActionTypes>(initialState.savedPersonalAccessToken)
|
||||
.handleAction(actions.savePersonalAccessToken.request, () => initialState.savedPersonalAccessToken)
|
||||
.handleAction(actions.savePersonalAccessToken.success, (store, action) => action.payload)
|
||||
.handleAction(actions.savePersonalAccessToken.failure, (store, action) => action.payload)
|
||||
.handleAction(actions.setSavedPersonalAccessToken, (store, action) => action.payload)
|
||||
.handleAction(actions.resetSavedPersonalAccessToken, () => initialState.savedPersonalAccessToken)
|
||||
|
||||
const newPersonalAccessTokenVisible = createReducer<boolean, ActionTypes>(initialState.newPersonalAccessTokenVisible)
|
||||
.handleAction(actions.setNewPersonalAccessTokenVisible, (store, action) => action.payload)
|
||||
|
||||
export default combineReducers({
|
||||
data,
|
||||
personalAccessToken: personalAccessToken,
|
||||
loading,
|
||||
failed,
|
||||
saving,
|
||||
deletedPersonalAccessToken: deletedPersonalAccessToken,
|
||||
savedPersonalAccessToken: savedPersonalAccessToken,
|
||||
newPersonalAccessTokenVisible: newPersonalAccessTokenVisible
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
import {all, call, put, select, takeLatest} from 'redux-saga/effects';
|
||||
import {ApiError, ApiResponse, CreateResponse, DeleteResponse} from '../../services/api-client/types';
|
||||
import {PersonalAccessToken, PersonalAccessTokenCreate, PersonalAccessTokenGenerated} from './types'
|
||||
import service from './service';
|
||||
import actions from './actions';
|
||||
|
||||
export function* getPersonalAccessTokens(action: ReturnType<typeof actions.getPersonalAccessTokens.request>): Generator {
|
||||
try {
|
||||
const effect = yield call(service.getAllPersonalAccessTokens, action.payload);
|
||||
const response = effect as ApiResponse<PersonalAccessToken[]>;
|
||||
|
||||
yield put(actions.getPersonalAccessTokens.success(response.body));
|
||||
} catch (err) {
|
||||
yield put(actions.getPersonalAccessTokens.failure(err as ApiError));
|
||||
}
|
||||
}
|
||||
|
||||
export function* savePersonalAccessToken(action: ReturnType<typeof actions.savePersonalAccessToken.request>): Generator {
|
||||
try {
|
||||
yield put(actions.setSavedPersonalAccessToken({
|
||||
loading: true,
|
||||
success: false,
|
||||
failure: false,
|
||||
error: null,
|
||||
data: null
|
||||
} as CreateResponse<PersonalAccessTokenGenerated | null>))
|
||||
|
||||
const tokenToSave = action.payload.payload
|
||||
|
||||
let effect = yield call(service.createPersonalAccessToken, {
|
||||
getAccessTokenSilently: action.payload.getAccessTokenSilently,
|
||||
payload: {
|
||||
user_id: tokenToSave.user_id,
|
||||
name: tokenToSave.name,
|
||||
expires_in: tokenToSave.expires_in,
|
||||
} as PersonalAccessTokenCreate
|
||||
});
|
||||
const response = effect as ApiResponse<PersonalAccessTokenGenerated>;
|
||||
|
||||
yield put(actions.savePersonalAccessToken.success({
|
||||
loading: false,
|
||||
success: true,
|
||||
failure: false,
|
||||
error: null,
|
||||
data: response.body
|
||||
} as CreateResponse<PersonalAccessTokenGenerated | null>));
|
||||
|
||||
yield put(actions.getPersonalAccessTokens.request({ getAccessTokenSilently: action.payload.getAccessTokenSilently, payload: tokenToSave.user_id }));
|
||||
} catch (err) {
|
||||
yield put(actions.savePersonalAccessToken.failure({
|
||||
loading: false,
|
||||
success: false,
|
||||
failure: false,
|
||||
error: err as ApiError,
|
||||
data: null
|
||||
} as CreateResponse<PersonalAccessTokenGenerated | null>));
|
||||
}
|
||||
}
|
||||
|
||||
export function* deletePersonalAccessToken(action: ReturnType<typeof actions.deletePersonalAccessToken.request>): Generator {
|
||||
try {
|
||||
yield call(actions.setDeletePersonalAccessToken,{
|
||||
loading: true,
|
||||
success: false,
|
||||
failure: false,
|
||||
error: null,
|
||||
data: null
|
||||
} as DeleteResponse<string | null>)
|
||||
|
||||
const effect = yield call(service.deletePersonalAccessToken, action.payload);
|
||||
const response = effect as ApiResponse<any>;
|
||||
|
||||
yield put(actions.deletePersonalAccessToken.success({
|
||||
loading: false,
|
||||
success: true,
|
||||
failure: false,
|
||||
error: null,
|
||||
data: response.body
|
||||
} as DeleteResponse<string | null>));
|
||||
|
||||
const personalAccessTokens = (yield select(state => state.personalAccessToken.data)) as PersonalAccessToken[]
|
||||
yield put(actions.getPersonalAccessTokens.success(personalAccessTokens.filter((p:PersonalAccessToken) => p.id !== action.payload.payload.id)))
|
||||
} catch (err) {
|
||||
yield put(actions.deletePersonalAccessToken.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.getPersonalAccessTokens.request, getPersonalAccessTokens),
|
||||
takeLatest(actions.savePersonalAccessToken.request, savePersonalAccessToken),
|
||||
takeLatest(actions.deletePersonalAccessToken.request, deletePersonalAccessToken)
|
||||
]);
|
||||
}
|
||||
|
||||
Loaded 20 of 38 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user