66 */
77
88import createContainer from 'constate' ;
9+ import * as rt from 'io-ts' ;
10+ import { pipe } from 'fp-ts/lib/pipeable' ;
11+ import { fold } from 'fp-ts/lib/Either' ;
12+ import { constant , identity } from 'fp-ts/lib/function' ;
913import { useCallback , useMemo , useState , useEffect , useContext } from 'react' ;
1014import { i18n } from '@kbn/i18n' ;
1115import { SimpleSavedObject , SavedObjectAttributes } from 'kibana/public' ;
16+ import { useUrlState } from '../../utils/use_url_state' ;
1217import { useFindSavedObject } from '../../hooks/use_find_saved_object' ;
1318import { useCreateSavedObject } from '../../hooks/use_create_saved_object' ;
1419import { useDeleteSavedObject } from '../../hooks/use_delete_saved_object' ;
@@ -39,6 +44,14 @@ interface Props {
3944 shouldLoadDefault : boolean ;
4045}
4146
47+ const savedViewUrlStateRT = rt . type ( {
48+ viewId : rt . string ,
49+ } ) ;
50+ type SavedViewUrlState = rt . TypeOf < typeof savedViewUrlStateRT > ;
51+ const DEFAULT_SAVED_VIEW_STATE : SavedViewUrlState = {
52+ viewId : '0' ,
53+ } ;
54+
4255export const useSavedView = ( props : Props ) => {
4356 const {
4457 source,
@@ -52,6 +65,13 @@ export const useSavedView = (props: Props) => {
5265 const { data, loading, find, error : errorOnFind , hasView } = useFindSavedObject <
5366 SavedViewSavedObject < ViewState >
5467 > ( viewType ) ;
68+ const [ urlState , setUrlState ] = useUrlState < SavedViewUrlState > ( {
69+ defaultState : DEFAULT_SAVED_VIEW_STATE ,
70+ decodeUrlState,
71+ encodeUrlState,
72+ urlStateKey : 'savedView' ,
73+ } ) ;
74+
5575 const [ shouldLoadDefault ] = useState ( props . shouldLoadDefault ) ;
5676 const [ currentView , setCurrentView ] = useState < SavedView < any > | null > ( null ) ;
5777 const [ loadingDefaultView , setLoadingDefaultView ] = useState < boolean | null > ( null ) ;
@@ -212,25 +232,35 @@ export const useSavedView = (props: Props) => {
212232 } ) ;
213233 } , [ setCurrentView , defaultViewId , defaultViewState ] ) ;
214234
215- useEffect ( ( ) => {
216- if ( loadingDefaultView || currentView || ! shouldLoadDefault ) {
217- return ;
218- }
219-
235+ const loadDefaultViewIfSet = useCallback ( ( ) => {
220236 if ( defaultViewId !== '0' ) {
221237 loadDefaultView ( ) ;
222238 } else {
223239 setDefault ( ) ;
224240 setLoadingDefaultView ( false ) ;
225241 }
226- } , [
227- loadDefaultView ,
228- shouldLoadDefault ,
229- setDefault ,
230- loadingDefaultView ,
231- currentView ,
232- defaultViewId ,
233- ] ) ;
242+ } , [ defaultViewId , loadDefaultView , setDefault , setLoadingDefaultView ] ) ;
243+
244+ useEffect ( ( ) => {
245+ if ( loadingDefaultView || currentView || ! shouldLoadDefault ) {
246+ return ;
247+ }
248+
249+ loadDefaultViewIfSet ( ) ;
250+ } , [ loadDefaultViewIfSet , loadingDefaultView , currentView , shouldLoadDefault ] ) ;
251+
252+ useEffect ( ( ) => {
253+ if ( currentView && urlState . viewId !== currentView . id && data )
254+ setUrlState ( { viewId : currentView . id } ) ;
255+ } , [ urlState , setUrlState , currentView , defaultViewId , data ] ) ;
256+
257+ useEffect ( ( ) => {
258+ if ( ! currentView && ! loading && data ) {
259+ const viewToSet = views . find ( ( v ) => v . id === urlState . viewId ) ;
260+ if ( viewToSet ) setCurrentView ( viewToSet ) ;
261+ else loadDefaultViewIfSet ( ) ;
262+ }
263+ } , [ loading , currentView , data , views , setCurrentView , loadDefaultViewIfSet , urlState . viewId ] ) ;
234264
235265 return {
236266 views,
@@ -260,3 +290,11 @@ export const useSavedView = (props: Props) => {
260290
261291export const SavedView = createContainer ( useSavedView ) ;
262292export const [ SavedViewProvider , useSavedViewContext ] = SavedView ;
293+
294+ const encodeUrlState = ( state : SavedViewUrlState ) => {
295+ return savedViewUrlStateRT . encode ( state ) ;
296+ } ;
297+ const decodeUrlState = ( value : unknown ) => {
298+ const state = pipe ( savedViewUrlStateRT . decode ( value ) , fold ( constant ( undefined ) , identity ) ) ;
299+ return state ;
300+ } ;
0 commit comments