import React, {useState, useEffect, useMemo, useRef, Fragment} from 'react'; import logo from './logo.svg'; import './App.css'; import Select from 'react-select/async' import {sortableContainer, sortableElement} from 'react-sortable-hoc'; import Dropzone from 'react-dropzone' import { GraphQLClient } from 'graphql-request'; import createModels2 from './front-models' let gql; const getGQL = () => new GraphQLClient(localStorage.url + 'graphql', {headers: localStorage.authToken ? {Authorization: 'Bearer '+localStorage.authToken} : {}}) if (localStorage.authToken && localStorage.url){ gql = getGQL() } const ShortName = ({record, options}) => { if (record && record.constructor) if (options.view.relations[record.constructor.name]){ const Formatter = options.view.relations[record.constructor.name] return {record} } return (<>{record && (record.name || record.key || record.login || record.originalFileName || record._id)}) } const EditFormRow = ({field, models={}, value, options=defaultAdminOptions, record, onChange}) => { return ( {field.name} {value} ) } const EditForm = ({record, models={}, model, options=defaultAdminOptions, Components:{EditFormRow:EFR}={EditFormRow}}) => { const [edit, setEdit] = useState({...record}) if (!record) return <> if (!record.save || !record._id){ Object.assign(record, edit) } const fields = model.fields const onlyInputs = model.inputs.filter(input => !fields.find(field => field.name === input.name)) return ( <> {Object.entries(fields).map(([key,field]) => { setEdit({...edit, [field.name]: event && event.target ? event.target.value : event}) }} />)} {Object.entries(onlyInputs).map(([key,field]) => setEdit({...edit, [field.name]: event && event.target ? event.target.value : event})} />)}
{record._id && record.save && } ) } const Row = ({top, selected, children}) => { console.log('row') return ( <>
{children}
) } const Cell = ({children, options, record, field, selected, model, models={}, onClick, ...props}) => { let Formatter = React.Fragment const type = (children && typeof children === 'object' && children.constructor) || model const viewOrEdit = (!record.constructor.inputs || record.constructor.inputs.some(input => input.name === field.name)) && selected ? 'edit' : 'view' const typeName = field.type.name || field.type.ofType.name if (typeName in options[viewOrEdit].formatters){ Formatter = options[viewOrEdit].formatters[typeName] } if (field.name in options[viewOrEdit].fields){ Formatter = options[viewOrEdit].fields[field.name] } if (type){ if (type.name in options[viewOrEdit].formatters) Formatter = options[viewOrEdit].formatters[type.name] else Formatter = options[viewOrEdit].formatters.Object } return(
{Formatter === React.Fragment ? (children && children.toString()) : children}
) } const ModelListItem = "div" const ModelList = ({models, selected, onChange, Item=ModelListItem}) => { return ( ) } const Search = ({...props}) => const Count = ({...props}) =>
const searchQueryBuilder = (search, model) => { if (!search) return {} const queryRegexp = `/${search.trim().split(/\s+/).join('|')}/` return {$or: model.fields.filter(field => field.type.kind == 'SCALAR').map(field => ({[field.name]: queryRegexp}))} } const GridHeaderItem = ({field, sort:[sort], ...props}) =>
{field.name in sort && sort[field.name] === -1 && '^ '} {field.name} {field.name in sort && sort[field.name] === 1 && ' v'}
const GridHeader = ({fields, sort, onSort}) =>
{fields.map(field => onSort(field.name)}/>)}
const getModelByField = (field, models={}) => { if (field.type.kind === 'OBJECT') { return models[field.type.name] } if (field.type.kind === 'LIST') return models[field.type.ofType.name] } const VirtualScroll = ({options, gridHeight, count, rowHeight, onScroll, records, skip, models={}}) => { const limit = gridHeight/rowHeight //const {Row, Cell} = Components const [edit, setEdit] = useState({field: null, record: null}) useEffect(() => setEdit({field: null, record: null}), [records]) const fields = records && records[0] && records[0].constructor.fields //console.log(Fragment, Row) return ( <>
{records && records.map((record,i) => {edit.record && edit.record._id === record._id ? : {fields.map(field => setEdit({record: {...record}, field})}> {record[field.name]} )} } )}
) } const ModelView = ({model, models={}, options, components:Components={Search, Count, GridHeader, Grid:VirtualScroll}, rowHeight=150, gridHeight=500, overload=2}) => { const [records, setRecords] = useState([]) const [search, setSearch] = useState("") const [count, setCount] = useState(0) const [query, setQuery] = useState({}) const [cursorCalls, setCursorCalls] = useState({sort:[{}], skip: [0]/*, limit: [gridHeight/rowHeight]*/}) const skip = cursorCalls.skip[0] console.log(cursorCalls) useEffect(() => { model.count(query, cursorCalls).then(count => setCount(count)) model.find(query, cursorCalls).then(records => Promise.all(records)).then(records => setRecords(records)) }, [query, model, cursorCalls]) const timeout = useRef(0) useEffect(() => { clearInterval(timeout.current) if (!search) setQuery(searchQueryBuilder(search, model)) else { timeout.current = setTimeout(() => { setQuery(searchQueryBuilder(search, model)) },1000) } },[search, model]) //console.log(Components) // const Add = options.add[model.name] || "button" return ( <> setSearch(value)}/> {count} setCursorCalls({...cursorCalls, sort: [{[sort]: cursorCalls.sort[0][sort] === 1 ? -1 : 1}] })}/> { if (Add === 'button') (new model).save() setCursorCalls({...cursorCalls, sort: [{_id: -1}]}) setSearch('') }} model={model}>+ {records && { limit = undefined; model.find(query, {...cursorCalls, limit: [limit], skip: [skip]}).then(records => Promise.all(records)).then(records => setRecords(records)).then(() => setCursorCalls({...cursorCalls, limit: [limit], skip: [skip]})) }}/> } ) } const ObjectShortView = ({children, options}) => { const [record, setRecord] = useState(children) if (!children) return <> if (typeof children === 'object' && 'then' in children){ children.then(child => setRecord({...child})) } if (typeof children === 'object' && children._id){ return (
) } else { return (
            {JSON.stringify(record, null, 4)}
            
) } } const ForeignAutocomplete = ({models={}, children:value, onChange, model, options={}}) => { return (