ywana-core8 0.0.678 → 0.0.680
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/dist/index.cjs +30 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +39 -0
- package/dist/index.css.map +1 -1
- package/dist/index.modern.js +30 -9
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +30 -9
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/commons.js +30 -0
- package/src/domain/CollectionAPI.js +86 -0
- package/src/domain/CollectionAPI.test.js +19 -0
- package/src/domain/CollectionPage.css +41 -10
- package/src/domain/CollectionPage.js +45 -21
- package/src/index.js +2 -1
- package/src/site/site.test.js +3 -3
package/package.json
CHANGED
package/src/commons.js
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
/**
|
2
|
+
* isEmpty
|
3
|
+
*
|
4
|
+
* @param {*} obj
|
5
|
+
* @returns
|
6
|
+
*/
|
7
|
+
export function isEmpty(obj) {
|
8
|
+
|
9
|
+
// null
|
10
|
+
if (obj === null) {
|
11
|
+
return true
|
12
|
+
}
|
13
|
+
// undefined
|
14
|
+
if (obj === undefined) {
|
15
|
+
return true
|
16
|
+
}
|
17
|
+
// empty string
|
18
|
+
if (typeof obj === "string" && obj.length === 0) {
|
19
|
+
return true
|
20
|
+
}
|
21
|
+
// empty array
|
22
|
+
if (Array.isArray(obj) && obj.length === 0) {
|
23
|
+
return true
|
24
|
+
}
|
25
|
+
// empty object
|
26
|
+
if (typeof obj === "object" && Object.keys(obj).length === 0 && obj.constructor === Object) {
|
27
|
+
return true
|
28
|
+
}
|
29
|
+
return false
|
30
|
+
}
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import { HTTPClient, Session } from '../http'
|
2
|
+
import { isEmpty} from '../commons'
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Collection API
|
6
|
+
*/
|
7
|
+
export const CollectionAPI = (url, host) => {
|
8
|
+
|
9
|
+
const http = HTTPClient(host || window.API || process.env.REACT_APP_API, Session);
|
10
|
+
|
11
|
+
/**
|
12
|
+
* objectToQueryParamString
|
13
|
+
*
|
14
|
+
* @param {*} obj
|
15
|
+
* @returns
|
16
|
+
*/
|
17
|
+
function objectToQueryParamString(obj, likes) {
|
18
|
+
|
19
|
+
if (isEmpty(obj)) {
|
20
|
+
return ""
|
21
|
+
}
|
22
|
+
|
23
|
+
const notEmptyFields = Object.keys(obj).filter(key => !isEmpty(obj[key]))
|
24
|
+
|
25
|
+
const paramString = notEmptyFields.reduce((query, key) => {
|
26
|
+
const value = obj[key]
|
27
|
+
const like = likes.includes(key) ? '%' : ''
|
28
|
+
|
29
|
+
if (Array.isArray(value)) {
|
30
|
+
const values = value.map(v => `${key}=${like}${v}${like}`).join("&")
|
31
|
+
return `${query}${values}&`
|
32
|
+
} else if (typeof value === "object") {
|
33
|
+
const params = objectToQueryParamString(value, likes)
|
34
|
+
params.split("&").forEach(param => {
|
35
|
+
query = query.concat(`${key}.${param}&`)
|
36
|
+
})
|
37
|
+
return query
|
38
|
+
} else {
|
39
|
+
return `${query}${key}=${like}${value}${like}&`
|
40
|
+
}
|
41
|
+
}, "")
|
42
|
+
|
43
|
+
return paramString
|
44
|
+
}
|
45
|
+
|
46
|
+
|
47
|
+
return {
|
48
|
+
|
49
|
+
all(filters, likes, page) {
|
50
|
+
let queryParams = page ? `?page=${page}&` : "?"
|
51
|
+
const filterQuery = objectToQueryParamString(filters, likes)
|
52
|
+
queryParams = `${queryParams}${filterQuery}`
|
53
|
+
queryParams = queryParams.substring(0, queryParams.length - 1)
|
54
|
+
return http.GET(`${url}${queryParams}`)
|
55
|
+
},
|
56
|
+
|
57
|
+
find(id) {
|
58
|
+
return http.GET(`${url}/${id}`)
|
59
|
+
},
|
60
|
+
|
61
|
+
create(form) {
|
62
|
+
const body = JSON.stringify(form)
|
63
|
+
return http.POST(url, body)
|
64
|
+
},
|
65
|
+
|
66
|
+
update(form) {
|
67
|
+
const body = JSON.stringify(form)
|
68
|
+
return http.PUT(`${url}/${form.id}`, body)
|
69
|
+
},
|
70
|
+
|
71
|
+
updateProperty(id, propertyName, form) {
|
72
|
+
const body = JSON.stringify(form)
|
73
|
+
return http.PUT(`${url}/${id}/${propertyName}`, body)
|
74
|
+
},
|
75
|
+
|
76
|
+
patch(id, form) {
|
77
|
+
const body = JSON.stringify(form)
|
78
|
+
return http.PATCH(`${url}/${id}`, body)
|
79
|
+
},
|
80
|
+
|
81
|
+
remove(id) {
|
82
|
+
return http.DELETE(`${url}/${id}`)
|
83
|
+
},
|
84
|
+
|
85
|
+
}
|
86
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import React, { useState } from 'react'
|
2
|
+
import { Button } from '../html'
|
3
|
+
|
4
|
+
import { CollectionAPI } from './CollectionAPI'
|
5
|
+
|
6
|
+
const CollectionAPITest = (prop) => {
|
7
|
+
|
8
|
+
const API = CollectionAPI('/references', 'http://localhost:3000')
|
9
|
+
|
10
|
+
function all() {
|
11
|
+
API.all({ name: "2223"}, ["name"]).then(res => console.log(res))
|
12
|
+
}
|
13
|
+
|
14
|
+
return (
|
15
|
+
<>
|
16
|
+
<Button label="ALL" action={all} />
|
17
|
+
</>
|
18
|
+
)
|
19
|
+
}
|
@@ -14,16 +14,8 @@ menu.collection-page>header {
|
|
14
14
|
padding: 0 0.5rem
|
15
15
|
}
|
16
16
|
|
17
|
-
menu.collection-page>
|
18
|
-
|
19
|
-
display: flex;
|
20
|
-
justify-content: flex-end;
|
21
|
-
border-bottom: dotted 1px var(--divider-color);
|
22
|
-
background-color: var(--background-color);
|
23
|
-
}
|
24
|
-
|
25
|
-
menu.collection-page>main.collection-filters {
|
26
|
-
border-bottom: dotted 1px var(--divider-color);
|
17
|
+
menu.collection-page>div.collection-filters {
|
18
|
+
border-bottom: solid 1px var(--divider-color);
|
27
19
|
background-color: var(--background-color);
|
28
20
|
}
|
29
21
|
|
@@ -67,4 +59,43 @@ main.collection-page.dock-to-right>main {
|
|
67
59
|
|
68
60
|
main.collection-page.dock-to-right>article {
|
69
61
|
grid-area: dock;
|
62
|
+
}
|
63
|
+
|
64
|
+
.filters-header>.icon {
|
65
|
+
width: 2rem;
|
66
|
+
font-size: 1.2rem;
|
67
|
+
}
|
68
|
+
|
69
|
+
.filters-resume {
|
70
|
+
flex: 1;
|
71
|
+
display: flex;
|
72
|
+
flex-wrap: wrap;
|
73
|
+
}
|
74
|
+
|
75
|
+
.filter-field {
|
76
|
+
flex: 0;
|
77
|
+
display: flex;
|
78
|
+
padding: .2rem .4rem;
|
79
|
+
margin: .2rem;
|
80
|
+
align-items: baseline;
|
81
|
+
background-color: var(--background-color);
|
82
|
+
border-radius: .2rem;
|
83
|
+
}
|
84
|
+
|
85
|
+
.filter-field>label {
|
86
|
+
display: flex;
|
87
|
+
font-size: .8rem;
|
88
|
+
color: var(--text-color-lighter);
|
89
|
+
margin-right: .2rem;
|
90
|
+
}
|
91
|
+
|
92
|
+
.filter-field>.value {
|
93
|
+
font-size: .9rem;
|
94
|
+
padding:
|
95
|
+
}
|
96
|
+
|
97
|
+
.placeholder {
|
98
|
+
font-size: .9rem;
|
99
|
+
font-style: italic;
|
100
|
+
color: var(--text-color-lighter);
|
70
101
|
}
|
@@ -2,7 +2,7 @@ import equal from 'deep-equal'
|
|
2
2
|
import React, { Fragment, useContext, useEffect, useRef, useState, useMemo } from 'react'
|
3
3
|
import { HTTPClient, Session } from '../http'
|
4
4
|
import { PageContext } from '../site'
|
5
|
-
import { Button, Header, Icon, List, Menu, MenuIcon, MenuItem, Text, Tree, TreeItem, TreeNode, TextField, Chip } from '../html'
|
5
|
+
import { Tooltip, Button, Header, Icon, List, Menu, MenuIcon, MenuItem, Text, Tree, TreeItem, TreeNode, TextField, Chip, Tooltip } from '../html'
|
6
6
|
import { Content, TYPES } from './ContentType'
|
7
7
|
import { ContentEditor, TabbedContentEditor, TreededContentEditor } from './ContentEditor'
|
8
8
|
import { CreateContentDialog } from './CreateContentDialog'
|
@@ -75,7 +75,7 @@ export const CollectionPage = (props) => {
|
|
75
75
|
</Header>
|
76
76
|
<menu className={`collection-page ${className}`}>
|
77
77
|
{canFilter ? <CollectionFilters schema={schema} /> : null}
|
78
|
-
{levels ? <CollectionTree schema={schema} icon={icon} levels={levels} onSelect={onSelect} sorter={sorter} searchBy={searchBy} namer={namer}/> : <CollectionList groupBy={groupBy} onSelect={onSelect} searchBy={searchBy} />}
|
78
|
+
{levels ? <CollectionTree schema={schema} icon={icon} levels={levels} onSelect={onSelect} sorter={sorter} searchBy={searchBy} namer={namer} /> : <CollectionList groupBy={groupBy} onSelect={onSelect} searchBy={searchBy} />}
|
79
79
|
</menu>
|
80
80
|
<main key={id} className={`collection-page ${className}`}>
|
81
81
|
<CollectionEditor icon={icon} schema={schema} layout={editor} autosave={autosave} delay={delay} canDelete={canDelete} onReload={reloadSelection} patch={patch} onChange={onChange} />
|
@@ -93,9 +93,9 @@ export const CollectionPage = (props) => {
|
|
93
93
|
*/
|
94
94
|
export const CollectionFilters = (props) => {
|
95
95
|
|
96
|
-
const { schema, onChange } = props
|
97
|
-
const [form, setForm] = useState(
|
98
|
-
const [
|
96
|
+
const { schema, initial = {}, onChange } = props
|
97
|
+
const [form, setForm] = useState(initial)
|
98
|
+
const [showFilters, setShowFilters] = useState(false)
|
99
99
|
|
100
100
|
const filterSchema = useMemo(() => {
|
101
101
|
const filterSchema = Object.assign({}, schema)
|
@@ -127,32 +127,56 @@ export const CollectionFilters = (props) => {
|
|
127
127
|
}
|
128
128
|
|
129
129
|
function toggleFilters() {
|
130
|
-
|
130
|
+
setShowFilters(!showFilters)
|
131
131
|
}
|
132
132
|
|
133
133
|
const content = new Content(filterSchema, form)
|
134
|
+
const expanded = showFilters ? "expanded" : ""
|
134
135
|
return (
|
135
136
|
<Fragment>
|
136
|
-
<header>
|
137
|
-
<
|
138
|
-
|
137
|
+
<Header icon="filter_list" className={`filters-header ${expanded}`}>
|
138
|
+
{showFilters ? <Icon icon="expand_less" size="small" clickable action={toggleFilters} /> : <Icon icon="expand_more" size="small" clickable action={toggleFilters} />}
|
139
|
+
<FilterResume schema={filterSchema} form={form} onClear={clear} />
|
140
|
+
</Header>
|
141
|
+
{showFilters ? (
|
142
|
+
<div className="collection-filters">
|
143
|
+
<ContentEditor content={content} onChange={change} />
|
139
144
|
</div>
|
140
|
-
{showFilter ? <Icon icon="expand_less" size="small" clickable action={toggleFilters} /> : <Icon icon="expand_more" size="small" clickable action={toggleFilters} />}
|
141
|
-
</header>
|
142
|
-
{showFilter ? (
|
143
|
-
<>
|
144
|
-
<nav className="collection-filters">
|
145
|
-
<Icon icon="clear_all" size="small" clickable action={clear} />
|
146
|
-
</nav>
|
147
|
-
<main className="collection-filters">
|
148
|
-
<ContentEditor content={content} onChange={change} />
|
149
|
-
</main>
|
150
|
-
</>
|
151
145
|
) : null}
|
152
146
|
</Fragment>
|
153
147
|
)
|
154
148
|
}
|
155
149
|
|
150
|
+
const FilterResume = (props) => {
|
151
|
+
|
152
|
+
const { schema, form = {}, onClear } = props
|
153
|
+
|
154
|
+
const fields = Object.keys(form)
|
155
|
+
.filter(key => form[key] !== undefined && form[key] !== null && form[key] !== "")
|
156
|
+
|
157
|
+
return (
|
158
|
+
<>
|
159
|
+
{fields.length > 0 ? (
|
160
|
+
<Tooltip text="Limpiar Filtros">
|
161
|
+
<Icon icon="clear_all" size="small" clickable action={onClear} />
|
162
|
+
</Tooltip>
|
163
|
+
) : null}
|
164
|
+
|
165
|
+
<div className='filters-resume'>
|
166
|
+
{
|
167
|
+
fields.length > 0 ? fields.map(key => (
|
168
|
+
<div className='filter-field'>
|
169
|
+
<label>{schema[key].label}</label>
|
170
|
+
<div className='value'>{form[key]}</div>
|
171
|
+
</div>
|
172
|
+
)) : <div className="placeholder">No se aplican filtros</div>
|
173
|
+
}
|
174
|
+
|
175
|
+
</div>
|
176
|
+
</>
|
177
|
+
)
|
178
|
+
}
|
179
|
+
|
156
180
|
/**
|
157
181
|
* Collection List
|
158
182
|
*/
|
@@ -304,7 +328,7 @@ export const CollectionTree = (props) => {
|
|
304
328
|
</main>
|
305
329
|
<footer>
|
306
330
|
<div className='search-box'>
|
307
|
-
<TextField
|
331
|
+
<TextField label="Search" onChange={changeSearch} outlined className="search-box" />
|
308
332
|
</div>
|
309
333
|
</footer>
|
310
334
|
</>
|
package/src/index.js
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
import 'material-design-icons-iconfont/dist/material-design-icons.css'
|
2
2
|
import './css/html.css'
|
3
3
|
|
4
|
+
export * from './commons'
|
5
|
+
|
4
6
|
export * from './http'
|
5
7
|
export * from './html'
|
6
8
|
export * from './widgets'
|
7
9
|
export * from './site'
|
8
10
|
export * from './domain'
|
9
11
|
|
10
|
-
|
11
12
|
export * from './incubator'
|
12
13
|
|
13
14
|
export const isFunction = value => value && (Object.prototype.toString.call(value) === "[object Function]" || "function" === typeof value || value instanceof Function);
|
package/src/site/site.test.js
CHANGED
@@ -205,11 +205,11 @@ const Page5 = (props) => {
|
|
205
205
|
{ label: "Pendiente", value: "NOT_CLASSIFIED" },
|
206
206
|
{ label: "Clasificada", value: "CLASSIFIED"},
|
207
207
|
]},
|
208
|
-
field1: { id: "field1", section: "A", type: TYPES.STRING , format: FORMATS.NONE , required: true, tab: false, grouper: true , column: true , filter:
|
209
|
-
field2: { id: "field2", section: "B", type: TYPES.STRING , format: FORMATS.NONE , required: true, tab: false, grouper: true , column: true , filter:
|
208
|
+
field1: { id: "field1", section: "A", type: TYPES.STRING , format: FORMATS.NONE , required: true, tab: false, grouper: true , column: true , filter: true , label: "field1" },
|
209
|
+
field2: { id: "field2", section: "B", type: TYPES.STRING , format: FORMATS.NONE , required: true, tab: false, grouper: true , column: true , filter: true , label: "field2" },
|
210
210
|
field4: { id: "field4", section: "B", type: TYPES.STRING , format: FORMATS.COLOR, required: true, tab: false, grouper: true , column: true , filter: false , label: "Color" },
|
211
211
|
field5: { id: "field5", section: "B", type: TYPES.ENTITY, item: ENTITYTYPE, format: FORMATS.NONE , editable: true, tab: false, grouper: false, column: true , filter: false, like: false, label: "Entity5"},
|
212
|
-
id
|
212
|
+
id : { id: "id" , type: TYPES.STRING , filter: false },
|
213
213
|
}
|
214
214
|
|
215
215
|
return (
|