Files
Levente Balogh 21459c7c97 Connections: Show core datasource plugins as well (#67815)
fix: add a new hook & selector that can show core plugins by default
2023-05-05 09:38:18 +02:00

97 lines
2.8 KiB
TypeScript

import { css } from '@emotion/css';
import React, { useMemo, useState } from 'react';
import { PluginType } from '@grafana/data';
import { useStyles2, LoadingPlaceholder } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { useGetAll } from 'app/features/plugins/admin/state/hooks';
import { AccessControlAction } from 'app/types';
import { ROUTES } from '../../constants';
import { CardGrid, type CardGridItem } from './CardGrid';
import { CategoryHeader } from './CategoryHeader';
import { NoAccessModal } from './NoAccessModal';
import { NoResults } from './NoResults';
import { Search } from './Search';
const getStyles = () => ({
spacer: css`
height: 16px;
`,
modal: css`
width: 500px;
`,
modalContent: css`
overflow: visible;
`,
});
export function AddNewConnection() {
const [searchTerm, setSearchTerm] = useState('');
const [isNoAccessModalOpen, setIsNoAccessModalOpen] = useState(false);
const [focusedItem, setFocusedItem] = useState<CardGridItem | null>(null);
const styles = useStyles2(getStyles);
const canCreateDataSources = contextSrv.hasPermission(AccessControlAction.DataSourcesCreate);
const handleSearchChange = (e: React.FormEvent<HTMLInputElement>) => {
setSearchTerm(e.currentTarget.value.toLowerCase());
};
const { isLoading, error, plugins } = useGetAll({
keyword: searchTerm,
type: PluginType.datasource,
});
const cardGridItems = useMemo(
() =>
plugins.map((plugin) => ({
id: plugin.id,
name: plugin.name,
description: plugin.description,
logo: plugin.info.logos.small,
url: ROUTES.DataSourcesDetails.replace(':id', plugin.id),
})),
[plugins]
);
const onClickCardGridItem = (e: React.MouseEvent<HTMLElement>, item: CardGridItem) => {
if (!canCreateDataSources) {
e.preventDefault();
e.stopPropagation();
openModal(item);
}
};
const openModal = (item: CardGridItem) => {
setIsNoAccessModalOpen(true);
setFocusedItem(item);
};
const closeModal = () => {
setIsNoAccessModalOpen(false);
setFocusedItem(null);
};
const showNoResults = useMemo(() => !isLoading && !error && plugins.length < 1, [isLoading, error, plugins]);
return (
<>
{focusedItem && <NoAccessModal item={focusedItem} isOpen={isNoAccessModalOpen} onDismiss={closeModal} />}
<Search onChange={handleSearchChange} />
{/* We need this extra spacing when there are no filters */}
<div className={styles.spacer} />
<CategoryHeader iconName="database" label="Data sources" />
{isLoading ? (
<LoadingPlaceholder text="Loading..." />
) : !!error ? (
<p>Error: {error.message}</p>
) : (
<CardGrid items={cardGridItems} onClickItem={onClickCardGridItem} />
)}
{showNoResults && <NoResults />}
</>
);
}