diff --git a/client/src/pages/databases/collections/data/CollectionData.tsx b/client/src/pages/databases/collections/data/CollectionData.tsx index 7ebe8ae2..254414d8 100644 --- a/client/src/pages/databases/collections/data/CollectionData.tsx +++ b/client/src/pages/databases/collections/data/CollectionData.tsx @@ -12,7 +12,7 @@ import Filter from '@/components/advancedSearch'; import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate'; import CustomToolBar from '@/components/grid/ToolBar'; import InsertDialog from '@/pages/dialogs/insert/Dialog'; -import EditEntityDialog from '@/pages/dialogs/EditEntityDialog'; +import EditJSONDialog from '@/pages/dialogs/EditJSONDialog'; import { getLabelDisplayedRows } from '@/pages/search/Utils'; import { getQueryStyles } from './Styles'; import { @@ -31,6 +31,7 @@ import CollectionColHeader from '../CollectionColHeader'; import DataView from '@/components/DataView/DataView'; import DataListView from '@/components/DataListView/DataListView'; import type { QueryState } from '../../types'; +import { CollectionFullObject } from '@server/types'; export interface CollectionDataProps { queryState: QueryState; @@ -148,7 +149,13 @@ const CollectionData = (props: CollectionDataProps) => { await fetchCollection(collectionName); }; - const onEditEntity = async (id: string) => { + const handleEditConfirm = async (data: Record) => { + const result = (await DataService.upsert(collection.collection_name, { + fields_data: [data], + })) as any; + + const idField = result.IDs.id_field; + const id = result.IDs[idField].data; // deselect all setSelectedData([]); const newExpr = `${collection.schema.primaryField.name} == ${id}`; @@ -163,6 +170,25 @@ const CollectionData = (props: CollectionDataProps) => { }); }; + const getEditData = (data: any, collection: CollectionFullObject) => { + // sort data by collection schema order + const schema = collection.schema; + let sortedData: { [key: string]: any } = {}; + schema.fields.forEach(field => { + if (data[field.name] !== undefined) { + sortedData[field.name] = data[field.name]; + } + }); + + // add dynamic fields if exist + const isDynamicSchema = collection.schema.dynamicFields.length > 0; + if (isDynamicSchema) { + sortedData = { ...sortedData, ...data[DYNAMIC_FIELD] }; + } + + return sortedData; + }; + // Toolbar settings const toolbarConfigs: ToolBarConfig[] = [ { @@ -270,10 +296,12 @@ const CollectionData = (props: CollectionDataProps) => { type: 'custom', params: { component: ( - ), }, diff --git a/client/src/pages/dialogs/EditEntityDialog.tsx b/client/src/pages/dialogs/EditEntityDialog.tsx deleted file mode 100644 index 6d36b7df..00000000 --- a/client/src/pages/dialogs/EditEntityDialog.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import { FC, useContext, useEffect, useRef, useState } from 'react'; -import { Theme, useTheme } from '@mui/material'; -import { EditorState, Compartment } from '@codemirror/state'; -import { EditorView, keymap, ViewUpdate } from '@codemirror/view'; -import { insertTab } from '@codemirror/commands'; -import { indentUnit } from '@codemirror/language'; -import { basicSetup } from 'codemirror'; -import { json, jsonParseLinter } from '@codemirror/lang-json'; -import { linter } from '@codemirror/lint'; -import { useTranslation } from 'react-i18next'; -import { rootContext } from '@/context'; -import DialogTemplate from '@/components/customDialog/DialogTemplate'; -import { DataService } from '@/http'; -import { DYNAMIC_FIELD } from '@/consts'; -import { makeStyles } from '@mui/styles'; -import { githubLight } from '@ddietr/codemirror-themes/github-light'; -import { githubDark } from '@ddietr/codemirror-themes/github-dark'; -import type { CollectionFullObject } from '@server/types'; - -const useStyles = makeStyles((theme: Theme) => ({ - code: { - border: `1px solid ${theme.palette.divider}`, - overflow: 'auto', - }, - tip: { - fontSize: 14, - marginBottom: 16, - fontWeight: 'bold', - color: theme.palette.warning.main, - }, -})); - -type EditEntityDialogProps = { - data: { [key: string]: any }; - collection: CollectionFullObject; - cb?: (id: string) => void; -}; - -// json linter for cm -const linterExtension = linter(jsonParseLinter()); - -const EditEntityDialog: FC = props => { - const theme = useTheme(); - const themeCompartment = new Compartment(); - - // props - const { data, collection } = props; - // UI states - const [disabled, setDisabled] = useState(true); - // context - const { handleCloseDialog } = useContext(rootContext); - // translations - const { t: btnTrans } = useTranslation('btn'); - const { t: dialogTrans } = useTranslation('dialog'); - // refs - const editorEl = useRef(null); - const editor = useRef(); - // styles - const classes = useStyles(); - - // sort data by collection schema order - const schema = collection.schema; - let sortedData: { [key: string]: any } = {}; - schema.fields.forEach(field => { - if (data[field.name] !== undefined) { - sortedData[field.name] = data[field.name]; - } - }); - - // add dynamic fields if exist - const isDynamicSchema = collection.schema.dynamicFields.length > 0; - if (isDynamicSchema) { - sortedData = { ...sortedData, ...data[DYNAMIC_FIELD] }; - } - - const originalData = JSON.stringify(sortedData, null, 2); - - // create editor - useEffect(() => { - if (!editor.current) { - const startState = EditorState.create({ - doc: originalData, - extensions: [ - basicSetup, - json(), - linterExtension, - keymap.of([{ key: 'Tab', run: insertTab }]), // fix tab behaviour - indentUnit.of(' '), // fix tab indentation - EditorView.theme({ - '&.cm-editor': { - '&.cm-focused': { - outline: 'none', - }, - }, - '.cm-content': { - fontSize: '12px', - }, - '.cm-tooltip-lint': { - width: '80%', - }, - }), - themeCompartment.of( - theme.palette.mode === 'light' ? githubLight : githubDark - ), - EditorView.lineWrapping, - EditorView.updateListener.of((viewUpdate: ViewUpdate) => { - if (viewUpdate.docChanged) { - const d = jsonParseLinter()(view); - if (d.length !== 0) { - setDisabled(true); - return; - } - - const doc = viewUpdate.state.doc; - const value = doc.toString(); - - setDisabled(value === originalData); - } - }), - ], - }); - - const view = new EditorView({ - state: startState, - parent: editorEl.current!, - }); - - editor.current = view; - - return () => { - view.destroy(); - editor.current = undefined; - }; - } - }, [JSON.stringify(data)]); - - // handle confirm - const handleConfirm = async () => { - const result = (await DataService.upsert(collection.collection_name, { - fields_data: [JSON.parse(editor.current?.state.doc.toString()!)], - })) as any; - - const idField = result.IDs.id_field; - const id = result.IDs[idField].data; - - props.cb && props.cb(id[0]); - handleCloseDialog(); - }; - - return ( - -
{dialogTrans('editEntityInfo')}
-
{ - if (editor.current) editor.current.focus(); - }} - >
- - } - confirmDisabled={disabled} - confirmLabel={btnTrans('edit')} - handleConfirm={handleConfirm} - showCancel={true} - /> - ); -}; - -export default EditEntityDialog; diff --git a/client/src/pages/dialogs/EditAnalyzerDialog.tsx b/client/src/pages/dialogs/EditJSONDialog.tsx similarity index 91% rename from client/src/pages/dialogs/EditAnalyzerDialog.tsx rename to client/src/pages/dialogs/EditJSONDialog.tsx index 65921dca..4984d41a 100644 --- a/client/src/pages/dialogs/EditAnalyzerDialog.tsx +++ b/client/src/pages/dialogs/EditJSONDialog.tsx @@ -26,17 +26,20 @@ const useStyles = makeStyles((theme: Theme) => ({ }, })); -type EditAnalyzerDialogProps = { +type EditJSONDialogProps = { data: { [key: string]: any }; handleConfirm: (data: { [key: string]: any }) => void; handleCloseDialog: () => void; + dialogTitle: string; + dialogTip: string; cb?: () => void; }; // json linter for cm const linterExtension = linter(jsonParseLinter()); -const EditAnalyzerDialog: FC = props => { +const EditJSONDialog: FC = props => { + // hooks const theme = useTheme(); const themeCompartment = new Compartment(); @@ -44,17 +47,15 @@ const EditAnalyzerDialog: FC = props => { const { data, handleCloseDialog, handleConfirm } = props; // UI states const [disabled, setDisabled] = useState(true); - // context // translations const { t: btnTrans } = useTranslation('btn'); - const { t: dialogTrans } = useTranslation('dialog'); // refs const editorEl = useRef(null); const editor = useRef(); // styles const classes = useStyles(); - const originalData = JSON.stringify(data, null, 4) + '\n'; + const originalData = JSON.stringify(data, null, 2) + '\n'; // create editor useEffect(() => { @@ -123,14 +124,14 @@ const EditAnalyzerDialog: FC = props => { return (
= props => { ); }; -export default EditAnalyzerDialog; +export default EditJSONDialog; diff --git a/client/src/pages/dialogs/create/CreateFields.tsx b/client/src/pages/dialogs/create/CreateFields.tsx index 058b1244..2d1fd6d0 100644 --- a/client/src/pages/dialogs/create/CreateFields.tsx +++ b/client/src/pages/dialogs/create/CreateFields.tsx @@ -37,7 +37,7 @@ import { } from '@/consts'; import { makeStyles } from '@mui/styles'; import CustomIconButton from '@/components/customButton/CustomIconButton'; -import EditAnalyzerDialog from '@/pages/dialogs/EditAnalyzerDialog'; +import EditJSONDialog from '@/pages/dialogs/EditJSONDialog'; import type { CreateFieldsProps, CreateFieldType, @@ -171,11 +171,15 @@ const CreateFields: FC = ({ autoID, setFieldsValidation, }) => { + // context const { setDialog2, handleCloseDialog2 } = useContext(rootContext); + // i18n const { t: collectionTrans } = useTranslation('collection'); const { t: warningTrans } = useTranslation('warning'); + const { t: dialogTrans } = useTranslation('dialog'); + // styles const classes = useStyles(); const AddIcon = icons.addOutline; @@ -628,10 +632,12 @@ const CreateFields: FC = ({ type: 'custom', params: { component: ( - { changeFields(field.id!, { analyzer_params: data }); }}