1import { useEffect } from 'react'; 2import { useDispatch, useSelector } from 'react-redux'; 3import { PluginError } from '@grafana/data'; 4import { setDisplayMode } from './reducer'; 5import { fetchAll, fetchDetails, fetchRemotePlugins, install, uninstall } from './actions'; 6import { CatalogPlugin, PluginCatalogStoreState, PluginListDisplayMode } from '../types'; 7import { 8 find, 9 selectAll, 10 selectById, 11 selectIsRequestPending, 12 selectRequestError, 13 selectIsRequestNotFetched, 14 selectDisplayMode, 15 selectPluginErrors, 16} from './selectors'; 17import { sortPlugins, Sorters } from '../helpers'; 18 19type Filters = { 20 query?: string; 21 filterBy?: string; 22 filterByType?: string; 23 sortBy?: Sorters; 24}; 25 26export const useGetAllWithFilters = ({ 27 query = '', 28 filterBy = 'installed', 29 filterByType = 'all', 30 sortBy = Sorters.nameAsc, 31}: Filters) => { 32 useFetchAll(); 33 34 const filtered = useSelector(find(query, filterBy, filterByType)); 35 const { isLoading, error } = useFetchStatus(); 36 const sortedAndFiltered = sortPlugins(filtered, sortBy); 37 38 return { 39 isLoading, 40 error, 41 plugins: sortedAndFiltered, 42 }; 43}; 44 45export const useGetAll = (): CatalogPlugin[] => { 46 useFetchAll(); 47 48 return useSelector(selectAll); 49}; 50 51export const useGetSingle = (id: string): CatalogPlugin | undefined => { 52 useFetchAll(); 53 useFetchDetails(id); 54 55 return useSelector((state: PluginCatalogStoreState) => selectById(state, id)); 56}; 57 58export const useGetErrors = (): PluginError[] => { 59 useFetchAll(); 60 61 return useSelector(selectPluginErrors); 62}; 63 64export const useInstall = () => { 65 const dispatch = useDispatch(); 66 return (id: string, version?: string, isUpdating?: boolean) => dispatch(install({ id, version, isUpdating })); 67}; 68 69export const useUninstall = () => { 70 const dispatch = useDispatch(); 71 72 return (id: string) => dispatch(uninstall(id)); 73}; 74 75export const useIsRemotePluginsAvailable = () => { 76 const error = useSelector(selectRequestError(fetchRemotePlugins.typePrefix)); 77 return error === null; 78}; 79 80export const useFetchStatus = () => { 81 const isLoading = useSelector(selectIsRequestPending(fetchAll.typePrefix)); 82 const error = useSelector(selectRequestError(fetchAll.typePrefix)); 83 84 return { isLoading, error }; 85}; 86 87export const useFetchDetailsStatus = () => { 88 const isLoading = useSelector(selectIsRequestPending(fetchDetails.typePrefix)); 89 const error = useSelector(selectRequestError(fetchDetails.typePrefix)); 90 91 return { isLoading, error }; 92}; 93 94export const useInstallStatus = () => { 95 const isInstalling = useSelector(selectIsRequestPending(install.typePrefix)); 96 const error = useSelector(selectRequestError(install.typePrefix)); 97 98 return { isInstalling, error }; 99}; 100 101export const useUninstallStatus = () => { 102 const isUninstalling = useSelector(selectIsRequestPending(uninstall.typePrefix)); 103 const error = useSelector(selectRequestError(uninstall.typePrefix)); 104 105 return { isUninstalling, error }; 106}; 107 108// Only fetches in case they were not fetched yet 109export const useFetchAll = () => { 110 const dispatch = useDispatch(); 111 const isNotFetched = useSelector(selectIsRequestNotFetched(fetchAll.typePrefix)); 112 113 useEffect(() => { 114 isNotFetched && dispatch(fetchAll()); 115 }, []); // eslint-disable-line 116}; 117 118export const useFetchDetails = (id: string) => { 119 const dispatch = useDispatch(); 120 const plugin = useSelector((state: PluginCatalogStoreState) => selectById(state, id)); 121 const isNotFetching = !useSelector(selectIsRequestPending(fetchDetails.typePrefix)); 122 const shouldFetch = isNotFetching && plugin && !plugin.details; 123 124 useEffect(() => { 125 shouldFetch && dispatch(fetchDetails(id)); 126 }, [plugin]); // eslint-disable-line 127}; 128 129export const useDisplayMode = () => { 130 const dispatch = useDispatch(); 131 const displayMode = useSelector(selectDisplayMode); 132 133 return { 134 displayMode, 135 setDisplayMode: (v: PluginListDisplayMode) => dispatch(setDisplayMode(v)), 136 }; 137}; 138