- { !!deleteHandler &&
-
deleteHandler(role) } id="trash">
-
-
- }
+
{ !!editHandler &&
editHandler(role) }>
@@ -43,7 +56,6 @@ function RoleItem({ role, deleteHandler, editHandler, isAdmin, permissions }: Pr
}
)}
-
);
}
diff --git a/frontend/app/components/Client/Roles/components/RoleItem/roleItem.css b/frontend/app/components/Client/Roles/components/RoleItem/roleItem.css
index af0aab35d..e5d3224ba 100644
--- a/frontend/app/components/Client/Roles/components/RoleItem/roleItem.css
+++ b/frontend/app/components/Client/Roles/components/RoleItem/roleItem.css
@@ -1,13 +1,5 @@
-.wrapper {
- display: flex;
- align-items: center;
- width: 100%;
- border-bottom: solid thin #e6e6e6;
- padding: 10px 0px;
-}
-
.actions {
- margin-left: auto;
+ /* margin-left: auto; */
/* opacity: 0; */
transition: all 0.4s;
display: flex;
@@ -37,11 +29,11 @@
}
.label {
- margin-left: 10px;
+ margin-right: 10px;
padding: 0 5px;
border-radius: 3px;
background-color: $gray-lightest;
- font-size: 10px;
+ font-size: 12px;
border: solid thin $gray-light;
width: fit-content;
}
\ No newline at end of file
diff --git a/frontend/app/components/Client/Sites/Sites.js b/frontend/app/components/Client/Sites/Sites.js
index 9b5e3b9b0..4769815e5 100644
--- a/frontend/app/components/Client/Sites/Sites.js
+++ b/frontend/app/components/Client/Sites/Sites.js
@@ -37,7 +37,7 @@ const GDPR_FORM = 'GDPR_FORM';
remove,
fetchGDPR
})
-@withPageTitle('Sites - OpenReplay Preferences')
+@withPageTitle('Projects - OpenReplay Preferences')
class Sites extends React.PureComponent {
state = {
showTrackingCode: false,
diff --git a/frontend/app/components/Errors/Errors.js b/frontend/app/components/Errors/Errors.js
index f9e7b5c9b..4eb671cf5 100644
--- a/frontend/app/components/Errors/Errors.js
+++ b/frontend/app/components/Errors/Errors.js
@@ -9,6 +9,7 @@ import { fetchList as fetchSlackList } from 'Duck/integrations/slack';
import { errors as errorsRoute, isRoute } from "App/routes";
import EventFilter from 'Components/BugFinder/EventFilter';
import DateRange from 'Components/BugFinder/DateRange';
+import withPageTitle from 'HOCs/withPageTitle';
import { SavedSearchList } from 'UI';
@@ -43,6 +44,7 @@ function getStatusLabel(status) {
applyFilter,
fetchSlackList,
})
+@withPageTitle("Errors - OpenReplay")
export default class Errors extends React.PureComponent {
state = {
status: UNRESOLVED,
diff --git a/frontend/app/duck/roles.js b/frontend/app/duck/roles.js
index 874bd9be6..8a8415475 100644
--- a/frontend/app/duck/roles.js
+++ b/frontend/app/duck/roles.js
@@ -2,6 +2,7 @@ import { List, Map } from 'immutable';
import Role from 'Types/role';
import crudDuckGenerator from './tools/crudDuck';
import { reduceDucks } from 'Duck/tools';
+import { array, request, success, failure, createListUpdater, mergeReducers } from './funcTools/tools';
const crudDuck = crudDuckGenerator('client/role', Role, { idKey: 'roleId' });
export const { fetchList, init, edit, remove, } = crudDuck.actions;
@@ -11,19 +12,29 @@ const RESET_ERRORS = 'roles/RESET_ERRORS';
const initialState = Map({
list: List(),
permissions: List([
- { name: 'Session Replay', value: 'SESSION_REPLAY' },
- { name: 'Developer Tools', value: 'DEV_TOOLS' },
- { name: 'Errors', value: 'ERRORS' },
- { name: 'Metrics', value: 'METRICS' },
- { name: 'Assist (Live)', value: 'ASSIST_LIVE' },
- { name: 'Assist (Call)', value: 'ASSIST_CALL' },
+ { text: 'Session Replay', value: 'SESSION_REPLAY' },
+ { text: 'Developer Tools', value: 'DEV_TOOLS' },
+ { text: 'Errors', value: 'ERRORS' },
+ { text: 'Metrics', value: 'METRICS' },
+ { text: 'Assist (Live)', value: 'ASSIST_LIVE' },
+ { text: 'Assist (Call)', value: 'ASSIST_CALL' },
])
});
+const name = "role";
+const idKey = "roleId";
+
+const updateItemInList = createListUpdater(idKey);
+const updateInstance = (state, instance) => state.getIn([ "instance", idKey ]) === instance[ idKey ]
+ ? state.mergeIn([ "instance" ], instance)
+ : state;
+
const reducer = (state = initialState, action = {}) => {
switch (action.type) {
case RESET_ERRORS:
return state.setIn(['removeRequest', 'errors'], null);
+ case crudDuck.actionTypes.SAVE.SUCCESS:
+ return updateItemInList(updateInstance(state, action.data), action.data);
}
return state;
};
diff --git a/frontend/app/routes.js b/frontend/app/routes.js
index 2ca5fd672..cdccc6327 100644
--- a/frontend/app/routes.js
+++ b/frontend/app/routes.js
@@ -59,8 +59,8 @@ export const forgotPassword = () => '/reset-password';
export const CLIENT_TABS = {
INTEGRATIONS: 'integrations',
PROFILE: 'account',
- MANAGE_USERS: 'manage-users',
- MANAGE_ROLES: 'manage-roles',
+ MANAGE_USERS: 'team',
+ MANAGE_ROLES: 'roles',
SITES: 'projects',
CUSTOM_FIELDS: 'metadata',
WEBHOOKS: 'webhooks',
@@ -73,7 +73,7 @@ export const client = (tab = routerClientTabString) => `/client/${ tab }`;
export const OB_TABS = {
INSTALLING: 'installing',
IDENTIFY_USERS: 'identify-users',
- MANAGE_USERS: 'manage-users',
+ MANAGE_USERS: 'team',
INTEGRATIONS: 'integrations',
};
export const OB_DEFAULT_TAB = OB_TABS.INSTALLING;
diff --git a/frontend/app/styles/main.css b/frontend/app/styles/main.css
index f27155e36..fc366bc39 100644
--- a/frontend/app/styles/main.css
+++ b/frontend/app/styles/main.css
@@ -117,4 +117,10 @@
.disabled {
opacity: 0.4;
pointer-events: none;
+}
+
+.hover {
+ &:hover {
+ background-color: $active-blue;
+ }
}
\ No newline at end of file
diff --git a/frontend/app/svg/icons/diagram-3.svg b/frontend/app/svg/icons/diagram-3.svg
new file mode 100644
index 000000000..03e448c17
--- /dev/null
+++ b/frontend/app/svg/icons/diagram-3.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/app/types/role.js b/frontend/app/types/role.js
index 52a74d400..d63afa5db 100644
--- a/frontend/app/types/role.js
+++ b/frontend/app/types/role.js
@@ -1,18 +1,21 @@
import Record from 'Types/Record';
-import { validateName } from 'App/validate';
+import { notEmptyString, validateName } from 'App/validate';
import { List } from 'immutable';
export default Record({
roleId: undefined,
name: '',
+ allProjects: true,
permissions: List(),
+ projects: List(),
protected: false,
- description: ''
+ description: '',
+ permissionOptions: List(),
}, {
idKey: 'roleId',
methods: {
validate() {
- return validateName(this.name, { diacritics: true });
+ return notEmptyString(this.name) && validateName(this.name, { diacritics: true }) && (this.allProjects || this.projects.size > 0);
},
toData() {
const js = this.toJS();
@@ -21,10 +24,11 @@ export default Record({
return js;
},
},
- fromJS({ permissions, ...rest }) {
+ fromJS({ projects = [], permissions = [], ...rest }) {
return {
...rest,
- permissions: List(permissions)
+ permissions: List(permissions),
+ projects: List(projects),
}
},
});