@@ -4,18 +4,8 @@ import 'moment/min/locales'
44import { parse as queryStringParse } from 'query-string'
55import Header from './Header'
66import {
7- setAllowStudio ,
8- setAllowConfigure ,
9- getAllowStudio ,
10- getAllowConfigure ,
11- setAllowDeveloper ,
12- setAllowTesting ,
13- getAllowTesting ,
14- getAllowDeveloper ,
157 setAllowSpeaking ,
168 setAllowVibrating ,
17- setAllowService ,
18- getAllowService ,
199 setHelpMode ,
2010 setUIZoom ,
2111 getUIZoom ,
@@ -48,6 +38,7 @@ import { Settings } from '../lib/Settings'
4838import { DocumentTitleProvider } from '../lib/DocumentTitleProvider'
4939import { catchError , firstIfArray , isRunningInPWA } from '../lib/lib'
5040import { protectString } from '@sofie-automation/shared-lib/dist/lib/protectedString'
41+ import { useUserPermissions , UserPermissionsContext } from './UserPermissions'
5142
5243const NullComponent = ( ) => null
5344
@@ -61,7 +52,7 @@ export const App: React.FC = function App() {
6152
6253 const [ lastStart ] = useState ( Date . now ( ) )
6354
64- const roles = useRoles ( )
55+ const roles = useUserPermissions ( )
6556 const featureFlags = useFeatureFlags ( )
6657
6758 useEffect ( ( ) => {
@@ -155,138 +146,97 @@ export const App: React.FC = function App() {
155146 } , [ ] )
156147
157148 return (
158- < Router getUserConfirmation = { onNavigationUserConfirmation } >
159- < div className = "container-fluid header-clear" >
160- { /* Header switch - render the usual header for all pages but the rundown view */ }
161- < ErrorBoundary >
162- < Switch >
163- < Route path = "/rundown/:playlistId" component = { NullComponent } />
164- < Route path = "/countdowns/:studioId" component = { NullComponent } />
165- < Route path = "/activeRundown" component = { NullComponent } />
166- < Route path = "/prompter/:studioId" component = { NullComponent } />
167- < Route
168- path = "/"
169- render = { ( props ) => (
170- < Header
171- { ...props }
172- allowConfigure = { roles . configure }
173- allowTesting = { roles . testing }
174- allowDeveloper = { roles . developer }
175- />
176- ) }
177- />
178- </ Switch >
179- </ ErrorBoundary >
180- { /* Main app switch */ }
181- < ErrorBoundary >
182- < Switch >
183- < Route exact path = "/" component = { RundownList } />
184- < Route path = "/rundowns" render = { ( ) => < RundownList /> } />
185- < Route
186- path = "/rundown/:playlistId/shelf"
187- exact
188- render = { ( props ) => (
189- < RundownView
190- playlistId = { protectString ( decodeURIComponent ( props . match . params . playlistId ) ) }
191- onlyShelf = { true }
192- />
193- ) }
194- />
195- < Route
196- path = "/rundown/:playlistId"
197- render = { ( props ) => (
198- < RundownView playlistId = { protectString ( decodeURIComponent ( props . match . params . playlistId ) ) } />
199- ) }
200- />
201- < Route
202- path = "/activeRundown/:studioId"
203- render = { ( props ) => (
204- < ActiveRundownView studioId = { protectString ( decodeURIComponent ( props . match . params . studioId ) ) } />
205- ) }
206- />
207- < Route
208- path = "/prompter/:studioId"
209- render = { ( props ) => (
210- < PrompterView studioId = { protectString ( decodeURIComponent ( props . match . params . studioId ) ) } />
211- ) }
212- />
213- { /* We switch to the general ClockView component, and allow it to do the switch between various types of countdowns */ }
214- < Route
215- path = "/countdowns/:studioId"
216- render = { ( props ) => (
217- < ClockView studioId = { protectString ( decodeURIComponent ( props . match . params . studioId ) ) } />
218- ) }
219- />
220- < Route path = "/status" render = { ( ) => < Status /> } />
221- < Route path = "/settings" render = { ( ) => < SettingsView /> } />
222- < Route path = "/testTools" render = { ( ) => < TestTools /> } />
223- < Route >
224- < Redirect to = "/" />
225- </ Route >
226- </ Switch >
227- </ ErrorBoundary >
228- < ErrorBoundary >
229- < Switch >
230- { /* Put views that should NOT have the Notification center here: */ }
231- < Route path = "/countdowns/:studioId" component = { NullComponent } />
232- < Route path = "/prompter/:studioId" component = { NullComponent } />
233- < Route path = "/" component = { ConnectionStatusNotification } />
234- </ Switch >
235- </ ErrorBoundary >
236- < ErrorBoundary >
237- < DocumentTitleProvider />
238- </ ErrorBoundary >
239- < ErrorBoundary >
240- < ModalDialogGlobalContainer />
241- </ ErrorBoundary >
242- </ div >
243- </ Router >
149+ < UserPermissionsContext . Provider value = { roles } >
150+ < Router getUserConfirmation = { onNavigationUserConfirmation } >
151+ < div className = "container-fluid header-clear" >
152+ { /* Header switch - render the usual header for all pages but the rundown view */ }
153+ < ErrorBoundary >
154+ < Switch >
155+ < Route path = "/rundown/:playlistId" component = { NullComponent } />
156+ < Route path = "/countdowns/:studioId" component = { NullComponent } />
157+ < Route path = "/activeRundown" component = { NullComponent } />
158+ < Route path = "/prompter/:studioId" component = { NullComponent } />
159+ < Route
160+ path = "/"
161+ render = { ( props ) => (
162+ < Header
163+ { ...props }
164+ allowConfigure = { roles . configure }
165+ allowTesting = { roles . testing }
166+ allowDeveloper = { roles . developer }
167+ />
168+ ) }
169+ />
170+ </ Switch >
171+ </ ErrorBoundary >
172+ { /* Main app switch */ }
173+ < ErrorBoundary >
174+ < Switch >
175+ < Route exact path = "/" component = { RundownList } />
176+ < Route path = "/rundowns" render = { ( ) => < RundownList /> } />
177+ < Route
178+ path = "/rundown/:playlistId/shelf"
179+ exact
180+ render = { ( props ) => (
181+ < RundownView
182+ playlistId = { protectString ( decodeURIComponent ( props . match . params . playlistId ) ) }
183+ onlyShelf = { true }
184+ />
185+ ) }
186+ />
187+ < Route
188+ path = "/rundown/:playlistId"
189+ render = { ( props ) => (
190+ < RundownView playlistId = { protectString ( decodeURIComponent ( props . match . params . playlistId ) ) } />
191+ ) }
192+ />
193+ < Route
194+ path = "/activeRundown/:studioId"
195+ render = { ( props ) => (
196+ < ActiveRundownView studioId = { protectString ( decodeURIComponent ( props . match . params . studioId ) ) } />
197+ ) }
198+ />
199+ < Route
200+ path = "/prompter/:studioId"
201+ render = { ( props ) => (
202+ < PrompterView studioId = { protectString ( decodeURIComponent ( props . match . params . studioId ) ) } />
203+ ) }
204+ />
205+ { /* We switch to the general ClockView component, and allow it to do the switch between various types of countdowns */ }
206+ < Route
207+ path = "/countdowns/:studioId"
208+ render = { ( props ) => (
209+ < ClockView studioId = { protectString ( decodeURIComponent ( props . match . params . studioId ) ) } />
210+ ) }
211+ />
212+ < Route path = "/status" render = { ( ) => < Status /> } />
213+ < Route path = "/settings" render = { ( ) => < SettingsView /> } />
214+ < Route path = "/testTools" render = { ( ) => < TestTools /> } />
215+ < Route >
216+ < Redirect to = "/" />
217+ </ Route >
218+ </ Switch >
219+ </ ErrorBoundary >
220+ < ErrorBoundary >
221+ < Switch >
222+ { /* Put views that should NOT have the Notification center here: */ }
223+ < Route path = "/countdowns/:studioId" component = { NullComponent } />
224+ < Route path = "/prompter/:studioId" component = { NullComponent } />
225+ < Route path = "/" component = { ConnectionStatusNotification } />
226+ </ Switch >
227+ </ ErrorBoundary >
228+ < ErrorBoundary >
229+ < DocumentTitleProvider />
230+ </ ErrorBoundary >
231+ < ErrorBoundary >
232+ < ModalDialogGlobalContainer />
233+ </ ErrorBoundary >
234+ </ div >
235+ </ Router >
236+ </ UserPermissionsContext . Provider >
244237 )
245238}
246239
247- function useRoles ( ) {
248- const location = window . location
249-
250- const [ roles , setRoles ] = useState ( {
251- studio : getAllowStudio ( ) ,
252- configure : getAllowConfigure ( ) ,
253- developer : getAllowDeveloper ( ) ,
254- testing : getAllowTesting ( ) ,
255- service : getAllowService ( ) ,
256- } )
257-
258- useEffect ( ( ) => {
259- if ( ! location . search ) return
260-
261- const params = queryStringParse ( location . search )
262-
263- if ( params [ 'studio' ] ) setAllowStudio ( params [ 'studio' ] === '1' )
264- if ( params [ 'configure' ] ) setAllowConfigure ( params [ 'configure' ] === '1' )
265- if ( params [ 'develop' ] ) setAllowDeveloper ( params [ 'develop' ] === '1' )
266- if ( params [ 'testing' ] ) setAllowTesting ( params [ 'testing' ] === '1' )
267- if ( params [ 'service' ] ) setAllowService ( params [ 'service' ] === '1' )
268-
269- if ( params [ 'admin' ] ) {
270- const val = params [ 'admin' ] === '1'
271- setAllowStudio ( val )
272- setAllowConfigure ( val )
273- setAllowDeveloper ( val )
274- setAllowTesting ( val )
275- setAllowService ( val )
276- }
277-
278- setRoles ( {
279- studio : getAllowStudio ( ) ,
280- configure : getAllowConfigure ( ) ,
281- developer : getAllowDeveloper ( ) ,
282- testing : getAllowTesting ( ) ,
283- service : getAllowService ( ) ,
284- } )
285- } , [ location . search ] )
286-
287- return roles
288- }
289-
290240function useFeatureFlags ( ) {
291241 const location = window . location
292242
0 commit comments