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