mirror of
https://github.com/grafana/grafana.git
synced 2026-07-30 00:08:10 -05:00
Search: folder view improvements (#24324)
* Search: Do not set items if no results returned * Search: Simplify canSave logic * Search: Add initialLoading state * Search: Add itemsFetching state to folder * Search: Fix props and tests * Search: Fix strict null check
This commit is contained in:
@@ -78,7 +78,7 @@ export class SearchSrv {
|
||||
if (query.layout === SearchLayout.List) {
|
||||
return backendSrv
|
||||
.search({ ...query, type: DashboardSearchItemType.DashDB })
|
||||
.then(results => [{ items: results }]);
|
||||
.then(results => (results.length ? [{ items: results }] : []));
|
||||
}
|
||||
|
||||
if (!filters) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { HorizontalGroup, LinkButton } from '@grafana/ui';
|
||||
export interface Props {
|
||||
folderId?: number;
|
||||
isEditor: boolean;
|
||||
canEdit: boolean;
|
||||
canEdit?: boolean;
|
||||
}
|
||||
|
||||
export const DashboardActions: FC<Props> = ({ folderId, isEditor, canEdit }) => {
|
||||
|
||||
@@ -28,14 +28,14 @@ export const DashboardListPage: FC<Props> = memo(({ navModel, uid, url }) => {
|
||||
getLocationSrv().update({ path });
|
||||
}
|
||||
|
||||
return { id: folder.id, pageNavModel: { ...navModel, ...model } };
|
||||
return { folder, pageNavModel: { ...navModel, ...model } };
|
||||
});
|
||||
}, [uid]);
|
||||
|
||||
return (
|
||||
<Page navModel={value?.pageNavModel}>
|
||||
<Page.Contents isLoading={loading}>
|
||||
<ManageDashboards folderUid={uid} folderId={value?.id} />
|
||||
<ManageDashboards folder={value?.folder} />
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
import React, { FC, memo, useState } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { HorizontalGroup, stylesFactory, useTheme } from '@grafana/ui';
|
||||
import { HorizontalGroup, stylesFactory, useTheme, Spinner } from '@grafana/ui';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
||||
import { FolderDTO } from 'app/types';
|
||||
import { useManageDashboards } from '../hooks/useManageDashboards';
|
||||
import { SearchLayout } from '../types';
|
||||
import { ConfirmDeleteModal } from './ConfirmDeleteModal';
|
||||
import { MoveToFolderModal } from './MoveToFolderModal';
|
||||
import { useSearchQuery } from '../hooks/useSearchQuery';
|
||||
import { useManageDashboards } from '../hooks/useManageDashboards';
|
||||
import { SearchResultsFilter } from './SearchResultsFilter';
|
||||
import { SearchResults } from './SearchResults';
|
||||
import { DashboardActions } from './DashboardActions';
|
||||
import { SearchLayout } from '../types';
|
||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
||||
|
||||
export interface Props {
|
||||
folderId?: number;
|
||||
folderUid?: string;
|
||||
folder?: FolderDTO;
|
||||
}
|
||||
|
||||
const { isEditor } = contextSrv;
|
||||
|
||||
export const ManageDashboards: FC<Props> = memo(({ folderId, folderUid }) => {
|
||||
export const ManageDashboards: FC<Props> = memo(({ folder }) => {
|
||||
const folderId = folder?.id;
|
||||
const folderUid = folder?.uid;
|
||||
const theme = useTheme();
|
||||
const styles = getStyles(theme);
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
@@ -47,6 +49,7 @@ export const ManageDashboards: FC<Props> = memo(({ folderId, folderUid }) => {
|
||||
const {
|
||||
results,
|
||||
loading,
|
||||
initialLoading,
|
||||
canSave,
|
||||
allChecked,
|
||||
hasEditPermissionInFolders,
|
||||
@@ -57,7 +60,8 @@ export const ManageDashboards: FC<Props> = memo(({ folderId, folderUid }) => {
|
||||
onToggleAllChecked,
|
||||
onDeleteItems,
|
||||
onMoveItems,
|
||||
} = useManageDashboards(query, { hasEditPermissionInFolders: contextSrv.hasEditPermissionInFolders }, folderUid);
|
||||
noFolders,
|
||||
} = useManageDashboards(query, {}, folder);
|
||||
|
||||
const onMoveTo = () => {
|
||||
setIsMoveModalOpen(true);
|
||||
@@ -67,7 +71,11 @@ export const ManageDashboards: FC<Props> = memo(({ folderId, folderUid }) => {
|
||||
setIsDeleteModalOpen(true);
|
||||
};
|
||||
|
||||
if (canSave && folderId && !hasFilters && results.length === 0 && !loading) {
|
||||
if (initialLoading) {
|
||||
return <Spinner className={styles.spinner} />;
|
||||
}
|
||||
|
||||
if (noFolders && !hasFilters) {
|
||||
return (
|
||||
<EmptyListCTA
|
||||
title="This folder doesn't have any dashboards yet"
|
||||
@@ -150,5 +158,11 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
height: 100%;
|
||||
margin-top: ${theme.spacing.xl};
|
||||
`,
|
||||
spinner: css`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 200px;
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import { FixedSizeList } from 'react-window';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { stylesFactory, useTheme, Spinner } from '@grafana/ui';
|
||||
import { DashboardSection, OnToggleChecked, SearchLayout, DashboardSearchHit } from '../types';
|
||||
import { DashboardSection, OnToggleChecked, SearchLayout } from '../types';
|
||||
import { SEARCH_ITEM_HEIGHT, SEARCH_ITEM_MARGIN } from '../constants';
|
||||
import { SearchItem } from './SearchItem';
|
||||
import { SectionHeader } from './SectionHeader';
|
||||
@@ -15,7 +15,7 @@ export interface Props {
|
||||
onTagSelected: (name: string) => any;
|
||||
onToggleChecked?: OnToggleChecked;
|
||||
onToggleSection: (section: DashboardSection) => void;
|
||||
results: DashboardSearchHit[];
|
||||
results: DashboardSection[];
|
||||
layout?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { FC, useCallback } from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { Icon, IconButton, stylesFactory, useTheme } from '@grafana/ui';
|
||||
import { Icon, IconButton, Spinner, stylesFactory, useTheme } from '@grafana/ui';
|
||||
import { DashboardSection, OnToggleChecked } from '../types';
|
||||
import { SearchCheckbox } from './SearchCheckbox';
|
||||
import { getSectionIcon } from '../utils';
|
||||
@@ -51,7 +51,7 @@ export const SectionHeader: FC<SectionHeaderProps> = ({
|
||||
<IconButton name="cog" className={styles.button} />
|
||||
</a>
|
||||
)}
|
||||
<Icon name={section.expanded ? 'angle-down' : 'angle-right'} />
|
||||
{section.itemsFetching ? <Spinner /> : <Icon name={section.expanded ? 'angle-down' : 'angle-right'} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,43 +1,26 @@
|
||||
import { useMemo, useReducer } from 'react';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { FolderDTO } from 'app/types';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { DashboardQuery, DashboardSection, OnDeleteItems, OnMoveItems, OnToggleChecked } from '../types';
|
||||
import {
|
||||
DELETE_ITEMS,
|
||||
MOVE_ITEMS,
|
||||
TOGGLE_ALL_CHECKED,
|
||||
TOGGLE_CHECKED,
|
||||
TOGGLE_CAN_SAVE,
|
||||
TOGGLE_EDIT_PERMISSIONS,
|
||||
} from '../reducers/actionTypes';
|
||||
import { DELETE_ITEMS, MOVE_ITEMS, TOGGLE_ALL_CHECKED, TOGGLE_CHECKED } from '../reducers/actionTypes';
|
||||
import { manageDashboardsReducer, manageDashboardsState, ManageDashboardsState } from '../reducers/manageDashboards';
|
||||
import { useSearch } from './useSearch';
|
||||
|
||||
export const useManageDashboards = (
|
||||
query: DashboardQuery,
|
||||
state: Partial<ManageDashboardsState> = {},
|
||||
folderUid?: string
|
||||
folder?: FolderDTO
|
||||
) => {
|
||||
const reducer = useReducer(manageDashboardsReducer, {
|
||||
...manageDashboardsState,
|
||||
...state,
|
||||
});
|
||||
|
||||
const searchCallback = (folderUid: string | undefined) => {
|
||||
if (folderUid) {
|
||||
backendSrv.getFolderByUid(folderUid).then(folder => {
|
||||
dispatch({ type: TOGGLE_CAN_SAVE, payload: folder.canSave });
|
||||
if (!folder.canSave) {
|
||||
dispatch({ type: TOGGLE_EDIT_PERMISSIONS, payload: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
state: { results, loading, canSave, allChecked, hasEditPermissionInFolders },
|
||||
state: { results, loading, initialLoading, allChecked },
|
||||
onToggleSection,
|
||||
dispatch,
|
||||
} = useSearch<ManageDashboardsState>(query, reducer, { folderUid, searchCallback });
|
||||
} = useSearch<ManageDashboardsState>(query, reducer, {});
|
||||
|
||||
const onToggleChecked: OnToggleChecked = item => {
|
||||
dispatch({ type: TOGGLE_CHECKED, payload: item });
|
||||
@@ -64,9 +47,14 @@ export const useManageDashboards = (
|
||||
results,
|
||||
]);
|
||||
|
||||
const canSave = folder?.canSave;
|
||||
const hasEditPermissionInFolders = canSave ? contextSrv.hasEditPermissionInFolders : false;
|
||||
const noFolders = canSave && folder?.id && results.length === 0 && !loading && !initialLoading;
|
||||
|
||||
return {
|
||||
results,
|
||||
loading,
|
||||
initialLoading,
|
||||
canSave,
|
||||
allChecked,
|
||||
hasEditPermissionInFolders,
|
||||
@@ -77,5 +65,6 @@ export const useManageDashboards = (
|
||||
onToggleAllChecked,
|
||||
onDeleteItems,
|
||||
onMoveItems,
|
||||
noFolders,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
||||
import { useDebounce } from 'react-use';
|
||||
import { SearchSrv } from 'app/core/services/search_srv';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { FETCH_RESULTS, FETCH_ITEMS, TOGGLE_SECTION, SEARCH_START } from '../reducers/actionTypes';
|
||||
import { FETCH_RESULTS, FETCH_ITEMS, TOGGLE_SECTION, SEARCH_START, FETCH_ITEMS_START } from '../reducers/actionTypes';
|
||||
import { DashboardSection, UseSearch } from '../types';
|
||||
import { hasId, getParsedQuery } from '../utils';
|
||||
|
||||
@@ -16,8 +16,8 @@ const searchSrv = new SearchSrv();
|
||||
* @param reducer - return result of useReducer
|
||||
* @param params - custom params
|
||||
*/
|
||||
export const useSearch: UseSearch = (query, reducer, params) => {
|
||||
const { queryParsing, folderUid, searchCallback } = params;
|
||||
export const useSearch: UseSearch = (query, reducer, params = {}) => {
|
||||
const { queryParsing } = params;
|
||||
const [state, dispatch] = reducer;
|
||||
|
||||
const search = () => {
|
||||
@@ -25,10 +25,6 @@ export const useSearch: UseSearch = (query, reducer, params) => {
|
||||
const parsedQuery = getParsedQuery(query, queryParsing);
|
||||
searchSrv.search(parsedQuery).then(results => {
|
||||
dispatch({ type: FETCH_RESULTS, payload: results });
|
||||
|
||||
if (searchCallback) {
|
||||
searchCallback(folderUid);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -37,11 +33,11 @@ export const useSearch: UseSearch = (query, reducer, params) => {
|
||||
dispatch({ type: SEARCH_START });
|
||||
}, [query.tag, query.sort, query.starred, query.layout]);
|
||||
|
||||
useDebounce(search, 300, [query, folderUid, queryParsing]);
|
||||
useDebounce(search, 300, [query, queryParsing]);
|
||||
|
||||
// TODO as possible improvement, show spinner after expanding section while items are fetching
|
||||
const onToggleSection = (section: DashboardSection) => {
|
||||
if (hasId(section.title) && !section.items.length) {
|
||||
dispatch({ type: FETCH_ITEMS_START, payload: section.id });
|
||||
backendSrv.search({ folderIds: [section.id] }).then(items => {
|
||||
dispatch({ type: FETCH_ITEMS, payload: { section, items } });
|
||||
dispatch({ type: TOGGLE_SECTION, payload: section });
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
export const FETCH_RESULTS = 'FETCH_RESULTS';
|
||||
export const TOGGLE_SECTION = 'TOGGLE_SECTION';
|
||||
export const FETCH_ITEMS = 'FETCH_ITEMS';
|
||||
export const FETCH_ITEMS_START = 'FETCH_ITEMS_START';
|
||||
export const MOVE_SELECTION_UP = 'MOVE_SELECTION_UP';
|
||||
export const MOVE_SELECTION_DOWN = 'MOVE_SELECTION_DOWN';
|
||||
export const SEARCH_START = 'SEARCH_START';
|
||||
|
||||
// Manage dashboards
|
||||
export const TOGGLE_CAN_SAVE = 'TOGGLE_CAN_SAVE';
|
||||
export const TOGGLE_EDIT_PERMISSIONS = 'TOGGLE_EDIT_PERMISSIONS';
|
||||
export const TOGGLE_ALL_CHECKED = 'TOGGLE_ALL_CHECKED';
|
||||
export const TOGGLE_CHECKED = 'TOGGLE_SECTION_CHECKED';
|
||||
export const MOVE_ITEMS = 'MOVE_ITEMS';
|
||||
|
||||
@@ -2,6 +2,7 @@ import { FETCH_ITEMS, FETCH_RESULTS, TOGGLE_SECTION, MOVE_SELECTION_DOWN, MOVE_S
|
||||
import { searchReducer as reducer, dashboardsSearchState } from './dashboardSearch';
|
||||
import { searchResults, sections } from '../testData';
|
||||
|
||||
const defaultState = { selectedIndex: 0, loading: false, results: sections as any[], initialLoading: false };
|
||||
describe('Dashboard Search reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
expect(reducer(dashboardsSearchState, {} as any)).toEqual(dashboardsSearchState);
|
||||
@@ -9,20 +10,14 @@ describe('Dashboard Search reducer', () => {
|
||||
|
||||
it('should set the results and mark first item as selected', () => {
|
||||
const newState = reducer(dashboardsSearchState, { type: FETCH_RESULTS, payload: searchResults });
|
||||
expect(newState).toEqual({ loading: false, selectedIndex: 0, results: searchResults });
|
||||
expect(newState).toEqual({ loading: false, selectedIndex: 0, results: searchResults, initialLoading: false });
|
||||
expect(newState.results[0].selected).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should toggle selected section', () => {
|
||||
const newState = reducer(
|
||||
{ selectedIndex: 0, loading: false, results: sections as any[] },
|
||||
{ type: TOGGLE_SECTION, payload: sections[5] }
|
||||
);
|
||||
const newState = reducer(defaultState, { type: TOGGLE_SECTION, payload: sections[5] });
|
||||
expect(newState.results[5].expanded).toBeFalsy();
|
||||
const newState2 = reducer(
|
||||
{ selectedIndex: 0, loading: false, results: sections as any[] },
|
||||
{ type: TOGGLE_SECTION, payload: sections[1] }
|
||||
);
|
||||
const newState2 = reducer(defaultState, { type: TOGGLE_SECTION, payload: sections[1] });
|
||||
expect(newState2.results[1].expanded).toBeTruthy();
|
||||
});
|
||||
|
||||
@@ -43,26 +38,20 @@ describe('Dashboard Search reducer', () => {
|
||||
isStarred: false,
|
||||
},
|
||||
];
|
||||
const newState = reducer(
|
||||
{ selectedIndex: 0, loading: false, results: sections as any[] },
|
||||
{
|
||||
type: FETCH_ITEMS,
|
||||
payload: {
|
||||
section: sections[2],
|
||||
items,
|
||||
},
|
||||
}
|
||||
);
|
||||
const newState = reducer(defaultState, {
|
||||
type: FETCH_ITEMS,
|
||||
payload: {
|
||||
section: sections[2],
|
||||
items,
|
||||
},
|
||||
});
|
||||
expect(newState.results[2].items).toEqual(items);
|
||||
});
|
||||
|
||||
it('should handle MOVE_SELECTION_DOWN', () => {
|
||||
const newState = reducer(
|
||||
{ loading: false, selectedIndex: 0, results: sections as any[] },
|
||||
{
|
||||
type: MOVE_SELECTION_DOWN,
|
||||
}
|
||||
);
|
||||
const newState = reducer(defaultState, {
|
||||
type: MOVE_SELECTION_DOWN,
|
||||
});
|
||||
|
||||
expect(newState.selectedIndex).toEqual(1);
|
||||
expect(newState.results[0].items[0].selected).toBeTruthy();
|
||||
@@ -76,7 +65,7 @@ describe('Dashboard Search reducer', () => {
|
||||
|
||||
// Shouldn't go over the visible results length - 1 (9)
|
||||
const newState3 = reducer(
|
||||
{ loading: false, selectedIndex: 9, results: sections as any[] },
|
||||
{ ...defaultState, selectedIndex: 9 },
|
||||
{
|
||||
type: MOVE_SELECTION_DOWN,
|
||||
}
|
||||
@@ -86,17 +75,14 @@ describe('Dashboard Search reducer', () => {
|
||||
|
||||
it('should handle MOVE_SELECTION_UP', () => {
|
||||
// shouldn't move beyond 0
|
||||
const newState = reducer(
|
||||
{ loading: false, selectedIndex: 0, results: sections as any[] },
|
||||
{
|
||||
type: MOVE_SELECTION_UP,
|
||||
}
|
||||
);
|
||||
const newState = reducer(defaultState, {
|
||||
type: MOVE_SELECTION_UP,
|
||||
});
|
||||
|
||||
expect(newState.selectedIndex).toEqual(0);
|
||||
|
||||
const newState2 = reducer(
|
||||
{ loading: false, selectedIndex: 3, results: sections as any[] },
|
||||
{ ...defaultState, selectedIndex: 3 },
|
||||
{
|
||||
type: MOVE_SELECTION_UP,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DashboardSearchHit, DashboardSection, SearchAction } from '../types';
|
||||
import { DashboardSection, SearchAction } from '../types';
|
||||
import { getFlattenedSections, getLookupField, markSelected } from '../utils';
|
||||
import {
|
||||
FETCH_ITEMS,
|
||||
@@ -7,17 +7,21 @@ import {
|
||||
MOVE_SELECTION_DOWN,
|
||||
MOVE_SELECTION_UP,
|
||||
SEARCH_START,
|
||||
FETCH_ITEMS_START,
|
||||
} from './actionTypes';
|
||||
|
||||
export interface DashboardsSearchState {
|
||||
results: DashboardSearchHit[];
|
||||
results: DashboardSection[];
|
||||
loading: boolean;
|
||||
selectedIndex: number;
|
||||
/** Used for first time page load */
|
||||
initialLoading: boolean;
|
||||
}
|
||||
|
||||
export const dashboardsSearchState: DashboardsSearchState = {
|
||||
results: [],
|
||||
loading: true,
|
||||
initialLoading: true,
|
||||
selectedIndex: 0,
|
||||
};
|
||||
|
||||
@@ -34,7 +38,7 @@ export const searchReducer = (state: DashboardsSearchState, action: SearchAction
|
||||
if (results.length > 0) {
|
||||
results[0].selected = true;
|
||||
}
|
||||
return { ...state, results, loading: false };
|
||||
return { ...state, results, loading: false, initialLoading: false };
|
||||
}
|
||||
case TOGGLE_SECTION: {
|
||||
const section = action.payload;
|
||||
@@ -53,14 +57,25 @@ export const searchReducer = (state: DashboardsSearchState, action: SearchAction
|
||||
const { section, items } = action.payload;
|
||||
return {
|
||||
...state,
|
||||
itemsFetching: false,
|
||||
results: state.results.map((result: DashboardSection) => {
|
||||
if (section.id === result.id) {
|
||||
return { ...result, items };
|
||||
return { ...result, items, itemsFetching: false };
|
||||
}
|
||||
return result;
|
||||
}),
|
||||
};
|
||||
}
|
||||
case FETCH_ITEMS_START: {
|
||||
const id = action.payload;
|
||||
if (id) {
|
||||
return {
|
||||
...state,
|
||||
results: state.results.map(result => (result.id === id ? { ...result, itemsFetching: true } : result)),
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case MOVE_SELECTION_DOWN: {
|
||||
const flatIds = getFlattenedSections(state.results);
|
||||
if (state.selectedIndex < flatIds.length - 1) {
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
TOGGLE_CAN_SAVE,
|
||||
TOGGLE_EDIT_PERMISSIONS,
|
||||
TOGGLE_ALL_CHECKED,
|
||||
TOGGLE_CHECKED,
|
||||
DELETE_ITEMS,
|
||||
MOVE_ITEMS,
|
||||
} from './actionTypes';
|
||||
import { TOGGLE_ALL_CHECKED, TOGGLE_CHECKED, DELETE_ITEMS, MOVE_ITEMS } from './actionTypes';
|
||||
import { manageDashboardsReducer as reducer, manageDashboardsState as state } from './manageDashboards';
|
||||
import { sections } from '../testData';
|
||||
import { UidsToDelete } from '../types';
|
||||
@@ -34,16 +27,6 @@ describe('Manage dashboards reducer', () => {
|
||||
expect(newState2.allChecked).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle TOGGLE_CAN_SAVE', () => {
|
||||
const newState = reducer(state, { type: TOGGLE_CAN_SAVE, payload: true });
|
||||
expect(newState.canSave).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle TOGGLE_EDIT_PERMISSIONS', () => {
|
||||
const newState = reducer(state, { type: TOGGLE_EDIT_PERMISSIONS, payload: true });
|
||||
expect(newState.hasEditPermissionInFolders).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle TOGGLE_CHECKED sections', () => {
|
||||
const newState = reducer({ ...state, results }, { type: TOGGLE_CHECKED, payload: results[0] });
|
||||
expect(newState.results[0].checked).toBe(true);
|
||||
|
||||
@@ -1,34 +1,19 @@
|
||||
import { DashboardSectionItem, SearchAction } from '../types';
|
||||
import {
|
||||
TOGGLE_CAN_SAVE,
|
||||
TOGGLE_EDIT_PERMISSIONS,
|
||||
TOGGLE_ALL_CHECKED,
|
||||
TOGGLE_CHECKED,
|
||||
MOVE_ITEMS,
|
||||
DELETE_ITEMS,
|
||||
} from './actionTypes';
|
||||
import { TOGGLE_ALL_CHECKED, TOGGLE_CHECKED, MOVE_ITEMS, DELETE_ITEMS } from './actionTypes';
|
||||
import { dashboardsSearchState, DashboardsSearchState, searchReducer } from './dashboardSearch';
|
||||
import { mergeReducers } from '../utils';
|
||||
|
||||
export interface ManageDashboardsState extends DashboardsSearchState {
|
||||
canSave: boolean;
|
||||
allChecked: boolean;
|
||||
hasEditPermissionInFolders: boolean;
|
||||
}
|
||||
|
||||
export const manageDashboardsState: ManageDashboardsState = {
|
||||
...dashboardsSearchState,
|
||||
canSave: false,
|
||||
allChecked: false,
|
||||
hasEditPermissionInFolders: false,
|
||||
};
|
||||
|
||||
const reducer = (state: ManageDashboardsState, action: SearchAction) => {
|
||||
switch (action.type) {
|
||||
case TOGGLE_CAN_SAVE:
|
||||
return { ...state, canSave: action.payload };
|
||||
case TOGGLE_EDIT_PERMISSIONS:
|
||||
return { ...state, hasEditPermissionInFolders: action.payload };
|
||||
case TOGGLE_ALL_CHECKED:
|
||||
const newAllChecked = !state.allChecked;
|
||||
return {
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface DashboardSection {
|
||||
selected?: boolean;
|
||||
type: DashboardSearchItemType;
|
||||
slug?: string;
|
||||
itemsFetching?: boolean;
|
||||
}
|
||||
|
||||
export interface DashboardSectionItem {
|
||||
|
||||
Reference in New Issue
Block a user