mirror of https://github.com/grafana/grafana
Navigation: Proof-of-concept for pinning navbar items (#44775)
parent
7c826cb43f
commit
b6682cdcb9
@ -1,15 +1,32 @@ |
||||
import { createSlice } from '@reduxjs/toolkit'; |
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'; |
||||
import { NavModelItem } from '@grafana/data'; |
||||
import config from 'app/core/config'; |
||||
|
||||
export const initialState: NavModelItem[] = config.bootData.navTree; |
||||
const defaultPins = ['home', 'dashboards', 'explore', 'alerting'].join(','); |
||||
const storedPins = (window.localStorage.getItem('pinnedNavItems') ?? defaultPins).split(','); |
||||
|
||||
export const initialState: NavModelItem[] = (config.bootData.navTree as NavModelItem[]).map((n: NavModelItem) => ({ |
||||
...n, |
||||
hideFromNavbar: n.id === undefined || !storedPins.includes(n.id), |
||||
})); |
||||
|
||||
const navTreeSlice = createSlice({ |
||||
name: 'navBarTree', |
||||
initialState, |
||||
reducers: {}, |
||||
reducers: { |
||||
togglePin: (state, action: PayloadAction<{ id: string }>) => { |
||||
const navItemIndex = state.findIndex((navItem) => navItem.id === action.payload.id); |
||||
state[navItemIndex].hideFromNavbar = !state[navItemIndex].hideFromNavbar; |
||||
window.localStorage.setItem( |
||||
'pinnedNavItems', |
||||
state |
||||
.filter((n) => !n.hideFromNavbar) |
||||
.map((n) => n.id) |
||||
.join(',') |
||||
); |
||||
}, |
||||
}, |
||||
}); |
||||
|
||||
export const {} = navTreeSlice.actions; |
||||
|
||||
export const { togglePin } = navTreeSlice.actions; |
||||
export const navTreeReducer = navTreeSlice.reducer; |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@ |
||||
import React from 'react'; |
||||
import { render as rtlRender } from '@testing-library/react'; |
||||
import { AnyAction, configureStore } from '@reduxjs/toolkit'; |
||||
import { ThunkMiddlewareFor } from '@reduxjs/toolkit/dist/getDefaultMiddleware'; |
||||
import { Provider } from 'react-redux'; |
||||
import { createRootReducer } from 'app/core/reducers/root'; |
||||
import { StoreState } from 'app/types'; |
||||
import { mockNavModel } from './mocks/navModel'; |
||||
|
||||
function render( |
||||
ui: React.ReactElement, |
||||
{ |
||||
preloadedState = { navIndex: mockNavModel }, |
||||
store = configureStore< |
||||
StoreState, |
||||
AnyAction, |
||||
ReadonlyArray<ThunkMiddlewareFor<StoreState, { thunk: true; serializableCheck: false; immutableCheck: false }>> |
||||
>({ |
||||
reducer: createRootReducer(), |
||||
preloadedState, |
||||
middleware: (getDefaultMiddleware) => |
||||
getDefaultMiddleware({ thunk: true, serializableCheck: false, immutableCheck: false }), |
||||
}), |
||||
...renderOptions |
||||
}: { preloadedState?: Partial<StoreState>; store?: ReturnType<typeof configureStore> } = {} |
||||
) { |
||||
function Wrapper({ children }: { children: React.ReactNode }) { |
||||
return <Provider store={store}>{children}</Provider>; |
||||
} |
||||
|
||||
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions }); |
||||
} |
||||
|
||||
export * from '@testing-library/react'; |
||||
export { render }; |
Loading…
Reference in new issue