The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx

119 lines
3.4 KiB

import { useCallback, useState } from 'react';
import { useAsync, useDebounce } from 'react-use';
import { Button, Icon, Input, Modal, useStyles2 } from '@grafana/ui';
import { getConnectedDashboards } from '../../state/api';
import { getModalStyles } from '../../styles';
import { PanelModelWithLibraryPanel } from '../../types';
import { usePanelSave } from '../../utils/usePanelSave';
interface Props {
panel: PanelModelWithLibraryPanel;
folderUid: string;
isUnsavedPrompt?: boolean;
onConfirm: () => void;
onDismiss: () => void;
onDiscard: () => void;
}
export const SaveLibraryPanelModal = ({
panel,
folderUid,
isUnsavedPrompt,
onDismiss,
onConfirm,
onDiscard,
}: Props) => {
const [searchString, setSearchString] = useState('');
const dashState = useAsync(async () => {
const searchHits = await getConnectedDashboards(panel.libraryPanel.uid);
if (searchHits.length > 0) {
return searchHits.map((dash) => dash.title);
}
return [];
}, [panel.libraryPanel.uid]);
const [filteredDashboards, setFilteredDashboards] = useState<string[]>([]);
useDebounce(
() => {
if (!dashState.value) {
return setFilteredDashboards([]);
}
return setFilteredDashboards(
dashState.value.filter((dashName) => dashName.toLowerCase().includes(searchString.toLowerCase()))
);
},
300,
[dashState.value, searchString]
);
const { saveLibraryPanel } = usePanelSave();
const styles = useStyles2(getModalStyles);
const discardAndClose = useCallback(() => {
onDiscard();
}, [onDiscard]);
const title = isUnsavedPrompt ? 'Unsaved library panel changes' : 'Save library panel';
return (
<Modal title={title} icon="save" onDismiss={onDismiss} isOpen={true}>
<div>
<p className={styles.textInfo}>
{'This update will affect '}
<strong>
{panel.libraryPanel.meta?.connectedDashboards}{' '}
{panel.libraryPanel.meta?.connectedDashboards === 1 ? 'dashboard' : 'dashboards'}.
</strong>
The following dashboards using the panel will be affected:
</p>
<Input
className={styles.dashboardSearch}
prefix={<Icon name="search" />}
placeholder="Search affected dashboards"
value={searchString}
onChange={(e) => setSearchString(e.currentTarget.value)}
/>
{dashState.loading ? (
<p>Loading connected dashboards...</p>
) : (
<table className={styles.myTable}>
<thead>
<tr>
<th>Dashboard name</th>
</tr>
</thead>
<tbody>
{filteredDashboards.map((dashName, i) => (
<tr key={`dashrow-${i}`}>
<td>{dashName}</td>
</tr>
))}
</tbody>
</table>
)}
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss} fill="outline">
Cancel
</Button>
{isUnsavedPrompt && (
<Button variant="destructive" onClick={discardAndClose}>
Discard
</Button>
)}
<Button
onClick={() => {
saveLibraryPanel(panel, folderUid).then(() => {
onConfirm();
});
}}
>
Update all
</Button>
</Modal.ButtonRow>
</div>
</Modal>
);
};