Skip to content

Commit 63f3e8d

Browse files
Arfeyjettify
authored andcommitted
Feat started to implement edit show views (#367)
* feat: added can edit/delete/create and per_page property + prepare view/edit page (cherry picked from commit b9a1552) * feat: added default value for ModelAdmin.fields, now it's primary keys (cherry picked from commit 830b1a6) * feat: fixed show page and added simple docs for `ReadMe.md` (cherry picked from commit 9ab2015) * fix: fixed node version for `CI` (cherry picked from commit 50a3bb1) * feat: added default representation of table's fields on edit/show/create pages.
1 parent 57ca0e5 commit 63f3e8d

17 files changed

Lines changed: 604 additions & 102 deletions

File tree

aiohttp_admin/backends/sa.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,28 @@
77
from ..utils import (json_response, validate_payload, validate_query,
88
calc_pagination, ASC)
99
from .sa_utils import table_to_trafaret, create_filter
10+
from ..contrib.constants import ReactComponent as rc
1011

1112

1213
__all__ = ['PGResource', 'MySQLResource']
1314

1415

15-
DATA_TYPES = {
16-
sa.Integer: 'integer',
17-
sa.Text: 'string',
18-
sa.Float: 'number',
19-
sa.Date: 'date',
20-
sa.Boolean: 'bool',
21-
postgresql.JSON: 'json',
16+
FIELD_TYPES = {
17+
sa.Integer: rc.TEXT_FIELD.value,
18+
sa.Text: rc.TEXT_FIELD.value,
19+
sa.Float: rc.NUMBER_FIELD.value,
20+
sa.Date: rc.DATE_FIELD.value,
21+
sa.Boolean: rc.BOOLEAN_FIELD.value,
22+
postgresql.JSON: rc.JSON_FIELD.value,
23+
}
24+
25+
INPUT_TYPES = {
26+
sa.Integer: rc.TEXT_INPUT.value,
27+
sa.Text: rc.TEXT_INPUT.value,
28+
sa.Float: rc.TEXT_INPUT.value,
29+
sa.Date: rc.DATE_INPUT.value,
30+
sa.Boolean: rc.NULLABLE_BOOLEAN_INPUT.value,
31+
postgresql.JSON: rc.JSON_INPUT.value,
2232
}
2333

2434

@@ -63,12 +73,31 @@ def get_type_of_fields(fields, table):
6373
]
6474

6575
data_type_fields = {
66-
name: DATA_TYPES.get(type(field_type.type), 'string')
76+
name: FIELD_TYPES.get(type(field_type.type), rc.TEXT_FIELD.value)
6777
for name, field_type in actual_fields
6878
}
6979

7080
return data_type_fields
7181

82+
@staticmethod
83+
def get_type_for_inputs(table):
84+
"""
85+
Return information about table's fields in dictionary type.
86+
87+
:param table: sa.Table - the current table
88+
:return: list - list of the dictionaries
89+
"""
90+
return [
91+
dict(
92+
type=INPUT_TYPES.get(
93+
type(field_type.type), rc.TEXT_INPUT.value
94+
),
95+
name=name,
96+
isPrimaryKey=(name in table.primary_key),
97+
props=None,
98+
) for name, field_type in table.c.items()
99+
]
100+
72101
async def list(self, request):
73102
await require(request, Permissions.view)
74103
columns_names = list(self._table.c.keys())

aiohttp_admin/backends/sa_utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ def table_to_trafaret(table, primary_key, skip_pk=False):
8282
for name, column in table.c.items():
8383
if skip_pk and column.name == primary_key:
8484
continue
85-
key = name
8685
default = column.server_default
8786
key = build_key(name, default)
8887

aiohttp_admin/contrib/constants.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from enum import Enum
2+
3+
4+
class ReactComponent(Enum):
5+
"""
6+
Represented React components of `admin-on-rest`.
7+
"""
8+
9+
# fields
10+
TEXT_FIELD = 'TextField'
11+
JSON_FIELD = 'JsonField'
12+
DATE_FIELD = 'DateField'
13+
NUMBER_FIELD = 'NumberField'
14+
BOOLEAN_FIELD = 'BooleanField'
15+
FUNCTION_FIELD = 'FunctionField'
16+
REFERENCE_MANY_FIELD = 'ReferenceManyField'
17+
PRODUCT_REFERENCE_FIELD = 'ProductReferenceField'
18+
STAR_RATING_FIELD = 'StarRatingField'
19+
MB_ITEMS_FIELD = 'NbItemsField'
20+
21+
# inputs
22+
TEXT_INPUT = 'TextInput'
23+
DATE_INPUT = 'DateInput'
24+
SEGMENTS_INPUT = 'SegmentsInput'
25+
NULLABLE_BOOLEAN_INPUT = 'NullableBooleanInput'
26+
LONG_TEXT_INPUT = 'LongTextInput'
27+
JSON_INPUT = 'JsonInput'

aiohttp_admin/contrib/models.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,80 @@ class Meta:
1717
can_delete = True
1818
per_page = 10
1919
fields = None
20+
form = None
21+
edit_form = None
22+
create_form = None
23+
show_form = None
2024

2125
def __init__(self):
2226
self.name = self.__class__.__name__.lower()
27+
self._table = self.Meta.table
28+
self._resource_type = self.Meta.resource_type
2329

2430
def to_dict(self):
2531
"""
2632
Return dict with the all base information about the instance.
2733
"""
28-
2934
data = {
3035
"name": self.name,
3136
"canEdit": self.can_edit,
3237
"canCreate": self.can_create,
3338
"canDelete": self.can_delete,
3439
"perPage": self.per_page,
40+
"showPage": self.generate_data_for_show_page(),
41+
"editPage": self.generate_data_for_edit_page(),
42+
"createPage": self.generate_data_for_create_page(),
3543
}
3644

3745
return data
46+
47+
def generate_simple_data_page(self):
48+
"""
49+
Generate a simple representation of table's fields in dictionary type.
50+
51+
:return: dict
52+
"""
53+
return self._resource_type.get_type_for_inputs(self._table)
54+
55+
def generate_data_for_edit_page(self):
56+
"""
57+
Generate a custom representation of table's fields in dictionary type
58+
if exist edit form else use default representation.
59+
60+
:return: dict
61+
"""
62+
63+
if not self.can_edit:
64+
return {}
65+
66+
if self.edit_form:
67+
return self.edit_form.to_dict()
68+
69+
return self.generate_simple_data_page()
70+
71+
def generate_data_for_show_page(self):
72+
"""
73+
Generate a custom representation of table's fields in dictionary type
74+
if exist show form else use default representation.
75+
76+
:return: dict
77+
"""
78+
if self.show_form:
79+
return self.show_form.to_dict()
80+
81+
return self.generate_simple_data_page()
82+
83+
def generate_data_for_create_page(self):
84+
"""
85+
Generate a custom representation of table's fields in dictionary type
86+
if exist create form else use default representation.
87+
88+
:return: dict
89+
"""
90+
if not self.can_create:
91+
return {}
92+
93+
if self.create_form:
94+
return self.create_form.to_dict()
95+
96+
return self.generate_simple_data_page()

aiohttp_admin/static/react-admin/dist/bundle.js

Lines changed: 88 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aiohttp_admin/static/react-admin/js/components/Create/Create.jsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,25 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33

44
import {
5-
TextInput,
6-
Create,
7-
SimpleForm,
8-
LongTextInput,
5+
Create,
6+
SimpleForm,
97
} from 'admin-on-rest';
108

9+
import { getInputs } from '../../utils/inputs';
10+
1111

1212
export const BaseCreate = (props) => (
13-
<Create {...props}>
14-
<SimpleForm>
15-
<TextInput source="body" />
16-
</SimpleForm>
17-
</Create>
13+
<Create {...props}>
14+
<SimpleForm>
15+
{getInputs(props.data.createPage)}
16+
</SimpleForm>
17+
</Create>
1818
);
19+
20+
BaseCreate.propTypes = {
21+
data: PropTypes.objectOf({
22+
createPage: PropTypes.object,
23+
})
24+
};
25+
26+
export default BaseCreate;

aiohttp_admin/static/react-admin/js/components/Edit/Edit.jsx

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,25 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33

44
import {
5-
Datagrid,
6-
List,
7-
TextField,
8-
DateField,
9-
NumberField,
10-
BooleanField,
11-
FunctionField,
12-
TabbedForm,
13-
FormTab,
14-
TextInput,
15-
DateInput,
16-
ReferenceManyField,
17-
NbItemsField,
18-
EditButton,
19-
ProductReferenceField,
20-
StarRatingField,
21-
SegmentsInput,
22-
NullableBooleanInput,
235
Edit,
246
SimpleForm
257
} from 'admin-on-rest';
268

9+
import { getInputs } from '../../utils/inputs';
10+
2711

2812
export const BaseEdit = (props) => (
2913
<Edit {...props}>
30-
<SimpleForm>
31-
<TextInput source="id" style={{ display: 'block' }} />
32-
</ SimpleForm>
14+
<SimpleForm>
15+
{getInputs(props.data.editPage)}
16+
</ SimpleForm>
3317
</Edit>
3418
);
19+
20+
BaseEdit.propTypes = {
21+
data: PropTypes.objectOf({
22+
editPage: PropTypes.object,
23+
})
24+
};
25+
26+
export default BaseEdit;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
5+
export function JsonField({ record = {}, source }) {
6+
const render = res => JSON.stringify(res[source], null, 2);
7+
8+
return <span>{render(record)}</span>;
9+
}
10+
11+
JsonField.propTypes = {
12+
source: PropTypes.string,
13+
record: PropTypes.object,
14+
};
15+
16+
export default JsonField;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import get from 'lodash.get';
4+
import { BooleanField } from 'admin-on-rest';
5+
6+
7+
export class ShowField extends React.Component {
8+
render () {
9+
const { source, record = {} } = this.props;
10+
let data = get(record, source);
11+
12+
if (data instanceof Object) {
13+
data = JSON.stringify(data, null, 2);
14+
} else if (typeof(data) === 'boolean') {
15+
return (
16+
<BooleanField
17+
{...this.props}
18+
elStyle={{width: '24px', margin: 0}}
19+
/>
20+
);
21+
}
22+
23+
return <span>{data}</span>;
24+
}
25+
}
26+
27+
ShowField.defaultProps = {
28+
addLabel: true,
29+
};
30+
31+
ShowField.propTypes ={
32+
source: PropTypes.string.isRequired,
33+
record: PropTypes.object,
34+
};
35+
36+
export default ShowField;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { FieldTitle } from 'admin-on-rest';
4+
5+
import TextField from 'material-ui/TextField';
6+
7+
8+
const JsonInput = ({
9+
input,
10+
isRequired,
11+
label,
12+
source,
13+
elStyle,
14+
resource,
15+
}) => {
16+
const toString = value => {
17+
if (value instanceof Object) {
18+
return JSON.stringify(value, null, 2);
19+
}
20+
return value;
21+
};
22+
23+
return (
24+
<TextField
25+
{...input}
26+
value={input.value}
27+
source={source}
28+
resource={resource}
29+
multiLine
30+
fullWidth
31+
floatingLabelText={
32+
<FieldTitle
33+
label={label}
34+
source={source}
35+
resource={resource}
36+
isRequired={isRequired}
37+
/>
38+
}
39+
style={elStyle}
40+
/>
41+
);
42+
};
43+
44+
JsonInput.propTypes = {
45+
addField: PropTypes.bool.isRequired,
46+
elStyle: PropTypes.object,
47+
input: PropTypes.object,
48+
isRequired: PropTypes.bool,
49+
label: PropTypes.string,
50+
resource: PropTypes.string,
51+
source: PropTypes.string,
52+
validate: PropTypes.oneOfType([
53+
PropTypes.func,
54+
PropTypes.arrayOf(PropTypes.func),
55+
]),
56+
};
57+
58+
JsonInput.defaultProps = {
59+
addField: true,
60+
options: {},
61+
};
62+
63+
export default JsonInput;

0 commit comments

Comments
 (0)