ywana-core8 0.0.679 → 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/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 +5 -13
- package/src/domain/CollectionPage.js +30 -25
- package/src/index.js +2 -1
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
|
|
@@ -92,18 +84,18 @@ main.collection-page.dock-to-right>article {
|
|
92
84
|
|
93
85
|
.filter-field>label {
|
94
86
|
display: flex;
|
95
|
-
font-size: .
|
87
|
+
font-size: .8rem;
|
96
88
|
color: var(--text-color-lighter);
|
97
89
|
margin-right: .2rem;
|
98
90
|
}
|
99
91
|
|
100
92
|
.filter-field>.value {
|
101
|
-
font-size: .
|
93
|
+
font-size: .9rem;
|
102
94
|
padding:
|
103
95
|
}
|
104
96
|
|
105
97
|
.placeholder {
|
106
|
-
font-size: .
|
98
|
+
font-size: .9rem;
|
107
99
|
font-style: italic;
|
108
100
|
color: var(--text-color-lighter);
|
109
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'
|
@@ -93,8 +93,8 @@ export const CollectionPage = (props) => {
|
|
93
93
|
*/
|
94
94
|
export const CollectionFilters = (props) => {
|
95
95
|
|
96
|
-
const { schema, onChange } = props
|
97
|
-
const [form, setForm] = useState(
|
96
|
+
const { schema, initial = {}, onChange } = props
|
97
|
+
const [form, setForm] = useState(initial)
|
98
98
|
const [showFilters, setShowFilters] = useState(false)
|
99
99
|
|
100
100
|
const filterSchema = useMemo(() => {
|
@@ -131,21 +131,17 @@ export const CollectionFilters = (props) => {
|
|
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 icon="filter_list" className=
|
137
|
+
<Header icon="filter_list" className={`filters-header ${expanded}`}>
|
137
138
|
{showFilters ? <Icon icon="expand_less" size="small" clickable action={toggleFilters} /> : <Icon icon="expand_more" size="small" clickable action={toggleFilters} />}
|
138
|
-
<FilterResume form={form} />
|
139
|
+
<FilterResume schema={filterSchema} form={form} onClear={clear} />
|
139
140
|
</Header>
|
140
141
|
{showFilters ? (
|
141
|
-
|
142
|
-
<
|
143
|
-
|
144
|
-
</nav>
|
145
|
-
<main className="collection-filters">
|
146
|
-
<ContentEditor content={content} onChange={change} />
|
147
|
-
</main>
|
148
|
-
</>
|
142
|
+
<div className="collection-filters">
|
143
|
+
<ContentEditor content={content} onChange={change} />
|
144
|
+
</div>
|
149
145
|
) : null}
|
150
146
|
</Fragment>
|
151
147
|
)
|
@@ -153,22 +149,31 @@ export const CollectionFilters = (props) => {
|
|
153
149
|
|
154
150
|
const FilterResume = (props) => {
|
155
151
|
|
156
|
-
const { form = {} } = props
|
152
|
+
const { schema, form = {}, onClear } = props
|
157
153
|
|
158
154
|
const fields = Object.keys(form)
|
159
155
|
.filter(key => form[key] !== undefined && form[key] !== null && form[key] !== "")
|
160
156
|
|
161
157
|
return (
|
162
|
-
|
163
|
-
{
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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
|
+
</>
|
172
177
|
)
|
173
178
|
}
|
174
179
|
|
@@ -323,7 +328,7 @@ export const CollectionTree = (props) => {
|
|
323
328
|
</main>
|
324
329
|
<footer>
|
325
330
|
<div className='search-box'>
|
326
|
-
<TextField
|
331
|
+
<TextField label="Search" onChange={changeSearch} outlined className="search-box" />
|
327
332
|
</div>
|
328
333
|
</footer>
|
329
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);
|