|
@@ -1,373 +1,21 @@
|
|
|
-import React, {useState, useEffect} from 'react';
|
|
|
+import React, {useState, useEffect, useMemo, useRef} from 'react';
|
|
|
import logo from './logo.svg';
|
|
|
import './App.css';
|
|
|
|
|
|
import { GraphQLClient } from 'graphql-request';
|
|
|
|
|
|
+import createModels2 from './front-models'
|
|
|
+
|
|
|
let gql = new GraphQLClient("/graphql", {headers: localStorage.authToken ? {Authorization: 'Bearer '+localStorage.authToken} : {}})
|
|
|
|
|
|
|
|
|
//TODO: use graphql-tag to get types, or, at least detect query
|
|
|
//for proper binding between model objects and result of gql query
|
|
|
|
|
|
-async function createModels(gql, config={create: 'Upsert', update: 'Upsert', delete: "Delete", findOne: "FindOne", find: 'Find', count: 'Count'}){
|
|
|
- const getQuery = name =>
|
|
|
- `query mutations{
|
|
|
- __type(name: "${name}") {
|
|
|
- name,
|
|
|
- kind,
|
|
|
- fields {
|
|
|
- name,
|
|
|
- type {
|
|
|
- kind,
|
|
|
- ofType{
|
|
|
- name,
|
|
|
- fields{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- kind
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- name,
|
|
|
- fields{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- kind
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- args{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- inputFields{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- kind,
|
|
|
- ofType{
|
|
|
- name
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }`
|
|
|
- let { __type: { fields: mutations }} = await gql.request(getQuery('Mutation'))
|
|
|
- let { __type: { fields: queries }} = await gql.request(getQuery('Query'))
|
|
|
- console.log(mutations)
|
|
|
- console.log(queries)
|
|
|
-
|
|
|
-
|
|
|
- let classes = {}
|
|
|
-
|
|
|
- const createClass = (name, fields) => {
|
|
|
- if (!(name in classes)) {
|
|
|
- classes[name] = class {
|
|
|
- constructor(data){
|
|
|
- Object.assign(this, data)
|
|
|
- }
|
|
|
-
|
|
|
- static get fields(){
|
|
|
- return fields
|
|
|
- }
|
|
|
- }
|
|
|
- Object.defineProperty(classes[name], 'name', {value: name})
|
|
|
- }
|
|
|
- return classes[name]
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- for (let query of queries){
|
|
|
- let className = query.type.name || query.type.ofType.name
|
|
|
- if (className === 'Int'){ //TODO: fuck this
|
|
|
- className = query.name.match(new RegExp(`([A-Za-z]+)(${Object.values(config).join('|')})`))[1]
|
|
|
- }
|
|
|
- let classFields = query.type.fields || query.type.ofType && query.type.ofType.fields
|
|
|
-
|
|
|
-
|
|
|
- console.log(classFields)
|
|
|
-
|
|
|
- let _class = createClass(className, classFields)
|
|
|
-
|
|
|
- for (let [method, methodName] of Object.entries(config)){
|
|
|
- if (!_class[method] && query.name.includes(methodName)){
|
|
|
- let methods = {
|
|
|
- find(q, cursorCalls={}){
|
|
|
- let queryText = `query FMFind($q:${query.args[0].type.name}){
|
|
|
- ${query.name}(${query.args[0].name}: $q)
|
|
|
- {${classFields.filter(x => x.type.kind === 'SCALAR').map(x => x.name).join(',')}}
|
|
|
- }
|
|
|
- `
|
|
|
- console.log(queryText, {q: JSON.stringify([q, cursorCalls])})
|
|
|
- return gql.request(queryText, {q: JSON.stringify([q, cursorCalls])}).then(data =>{
|
|
|
- return data[query.name].map(record => new _class(record))
|
|
|
- })
|
|
|
- },
|
|
|
- findOne(query){
|
|
|
-
|
|
|
- },
|
|
|
- count(q, cursorCalls={}){
|
|
|
- let queryText = `query FMFind($q:${query.args[0].type.name}){
|
|
|
- ${query.name}(${query.args[0].name}: $q)
|
|
|
- }
|
|
|
- `
|
|
|
- return gql.request(queryText, {q: JSON.stringify([q, cursorCalls])}).then(data =>{
|
|
|
- return data[query.name]
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
- _class[method] = methods[method]
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return classes
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-async function createModels2(gql, config={create: 'Upsert', update: 'Upsert', delete: "Delete", findOne: "FindOne", find: 'Find', count: 'Count'}){
|
|
|
- const universeQuery = `query universe{
|
|
|
- __schema{
|
|
|
- types {
|
|
|
- name,
|
|
|
- kind,
|
|
|
- inputFields{
|
|
|
- name,
|
|
|
- type {
|
|
|
- kind,
|
|
|
- ofType{
|
|
|
- name,
|
|
|
- fields{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- kind
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- name,
|
|
|
- fields{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- kind
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- fields {
|
|
|
- name,
|
|
|
- type {
|
|
|
- kind,
|
|
|
- ofType{
|
|
|
- name,
|
|
|
- fields{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- kind
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- name,
|
|
|
- fields{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- kind
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- args{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- inputFields{
|
|
|
- name,
|
|
|
- type{
|
|
|
- name,
|
|
|
- kind,
|
|
|
- ofType{
|
|
|
- name
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }}
|
|
|
- `
|
|
|
-
|
|
|
- const universe = await gql.request(universeQuery)
|
|
|
- console.log(universe)
|
|
|
- const types = []
|
|
|
- const inputs = []
|
|
|
- for (let type of universe.__schema.types){
|
|
|
- if (!["Query", "Mutation"].includes(type.name) && type.kind === "OBJECT" && !type.name.startsWith('__')) types.push(type)
|
|
|
- if (!["Query", "Mutation"].includes(type.name) && type.kind === "INPUT_OBJECT" && !type.name.startsWith('__')) inputs.push(type)
|
|
|
- }
|
|
|
- console.log(types, inputs)
|
|
|
-
|
|
|
- let classes = {}
|
|
|
-
|
|
|
- const inTypes = name => types.find(type => type.name === name)
|
|
|
- const inInputs = name => inputs.find(type => type.name === name)
|
|
|
-
|
|
|
- const projectionBuilder = (type, allFields=true) => {
|
|
|
- if (!allFields && type.fields[0].name !== '_id') allFields = true
|
|
|
- if (allFields)
|
|
|
- return '{' +
|
|
|
- type.fields.map(field => {
|
|
|
- return field.name + ((field.type.kind === 'OBJECT' && (inTypes(field.type.name)) && projectionBuilder(inTypes(field.type.name), false)) ||
|
|
|
- (field.type.kind === 'LIST' && (inTypes(field.type.ofType.name)) && projectionBuilder(inTypes(field.type.ofType.name), false)) || '')
|
|
|
- })
|
|
|
- .join(',')
|
|
|
- + '}'
|
|
|
- else return `{_id}`
|
|
|
- }
|
|
|
|
|
|
- const identityMap = {}
|
|
|
-
|
|
|
-
|
|
|
- const createClass = (name, type, input) => {
|
|
|
- if (!(name in classes)) {
|
|
|
- classes[name] = class {
|
|
|
- constructor(data={}, empty = false){
|
|
|
- if (data._id && data._id in identityMap)
|
|
|
- return identityMap[data._id]
|
|
|
-
|
|
|
- this.populate(data)
|
|
|
-
|
|
|
- this.empty = empty
|
|
|
-
|
|
|
- if (this._id) identityMap[this._id] = this
|
|
|
- }
|
|
|
-
|
|
|
- populate(data){
|
|
|
- type.fields.forEach(({name, type:{ ofType, kind, name:otherName}}) => {
|
|
|
- ({SCALAR(){
|
|
|
- if (data && typeof data === 'object' && name in data) this[name] = data[name]
|
|
|
- },
|
|
|
- LIST(){
|
|
|
- const otherType = inTypes(ofType.name)
|
|
|
- if (otherType && data[name])
|
|
|
- this[name] = data[name].map(otherEntity => new classes[otherType.name](otherEntity, otherEntity._id && Object.keys(otherEntity).length === 1))
|
|
|
- else if (data && typeof data === 'object' && name in data) this[name] = data[name]
|
|
|
- },
|
|
|
- OBJECT(){
|
|
|
- const otherType = inTypes(otherName)
|
|
|
- if (otherType && data[name])
|
|
|
- this[name] = new classes[otherType.name](data[name], data[name]._id && Object.keys(data[name]).length === 1)
|
|
|
- else if (data && typeof data === 'object' && name in data) this[name] = data[name]
|
|
|
- }})[kind].call(this)
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- get empty(){
|
|
|
- return this.then
|
|
|
- }
|
|
|
-
|
|
|
- set empty(value){
|
|
|
- if (value){
|
|
|
- this.then = async (onFullfilled, onRejected) => {
|
|
|
- const gqlQuery = `
|
|
|
- query ${name}FindOne($query: String){
|
|
|
- ${name}FindOne(query: $query)
|
|
|
- ${projectionBuilder(type)}
|
|
|
-
|
|
|
- }
|
|
|
- `
|
|
|
- const data = await gql.request(gqlQuery, {query: JSON.stringify([{_id: this._id}])})
|
|
|
- this.populate(data[name + 'FindOne'])
|
|
|
- this.empty = false
|
|
|
- const thenResult = onFullfilled(this)
|
|
|
- if (thenResult && typeof thenResult === 'object' && typeof thenResult.then === 'function'){
|
|
|
- return await thenResult
|
|
|
- }
|
|
|
- return thenResult
|
|
|
- }
|
|
|
- }
|
|
|
- else delete this.then
|
|
|
- }
|
|
|
-
|
|
|
- static get type(){
|
|
|
- return type
|
|
|
- }
|
|
|
-
|
|
|
- static get input(){
|
|
|
- return input
|
|
|
- }
|
|
|
-
|
|
|
- async save(){
|
|
|
- if (this.empty) throw new ReferenceError('Cannot save empty object')
|
|
|
- const data = {}
|
|
|
- input.inputFields.forEach(({name, type:{ ofType, kind, name:otherName}}) => {
|
|
|
- ({SCALAR(){
|
|
|
- if (this[name]) data[name] = this[name]
|
|
|
- },
|
|
|
- LIST(){
|
|
|
- const otherType = inInputs(ofType.name)
|
|
|
- if (otherType && this[name] && this[name] instanceof Array)
|
|
|
- data[name] = this[name].map(otherEntity => (otherEntity._id ? {_id: otherEntity._id} : otherEntity))
|
|
|
- },
|
|
|
- INPUT_OBJECT(){
|
|
|
- const otherType = inInputs(otherName)
|
|
|
- if (otherType && this[name] && typeof this[name] === 'object')
|
|
|
- data[name] = (this[name]._id ? {_id: this[name]._id} : this[name])
|
|
|
- }})[kind].call(this)
|
|
|
- })
|
|
|
- const gqlQuery = `
|
|
|
- mutation ${name}Upsert($data: ${input.name}){
|
|
|
- ${name}Upsert(${name.toLowerCase()}: $data)
|
|
|
- ${projectionBuilder(type)}
|
|
|
- }
|
|
|
- `
|
|
|
- let result = await gql.request(gqlQuery, {data})
|
|
|
- this.populate(result)
|
|
|
- }
|
|
|
-
|
|
|
- static async find(query){
|
|
|
- const gqlQuery = `
|
|
|
- query ${name}Find($query: String){
|
|
|
- ${name}Find(query: $query)
|
|
|
- ${projectionBuilder(type)}
|
|
|
- }
|
|
|
- `
|
|
|
- let result = await gql.request(gqlQuery, {query: JSON.stringify(query)})
|
|
|
- return result[name + 'Find'].map(entity => new classes[name](entity))
|
|
|
- }
|
|
|
-
|
|
|
- static async count(query){
|
|
|
- const gqlQuery = `
|
|
|
- query ${name}Count($query: String){
|
|
|
- ${name}Count(query: $query)
|
|
|
- }
|
|
|
- `
|
|
|
- let result = await gql.request(gqlQuery, {query: JSON.stringify(query)})
|
|
|
- return result[name + 'Count']
|
|
|
- }
|
|
|
- }
|
|
|
- Object.defineProperty(classes[name], 'name', {value: name})
|
|
|
- }
|
|
|
- return classes[name]
|
|
|
- }
|
|
|
-
|
|
|
- types.forEach((type) => createClass(type.name, type, inputs.find(input => input.name === `${type.name}Input`)))
|
|
|
- return classes;
|
|
|
-}
|
|
|
|
|
|
const dataReader = async () => {
|
|
|
- const { PriceItem } = await createModels(gql)
|
|
|
+ const { PriceItem } = await createModels2(gql)
|
|
|
let data = await PriceItem.find({}, {limit: [10]})
|
|
|
return {data, PriceItem }
|
|
|
}
|
|
@@ -390,16 +38,8 @@ function ModelGrid({model, rowHeight, gridHeight, overload, query, cellDoubleCli
|
|
|
const onScreenRowCount = gridHeight/rowHeight
|
|
|
const overloadedRowCount = overload * onScreenRowCount
|
|
|
|
|
|
+ const [totalCount, setTotalCount] = useState(-1)
|
|
|
|
|
|
- const [oldQuery, setOldQuery] = useState()
|
|
|
-
|
|
|
- const jsonQuery = JSON.stringify(query)
|
|
|
-
|
|
|
- const [totalCount, setTotalCount] = useState()
|
|
|
-
|
|
|
- if (!totalCount || oldQuery !== jsonQuery) {
|
|
|
- model && model.count(query).then(count => { setTotalCount(count); setOldQuery(jsonQuery)})
|
|
|
- }
|
|
|
|
|
|
const [gridContentRef, setGridContentRef] = useState()
|
|
|
const [scroll, setScroll] = useState(0)
|
|
@@ -417,16 +57,21 @@ function ModelGrid({model, rowHeight, gridHeight, overload, query, cellDoubleCli
|
|
|
const cursorCalls = {skip: [skip], limit: [overloadedRowCount]}
|
|
|
|
|
|
|
|
|
- if (!model) return <>No model</>;
|
|
|
|
|
|
if (sort.length) cursorCalls.sort = [sort]
|
|
|
|
|
|
- if (!records || oldQuery !== jsonQuery) {
|
|
|
- model.find(query, cursorCalls)
|
|
|
- .then(records => (setRecords(records), setOldQuery(jsonQuery)))
|
|
|
- }
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (totalCount > 0) {
|
|
|
+ model.find(query, cursorCalls).then(records => setRecords(records))
|
|
|
+ }
|
|
|
+ },[model, query, sort, totalCount])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ model && model.count(query).then(count => setTotalCount(count))
|
|
|
+ },[model, query, totalCount])
|
|
|
|
|
|
+ if (!model) return <>No model</>;
|
|
|
return(
|
|
|
<>
|
|
|
<div className='GridHeader'>
|
|
@@ -443,11 +88,11 @@ function ModelGrid({model, rowHeight, gridHeight, overload, query, cellDoubleCli
|
|
|
<div className='GridContent'
|
|
|
style={{height: totalCount*rowHeight}}
|
|
|
ref={e => setGridContentRef(e)}>
|
|
|
- {records && records.map((record,i) =>
|
|
|
+ {console.log(records), records && records.map((record,i) =>
|
|
|
<Row top={(skip)*rowHeight}>
|
|
|
{model.fields.map(field =>
|
|
|
<Cell onDoubleClick={e => cellDoubleClick(field.name, record[field.name], record._id)}>
|
|
|
- {record[field.name]}
|
|
|
+ {record[field.name] === 'object' ? record[field.name].toString() : record[field.name]}
|
|
|
</Cell>)}
|
|
|
</Row>)}
|
|
|
</div>
|
|
@@ -456,6 +101,141 @@ function ModelGrid({model, rowHeight, gridHeight, overload, query, cellDoubleCli
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+const ModelListItem = "div"
|
|
|
+
|
|
|
+const ModelList = ({models, selected, onChange, Item=ModelListItem}) => {
|
|
|
+ return (
|
|
|
+ <aside>
|
|
|
+ {Object.entries(models).map(([name, model]) => {
|
|
|
+ return (
|
|
|
+ <Item key={name}
|
|
|
+ selected={name === selected}
|
|
|
+ className={name === selected && "selected"}
|
|
|
+ onClick = {() => onChange(name)}
|
|
|
+ >
|
|
|
+ {name}
|
|
|
+ </Item>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </aside>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const Search = ({...props}) =>
|
|
|
+<input placeholder="Search..." {...props} className="Search"/>
|
|
|
+
|
|
|
+const Count = ({...props}) => <div className="Count" {...props} />
|
|
|
+
|
|
|
+const searchQueryBuilder = (search, model) => {
|
|
|
+ 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, ...props}) =>
|
|
|
+<div className="GridHeaderItem" {...props}>
|
|
|
+ {field.name in sort && sort[field.name] === -1 && '^ '}
|
|
|
+ {field.name}
|
|
|
+ {field.name in sort && sort[field.name] === 1 && ' v'}
|
|
|
+</div>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const GridHeader = ({fields, sort, onSort}) =>
|
|
|
+<div className="GridHeader">
|
|
|
+ {fields.map(field => <GridHeaderItem field={field} sort={sort} onClick={() => onSort(field.name)}/>)}
|
|
|
+</div>
|
|
|
+
|
|
|
+const Grid = ({fields, sort, onSort}) =>
|
|
|
+ <div className='GridViewport'
|
|
|
+ onScroll={e => {
|
|
|
+ if (Math.abs(e.target.scrollTop - scroll) > gridHeight*overload/3){
|
|
|
+ setScroll(e.target.scrollTop);
|
|
|
+ setRecords(null)
|
|
|
+ } }}
|
|
|
+ style={{maxHeight: gridHeight, height: gridHeight}}>
|
|
|
+
|
|
|
+ <div className='GridContent'
|
|
|
+ style={{height: totalCount*rowHeight}}
|
|
|
+ ref={e => setGridContentRef(e)}>
|
|
|
+ {console.log(records), records && records.map((record,i) =>
|
|
|
+ <Row top={(skip)*rowHeight}>
|
|
|
+ {model.fields.map(field =>
|
|
|
+ <Cell onDoubleClick={e => cellDoubleClick(field.name, record[field.name], record._id)}>
|
|
|
+ {record[field.name] === 'object' ? record[field.name].toString() : record[field.name]}
|
|
|
+ </Cell>)}
|
|
|
+ </Row>)}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+const ModelView = ({model, components:Components={Search, Count, GridHeader, Grid}, rowHeight, gridHeight, overload}) => {
|
|
|
+ const onScreenRowCount = gridHeight/rowHeight
|
|
|
+ const overloadedRowCount = overload * onScreenRowCount
|
|
|
+ const [scroll, setScroll] = useState(0)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ const onScreenFirstRowIndex = Math.floor(scroll/rowHeight)
|
|
|
+ let skip = onScreenFirstRowIndex - (overloadedRowCount - onScreenRowCount)/2;
|
|
|
+
|
|
|
+ if (skip < 0) skip = 0
|
|
|
+
|
|
|
+ const [records, setRecords] = useState()
|
|
|
+
|
|
|
+
|
|
|
+ const [search, setSearch] = useState("")
|
|
|
+ const [count, setCount] = useState()
|
|
|
+
|
|
|
+ const [query, setQuery] = useState({})
|
|
|
+ const [cursorCalls, setCursorCalls] = useState({sort:{}, skip: [skip], limit: [overloadedRowCount]})
|
|
|
+
|
|
|
+ console.log(cursorCalls)
|
|
|
+
|
|
|
+ const timeout = useRef(0)
|
|
|
+ useEffect(() => {
|
|
|
+ clearInterval(timeout.current)
|
|
|
+ timeout.current = setTimeout(() => {
|
|
|
+ setQuery(searchQueryBuilder(search, model))
|
|
|
+ }, 1000)
|
|
|
+ },[search, model])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ model.count(query, cursorCalls).then(count => setCount(count))
|
|
|
+ model.find(query, cursorCalls).then(records => setRecords(records))
|
|
|
+ }, [query, model, cursorCalls])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <Components.Search value={search} onChange={({target: {value}}) => setSearch(value)}/>
|
|
|
+ <Components.Count>
|
|
|
+ {count}
|
|
|
+ </Components.Count>
|
|
|
+ <GridHeader fields={model.fields}
|
|
|
+ sort={cursorCalls.sort}
|
|
|
+ onSort={sort => setCursorCalls({...cursorCalls,
|
|
|
+ sort: {[sort]: cursorCalls.sort[sort] === 1 ? -1 : 1}
|
|
|
+ })}/>
|
|
|
+ <Grid records={records}/>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const Admin = ({models, components:Components={ModelList, Search}}) => {
|
|
|
+ const [selected, setSelected] = useState()
|
|
|
+
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <Components.ModelList models={models} onChange={(name) => setSelected(name)} selected={selected}/>
|
|
|
+ <content>
|
|
|
+ {selected && <ModelView model={models[selected]} /> }
|
|
|
+ </content>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+ //{selected && <ModelGrid key={selected} model={models[selected]} rowHeight={50} gridHeight={700} overload={5} query={query}/> }
|
|
|
+
|
|
|
function App() {
|
|
|
let [models, setModels] = useState()
|
|
|
let [queryText, setQueryText] = useState('{manufacturerName: "TOYOTA"}')
|
|
@@ -466,15 +246,15 @@ function App() {
|
|
|
const classes = models
|
|
|
console.log(classes)
|
|
|
if (classes && Object.keys(classes).length){
|
|
|
- classes.Good.find([{}]).then(goods => console.log(goods))
|
|
|
- classes.Image.count([{}]).then(count => console.log(count))
|
|
|
+ classes.Good.find().then(goods => console.log(goods))
|
|
|
+ classes.Image.find().then(images => console.log(images))
|
|
|
}
|
|
|
|
|
|
return (
|
|
|
<div className="App">
|
|
|
- {models && Object.entries(models).map(([key, model]) => <div>{key}</div>)}
|
|
|
- {models && <ModelGrid model={models.jk} rowHeight={50} gridHeight={700} overload={5} query={query}
|
|
|
- cellDoubleClick={(name, text, _id) => setQueryText(`{${name}:\`${text}\`}`)}/> }
|
|
|
+ {models && <Admin models={models} />}
|
|
|
+ {/*models && <ModelGrid model={models.Image} rowHeight={50} gridHeight={700} overload={5} query={query}
|
|
|
+ cellDoubleClick={(name, text, _id) => setQueryText(`{${name}:\`${text}\`}`)}/> */}
|
|
|
<textarea onChange={e => setQueryText(e.target.value)} value={queryText} />
|
|
|
<button onClick={() => setQuery(eval(`(${queryText})`))}>Run</button>
|
|
|
</div>
|