AddLibraryPanelModal.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { useAsync, useDebounce } from 'react-use';
  3. import { Button, Field, Input, Modal } from '@grafana/ui';
  4. import { FolderPicker } from 'app/core/components/Select/FolderPicker';
  5. import { PanelModel } from '../../../dashboard/state';
  6. import { getLibraryPanelByName } from '../../state/api';
  7. import { usePanelSave } from '../../utils/usePanelSave';
  8. interface AddLibraryPanelContentsProps {
  9. onDismiss: () => void;
  10. panel: PanelModel;
  11. initialFolderId?: number;
  12. }
  13. export const AddLibraryPanelContents = ({ panel, initialFolderId, onDismiss }: AddLibraryPanelContentsProps) => {
  14. const [folderId, setFolderId] = useState(initialFolderId);
  15. const [panelName, setPanelName] = useState(panel.title);
  16. const [debouncedPanelName, setDebouncedPanelName] = useState(panel.title);
  17. const [waiting, setWaiting] = useState(false);
  18. useEffect(() => setWaiting(true), [panelName]);
  19. useDebounce(() => setDebouncedPanelName(panelName), 350, [panelName]);
  20. const { saveLibraryPanel } = usePanelSave();
  21. const onCreate = useCallback(() => {
  22. panel.libraryPanel = { uid: undefined, name: panelName };
  23. saveLibraryPanel(panel, folderId!).then((res) => {
  24. if (!(res instanceof Error)) {
  25. onDismiss();
  26. }
  27. });
  28. }, [panel, panelName, folderId, onDismiss, saveLibraryPanel]);
  29. const isValidName = useAsync(async () => {
  30. try {
  31. return !(await getLibraryPanelByName(panelName)).some((lp) => lp.folderId === folderId);
  32. } catch (err) {
  33. err.isHandled = true;
  34. return true;
  35. } finally {
  36. setWaiting(false);
  37. }
  38. }, [debouncedPanelName, folderId]);
  39. const invalidInput =
  40. !isValidName?.value && isValidName.value !== undefined && panelName === debouncedPanelName && !waiting;
  41. return (
  42. <>
  43. <Field
  44. label="Library panel name"
  45. invalid={invalidInput}
  46. error={invalidInput ? 'Library panel with this name already exists' : ''}
  47. >
  48. <Input
  49. id="share-panel-library-panel-name-input"
  50. name="name"
  51. value={panelName}
  52. onChange={(e) => setPanelName(e.currentTarget.value)}
  53. />
  54. </Field>
  55. <Field label="Save in folder" description="Library panel permissions are derived from the folder permissions">
  56. <FolderPicker
  57. onChange={({ id }) => setFolderId(id)}
  58. initialFolderId={initialFolderId}
  59. inputId="share-panel-library-panel-folder-picker"
  60. />
  61. </Field>
  62. <Modal.ButtonRow>
  63. <Button variant="secondary" onClick={onDismiss} fill="outline">
  64. Cancel
  65. </Button>
  66. <Button onClick={onCreate} disabled={invalidInput}>
  67. Create library panel
  68. </Button>
  69. </Modal.ButtonRow>
  70. </>
  71. );
  72. };
  73. interface Props extends AddLibraryPanelContentsProps {
  74. isOpen?: boolean;
  75. }
  76. export const AddLibraryPanelModal: React.FC<Props> = ({ isOpen = false, panel, initialFolderId, ...props }) => {
  77. return (
  78. <Modal title="Create library panel" isOpen={isOpen} onDismiss={props.onDismiss}>
  79. <AddLibraryPanelContents panel={panel} initialFolderId={initialFolderId} onDismiss={props.onDismiss} />
  80. </Modal>
  81. );
  82. };