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 {buildAST, toReact, getTimeCodes, getTimeCodeFromSeconds} from 'mdast';
import { GraphQLClient } from 'graphql-request';
import createModels2 from './front-models.mjs'
import AceEditor from 'react-ace';
import "ace-builds/src-noconflict/mode-markdown";
import "ace-builds/src-noconflict/theme-github";
Object.defineProperty(HTMLMediaElement.prototype, 'playing', {
get: function(){
return !!(this.currentTime > 0 && !this.paused && !this.ended && this.readyState > 2);
}
})
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})
useEffect(() => {
if (record && record.empty){
record.then(() => setEdit({...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}) => {
const columnWidths = getColumnWidths(record.constructor.name, field.name)
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 getColumnWidths = (mn, fn) => {
const columnWidths = JSON.parse(localStorage.columnWidths || '{}')
if (!columnWidths[localStorage.url]) columnWidths[localStorage.url] = {}
if (!columnWidths[localStorage.url][mn]) columnWidths[localStorage.url][mn] = {}
if (!columnWidths[localStorage.url][mn][fn]) columnWidths[localStorage.url][mn][fn] = 100
return columnWidths;
}
const GridHeaderItem = ({field, sort:[sort], model, onWheel, ...props}) => {
const columnWidths = getColumnWidths(model.name, field.name)
return (
{
const columnWidths = getColumnWidths(model.name, field.name)
columnWidths[localStorage.url][model.name][field.name] += e.deltaY > 0 ? 5 : -5
localStorage.columnWidths = JSON.stringify(columnWidths)
onWheel()
}}
{...props} style={{width: columnWidths[localStorage.url][model.name][field.name] + '%'}}>
{field.name in sort && sort[field.name] === -1 && '^ '}
{field.name}
{field.name in sort && sort[field.name] === 1 && ' v'}
)
}
const GridHeader = ({fields, sort, onSort, onWheel, model}) =>
{fields.map(field => onSort(field.name)} onWheel={onWheel}/>)}
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 [wheel, setWheel] = 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}
setWheel(Math.random())}
onSort={sort => setCursorCalls({...cursorCalls,
sort: [{[sort]: cursorCalls.sort[0][sort] === 1 ? -1 : 1}]
})}
model={model}
/>
{
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 (