import './importJSON.styles.scss'; import { red } from '@ant-design/colors'; import { ExclamationCircleTwoTone } from '@ant-design/icons'; import MEditor, { Monaco } from '@monaco-editor/react'; import { Color } from '@signozhq/design-tokens'; import { Button, Flex, Modal, Space, Typography, Upload, UploadProps, } from 'antd'; import logEvent from 'api/common/logEvent'; import createDashboard from 'api/v1/dashboards/create'; import ROUTES from 'constants/routes'; import { useIsDarkMode } from 'hooks/useDarkMode'; import { useNotifications } from 'hooks/useNotifications'; import { useSafeNavigate } from 'hooks/useSafeNavigate'; import { getUpdatedLayout } from 'lib/dashboard/getUpdatedLayout'; import { ExternalLink, Github, MonitorDot, MoveRight, X } from 'lucide-react'; import { useErrorModal } from 'providers/ErrorModalProvider'; // #TODO: Lucide will be removing brand icons like GitHub in the future. In that case, we can use Simple Icons. https://simpleicons.org/ // See more: https://github.com/lucide-icons/lucide/issues/94 import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { generatePath } from 'react-router-dom'; import { DashboardData } from 'types/api/dashboard/getAll'; import APIError from 'types/api/error'; function ImportJSON({ isImportJSONModalVisible, uploadedGrafana, onModalHandler, }: ImportJSONProps): JSX.Element { const { safeNavigate } = useSafeNavigate(); const [jsonData, setJsonData] = useState>(); const { t } = useTranslation(['dashboard', 'common']); const [isUploadJSONError, setIsUploadJSONError] = useState(false); const [isCreateDashboardError, setIsCreateDashboardError] = useState( false, ); const [dashboardCreating, setDashboardCreating] = useState(false); const [editorValue, setEditorValue] = useState(''); const { notifications } = useNotifications(); const onChangeHandler: UploadProps['onChange'] = (info) => { const { fileList } = info; const reader = new FileReader(); const lastFile = fileList[fileList.length - 1]; if (lastFile.originFileObj) { reader.onload = async (event): Promise => { if (event.target) { const target = event.target.result; try { if (target) { const targetFile = target.toString(); const parsedValue = JSON.parse(targetFile); setJsonData(parsedValue); setEditorValue(JSON.stringify(parsedValue, null, 2)); setIsUploadJSONError(false); } } catch (error) { setIsUploadJSONError(true); } } }; reader.readAsText(lastFile.originFileObj); } }; const { showErrorModal } = useErrorModal(); const onClickLoadJsonHandler = async (): Promise => { try { setDashboardCreating(true); logEvent('Dashboard List: Import and next clicked', {}); const dashboardData = JSON.parse(editorValue) as DashboardData; if (dashboardData?.layout) { dashboardData.layout = getUpdatedLayout(dashboardData.layout); } else { dashboardData.layout = []; } const response = await createDashboard({ ...dashboardData, uploadedGrafana, }); safeNavigate( generatePath(ROUTES.DASHBOARD, { dashboardId: response.data.id, }), ); logEvent('Dashboard List: New dashboard imported successfully', { dashboardId: response.data?.id, dashboardName: response.data?.data?.title, }); setDashboardCreating(false); } catch (error) { showErrorModal(error as APIError); setDashboardCreating(false); setIsCreateDashboardError(true); notifications.error({ message: error instanceof Error ? error.message : t('error_loading_json'), }); } }; const getErrorNode = (error: string): JSX.Element => ( {error} ); const onCancelHandler = (): void => { setIsUploadJSONError(false); setIsCreateDashboardError(false); onModalHandler(); }; const isDarkMode = useIsDarkMode(); function setEditorTheme(monaco: Monaco): void { monaco.editor.defineTheme('my-theme', { base: 'vs-dark', inherit: true, rules: [ { token: 'string.key.json', foreground: Color.BG_VANILLA_400 }, { token: 'string.value.json', foreground: Color.BG_ROBIN_400 }, ], colors: { 'editor.background': Color.BG_INK_300, }, }); } return ( {isCreateDashboardError && (
{getErrorNode(t('error_loading_json'))}
)} {isUploadJSONError && (
{getErrorNode(t('error_upload_json'))}
)}
false} action="none" data={jsonData} >
} >
{t('import_json')}
setEditorValue(newValue || '')} value={editorValue} options={{ scrollbar: { alwaysConsumeMouseWheel: false, }, minimap: { enabled: false, }, fontSize: 14, fontFamily: 'Space Mono', }} theme={isDarkMode ? 'my-theme' : 'light'} onMount={(_, monaco): void => { document.fonts.ready.then(() => { monaco.editor.remeasureFonts(); }); }} // eslint-disable-next-line react/jsx-no-bind beforeMount={setEditorTheme} />
); } interface ImportJSONProps { isImportJSONModalVisible: boolean; onModalHandler: VoidFunction; uploadedGrafana: boolean; } export default ImportJSON;