ywana-core8 0.0.469 → 0.0.470
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/db/db.json +50 -0
- package/db/routes.json +0 -0
- package/package.json +1 -1
- package/src/domain/TabbedTablePage.js +713 -0
- package/src/site/site.test.js +17 -3
package/db/db.json
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
{
|
2
|
+
"references": [
|
3
|
+
{
|
4
|
+
"name": "1",
|
5
|
+
"state": "NOT_CLASSIFIED",
|
6
|
+
"field1": "1",
|
7
|
+
"field2": "1",
|
8
|
+
"id": 1
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"name": "3",
|
12
|
+
"state": "CLASSIFIED",
|
13
|
+
"field1": "3",
|
14
|
+
"field2": "3",
|
15
|
+
"field4": "#4d19c8",
|
16
|
+
"id": 3
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"name": "44",
|
20
|
+
"state": "NOT_CLASSIFIED",
|
21
|
+
"field1": "44",
|
22
|
+
"field2": "44",
|
23
|
+
"field4": "#0bda81",
|
24
|
+
"id": 4
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"name": "555",
|
28
|
+
"state": "CLASSIFIED",
|
29
|
+
"field1": "555",
|
30
|
+
"field2": "555",
|
31
|
+
"id": 5
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"name": "666",
|
35
|
+
"state": "NOT_CLASSIFIED",
|
36
|
+
"field1": "666",
|
37
|
+
"field2": "666",
|
38
|
+
"field4": "#cae407",
|
39
|
+
"id": 6
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"name": "7777",
|
43
|
+
"state": "NOT_CLASSIFIED",
|
44
|
+
"field1": "777",
|
45
|
+
"field2": "777",
|
46
|
+
"field4": "#09dee1",
|
47
|
+
"id": 7
|
48
|
+
}
|
49
|
+
]
|
50
|
+
}
|
package/db/routes.json
ADDED
File without changes
|
package/package.json
CHANGED
@@ -0,0 +1,713 @@
|
|
1
|
+
import equal from 'deep-equal'
|
2
|
+
import React, { Fragment, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
3
|
+
import { Button, DataTable, DropDown, Header, Icon, MenuIcon, MenuItem, Text, Tabs, Tab } from '../html'
|
4
|
+
import { HTTPClient, Session } from '../http'
|
5
|
+
import { PageContext, SiteContext } from '../site'
|
6
|
+
import { ContentEditor } from './ContentEditor'
|
7
|
+
import { CHECK, Content, TYPES } from './ContentType'
|
8
|
+
import { ContentViewer } from './ContentViewer'
|
9
|
+
import { CreateContentDialog } from './CreateContentDialog'
|
10
|
+
import { QUERY } from './squema'
|
11
|
+
import "./TablePage.css"
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Tabbed Table Page
|
15
|
+
*/
|
16
|
+
export const TabbedTablePage = (props) => {
|
17
|
+
|
18
|
+
const site = useContext(SiteContext)
|
19
|
+
const { id = "table",
|
20
|
+
icon, title, name,
|
21
|
+
schema, url, field, host,
|
22
|
+
autosave = true, delay = 1000,
|
23
|
+
editable,
|
24
|
+
actions = [], dev = false, tableActions, selectionActions = [],
|
25
|
+
canFilter = false, canAdd = true, canDelete = true, canEdit = true,
|
26
|
+
canQuery = false, urlQuery, user,
|
27
|
+
groupBy, validator, scenario,
|
28
|
+
formFilter, tableFilter, editorFilter = false,
|
29
|
+
children
|
30
|
+
} = props
|
31
|
+
|
32
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
33
|
+
const context = TableContext(url, field, host, urlQuery)
|
34
|
+
const { selected, tab } = pageContext
|
35
|
+
const timer = useRef(null)
|
36
|
+
const [form, setForm] = useState(selected)
|
37
|
+
const [tabs, setTabs] = useState([])
|
38
|
+
|
39
|
+
useEffect(async () => {
|
40
|
+
const field = Object.values(schema).find(field => field.tab && field.tab === true)
|
41
|
+
const tabs = field.options.map(option => Object.assign({}, option, { field: field.id}))
|
42
|
+
setTabs(tabs)
|
43
|
+
context.changeTab(tabs[0])
|
44
|
+
setPageContext(context)
|
45
|
+
}, [])
|
46
|
+
|
47
|
+
useEffect( async () => {
|
48
|
+
console.log("TAB", tab)
|
49
|
+
if (tab) {
|
50
|
+
const filter = { [tab.field]: tab.value }
|
51
|
+
await pageContext.load(filter, false)
|
52
|
+
setPageContext(Object.assign({}, pageContext))
|
53
|
+
}
|
54
|
+
}, [tab])
|
55
|
+
|
56
|
+
useEffect(() => {
|
57
|
+
setForm(selected)
|
58
|
+
}, [selected])
|
59
|
+
|
60
|
+
useEffect(() => {
|
61
|
+
if (autosave) {
|
62
|
+
clearTimeout(timer.current)
|
63
|
+
timer.current = setTimeout(() => {
|
64
|
+
if (canSave()) save()
|
65
|
+
}, delay)
|
66
|
+
}
|
67
|
+
}, [form])
|
68
|
+
|
69
|
+
async function reload() {
|
70
|
+
const filter = { [tab.field]: tab.value }
|
71
|
+
await pageContext.load(filter, false)
|
72
|
+
setPageContext(Object.assign({}, pageContext))
|
73
|
+
}
|
74
|
+
|
75
|
+
function add() {
|
76
|
+
const onOK = async (form) => {
|
77
|
+
await pageContext.create(form);
|
78
|
+
setPageContext(Object.assign({}, pageContext))
|
79
|
+
}
|
80
|
+
site.openDialog(<CreateContentDialog label={`Crear ${name}`} type={schema} onOK={onOK} validator={validator} filter={formFilter} />);
|
81
|
+
}
|
82
|
+
|
83
|
+
function saveQuery(filters) {
|
84
|
+
const onOK = async (form) => {
|
85
|
+
form.filters = filters
|
86
|
+
form.layout = {}
|
87
|
+
form.user = user
|
88
|
+
form.url = url
|
89
|
+
await pageContext.createQuery(form, user)
|
90
|
+
setPageContext(Object.assign({}, pageContext))
|
91
|
+
}
|
92
|
+
site.openDialog(<CreateContentDialog label="Nueva query" type={QUERY} onOK={onOK} />)
|
93
|
+
}
|
94
|
+
|
95
|
+
function change(next) {
|
96
|
+
setForm(next)
|
97
|
+
}
|
98
|
+
|
99
|
+
function canSave() {
|
100
|
+
const can = !equal(form, selected)
|
101
|
+
return can
|
102
|
+
}
|
103
|
+
|
104
|
+
async function save() {
|
105
|
+
console.log('saving.....')
|
106
|
+
await pageContext.update(form)
|
107
|
+
setPageContext(Object.assign({}, pageContext))
|
108
|
+
}
|
109
|
+
|
110
|
+
async function playScenario() {
|
111
|
+
const promises1 = pageContext.all.map(async item => await pageContext.remove(item.id))
|
112
|
+
Promise.all(promises1).then(async () => {
|
113
|
+
const promises2 = scenario.map(async (item) => await pageContext.create(item))
|
114
|
+
Promise.all(promises2).then(async () => {
|
115
|
+
await pageContext.load()
|
116
|
+
setPageContext(Object.assign({}, pageContext))
|
117
|
+
})
|
118
|
+
})
|
119
|
+
}
|
120
|
+
|
121
|
+
function closeAside() {
|
122
|
+
pageContext.select(null)
|
123
|
+
setPageContext(Object.assign({}, pageContext))
|
124
|
+
}
|
125
|
+
|
126
|
+
function renderAside() {
|
127
|
+
const rowSelected = selected && form
|
128
|
+
const rowChecked = pageContext.checked && pageContext.checked.size > 0
|
129
|
+
if (rowSelected || rowChecked) {
|
130
|
+
return (
|
131
|
+
<aside className="table-page">
|
132
|
+
{rowSelected ? <TableRowEditor content={new Content(schema, form)} filter={editorFilter} onChange={change} onClose={closeAside} editable={canEdit} /> : null}
|
133
|
+
{rowChecked ? <TableSelector schema={schema} actions={selectionActions} /> : null}
|
134
|
+
</aside>
|
135
|
+
)
|
136
|
+
}
|
137
|
+
return null;
|
138
|
+
}
|
139
|
+
|
140
|
+
function renderActions() {
|
141
|
+
return actions.map(element => {
|
142
|
+
const action = () => element.props.action(pageContext)
|
143
|
+
const clone = React.cloneElement(element, { action })
|
144
|
+
return clone
|
145
|
+
})
|
146
|
+
}
|
147
|
+
|
148
|
+
function changeTab(id) {
|
149
|
+
const tab = tabs.find(tab => tab.value === id)
|
150
|
+
pageContext.changeTab(tab)
|
151
|
+
setPageContext(Object.assign({}, pageContext))
|
152
|
+
}
|
153
|
+
|
154
|
+
function renderTabs() {
|
155
|
+
const selected = tab ? tab.value : null
|
156
|
+
console.log(selected)
|
157
|
+
return (
|
158
|
+
<Tabs selected={selected} onChange={changeTab}>
|
159
|
+
{tabs.map(tab => <Tab id={tab.value} label={tab.label} />)}
|
160
|
+
</Tabs>
|
161
|
+
)
|
162
|
+
}
|
163
|
+
|
164
|
+
return (
|
165
|
+
<Fragment>
|
166
|
+
<Header className="table-page" title={<Text>{title}</Text>}>
|
167
|
+
{canAdd ? <Button icon="add" label="Añadir" action={add} raised /> : null}
|
168
|
+
|
169
|
+
<Button icon="refresh" label="Reload" action={reload} />
|
170
|
+
{dev ? (
|
171
|
+
<MenuIcon align="alignRight">
|
172
|
+
<MenuItem label="Cargar Escenario 1" onSelect={playScenario} />
|
173
|
+
</MenuIcon>
|
174
|
+
) : null}
|
175
|
+
{renderActions()}
|
176
|
+
|
177
|
+
{renderTabs()}
|
178
|
+
|
179
|
+
</Header>
|
180
|
+
{canQuery || canFilter ? (
|
181
|
+
<menu className="table-page">
|
182
|
+
{canQuery ? <TableQueries schema={schema} url={url} user={user} /> : null}
|
183
|
+
{canFilter ? <TableFilters schema={schema} onSave={canQuery ? saveQuery : null} /> : null}
|
184
|
+
</menu>
|
185
|
+
) : null}
|
186
|
+
<main key={id} className="table-page">
|
187
|
+
<TableEditor icon={icon} title={name} schema={schema} delay={delay} editable={editable} groupBy={groupBy} filter={tableFilter} actions={tableActions} canDelete={canDelete} />
|
188
|
+
{children ? <article>{children}</article> : null}
|
189
|
+
</main>
|
190
|
+
{renderAside()}
|
191
|
+
</Fragment>
|
192
|
+
)
|
193
|
+
}
|
194
|
+
|
195
|
+
/**
|
196
|
+
* TableRowEditor
|
197
|
+
*/
|
198
|
+
const TableRowEditor = (props) => {
|
199
|
+
const { name, content, filter, editable, onChange, onClose } = props
|
200
|
+
return (
|
201
|
+
<div className="table-row-editor">
|
202
|
+
<Header icon="local_offer" title={name || "Propiedades"}>
|
203
|
+
<Icon icon="close" clickable action={onClose} />
|
204
|
+
</Header>
|
205
|
+
<main>
|
206
|
+
{editable ? <ContentEditor content={content} onChange={onChange} filter={filter} /> : <ContentViewer content={content} />}
|
207
|
+
</main>
|
208
|
+
</div>
|
209
|
+
)
|
210
|
+
}
|
211
|
+
|
212
|
+
/**
|
213
|
+
* Table Selector
|
214
|
+
*/
|
215
|
+
const TableSelector = (props) => {
|
216
|
+
|
217
|
+
const { schema, actions = [] } = props
|
218
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
219
|
+
const { all, checked } = pageContext
|
220
|
+
|
221
|
+
const count = `${checked.size}/${all.length}`
|
222
|
+
|
223
|
+
const columns = Object.keys(schema)
|
224
|
+
.filter(key => schema[key].selectorColumn === true)
|
225
|
+
.map(key => {
|
226
|
+
const field = schema[key]
|
227
|
+
return { id: field.id, label: field.label }
|
228
|
+
})
|
229
|
+
|
230
|
+
const rows = all.filter(item => checked.has(item.id))
|
231
|
+
const table = {
|
232
|
+
columns,
|
233
|
+
rows: rows || []
|
234
|
+
}
|
235
|
+
const buttons = actions.map(({ label, action, validate }) => {
|
236
|
+
return <Button
|
237
|
+
label={label} raised
|
238
|
+
action={() => action(checked, pageContext, async () => {
|
239
|
+
await pageContext.load()
|
240
|
+
setPageContext(Object.assign({}, pageContext))
|
241
|
+
}, rows)}
|
242
|
+
disabled={!validate(checked, rows)}
|
243
|
+
/>
|
244
|
+
})
|
245
|
+
|
246
|
+
return (
|
247
|
+
<div className="table-selector">
|
248
|
+
<Header icon="checklist_rtl" title="Selección">
|
249
|
+
<span className="size">{count}</span>
|
250
|
+
</Header>
|
251
|
+
<main>
|
252
|
+
<DataTable {...table} />
|
253
|
+
</main>
|
254
|
+
<footer>
|
255
|
+
{buttons}
|
256
|
+
</footer>
|
257
|
+
</div>
|
258
|
+
)
|
259
|
+
}
|
260
|
+
|
261
|
+
/**
|
262
|
+
* Table Queries
|
263
|
+
*/
|
264
|
+
const TableQueries = (props) => {
|
265
|
+
|
266
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
267
|
+
const { url, user } = props
|
268
|
+
const { queries = [] } = pageContext
|
269
|
+
const [selected, setSelected] = useState()
|
270
|
+
|
271
|
+
function select(query) {
|
272
|
+
setSelected(query.id)
|
273
|
+
pageContext.changeFilters(query.filters)
|
274
|
+
setPageContext(Object.assign({}, pageContext))
|
275
|
+
}
|
276
|
+
|
277
|
+
async function remove(id) {
|
278
|
+
await pageContext.removeQuery(id, user)
|
279
|
+
setPageContext(Object.assign({}, pageContext))
|
280
|
+
}
|
281
|
+
|
282
|
+
return (
|
283
|
+
<Fragment>
|
284
|
+
<Header className="table-queries" title={<Text>Queries</Text>} />
|
285
|
+
<main className="table-queries">
|
286
|
+
{queries ? queries
|
287
|
+
.filter(query => query.url === url)
|
288
|
+
.map(query => {
|
289
|
+
const style = selected === query.id ? "selected" : ""
|
290
|
+
return (
|
291
|
+
<div className={`table-queries-item ${style}`} onClick={() => select(query)}>
|
292
|
+
<Icon icon="star" size="small" />
|
293
|
+
<label>{query.name}</label>
|
294
|
+
<Icon icon="close" clickable size="small" action={() => remove(query.id)} />
|
295
|
+
</div>
|
296
|
+
)
|
297
|
+
}) : <div>...empty...</div>}
|
298
|
+
</main>
|
299
|
+
</Fragment>
|
300
|
+
)
|
301
|
+
}
|
302
|
+
|
303
|
+
/**
|
304
|
+
* Table Filters
|
305
|
+
*/
|
306
|
+
const TableFilters = (props) => {
|
307
|
+
|
308
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
309
|
+
const { filters } = pageContext
|
310
|
+
const { schema, onSave } = props
|
311
|
+
const [form, setForm] = useState({})
|
312
|
+
|
313
|
+
const filterSchema = useMemo(() => {
|
314
|
+
const filterSchema = Object.assign({}, schema)
|
315
|
+
for (var key in filterSchema) {
|
316
|
+
if (filterSchema[key].filter === false) {
|
317
|
+
delete filterSchema[key]
|
318
|
+
} else {
|
319
|
+
if (filterSchema[key].type === TYPES.ENTITY) {
|
320
|
+
const fs = filterSchema[key].item
|
321
|
+
for (var key in fs) {
|
322
|
+
if (fs[key].filter === false) delete fs[key]
|
323
|
+
}
|
324
|
+
}
|
325
|
+
}
|
326
|
+
}
|
327
|
+
//Object.values(filterSchema).forEach(field => field.section = null)
|
328
|
+
delete filterSchema.flows
|
329
|
+
return filterSchema
|
330
|
+
}, [schema])
|
331
|
+
|
332
|
+
useEffect(() => {
|
333
|
+
if (filters) setForm(filters)
|
334
|
+
}, [filters])
|
335
|
+
|
336
|
+
useEffect(() => {
|
337
|
+
reload()
|
338
|
+
}, [form])
|
339
|
+
|
340
|
+
async function change(next) {
|
341
|
+
setForm(next)
|
342
|
+
}
|
343
|
+
|
344
|
+
async function reload() {
|
345
|
+
await pageContext.load(form)
|
346
|
+
setPageContext(Object.assign({}, pageContext))
|
347
|
+
}
|
348
|
+
|
349
|
+
function clear() {
|
350
|
+
change({})
|
351
|
+
}
|
352
|
+
|
353
|
+
function save() {
|
354
|
+
if (onSave) {
|
355
|
+
onSave(form)
|
356
|
+
}
|
357
|
+
}
|
358
|
+
|
359
|
+
const content = new Content(filterSchema, form)
|
360
|
+
return (
|
361
|
+
<Fragment>
|
362
|
+
<Header className="table-filters" title={<Text>Filters</Text>} >
|
363
|
+
<Icon icon="filter_list_off" size="small" clickable action={clear} />
|
364
|
+
{onSave ? <Icon icon="save" size="small" clickable action={save} /> : null}
|
365
|
+
</Header>
|
366
|
+
<main className="table-filters">
|
367
|
+
<ContentEditor content={content} onChange={change} />
|
368
|
+
</main>
|
369
|
+
</Fragment>
|
370
|
+
)
|
371
|
+
}
|
372
|
+
|
373
|
+
/**
|
374
|
+
* Table Editor
|
375
|
+
*/
|
376
|
+
export const TableEditor = (props) => {
|
377
|
+
|
378
|
+
const site = useContext(SiteContext)
|
379
|
+
const [pageContext, setPageContext] = useContext(PageContext)
|
380
|
+
const { all = [], filters } = pageContext
|
381
|
+
const { icon, title, schema, editable, canDelete, filter, actions } = props
|
382
|
+
const [groupBy, setGroupBy] = useState(props.groupBy)
|
383
|
+
|
384
|
+
function changeGroup(id, value) {
|
385
|
+
setGroupBy(value)
|
386
|
+
}
|
387
|
+
|
388
|
+
async function remove(id) {
|
389
|
+
const confirm = await site.confirm("Are you sure ?")
|
390
|
+
if (confirm) {
|
391
|
+
await pageContext.remove(id)
|
392
|
+
pageContext.clear()
|
393
|
+
setPageContext(Object.assign({}, pageContext))
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
function change(rowID, cellID, value) {
|
398
|
+
const row = all.find(r => r.id === rowID)
|
399
|
+
const next = Object.assign({}, row, { [cellID]: value })
|
400
|
+
delete next.actions
|
401
|
+
pageContext.update(next)
|
402
|
+
setPageContext(Object.assign({}, pageContext))
|
403
|
+
}
|
404
|
+
|
405
|
+
function clear() {
|
406
|
+
pageContext.clear()
|
407
|
+
setPageContext(Object.assign({}, pageContext))
|
408
|
+
}
|
409
|
+
|
410
|
+
async function select(row, event) {
|
411
|
+
clear()
|
412
|
+
await pageContext.select(row.id)
|
413
|
+
setPageContext(Object.assign({}, pageContext))
|
414
|
+
}
|
415
|
+
|
416
|
+
async function check(ids, value) {
|
417
|
+
pageContext.check(ids, value)
|
418
|
+
setPageContext(Object.assign({}, pageContext))
|
419
|
+
}
|
420
|
+
|
421
|
+
async function checkOne(id, field, value) {
|
422
|
+
check([id], value)
|
423
|
+
}
|
424
|
+
|
425
|
+
function run(action, item) {
|
426
|
+
action.action(item.id, pageContext, async () => {
|
427
|
+
await pageContext.load()
|
428
|
+
setPageContext(Object.assign({}, pageContext))
|
429
|
+
})
|
430
|
+
}
|
431
|
+
|
432
|
+
function renderGroupLabel(groupName) {
|
433
|
+
const grouper = schema[groupBy]
|
434
|
+
if (!groupName || !grouper) return ""
|
435
|
+
if (grouper.options) {
|
436
|
+
const options = CHECK['isFunction'](grouper.options) ? grouper.options() : grouper.options
|
437
|
+
const option = options.find(option => option.value === groupName)
|
438
|
+
return option ? option.label : groupName
|
439
|
+
} else {
|
440
|
+
return groupName
|
441
|
+
}
|
442
|
+
}
|
443
|
+
|
444
|
+
function renderGroups() {
|
445
|
+
const items = filter ? filter(all) : all
|
446
|
+
const groups = items.reduce((groups, item) => {
|
447
|
+
const groupName = item[groupBy]
|
448
|
+
const group = groups[groupName]
|
449
|
+
if (!group) groups[groupName] = []
|
450
|
+
groups[groupName].push(item)
|
451
|
+
return groups
|
452
|
+
}, {})
|
453
|
+
return Object.keys(groups).map(groupName => {
|
454
|
+
const table = {
|
455
|
+
columns: Object.values(schema)
|
456
|
+
.filter(field => field.column === true)
|
457
|
+
.map(field => {
|
458
|
+
let options = field.options;
|
459
|
+
if (options && typeof (options) == 'function') {
|
460
|
+
options = options()
|
461
|
+
}
|
462
|
+
return {
|
463
|
+
id: field.id,
|
464
|
+
label: field.label,
|
465
|
+
type: field.type,
|
466
|
+
format: field.format,
|
467
|
+
item: field.item ? field.item : [],
|
468
|
+
onChange: field.id === "checked" ? checkOne : field.editable ? change : null, /* checked has it´s own handler */
|
469
|
+
options
|
470
|
+
}
|
471
|
+
}),
|
472
|
+
rows: groups[groupName]
|
473
|
+
.map(item => {
|
474
|
+
item.checked = pageContext.checked ? pageContext.checked.has(item.id) : false
|
475
|
+
item.actions = actions ? actions.map(action => {
|
476
|
+
return action.filter ?
|
477
|
+
action.filter(item) ? <Icon icon={action.icon} clickable size="small" action={() => run(action, item)} /> : null
|
478
|
+
: <Icon icon={action.icon} clickable size="small" action={() => run(action, item)} />
|
479
|
+
}) : []
|
480
|
+
if (canDelete) item.actions.push(<Icon icon="delete" size="small" clickable action={() => remove(item.id)} />)
|
481
|
+
return item
|
482
|
+
})
|
483
|
+
}
|
484
|
+
table.columns.push({ id: "actions" })
|
485
|
+
const groupSize = groups[groupName].length
|
486
|
+
const title = <span><span className="size">{groupSize}</span>{renderGroupLabel(groupName)}</span>
|
487
|
+
return (
|
488
|
+
<Fragment key={groupName}>
|
489
|
+
<Header title={title} >
|
490
|
+
<span className="size">{groupSize}</span>
|
491
|
+
</Header>
|
492
|
+
<DataTable {...table} onRowSelection={select} editable={editable} onCheckAll={check} />
|
493
|
+
</Fragment>
|
494
|
+
)
|
495
|
+
})
|
496
|
+
}
|
497
|
+
|
498
|
+
function buildGroupOptions(schema) {
|
499
|
+
return Object.values(schema)
|
500
|
+
.filter(field => field.grouper === true)
|
501
|
+
.map(field => ({ label: field.label, value: field.id }))
|
502
|
+
}
|
503
|
+
|
504
|
+
return (
|
505
|
+
<Fragment>
|
506
|
+
<Header icon={icon} title={<Text>{title}</Text>}>
|
507
|
+
<DropDown id="groupBy" label="Agrupar Por" value={groupBy} options={buildGroupOptions(schema)} onChange={changeGroup} />
|
508
|
+
</Header>
|
509
|
+
<main className="table-editor">
|
510
|
+
{renderGroups()}
|
511
|
+
</main>
|
512
|
+
</Fragment>
|
513
|
+
)
|
514
|
+
}
|
515
|
+
|
516
|
+
/**
|
517
|
+
* Table Context
|
518
|
+
*/
|
519
|
+
const TableContext = (url, field, host, urlQuery) => {
|
520
|
+
|
521
|
+
const API = TableAPI(url, host)
|
522
|
+
|
523
|
+
return {
|
524
|
+
|
525
|
+
all: [],
|
526
|
+
checked: new Set([]),
|
527
|
+
selected: null,
|
528
|
+
filters: {},
|
529
|
+
queries: [],
|
530
|
+
tab: null,
|
531
|
+
|
532
|
+
async load(filter, like) {
|
533
|
+
try {
|
534
|
+
const filters = filter ? Object.keys(filter).reduce((filters, key) => {
|
535
|
+
const field = filter[key];
|
536
|
+
if (field) {
|
537
|
+
if (CHECK['isObject'](field)) {
|
538
|
+
Object.keys(field).forEach(key2 => {
|
539
|
+
const subfield = field[key2]
|
540
|
+
if (subfield) filters[`${key}.${key2}`] = subfield
|
541
|
+
})
|
542
|
+
} else {
|
543
|
+
filters[key] = field;
|
544
|
+
}
|
545
|
+
}
|
546
|
+
|
547
|
+
return filters;
|
548
|
+
}, {}) : []
|
549
|
+
|
550
|
+
if (this.tab) {
|
551
|
+
filters[this.tab.field] = this.tab.value
|
552
|
+
}
|
553
|
+
|
554
|
+
const data = await API.all(filters, like);
|
555
|
+
this.all = field ? data[field] : data;
|
556
|
+
} catch (error) {
|
557
|
+
console.log(error)
|
558
|
+
}
|
559
|
+
return
|
560
|
+
},
|
561
|
+
|
562
|
+
check(ids, isChecked = true) {
|
563
|
+
if (isChecked) {
|
564
|
+
ids.forEach(id => this.checked.add(id))
|
565
|
+
} else {
|
566
|
+
ids.forEach(id => this.checked.delete(id))
|
567
|
+
}
|
568
|
+
},
|
569
|
+
|
570
|
+
changeTab(tab) {
|
571
|
+
this.tab = tab
|
572
|
+
},
|
573
|
+
|
574
|
+
select(id) {
|
575
|
+
const result = this.all.find(item => item.id === id);
|
576
|
+
this.selected = result;
|
577
|
+
},
|
578
|
+
|
579
|
+
clear() {
|
580
|
+
this.selected = null
|
581
|
+
},
|
582
|
+
|
583
|
+
async create(form) {
|
584
|
+
try {
|
585
|
+
await API.create(form);
|
586
|
+
await this.load({}, false);
|
587
|
+
} catch (error) {
|
588
|
+
console.log(error)
|
589
|
+
}
|
590
|
+
return
|
591
|
+
},
|
592
|
+
|
593
|
+
async update(form) {
|
594
|
+
try {
|
595
|
+
await API.update(form)
|
596
|
+
await this.load()
|
597
|
+
} catch (error) {
|
598
|
+
console.log(error)
|
599
|
+
}
|
600
|
+
return
|
601
|
+
},
|
602
|
+
|
603
|
+
async remove(id) {
|
604
|
+
try {
|
605
|
+
await API.remove(id)
|
606
|
+
await this.load()
|
607
|
+
} catch (error) {
|
608
|
+
console.log(error)
|
609
|
+
}
|
610
|
+
return
|
611
|
+
},
|
612
|
+
|
613
|
+
changeFilters(filters) {
|
614
|
+
this.filters = filters
|
615
|
+
},
|
616
|
+
|
617
|
+
async loadQueries(user) {
|
618
|
+
try {
|
619
|
+
this.queries = await API.queries(user, urlQuery)
|
620
|
+
} catch (error) {
|
621
|
+
console.log(error)
|
622
|
+
}
|
623
|
+
},
|
624
|
+
|
625
|
+
async createQuery(query, user) {
|
626
|
+
try {
|
627
|
+
await API.createQuery(query, urlQuery)
|
628
|
+
await this.loadQueries(user)
|
629
|
+
} catch (error) {
|
630
|
+
console.log(error)
|
631
|
+
}
|
632
|
+
},
|
633
|
+
|
634
|
+
async removeQuery(id, user) {
|
635
|
+
try {
|
636
|
+
await API.removeQuery(id, urlQuery)
|
637
|
+
await this.loadQueries(user)
|
638
|
+
} catch (error) {
|
639
|
+
console.log(error)
|
640
|
+
}
|
641
|
+
return
|
642
|
+
}
|
643
|
+
|
644
|
+
}
|
645
|
+
}
|
646
|
+
|
647
|
+
/**
|
648
|
+
* table API
|
649
|
+
*/
|
650
|
+
const TableAPI = (url, host) => {
|
651
|
+
|
652
|
+
const http = HTTPClient(host || window.API || process.env.REACT_APP_API, Session);
|
653
|
+
|
654
|
+
return {
|
655
|
+
all(filters, like = true) {
|
656
|
+
let queryParams = "?"
|
657
|
+
if (filters) {
|
658
|
+
const filterQuery = Object.keys(filters).reduce((query, key) => {
|
659
|
+
const value = filters[key]
|
660
|
+
if (typeof (value) === 'boolean') {
|
661
|
+
return query.concat(`${key}=${value}&`)
|
662
|
+
} else if (Array.isArray(value)) {
|
663
|
+
const param = value.length === 0 ? '' : value.reduce((param, item) => {
|
664
|
+
param = param.concat(`${key}=${item}&`)
|
665
|
+
return param
|
666
|
+
}, "")
|
667
|
+
return query.concat(param)
|
668
|
+
} else {
|
669
|
+
return like ? query.concat(`${key}=%${filters[key]}%&`) : query.concat(`${key}=${filters[key]}&`)
|
670
|
+
}
|
671
|
+
}, "")
|
672
|
+
queryParams = queryParams.concat(filterQuery)
|
673
|
+
}
|
674
|
+
return http.GET(url + queryParams)
|
675
|
+
},
|
676
|
+
|
677
|
+
find(id) {
|
678
|
+
return http.GET(`${url}/${id}`)
|
679
|
+
},
|
680
|
+
|
681
|
+
create(form) {
|
682
|
+
const body = JSON.stringify(form)
|
683
|
+
return http.POST(url, body)
|
684
|
+
},
|
685
|
+
|
686
|
+
update(form) {
|
687
|
+
const body = JSON.stringify(form)
|
688
|
+
return http.PUT(`${url}/${form.id}`, body)
|
689
|
+
},
|
690
|
+
|
691
|
+
remove(id) {
|
692
|
+
return http.DELETE(`${url}/${id}`)
|
693
|
+
},
|
694
|
+
|
695
|
+
queries(user, url2) {
|
696
|
+
let url3 = url2 ? url2 : url
|
697
|
+
url3 = url3 + "queries"
|
698
|
+
if (user) url3 = url3 + `?user=${user}`
|
699
|
+
return http.GET(url3)
|
700
|
+
},
|
701
|
+
|
702
|
+
createQuery(form, url2) {
|
703
|
+
const url3 = url2 ? url2 : url
|
704
|
+
const body = JSON.stringify(form)
|
705
|
+
return http.POST(`${url3}queries`, body)
|
706
|
+
},
|
707
|
+
|
708
|
+
removeQuery(id, url2) {
|
709
|
+
const url3 = url2 ? url2 : url
|
710
|
+
return http.DELETE(`${url3}queries/${id}`)
|
711
|
+
},
|
712
|
+
}
|
713
|
+
}
|
package/src/site/site.test.js
CHANGED
@@ -8,20 +8,24 @@ import { Dialog } from './dialog'
|
|
8
8
|
import { Button, DropDown, TextField, TextArea } from '../html'
|
9
9
|
import { UploadDialog } from '../widgets/upload/UploadDialog'
|
10
10
|
import { Uploader } from '../widgets/upload/Uploader'
|
11
|
-
import {
|
11
|
+
import { TabbedTablePage } from '../domain/TabbedTablePage'
|
12
|
+
import { FORMATS, TYPES } from '../domain/ContentType'
|
12
13
|
|
13
14
|
const SiteTest = (prop) => {
|
14
15
|
|
15
16
|
const footer = <div>FOOTER</div>
|
16
17
|
|
17
18
|
return (
|
18
|
-
<Site icon="star" title="Site Test" init={"
|
19
|
+
<Site icon="star" title="Site Test" init={"PAGE3"} footer={footer}>
|
19
20
|
<Page id="PAGE1" section="SECTION1" icon="description" title="Page 1" layout="workspace">
|
20
21
|
<Page1 />
|
21
22
|
</Page>
|
22
23
|
<Page id="PAGE2" section="SECTION1" icon="description" title="Page 2" layout="workspace">
|
23
24
|
<Page2 />
|
24
25
|
</Page>
|
26
|
+
<Page id="PAGE3" section="SECTION1" icon="description" title="Page 3" layout="workspace">
|
27
|
+
<Page3 />
|
28
|
+
</Page>
|
25
29
|
</Site>
|
26
30
|
)
|
27
31
|
}
|
@@ -110,10 +114,20 @@ const Page2 = (props) => {
|
|
110
114
|
|
111
115
|
const Page3 = (props) => {
|
112
116
|
|
113
|
-
const
|
117
|
+
const schema = {
|
118
|
+
name : { id: "name" , type: TYPES.STRING, format: FORMATS.NONE , required: true, tab: false, column: true , filter: true , label: "Name" },
|
119
|
+
state : { id: "state" , type: TYPES.STRING, format: FORMATS.NONE , required: true, tab: true , column: true , filter: false, label: "State" , options: [
|
120
|
+
{ label: "Pendiente", value: "NOT_CLASSIFIED" },
|
121
|
+
{ label: "Clasificada", value: "CLASSIFIED"},
|
122
|
+
]},
|
123
|
+
field1: { id: "field1", type: TYPES.STRING, format: FORMATS.NONE , required: true, tab: false, column: true , filter: true , label: "field1" },
|
124
|
+
field2: { id: "field2", type: TYPES.STRING, format: FORMATS.NONE , required: true, tab: false, column: true , filter: true , label: "field2" },
|
125
|
+
field4: { id: "field4", type: TYPES.STRING, format: FORMATS.COLOR, required: true, tab: false, column: true , filter: true , label: "Color" },
|
126
|
+
}
|
114
127
|
|
115
128
|
return (
|
116
129
|
<Fragment>
|
130
|
+
<TabbedTablePage title="Referencias" schema={schema} host="http://localhost:3000" url="/references"/>
|
117
131
|
</Fragment>
|
118
132
|
)
|
119
133
|
}
|