drf-react-by-schema 0.1.0 → 0.2.0

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.
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import Alert, { AlertColor } from '@mui/material/Alert';
3
+ import List from '@mui/material/List';
4
+ import ListItem from '@mui/material/ListItem';
5
+ import { NumericFormat } from 'react-number-format';
6
+ import { Item } from '../utils';
7
+ import { DRFReactBySchemaContext, DRFReactBySchemaContextType } from '../context/DRFReactBySchemaProvider';
8
+
9
+ export interface SumRowsType {
10
+ rows: Item[],
11
+ severity?: AlertColor;
12
+ }
13
+
14
+ interface DataTotalsProps {
15
+ data?: Item[];
16
+ sumRows?: SumRowsType;
17
+ visibleRows?: string[];
18
+ };
19
+
20
+ const DataTotals = ({
21
+ data,
22
+ sumRows,
23
+ visibleRows
24
+ }: DataTotalsProps) => {
25
+ return (
26
+ <>
27
+ {data && sumRows && sumRows.rows.length > 0 &&
28
+ <Alert severity={sumRows.severity || 'info'}>
29
+ <List dense={true}>
30
+ {sumRows.rows.map(row => (
31
+ <ListItem key={`sumRows_${row.field}`}>
32
+ <NumericFormat
33
+ value={data.reduce((total, item) => {
34
+ if (parseFloat(item[row.field]) && visibleRows && visibleRows.includes(item.id)) {
35
+ return total + parseFloat(item[row.field]);
36
+ }
37
+ return total;
38
+ }, 0)}
39
+ thousandSeparator='.'
40
+ decimalSeparator=','
41
+ displayType={'text'}
42
+ decimalScale={row.isCount ? 0 : 2}
43
+ fixedDecimalScale={true}
44
+ prefix={row.prefix}
45
+ suffix={row.suffix}
46
+ />
47
+ </ListItem>
48
+ ))}
49
+ </List>
50
+ </Alert>
51
+ }
52
+ </>
53
+ );
54
+ };
55
+
56
+ export default DataTotals;
@@ -0,0 +1,155 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import Box from '@mui/material/Box';
3
+
4
+ import DataGridBySchemaEditable from './DataGridBySchemaEditable';
5
+ import DataTotals, { SumRowsType } from './DataTotals';
6
+ import { Layout } from '../styles';
7
+ // import CONSTANTS from '../constants';
8
+ import { GridEnrichedBySchemaColDef, Item, SchemaType } from '../utils';
9
+ import { DataSchemaColumnsType, getGenericModelList, getGenericModelListProps } from '../api';
10
+ import { DRFReactBySchemaContext, DRFReactBySchemaContextType } from '../context/DRFReactBySchemaProvider';
11
+
12
+ interface GenericModelListProps {
13
+ columnFields: string[];
14
+ hiddenFields?: string[];
15
+ minWidthFields?: Record<string, number>;
16
+ indexFieldBasePath: string;
17
+ indexField: string;
18
+ customColumnOperations?: (column: GridEnrichedBySchemaColDef) => GridEnrichedBySchemaColDef;
19
+ customLinkDestination?: (p: any) => string;
20
+ sumRows?: SumRowsType;
21
+ isAutoHeight?: boolean;
22
+ model: string;
23
+ handleLoading: (p: any) => void;
24
+ forceReload: boolean;
25
+ LinkComponent: React.ReactNode;
26
+ }
27
+
28
+ const GenericModelList = ({
29
+ columnFields,
30
+ hiddenFields = [],
31
+ minWidthFields,
32
+ indexFieldBasePath,
33
+ indexField,
34
+ customColumnOperations,
35
+ customLinkDestination,
36
+ sumRows,
37
+ isAutoHeight = true,
38
+ model,
39
+ handleLoading,
40
+ forceReload = false,
41
+ LinkComponent = null
42
+ }: GenericModelListProps) => {
43
+ const { serverEndPoint, isInBatches, firstBatchLength }:DRFReactBySchemaContextType = DRFReactBySchemaContext
44
+ ? React.useContext(DRFReactBySchemaContext) as DRFReactBySchemaContextType
45
+ : { serverEndPoint: null };
46
+ if (!serverEndPoint) {
47
+ console.error('Error: There is no endpoint defined in DRFReactBySchemaProvider!');
48
+ return (<></>);
49
+ }
50
+ interface dataProps {
51
+ data: Item[];
52
+ schema: SchemaType;
53
+ columns: GridEnrichedBySchemaColDef[]
54
+ };
55
+ const [data, setData] = useState<DataSchemaColumnsType | boolean>(false);
56
+ const [visibleRows, setVisibleRows] = useState<string[]>([]);
57
+ const [hideFooterPagination, setHideFooterPagination] = useState(false);
58
+
59
+ const finalCustomColumnOperations = (column: GridEnrichedBySchemaColDef) => {
60
+ if (minWidthFields) {
61
+ if (Object.prototype.hasOwnProperty.call(minWidthFields, column.field)) {
62
+ column.minWidth = minWidthFields[column.field];
63
+ }
64
+ }
65
+
66
+ if (customColumnOperations) {
67
+ return customColumnOperations(column);
68
+ }
69
+
70
+ return column;
71
+ };
72
+
73
+ const loadObjectList = async () => {
74
+ const loadParams:getGenericModelListProps = {
75
+ model,
76
+ serverEndPoint,
77
+ columnFields,
78
+ hiddenFields,
79
+ isInBatches
80
+ };
81
+ handleLoading(true);
82
+ const loadedData = await getGenericModelList(loadParams);
83
+ if (loadedData && typeof loadedData !== 'boolean') {
84
+ setData(loadedData);
85
+ handleLoading(false);
86
+ if (isInBatches && loadedData.data.length === firstBatchLength) {
87
+ setHideFooterPagination(true);
88
+ getGenericModelList({
89
+ ...loadParams,
90
+ loadedSchema: loadedData.schema
91
+ }).then(lastBatchData => {
92
+ if (lastBatchData && typeof lastBatchData !== 'boolean') {
93
+ setData({
94
+ ...loadedData,
95
+ data: [
96
+ ...loadedData.data,
97
+ ...lastBatchData.data
98
+ ]
99
+ });
100
+ }
101
+ setHideFooterPagination(false);
102
+ });
103
+ }
104
+ return;
105
+ }
106
+ console.log('error retrieving data!');
107
+ };
108
+
109
+ if (forceReload) {
110
+ loadObjectList();
111
+ }
112
+
113
+ useEffect(() => {
114
+ loadObjectList();
115
+ }, []);
116
+
117
+ return (
118
+ <>
119
+ {data && typeof data !== 'boolean' && data.columns &&
120
+ <>
121
+ <Box sx={Layout.dataGridWithTabs}>
122
+ <DataGridBySchemaEditable
123
+ data={data.data}
124
+ columns={data.columns}
125
+ schema={data.schema || {}}
126
+ model={model}
127
+ indexField={indexField}
128
+ indexFieldBasePath={indexFieldBasePath}
129
+ isEditable={false}
130
+ isAutoHeight={isAutoHeight}
131
+ hideFooterPagination={hideFooterPagination}
132
+ customColumnOperations={finalCustomColumnOperations}
133
+ customLinkDestination={customLinkDestination}
134
+ setVisibleRows={setVisibleRows}
135
+ onDataChange={newData => {
136
+ setData({
137
+ ...data,
138
+ data: newData
139
+ });
140
+ }}
141
+ LinkComponent={LinkComponent}
142
+ />
143
+ </Box>
144
+ <DataTotals
145
+ data={data.data}
146
+ sumRows={sumRows}
147
+ visibleRows={visibleRows}
148
+ />
149
+ </>
150
+ }
151
+ </>
152
+ );
153
+ };
154
+
155
+ export default GenericModelList;
@@ -0,0 +1,62 @@
1
+ import React from 'react';
2
+ import { Control } from "react-hook-form";
3
+ import TextField from '@mui/material/TextField';
4
+
5
+ import { errorProps } from '../utils';
6
+
7
+ export interface TextFieldBySchemaType {
8
+ name: string;
9
+ Controller: React.ReactNode;
10
+ control: Control;
11
+ errors:
12
+ }
13
+
14
+ export default function TextFieldBySchema ({
15
+ Controller,
16
+ name,
17
+ schema,
18
+ control,
19
+ errors,
20
+ multiline = false,
21
+ fieldKey = null,
22
+ index = null,
23
+ sx = { mr: 2 },
24
+ ...other
25
+ }) {
26
+ const model = name;
27
+ if (fieldKey && index >= 0) {
28
+ name = `${fieldKey}.${index}.${name}`;
29
+ }
30
+ const { error, helperText } = (fieldKey && index >= 0)
31
+ ? errorProps({
32
+ fieldKey,
33
+ index,
34
+ fieldKeyProp: name,
35
+ errors
36
+ })
37
+ : {
38
+ error: errors && Boolean(errors[name]),
39
+ helperText: (errors && errors[name]) ? errors[name].message : ''
40
+ };
41
+ return (
42
+ <Controller
43
+ name={name}
44
+ control={control}
45
+ render={({ field }) => (
46
+ <TextField
47
+ {...field}
48
+ {...other}
49
+ id={name}
50
+ key={name}
51
+ label={schema[model].label}
52
+ margin="normal"
53
+ fullWidth
54
+ multiline={multiline}
55
+ error={error}
56
+ helperText={helperText}
57
+ sx={sx}
58
+ />
59
+ )}
60
+ />
61
+ );
62
+ }
@@ -0,0 +1,50 @@
1
+ DRFReactBySchemaProvider example:
2
+
3
+ ```js
4
+ import DataGridBySchemaEditable from '../components/DataGridBySchemaEditable';
5
+ const data = {
6
+ data: [],
7
+ columns: [],
8
+ schema: {}
9
+ };
10
+ const model = 'example';
11
+ const indexField = null;
12
+ const indexFieldBasePath = null;
13
+ const isAutoHeight = true;
14
+ const hideFooterPagination = false;
15
+ const finalCustomColumnOperations = null;
16
+ const customLinkDestination = null;
17
+ const setVisibleRows = null;
18
+ const setData = (newData) => {
19
+ return '';
20
+ };
21
+ const Link = null;
22
+ <DRFReactBySchemaProvider
23
+ serverEndPoint={{
24
+ url: 'https://icv.eita.org.br/api',
25
+ apiTokenUrl: 'https://icv.eita.org.br/api-auth/token'
26
+ }}
27
+ >
28
+ <DataGridBySchemaEditable
29
+ data={data.data}
30
+ columns={data.columns}
31
+ schema={data.schema}
32
+ model={model}
33
+ indexField={indexField}
34
+ indexFieldBasePath={indexFieldBasePath}
35
+ isEditable={false}
36
+ isAutoHeight={isAutoHeight}
37
+ hideFooterPagination={hideFooterPagination}
38
+ customColumnOperations={finalCustomColumnOperations}
39
+ customLinkDestination={customLinkDestination}
40
+ setVisibleRows={setVisibleRows}
41
+ onDataChange={newData => {
42
+ setData({
43
+ ...data,
44
+ data: newData
45
+ });
46
+ }}
47
+ LinkComponent={Link}
48
+ />
49
+ </DRFReactBySchemaProvider>
50
+ ```
@@ -0,0 +1,78 @@
1
+ import { ServerResponse } from 'http';
2
+ import React from 'react';
3
+
4
+ export interface serverEndPointType {
5
+ url: string;
6
+ autocomplete?: string;
7
+ api?: string;
8
+ JSONSchema?: string;
9
+ apiTokenUrl: string;
10
+ getToken?: string;
11
+ refreshToken?: string,
12
+ verifyToken?: string
13
+ }
14
+ export interface DRFReactBySchemaContextType {
15
+ serverEndPoint: serverEndPointType | null;
16
+ isInBatches?: boolean;
17
+ firstBatchLength?: number;
18
+ }
19
+
20
+ interface DRFReactBySchemaProviderProps extends DRFReactBySchemaContextType {
21
+ children: React.ReactNode;
22
+ }
23
+
24
+ export const DRFReactBySchemaContext = React.createContext<DRFReactBySchemaContextType>({
25
+ serverEndPoint: null,
26
+ isInBatches: true,
27
+ firstBatchLength: 100
28
+ });
29
+
30
+ /**
31
+ *
32
+ *
33
+ * @param {*} props
34
+ * @returns {*}
35
+ */
36
+ const DRFReactBySchemaProvider: React.FC<DRFReactBySchemaProviderProps> = ({
37
+ serverEndPoint,
38
+ isInBatches,
39
+ firstBatchLength,
40
+ children
41
+ }) => {
42
+ if (serverEndPoint) {
43
+ const defaultKeys = [
44
+ 'autocomplete',
45
+ 'api',
46
+ ['JSONSchema', 'jsonschema'],
47
+ ['getToken', ''],
48
+ ['refreshToken', 'refresh'],
49
+ ['verifyToken', 'verify']
50
+ ];
51
+ for (const key of defaultKeys) {
52
+ const hybridKey = (typeof key === 'string')
53
+ ? key as keyof serverEndPointType
54
+ : key[0] as keyof serverEndPointType;
55
+ const hybridUrl = (typeof key === 'string')
56
+ ? key
57
+ : key[1];
58
+ if (serverEndPoint[hybridKey]) {
59
+ continue;
60
+ }
61
+ serverEndPoint[hybridKey] = `${serverEndPoint.url}/${hybridUrl}`;
62
+ }
63
+ }
64
+
65
+ return (
66
+ <DRFReactBySchemaContext.Provider
67
+ value={{
68
+ serverEndPoint,
69
+ isInBatches,
70
+ firstBatchLength
71
+ }}
72
+ >
73
+ {children}
74
+ </DRFReactBySchemaContext.Provider>
75
+ );
76
+ }
77
+
78
+ export default DRFReactBySchemaProvider;
package/src/index.ts CHANGED
@@ -1,3 +1,64 @@
1
+ import {
2
+ updateData,
3
+ partialUpdateData,
4
+ createData,
5
+ deleteData,
6
+ createOrUpdateData,
7
+ updateDataBySchema,
8
+ addExistingRelatedModel,
9
+ getAutoComplete,
10
+ getJSONSchema,
11
+ createOrUpdateJSONSchema,
12
+ loginByPayload,
13
+ setAuthToken,
14
+ isLoggedIn,
15
+ getGenericModelList,
16
+ getGenericModel
17
+ } from './api';
18
+ import {
19
+ emptyByType,
20
+ getChoiceByValue,
21
+ populateValues,
22
+ buildGenericYupValidationSchema,
23
+ errorProps,
24
+ getTmpId,
25
+ isTmpId,
26
+ getPatternFormat
27
+ } from './utils';
28
+
29
+ // Components:
30
+ import DRFReactBySchemaProvider, { DRFReactBySchemaContext } from './context/DRFReactBySchemaProvider';
1
31
  import DataGridBySchemaEditable from './components/DataGridBySchemaEditable';
32
+ import GenericModelList from './components/GenericModelList';
33
+ import DataTotals from './components/DataTotals';
2
34
 
3
- export { DataGridBySchemaEditable }
35
+ export {
36
+ DRFReactBySchemaProvider,
37
+ DRFReactBySchemaContext,
38
+ DataGridBySchemaEditable,
39
+ GenericModelList,
40
+ DataTotals,
41
+ updateData,
42
+ partialUpdateData,
43
+ createData,
44
+ deleteData,
45
+ createOrUpdateData,
46
+ updateDataBySchema,
47
+ addExistingRelatedModel,
48
+ getAutoComplete,
49
+ getJSONSchema,
50
+ createOrUpdateJSONSchema,
51
+ loginByPayload,
52
+ setAuthToken,
53
+ isLoggedIn,
54
+ getGenericModelList,
55
+ getGenericModel,
56
+ emptyByType,
57
+ getChoiceByValue,
58
+ populateValues,
59
+ buildGenericYupValidationSchema,
60
+ errorProps,
61
+ getTmpId,
62
+ isTmpId,
63
+ getPatternFormat
64
+ };
package/src/utils.ts CHANGED
@@ -3,16 +3,16 @@ import { GridActionsColDef, GridColDef } from '@mui/x-data-grid';
3
3
 
4
4
  export type Id = string | number;
5
5
  export type Item = Record<string, any>;
6
- export type Schema = Record<string, Field>;
6
+ export type SchemaType = Record<string, Field>;
7
7
  export interface Choice {
8
8
  value: string | number,
9
9
  display_name: string
10
10
  };
11
- type FieldChild = Record<string, Schema>;
11
+ type FieldChild = Record<string, SchemaType>;
12
12
  export interface Field {
13
13
  type: string,
14
14
  child?: FieldChild,
15
- children?: Schema,
15
+ children?: SchemaType,
16
16
  model_default?: any,
17
17
  model_required?: boolean
18
18
  choices?: Choice[],
@@ -82,7 +82,7 @@ export const populateValues = ({
82
82
  }: {
83
83
  model:string,
84
84
  data:Item,
85
- schema:Schema
85
+ schema:SchemaType
86
86
  }) => {
87
87
  const values:Record<string, any> = {};
88
88
  for (const entry of Object.entries(schema)) {
@@ -193,7 +193,7 @@ export const buildGenericYupValidationSchema = ({
193
193
  extraValidators = {}
194
194
  }:{
195
195
  data:Item,
196
- schema:Schema,
196
+ schema:SchemaType,
197
197
  many?:boolean,
198
198
  skipFields?: string[],
199
199
  extraValidators?:Item
@@ -0,0 +1,18 @@
1
+ const path = require('path');
2
+ const glob = require('glob');
3
+
4
+ module.exports = {
5
+ title: 'React Style Guide Example',
6
+ // components: function () {
7
+ // return glob.sync(path.resolve(__dirname, 'src/components/**/*.tsx'))
8
+ // .filter(function (module) {
9
+ // return /\/[A-Z]\w*\.tsx$/.test(module);
10
+ // });
11
+ // },
12
+ components: [
13
+ 'src/components/*.tsx',
14
+ 'src/context/*.tsx'
15
+ ],
16
+ resolver: require('react-docgen').resolver.findAllComponentDefinitions,
17
+ propsParser: require('react-docgen-typescript').withDefaultConfig({ propFilter: { skipPropsWithoutDoc: false } }).parse
18
+ };
@@ -0,0 +1,24 @@
1
+ var path = require('path');
2
+
3
+ module.exports = {
4
+ entry: {
5
+ bundle: ['./src/index.ts'],
6
+ },
7
+ context: path.resolve(__dirname),
8
+ output: {
9
+ filename: 'bundle.js',
10
+ path: path.join(__dirname, 'temp')
11
+ },
12
+ module: {
13
+ rules: [
14
+ {
15
+ test: /\.tsx?$/,
16
+ loader: 'ts-loader',
17
+ exclude: /node_modules/,
18
+ }
19
+ ]
20
+ },
21
+ resolve: {
22
+ extensions: [".tsx", ".ts", ".js"]
23
+ }
24
+ };