import * as React from 'react'; import { Header } from '../Header'; import { useRecoilValue } from 'recoil'; import { SettingsSelector } from '../../state'; import { DataForm } from './DataForm'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { DataFile } from '../../../models/DataFile'; import { messageHandler, Messenger } from '@estruyf/vscode/dist/client'; import { DashboardMessage } from '../../DashboardMessage'; import { SponsorMsg } from '../Layout/SponsorMsg'; import { EventData } from '@estruyf/vscode'; import { DashboardCommand } from '../../DashboardCommand'; import { arrayMoveImmutable } from 'array-move'; import { EmptyView } from './EmptyView'; import { Container } from './SortableContainer'; import { SortableItem } from './SortableItem'; import { ChevronRightIcon, CircleStackIcon, EyeIcon, XMarkIcon } from '@heroicons/react/24/outline'; import { DataType } from '../../../models/DataType'; import { GeneralCommands, WEBSITE_LINKS } from '../../../constants'; import { NavigationItem } from '../Layout'; import { LocalizationKey, localize } from '../../../localization'; import { DropdownMenu, DropdownMenuContent } from '../../../components/shadcn/Dropdown'; import { MenuButton, MenuItem } from '../Menu'; import { Transition } from '@headlessui/react'; import { DataFolder } from '../../../models'; import { ActionsBarItem } from '../Header/ActionsBarItem'; import { Spinner } from '../Common/Spinner'; import { openFile } from '../../utils/MessageHandlers'; import { Button } from 'vscrui'; export interface IDataViewProps { } export const DataView: React.FunctionComponent = () => { const [selectedData, setSelectedData] = useState(null); const [selectedIndex, setSelectedIndex] = useState(null); const [dataEntries, setDataEntries] = useState(null); const [loading, setLoading] = useState(false); const settings = useRecoilValue(SettingsSelector); const setSchema = (dataFile: DataFile) => { setSelectedData(dataFile); setSelectedIndex(null); setDataEntries(null); Messenger.send(DashboardMessage.getDataEntries, { ...dataFile }); }; const messageListener = (message: MessageEvent>) => { if (message.data.command === DashboardCommand.dataFileEntries) { setDataEntries(message.data.payload); } }; const deleteItem = useCallback( (index: number) => { const dataClone: any[] = Object.assign([], dataEntries); if (!selectedData) { return; } dataClone.splice(index, 1); updateData(dataClone); }, [selectedData, dataEntries] ); const onSubmit = useCallback( (data: unknown) => { if (selectedData?.singleEntry) { // Needs to add a single entry updateData(data); return; } const dataClone: unknown[] = Object.assign([], dataEntries); if (selectedIndex !== null && selectedIndex !== undefined) { dataClone[selectedIndex] = data; } else { dataClone.push(data); } updateData(dataClone); }, [selectedData, dataEntries, selectedIndex] ); const onSortEnd = useCallback( ({ oldIndex, newIndex }: any) => { if (!dataEntries || dataEntries.length === 0) { return null; } if (selectedIndex !== null && selectedIndex !== undefined) { setSelectedIndex(newIndex); } const newEntries = arrayMoveImmutable(dataEntries, oldIndex, newIndex); updateData(newEntries); }, [selectedData, dataEntries, selectedIndex] ); const updateData = useCallback( (data: any) => { if (!selectedData) { return; } Messenger.send(DashboardMessage.putDataEntries, { file: selectedData.file, fileType: selectedData.fileType, entries: data }); Messenger.send(DashboardMessage.showNotification, localize(LocalizationKey.dashboardDataViewDataViewUpdateMessage)); }, [selectedData] ); const createDataFile = (folder: DataFolder) => { setLoading(true); messageHandler.request(DashboardMessage.createDataFile, folder).then(dataFile => { if (dataFile) { setSchema(dataFile); } setLoading(false); }).catch((_: any) => { setLoading(false); }); } const dataEntry = useMemo(() => { if (selectedData?.singleEntry) { return dataEntries || {}; } return dataEntries && selectedIndex !== null && selectedIndex !== undefined ? dataEntries[selectedIndex] : null; }, [selectedData, dataEntries, selectedIndex]); // Retrieve the data files, check if they have a schema or ID, if not, they shouldn't be shown const dataFiles = useMemo(() => { return (settings?.dataFiles || []) .map((dataFile: DataFile) => { if (!dataFile.schema && !dataFile.id) { return null; } const clonedFile = Object.assign({}, dataFile); if (clonedFile.type) { const dataType = settings?.dataTypes?.find( (dataType: DataType) => dataType.id === clonedFile.type ); if (!dataType) { return null; } clonedFile.schema = Object.assign({}, dataType.schema); } return clonedFile; }) .filter((d) => d !== null) as DataFile[]; }, [settings?.dataFiles]); const fileCreationFolders = useMemo(() => { return (settings?.dataFolders || []) .filter((folder) => folder.enableFileCreation); }, [settings?.dataFolders]); const hasOnlyDataCreationFolders = useMemo(() => (!dataFiles || dataFiles.length === 0) && (fileCreationFolders && fileCreationFolders.length > 0), [dataFiles, fileCreationFolders]); useEffect(() => { Messenger.listen(messageListener); Messenger.send(DashboardMessage.setTitle, localize(LocalizationKey.dashboardHeaderTabsData)); Messenger.send(GeneralCommands.toVSCode.logging.info, { message: 'Data view loaded', location: 'DASHBOARD' }); return () => { Messenger.unlisten(messageListener); }; }, []); return (
{(dataFiles && dataFiles.length > 0) || (fileCreationFolders && fileCreationFolders.length > 0) ? (
{ !selectedData && (dataFiles && dataFiles.length > 0) && (
) }
{ selectedData && ( {dataFiles.map((dataFile) => ( setSchema(dataFile)} /> ))} ) } { fileCreationFolders && fileCreationFolders.length > 0 && ( {fileCreationFolders.map((folder) => ( createDataFile(folder)} /> ))} ) }
{ selectedData && (
openFile(selectedData.file)} title={localize(LocalizationKey.commonView)} > setSelectedData(null)} title={localize(LocalizationKey.dashboardDataViewDataViewCloseSelectedDataFile)} >
) }
{selectedData ? ( <> {!selectedData.singleEntry && (

{localize(LocalizationKey.dashboardDataViewDataViewTitle, selectedData?.title?.toLowerCase() || '')}

{dataEntries && dataEntries.length > 0 ? ( <> {((dataEntries as any[]) || []).map((dataEntry, idx) => ( setSelectedIndex(index)} onDeleteItem={deleteItem} /> ))} ) : (

{localize(LocalizationKey.dashboardDataViewDataViewEmpty, selectedData.title.toLowerCase())}

)}
)}

{localize(LocalizationKey.dashboardDataViewDataViewCreateOrModify, selectedData.title.toLowerCase())}

{selectedData ? ( setSelectedIndex(null)} /> ) : (

{localize(LocalizationKey.dashboardDataViewDataViewGetStarted)}

)}
) : ( )}
) : (

{localize(LocalizationKey.dashboardDataViewDataViewNoDataFiles)}

{localize(LocalizationKey.dashboardDataViewDataViewGetStartedLink)}

) } {loading && } DataView metrics
); };