diff --git a/frontend/app/Router.js b/frontend/app/Router.js index da52b3ee9..574cf08a3 100644 --- a/frontend/app/Router.js +++ b/frontend/app/Router.js @@ -10,6 +10,7 @@ import Header from 'Components/Header/Header'; import { fetchList as fetchSiteList } from 'Duck/site'; import { withStore } from 'App/mstore'; + import APIClient from './api_client'; import * as routes from './routes'; import { OB_DEFAULT_TAB, isRoute } from 'App/routes'; diff --git a/frontend/app/api_client.js b/frontend/app/api_client.js index 41d6fd89f..df531c956 100644 --- a/frontend/app/api_client.js +++ b/frontend/app/api_client.js @@ -15,7 +15,6 @@ const siteIdRequiredPaths = [ '/assignments', '/integration/sources', '/issue_types', - '/sample_rate', '/saved_search', '/rehydrations', '/sourcemaps', diff --git a/frontend/app/components/Client/Sites/NewSiteForm.js b/frontend/app/components/Client/Sites/NewSiteForm.tsx similarity index 81% rename from frontend/app/components/Client/Sites/NewSiteForm.js rename to frontend/app/components/Client/Sites/NewSiteForm.tsx index 8efa0da24..2d55e68c0 100644 --- a/frontend/app/components/Client/Sites/NewSiteForm.js +++ b/frontend/app/components/Client/Sites/NewSiteForm.tsx @@ -1,10 +1,10 @@ -import React, { useState, useEffect } from 'react'; -import { connect } from 'react-redux'; +import React, { useState, useEffect, ChangeEvent, FormEvent } from 'react'; +import { connect, ConnectedProps } from 'react-redux'; import { Form, Input, Button, Icon } from 'UI'; import { save, edit, update, fetchList, remove } from 'Duck/site'; import { pushNewSite } from 'Duck/user'; import { setSiteId } from 'Duck/site'; -import { withRouter } from 'react-router-dom'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; import styles from './siteForm.module.css'; import { confirm } from 'UI'; import { clearSearch } from 'Duck/search'; @@ -12,6 +12,16 @@ import { clearSearch as clearSearchLive } from 'Duck/liveSearch'; import { withStore } from 'App/mstore'; import { toast } from 'react-toastify'; +type OwnProps = { + onClose: (arg: any) => void; + mstore: any; + canDelete: boolean; +}; + +type PropsFromRedux = ConnectedProps; + +type Props = PropsFromRedux & RouteComponentProps & OwnProps; + const NewSiteForm = ({ site, loading, @@ -29,7 +39,7 @@ const NewSiteForm = ({ mstore, activeSiteId, canDelete, -}) => { +}: Props) => { const [existsError, setExistsError] = useState(false); useEffect(() => { @@ -38,11 +48,11 @@ const NewSiteForm = ({ } }, []); - const onSubmit = (e) => { + const onSubmit = (e: FormEvent) => { e.preventDefault(); if (site.exists()) { - update(site, site.id).then((response) => { + update(site, site.id).then((response: any) => { if (!response || !response.errors || response.errors.size === 0) { onClose(null); if (!pathname.includes('onboarding')) { @@ -54,7 +64,7 @@ const NewSiteForm = ({ } }); } else { - save(site).then((response) => { + save(site).then((response: any) => { if (!response || !response.errors || response.errors.size === 0) { onClose(null); clearSearch(); @@ -78,13 +88,13 @@ const NewSiteForm = ({ remove(site.id).then(() => { onClose(null); if (site.id === activeSiteId) { - setSiteId(null) + setSiteId(null); } }); } }; - const handleEdit = ({ target: { name, value } }) => { + const handleEdit = ({ target: { name, value } }: ChangeEvent) => { setExistsError(false); edit({ [name]: value }); }; @@ -128,7 +138,7 @@ const NewSiteForm = ({ ); }; -const mapStateToProps = (state) => ({ +const mapStateToProps = (state: any) => ({ activeSiteId: state.getIn(['site', 'active', 'id']), site: state.getIn(['site', 'instance']), siteList: state.getIn(['site', 'list']), @@ -136,7 +146,7 @@ const mapStateToProps = (state) => ({ canDelete: state.getIn(['site', 'list']).size > 1, }); -export default connect(mapStateToProps, { +const connector = connect(mapStateToProps, { save, remove, edit, @@ -146,4 +156,6 @@ export default connect(mapStateToProps, { setSiteId, clearSearch, clearSearchLive, -})(withRouter(withStore(NewSiteForm))); +}); + +export default connector(withRouter(withStore(NewSiteForm))); diff --git a/frontend/app/components/Client/Sites/Sites.js b/frontend/app/components/Client/Sites/Sites.js deleted file mode 100644 index feea944ce..000000000 --- a/frontend/app/components/Client/Sites/Sites.js +++ /dev/null @@ -1,140 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import withPageTitle from 'HOCs/withPageTitle'; -import { Loader, Button, TextLink, NoContent } from 'UI'; -import { init, remove, fetchGDPR, setSiteId } from 'Duck/site'; -import stl from './sites.module.css'; -import NewSiteForm from './NewSiteForm'; -import { confirm, PageTitle } from 'UI'; -import SiteSearch from './SiteSearch'; -import AddProjectButton from './AddProjectButton'; -import InstallButton from './InstallButton'; -import ProjectKey from './ProjectKey'; -import { useModal } from 'App/components/Modal'; -import { getInitials } from 'App/utils'; -import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG'; -import cn from 'classnames' - -const NEW_SITE_FORM = 'NEW_SITE_FORM'; - -@connect( - (state) => ({ - site: state.getIn(['site', 'instance']), - sites: state.getIn(['site', 'list']), - loading: state.getIn(['site', 'loading']), - user: state.getIn(['user', 'account']), - account: state.getIn(['user', 'account']), - }), - { - init, - remove, - fetchGDPR, - setSiteId, - } -) -@withPageTitle('Projects - OpenReplay Preferences') -class Sites extends React.PureComponent { - state = { - searchQuery: '', - }; - - edit = (site) => { - this.props.init(site); - this.setState({ modalContent: NEW_SITE_FORM }); - }; - - remove = async (site) => { - if ( - await confirm({ - header: 'Projects', - confirmation: `Are you sure you want to delete this Project? We won't be able to record anymore sessions.`, - }) - ) { - this.props.remove(site.id) - this.props.setSiteId(null); - } - }; - - render() { - const { loading, sites, user } = this.props; - const isAdmin = user.admin || user.superAdmin; - const filteredSites = sites.filter((site) => site.name.toLowerCase().includes(this.state.searchQuery.toLowerCase())); - - return ( - -
-
- Projects
} actionButton={} /> - -
- -
- this.setState({ searchQuery: value })} /> -
-
- -
- - -
No matching results.
-
- } - size="small" - show={!loading && filteredSites.size === 0} - > -
-
Project Name
-
Key
-
-
- {filteredSites.map((_site) => ( -
-
-
-
-
-
- {getInitials(_site.name)} -
-
- {_site.host} -
-
-
- -
-
-
- -
-
- this.props.init(_site)} /> -
-
-
- ))} - -
-
-
- ); - } -} - -export default Sites; - -function EditButton({ isAdmin, onClick }) { - const { showModal, hideModal } = useModal(); - const _onClick = () => { - onClick(); - showModal(); - }; - return - - )} - - ); + + + {!captureAll && ( +
+ +
+ ) => changeCaptureRate(e.target.value)} + value={captureRate.toString()} + style={{ height: '38px', width: '100px' }} + disabled={captureAll} + min={0} + max={100} + /> + +
+
+ of the sessions + +
+ )} + + ); } export default connect((state: any) => ({ - isAdmin: state.getIn(['user', 'account', 'admin']) || state.getIn(['user', 'account', 'superAdmin']), + isAdmin: state.getIn(['user', 'account', 'admin']) || state.getIn(['user', 'account', 'superAdmin']) }))(observer(CaptureRate)); diff --git a/frontend/app/mstore/settingsStore.ts b/frontend/app/mstore/settingsStore.ts index 641167dd5..35cf9d2d5 100644 --- a/frontend/app/mstore/settingsStore.ts +++ b/frontend/app/mstore/settingsStore.ts @@ -22,9 +22,9 @@ export default class SettingsStore { }); } - saveCaptureRate(data: any) { + saveCaptureRate(projectId: number, data: any) { return sessionService - .saveCaptureRate(data) + .saveCaptureRate(projectId, data) .then((data) => data.json()) .then(({ data }) => { this.sessionSettings.merge({ @@ -38,10 +38,10 @@ export default class SettingsStore { }); } - fetchCaptureRate(): Promise { + fetchCaptureRate(projectId: number): Promise { this.loadingCaptureRate = true; return sessionService - .fetchCaptureRate() + .fetchCaptureRate(projectId) .then((data) => { this.sessionSettings.merge({ captureRate: data.rate, diff --git a/frontend/app/services/SessionService.ts b/frontend/app/services/SessionService.ts index 6537a2dbb..aaf511873 100644 --- a/frontend/app/services/SessionService.ts +++ b/frontend/app/services/SessionService.ts @@ -14,13 +14,13 @@ export default class SettingsService { this.client = client || new APIClient(); } - saveCaptureRate(data: any) { - return this.client.post('/sample_rate', data); + saveCaptureRate(projectId: number, data: any) { + return this.client.post(`/${projectId}/sample_rate`, data); } - fetchCaptureRate() { + fetchCaptureRate(projectId: number) { return this.client - .get('/sample_rate') + .get(`/${projectId}/sample_rate`) .then((response) => response.json()) .then((response) => response.data || 0); } diff --git a/frontend/app/types/site/site.js b/frontend/app/types/site/site.js index 158855bbc..c5c0e4f1e 100644 --- a/frontend/app/types/site/site.js +++ b/frontend/app/types/site/site.js @@ -23,6 +23,7 @@ export default Record({ projectKey: undefined, trackerVersion: undefined, saveRequestPayloads: false, + sampleRate: 0, }, { idKey: 'id', methods: {