mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-06-23 11:31:30 +02:00
#406 - Single data entries
This commit is contained in:
@@ -1,5 +1,17 @@
|
||||
# Change Log
|
||||
|
||||
## [8.2.0] - 2022-xx-xx
|
||||
|
||||
### ✨ New features
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#406](https://github.com/estruyf/vscode-front-matter/issues/406): Added support for single data entries in the data dashboard
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
## [8.1.1] - 2022-09-23
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
@@ -550,6 +550,11 @@
|
||||
"type": "string",
|
||||
"default": "content",
|
||||
"description": "If you are using data types, you can specify your type ID."
|
||||
},
|
||||
"singleEntry": {
|
||||
"type": "boolean",
|
||||
"description": "If you want to use a single entry for your data file.",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -601,6 +606,11 @@
|
||||
"type": "string",
|
||||
"default": "content",
|
||||
"description": "If you are using data types, you can specify your type ID."
|
||||
},
|
||||
"singleEntry": {
|
||||
"type": "boolean",
|
||||
"description": "If you want to use a single entry for your data files in the folder.",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Header } from '../Header';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { SettingsSelector } from '../../state';
|
||||
import { DataForm } from './DataForm';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { DataFile } from '../../../models/DataFile';
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
@@ -27,7 +27,7 @@ export interface IDataViewProps {}
|
||||
export const DataView: React.FunctionComponent<IDataViewProps> = (props: React.PropsWithChildren<IDataViewProps>) => {
|
||||
const [ selectedData, setSelectedData ] = useState<DataFile | null>(null);
|
||||
const [ selectedIndex, setSelectedIndex ] = useState<number | null>(null);
|
||||
const [ dataEntries, setDataEntries ] = useState<any[] | null>(null);
|
||||
const [ dataEntries, setDataEntries ] = useState<any | any[] | null>(null);
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
|
||||
const setSchema = (dataFile: DataFile) => {
|
||||
@@ -57,6 +57,12 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (props: React.P
|
||||
|
||||
|
||||
const onSubmit = useCallback((data: any) => {
|
||||
if (selectedData?.singleEntry) {
|
||||
// Needs to add a single entry
|
||||
updateData(data);
|
||||
return;
|
||||
}
|
||||
|
||||
const dataClone: any[] = Object.assign([], dataEntries);
|
||||
if (selectedIndex !== null && selectedIndex !== undefined) {
|
||||
dataClone[selectedIndex] = data;
|
||||
@@ -102,6 +108,14 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (props: React.P
|
||||
});
|
||||
}, [selectedData]);
|
||||
|
||||
const dataEntry = useMemo(() => {
|
||||
if (selectedData?.singleEntry) {
|
||||
return dataEntries || {};
|
||||
}
|
||||
|
||||
return (dataEntries && selectedIndex !== null && selectedIndex !== undefined) ? dataEntries[selectedIndex] : null;
|
||||
}, [selectedData, , dataEntries, selectedIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
Messenger.listen(messageListener);
|
||||
|
||||
@@ -171,49 +185,53 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (props: React.P
|
||||
{
|
||||
selectedData ? (
|
||||
<>
|
||||
<div className={`w-1/3 py-6 px-4 flex-1 border-r border-gray-200 dark:border-vulcan-300 overflow-auto`}>
|
||||
<h2 className={`text-lg text-gray-500 dark:text-whisper-900`}>Your {selectedData?.title?.toLowerCase() || ""} data items</h2>
|
||||
{
|
||||
!selectedData.singleEntry && (
|
||||
<div className={`w-1/3 py-6 px-4 flex-1 border-r border-gray-200 dark:border-vulcan-300 overflow-auto`}>
|
||||
<h2 className={`text-lg text-gray-500 dark:text-whisper-900`}>Your {selectedData?.title?.toLowerCase() || ""} data items</h2>
|
||||
|
||||
<div className='py-4'>
|
||||
{
|
||||
(dataEntries && dataEntries.length > 0) ? (
|
||||
<>
|
||||
<Container onSortEnd={onSortEnd} useDragHandle>
|
||||
{
|
||||
(dataEntries || []).map((dataEntry, idx) => (
|
||||
<SortableItem
|
||||
key={dataEntry[selectedData.labelField] || `entry-${idx}`}
|
||||
value={dataEntry[selectedData.labelField] || `Entry ${idx+1}`}
|
||||
index={idx}
|
||||
crntIndex={idx}
|
||||
selectedIndex={selectedIndex}
|
||||
onSelectedIndexChange={(index: number) => setSelectedIndex(index)}
|
||||
onDeleteItem={deleteItem}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</Container>
|
||||
<Button
|
||||
className='mt-4'
|
||||
onClick={() => setSelectedIndex(null)}>
|
||||
Add a new entry
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<div className={`flex flex-col items-center justify-center`}>
|
||||
<p className={`text-gray-500 dark:text-whisper-900`}>No {selectedData.title.toLowerCase()} data entries found</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`w-2/3 py-6 px-4 overflow-auto`}>
|
||||
<div className='py-4'>
|
||||
{
|
||||
(dataEntries && dataEntries.length > 0) ? (
|
||||
<>
|
||||
<Container onSortEnd={onSortEnd} useDragHandle>
|
||||
{
|
||||
(dataEntries as any[] || []).map((dataEntry, idx) => (
|
||||
<SortableItem
|
||||
key={dataEntry[selectedData.labelField] || `entry-${idx}`}
|
||||
value={dataEntry[selectedData.labelField] || `Entry ${idx+1}`}
|
||||
index={idx}
|
||||
crntIndex={idx}
|
||||
selectedIndex={selectedIndex}
|
||||
onSelectedIndexChange={(index: number) => setSelectedIndex(index)}
|
||||
onDeleteItem={deleteItem}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</Container>
|
||||
<Button
|
||||
className='mt-4'
|
||||
onClick={() => setSelectedIndex(null)}>
|
||||
Add a new entry
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<div className={`flex flex-col items-center justify-center`}>
|
||||
<p className={`text-gray-500 dark:text-whisper-900`}>No {selectedData.title.toLowerCase()} data entries found</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className={`${selectedData.singleEntry ? "w-full" : "w-2/3"} py-6 px-4 overflow-auto`}>
|
||||
<h2 className={`text-lg text-gray-500 dark:text-whisper-900`}>Create or modify your {selectedData.title.toLowerCase()} data</h2>
|
||||
{
|
||||
selectedData ? (
|
||||
<DataForm
|
||||
schema={selectedData?.schema}
|
||||
model={(dataEntries && selectedIndex !== null && selectedIndex !== undefined) ? dataEntries[selectedIndex] : null}
|
||||
model={dataEntry}
|
||||
onSubmit={onSubmit}
|
||||
onClear={() => setSelectedIndex(null)} />
|
||||
) : (
|
||||
|
||||
@@ -113,7 +113,8 @@ export class DashboardSettings {
|
||||
fileType: dataFile.fsPath.endsWith('.json') ? 'json' : 'yaml',
|
||||
labelField: folder.labelField,
|
||||
schema: folder.schema,
|
||||
type: folder.type
|
||||
type: folder.type,
|
||||
singleEntry: typeof folder.singleEntry === 'boolean' ? folder.singleEntry : false,
|
||||
} as DataFile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export class DataListener extends BaseListener {
|
||||
* @param msgData
|
||||
*/
|
||||
private static processDataUpdate(msgData: any) {
|
||||
const { file, fileType, entries } = msgData as { file: string, fileType: string, entries: any[] };
|
||||
const { file, fileType, entries } = msgData as { file: string, fileType: string, entries: unknown | unknown[] };
|
||||
|
||||
const absPath = Folders.getAbsFilePath(file);
|
||||
if (!existsSync(absPath)) {
|
||||
|
||||
@@ -6,4 +6,5 @@ export interface DataFile {
|
||||
labelField: string;
|
||||
schema?: any;
|
||||
type?: string;
|
||||
singleEntry?: boolean;
|
||||
}
|
||||
@@ -6,4 +6,5 @@ export interface DataFolder {
|
||||
labelField: string;
|
||||
schema?: any;
|
||||
type?: string;
|
||||
singleEntry?: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user