From 8fadb8e8f57b0acb6897246566bd0f11e446f375 Mon Sep 17 00:00:00 2001 From: ES Date: Sun, 9 Jun 2019 16:32:43 +0530 Subject: [PATCH 01/14] Removed redundant code --- src/Renderer/Body/Actions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Renderer/Body/Actions.js b/src/Renderer/Body/Actions.js index 953afbb..3b4fbb5 100644 --- a/src/Renderer/Body/Actions.js +++ b/src/Renderer/Body/Actions.js @@ -2,7 +2,6 @@ import _ from 'lodash'; import { connect } from 'react-redux'; import React, { Component } from 'react'; import { deleteData } from '../../actions'; -import { withTableConfig } from '../../TableProvider'; import { paramsResolver, prepareActionPayload, isUndefined } from '../../utils'; import Button from '../../components/Button'; From b50d1061d48a60f9a0fbd950e94007c73cc840a8 Mon Sep 17 00:00:00 2001 From: ES Date: Sun, 9 Jun 2019 16:33:04 +0530 Subject: [PATCH 02/14] Update package --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index c3fd29f..50f9055 100644 --- a/package-lock.json +++ b/package-lock.json @@ -748,9 +748,9 @@ } }, "axios-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/axios-observable/-/axios-observable-1.1.0.tgz", - "integrity": "sha512-+dmhX0BgbNt27DvsyA9lRmOJpk4yNXK8k2pCjeiFbbVdaiUR9A9g0x49z8O97SI25m5otadmTIrSPUG8bKhDdQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/axios-observable/-/axios-observable-1.1.1.tgz", + "integrity": "sha512-mjrRa8qJSLxTIKqThB7aWpMLZVDKrwYo/PwbbnnOzEo7u7s6n9sUjCYudCR9FVRZ8T3MexgnvXpSjwgdQTylXA==", "dev": true }, "babel-cli": { diff --git a/package.json b/package.json index cf9c74a..5b7d6a7 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ }, "devDependencies": { "axios": "^0.19.0", - "axios-observable": "^1.1.0", + "axios-observable": "^1.1.1", "bootstrap": "^4.3.1", "lodash": ">=4.17.11", "nwb": "0.23.x", From 9b4c448744a48702b2a14c2f09ccca135e472a7f Mon Sep 17 00:00:00 2001 From: ES Date: Mon, 10 Jun 2019 18:57:44 +0530 Subject: [PATCH 03/14] Table layout update (Incomplete) --- demo/src/schema/basic.js | 597 ++++++++++------ src/Renderer.js | 138 +++- src/Renderer/Toolbar/Button.js | 16 - src/Renderer/Toolbar/Print.js | 14 - src/TableProvider.js | 95 ++- src/{Renderer => components}/Body/Actions.js | 2 +- src/{Renderer => components}/Body/Date.js | 4 +- src/{Renderer => components}/Body/Image.js | 0 src/{Renderer => components}/Body/Options.js | 4 +- .../Body/Selection.js | 2 +- src/{Renderer => components}/Body/Text.js | 4 +- src/components/Body/index.js | 6 + src/components/Button.js | 85 +-- .../Toolbar => components}/Columns.js | 13 +- .../Editable.js} | 24 +- src/{Renderer => components}/Filter/Date.js | 4 +- src/{Renderer => components}/Filter/Number.js | 4 +- .../Filter/Options.js | 2 +- src/{Renderer => components}/Filter/String.js | 2 +- src/components/Filter/index.js | 4 + src/{Renderer => components}/Header/Column.js | 2 +- .../Header/Selection.js | 2 +- src/components/Header/index.js | 2 + .../Pagination => components}/Limiter.js | 19 +- .../Toolbar => components}/MassActions.js | 10 +- .../Pagination => components}/Pages.js | 14 +- src/components/Pagination.js | 87 --- src/components/Print.js | 37 +- .../Toolbar => components}/ResetFilters.js | 13 +- .../Pagination => components}/ResultCount.js | 4 + src/components/Toolbar.js | 66 -- src/components/index.js | 12 + src/constants.js | 23 + src/containers/Layout.js | 12 + src/containers/Print.js | 19 + src/{components => containers}/Tbody.js | 23 +- src/createTable.js | 661 +++++++++--------- src/hoc/withScrollSpy.js | 55 ++ src/hooks/useColumns.js | 61 ++ src/index.js | 11 +- src/styled-components/Button.js | 72 ++ .../Container.js | 0 .../Dropdown.js | 0 .../ExtendedDiv.js | 0 .../Field.js | 0 .../Label.js | 0 .../Loader.js | 0 src/styled-components/Print.js | 16 + src/{components => styled-components}/Row.js | 0 .../Sortable.js | 0 .../Table.js | 0 src/styled-components/Tbody.js | 16 + src/{components => styled-components}/Td.js | 0 src/{components => styled-components}/Th.js | 0 .../Thead.js | 0 src/{components => styled-components}/Tr.js | 0 src/utils.js | 20 + 57 files changed, 1310 insertions(+), 967 deletions(-) delete mode 100644 src/Renderer/Toolbar/Button.js delete mode 100644 src/Renderer/Toolbar/Print.js rename src/{Renderer => components}/Body/Actions.js (94%) rename src/{Renderer => components}/Body/Date.js (90%) rename src/{Renderer => components}/Body/Image.js (100%) rename src/{Renderer => components}/Body/Options.js (92%) rename src/{Renderer => components}/Body/Selection.js (95%) rename src/{Renderer => components}/Body/Text.js (88%) create mode 100644 src/components/Body/index.js rename src/{Renderer/Toolbar => components}/Columns.js (91%) rename src/{Renderer/Toolbar/EditableButtons.js => components/Editable.js} (51%) rename src/{Renderer => components}/Filter/Date.js (93%) rename src/{Renderer => components}/Filter/Number.js (93%) rename src/{Renderer => components}/Filter/Options.js (94%) rename src/{Renderer => components}/Filter/String.js (92%) create mode 100644 src/components/Filter/index.js rename src/{Renderer => components}/Header/Column.js (86%) rename src/{Renderer => components}/Header/Selection.js (92%) create mode 100644 src/components/Header/index.js rename src/{Renderer/Pagination => components}/Limiter.js (64%) rename src/{Renderer/Toolbar => components}/MassActions.js (88%) rename src/{Renderer/Pagination => components}/Pages.js (84%) delete mode 100644 src/components/Pagination.js rename src/{Renderer/Toolbar => components}/ResetFilters.js (50%) rename src/{Renderer/Pagination => components}/ResultCount.js (79%) delete mode 100644 src/components/Toolbar.js create mode 100644 src/components/index.js create mode 100644 src/containers/Layout.js create mode 100644 src/containers/Print.js rename src/{components => containers}/Tbody.js (62%) create mode 100644 src/hoc/withScrollSpy.js create mode 100644 src/hooks/useColumns.js create mode 100644 src/styled-components/Button.js rename src/{components => styled-components}/Container.js (100%) rename src/{components => styled-components}/Dropdown.js (100%) rename src/{components => styled-components}/ExtendedDiv.js (100%) rename src/{components => styled-components}/Field.js (100%) rename src/{components => styled-components}/Label.js (100%) rename src/{components => styled-components}/Loader.js (100%) create mode 100644 src/styled-components/Print.js rename src/{components => styled-components}/Row.js (100%) rename src/{components => styled-components}/Sortable.js (100%) rename src/{components => styled-components}/Table.js (100%) create mode 100644 src/styled-components/Tbody.js rename src/{components => styled-components}/Td.js (100%) rename src/{components => styled-components}/Th.js (100%) rename src/{components => styled-components}/Thead.js (100%) rename src/{components => styled-components}/Tr.js (100%) diff --git a/demo/src/schema/basic.js b/demo/src/schema/basic.js index 2507824..345ec8d 100644 --- a/demo/src/schema/basic.js +++ b/demo/src/schema/basic.js @@ -5,11 +5,211 @@ export default { name: 'posts', height: 400, rowHeight: 50, - filterable: true, - headers: true, - editable: true, + // filterable: true, + // headers: true, + // editable: true, editing: false, primaryKey: 'pageId', + routes: { + get: { + route: '/page', + sort: 'id', + dir: 'asc', + resultPath: { + data: 'data' + } + }, + delete: { + route: '/users/:id' + } + }, + layout: [ + ['Editable'], + ['MassActions', 'SimpleButton', 'ResetFilters', /*'Spacer',*/'Print', /*'Columns'*/], + ['Limiter', /*'Spacer',*/ 'ResultCount', 'Pages'], + // [{ id: 'table', layout: [ + // [{ id: 'head', layout: [ + // ['header'], + // ['filters'] + // ]}], + // ['body'], + // [{ id: 'head', layout: [ + // ['header'], + // ]}], + // ]}], + ['Limiter', /*'Spacer',*/ 'ResultCount', 'Pages'], + ], + components: { + Editable: { + type: 'editable', + labels: { + show: 'Make editable', + hide: 'Hide editable', + save: 'Save', + }, + save: ( config ) => ( dispatch, getState ) => { + const tableState = getState()[config.reducerName][config.name]; + console.log('toolbar save click with modified data', config, tableState.modified); + config.action(MODIFY_DATA)({ clear: true }); + // Dispatch MODIFY_DATA action with clear: true, to reset the modified data + // Dispatch REQUEST_DATA action "config.action(REQUEST_DATA)" to refresh data. + }, + // renderer: ( props ) => {} + }, + MassActions: { + name: 'actions', + label: 'Actions', + id: 'dropdown', + options: [{ + type: 'action', + name: 'delete', + label: 'Delete', + indexField: '@id', + thunk: ( config ) => ( dispatch, getState ) => { + // Get current table state. + const tableState = getState()[payload.reducerName][payload.name]; + confirm('Are your sure you want to delete the selected items?') + ? console.log('delete items', config, getState(), tableState) + : console.log(false); + + // Filter your selected item ids here for deletion + // You can find the selection data in the selection key of the tableState. + // When all:true, exclude the ids in the selected object with value false and vice versa. + } + }, { + type: 'action', + name: 'edit', + label: 'Edit this field', + indexField: '@id' + }] + }, + SimpleButton: { + type: 'button', + label: 'Simple Button', + state: false, + thunk: ( config ) => ( dispatch, getState ) => { + const tableState = getState()[config.reducerName][config.name]; + console.log('toolbar button click', config, tableState); + config.action(REQUEST_DATA)(); + config.action(IS_LOADING)({ value: true }); + setTimeout(function() { + config.action(IS_LOADING)({ value: false }); + }, 1000); + } + }, + ResetFilters: { + type: 'reset-filters', + label: 'Reset Filters', + state: false, + }, + Print: { + type: 'print', + label: 'Print Table', + state: false, + }, + Columns: { + name: 'columns', + type: 'columns', + label: 'Columns', + visible: true, + state: false + }, + Limiter: { + type: 'limiter', + options: [10, 20, 50, 200, 2000, 0], + default: 200, + }, + table: [{ + name: 'ids', + label: '', + sortable: false, + type: 'selection', + indexField: '@pageId', + width: 50, + extraData: 'selection' + }, { + label: 'ID', + type: 'number', + name: 'pageId', + width: 150, + filterable: true, + sortable: true, + // editable: true + }, { + label: "Status", + type: "options", + name: "entityData.data.status", + sortable: true, + filterable: true, + textAlign: "center", + width: 150, + options: { + "published": { + "label": "Published" + }, + "draft": { + "label": "Draft" + }, + "unpublished": { + "label": "Unpublished" + }, + "pending-review": { + "label": "Pending Review" + }, + "trashed": { + "label": "Trashed" + }, + "archived": { + "label": "Archived" + } + }, + editable: true + // renderer: ({ + // data, + // colConfig: { name, options } + // }) =>
Not specified
+ }, { + label: 'Created at', + type: 'date', + name: 'createdAt', + sortable: true, + textAlign: 'left', + width: 200, + editable: true, + filterable: true, + }, { + label: 'Actions', + type: 'actions', + name: 'actions', + width: 100, + items: [{ + type: 'action', + name: 'edit', + label: 'Edit', + htmlClass: 'btn btn-secondary', + params: { + id: '@id', + }, + thunk: ( config ) => ( dispatch, getState ) => { + console.log('edit', config, getState()); + } + }, { + type: 'action', + name: 'delete', + label: 'Delete', + icon: 'trash-alt', + params: { + id: '@id' + }, + thunk: ( config ) => ( dispatch, getState ) => { + confirm('Are your sure you want to delete this page?') + ? console.log('delete', getState()) + : console.log(false); + + } + }] + }] + } // styles: { // loader: { // mask: { @@ -103,206 +303,193 @@ export default { // // [name]: // } // }, - pagination: { - // visible: true, // or an object { top: true, bottom: false } default visible - items: { - limiter: { - type: 'limiter', - visible: true, - position: 10, - options: [10, 20, 50, 200, 2000, 0], - default: 200, - }, - pages: { - type: 'pages', - visible: true, - position: 20, - right: true, - }, - resultCount: { - type: 'resultCount', - visible: true, - position: 30, - right: true, - }, - } - }, - routes: { - get: { - route: '/page', - sort: 'id', - dir: 'asc', - resultPath: { - data: 'data' - } - }, - delete: { - route: '/users/:id' - } - }, - toolbar: [ - [{ - name: 'actions', - label: 'Actions', - id: 'dropdown', - options: [{ - type: 'action', - name: 'delete', - label: 'Delete', - indexField: '@id', - thunk: ( config ) => ( dispatch, getState ) => { - // Get current table state. - const tableState = getState()[payload.reducerName][payload.name]; - confirm('Are your sure you want to delete the selected items?') - ? console.log('delete items', config, getState(), tableState) - : console.log(false); - - // Filter your selected item ids here for deletion - // You can find the selection data in the selection key of the tableState. - // When all:true, exclude the ids in the selected object with value false and vice versa. - } - }, { - type: 'action', - name: 'edit', - label: 'Edit this field', - indexField: '@id' - }], - visible: true - }, { - type: 'button', - label: 'Simple Button', - visible: true, - state: false, - thunk: ( config ) => ( dispatch, getState ) => { - const tableState = getState()[config.reducerName][config.name]; - console.log('toolbar button click', config, tableState); - config.action(REQUEST_DATA)(); - config.action(IS_LOADING)({ value: true }); - setTimeout(function() { - config.action(IS_LOADING)({ value: false }); - }, 1000); - } - }, { - type: 'resetFilters', - label: 'Reset Filters', - visible: true, - state: false, - }, { - type: 'print', - label: 'Print Table', - visible: true, - state: false, - }, { - name: 'columns', - type: 'columns', - label: 'Columns', - visible: true, - state: false - }, { - name: 'editable', - type: 'editable', - labels: { - show: 'Make editable', - hide: 'Hide editable', - save: 'Save', - }, - save: ( config ) => ( dispatch, getState ) => { - const tableState = getState()[config.reducerName][config.name]; - console.log('toolbar save click with modified data', config, tableState.modified); - config.action(MODIFY_DATA)({ clear: true }); - // Dispatch MODIFY_DATA action with clear: true, to reset the modified data - // Dispatch REQUEST_DATA action "config.action(REQUEST_DATA)" to refresh data. - } - }], - ], - columns: [{ - name: 'ids', - label: '', - sortable: false, - type: 'selection', - indexField: '@pageId', - width: 50, - extraData: 'selection' - }, { - label: 'ID', - type: 'number', - name: 'pageId', - width: 150, - filterable: true, - sortable: true, - // editable: true - }, { - label: "Status", - type: "options", - name: "entityData.data.status", - sortable: true, - filterable: true, - textAlign: "center", - width: 150, - options: { - "published": { - "label": "Published" - }, - "draft": { - "label": "Draft" - }, - "unpublished": { - "label": "Unpublished" - }, - "pending-review": { - "label": "Pending Review" - }, - "trashed": { - "label": "Trashed" - }, - "archived": { - "label": "Archived" - } - }, - editable: true - // renderer: ({ - // data, - // colConfig: { name, options } - // }) =>
Not specified
- }, { - label: 'Created at', - type: 'date', - name: 'createdAt', - sortable: true, - textAlign: 'left', - width: 200, - editable: true, - filterable: true, - }, { - label: 'Actions', - type: 'actions', - name: 'actions', - width: 100, - items: [{ - type: 'action', - name: 'edit', - label: 'Edit', - htmlClass: 'btn btn-secondary', - params: { - id: '@id', - }, - thunk: ( config ) => ( dispatch, getState ) => { - console.log('edit', config, getState()); - } - }, { - type: 'action', - name: 'delete', - label: 'Delete', - icon: 'trash-alt', - params: { - id: '@id' - }, - thunk: ( config ) => ( dispatch, getState ) => { - confirm('Are your sure you want to delete this page?') - ? console.log('delete', getState()) - : console.log(false); - - } - }] - }] + // pagination: { + // // visible: true, // or an object { top: true, bottom: false } default visible + // items: { + // limiter: { + // type: 'limiter', + // visible: true, + // position: 10, + // options: [10, 20, 50, 200, 2000, 0], + // default: 200, + // }, + // pages: { + // type: 'pages', + // visible: true, + // position: 20, + // right: true, + // }, + // resultCount: { + // type: 'resultCount', + // visible: true, + // position: 30, + // right: true, + // }, + // } + // }, + // toolbar: [ + // [{ + // name: 'actions', + // label: 'Actions', + // id: 'dropdown', + // options: [{ + // type: 'action', + // name: 'delete', + // label: 'Delete', + // indexField: '@id', + // thunk: ( config ) => ( dispatch, getState ) => { + // // Get current table state. + // const tableState = getState()[payload.reducerName][payload.name]; + // confirm('Are your sure you want to delete the selected items?') + // ? console.log('delete items', config, getState(), tableState) + // : console.log(false); + // + // // Filter your selected item ids here for deletion + // // You can find the selection data in the selection key of the tableState. + // // When all:true, exclude the ids in the selected object with value false and vice versa. + // } + // }, { + // type: 'action', + // name: 'edit', + // label: 'Edit this field', + // indexField: '@id' + // }], + // visible: true + // }, { + // type: 'button', + // label: 'Simple Button', + // visible: true, + // state: false, + // thunk: ( config ) => ( dispatch, getState ) => { + // const tableState = getState()[config.reducerName][config.name]; + // console.log('toolbar button click', config, tableState); + // config.action(REQUEST_DATA)(); + // config.action(IS_LOADING)({ value: true }); + // setTimeout(function() { + // config.action(IS_LOADING)({ value: false }); + // }, 1000); + // } + // }, { + // type: 'resetFilters', + // label: 'Reset Filters', + // visible: true, + // state: false, + // }, { + // type: 'print', + // label: 'Print Table', + // visible: true, + // state: false, + // }, { + // name: 'columns', + // type: 'columns', + // label: 'Columns', + // visible: true, + // state: false + // }, { + // name: 'editable', + // type: 'editable', + // labels: { + // show: 'Make editable', + // hide: 'Hide editable', + // save: 'Save', + // }, + // save: ( config ) => ( dispatch, getState ) => { + // const tableState = getState()[config.reducerName][config.name]; + // console.log('toolbar save click with modified data', config, tableState.modified); + // config.action(MODIFY_DATA)({ clear: true }); + // // Dispatch MODIFY_DATA action with clear: true, to reset the modified data + // // Dispatch REQUEST_DATA action "config.action(REQUEST_DATA)" to refresh data. + // } + // }], + // ], + // columns: [{ + // name: 'ids', + // label: '', + // sortable: false, + // type: 'selection', + // indexField: '@pageId', + // width: 50, + // extraData: 'selection' + // }, { + // label: 'ID', + // type: 'number', + // name: 'pageId', + // width: 150, + // filterable: true, + // sortable: true, + // // editable: true + // }, { + // label: "Status", + // type: "options", + // name: "entityData.data.status", + // sortable: true, + // filterable: true, + // textAlign: "center", + // width: 150, + // options: { + // "published": { + // "label": "Published" + // }, + // "draft": { + // "label": "Draft" + // }, + // "unpublished": { + // "label": "Unpublished" + // }, + // "pending-review": { + // "label": "Pending Review" + // }, + // "trashed": { + // "label": "Trashed" + // }, + // "archived": { + // "label": "Archived" + // } + // }, + // editable: true + // // renderer: ({ + // // data, + // // colConfig: { name, options } + // // }) =>
Not specified
+ // }, { + // label: 'Created at', + // type: 'date', + // name: 'createdAt', + // sortable: true, + // textAlign: 'left', + // width: 200, + // editable: true, + // filterable: true, + // }, { + // label: 'Actions', + // type: 'actions', + // name: 'actions', + // width: 100, + // items: [{ + // type: 'action', + // name: 'edit', + // label: 'Edit', + // htmlClass: 'btn btn-secondary', + // params: { + // id: '@id', + // }, + // thunk: ( config ) => ( dispatch, getState ) => { + // console.log('edit', config, getState()); + // } + // }, { + // type: 'action', + // name: 'delete', + // label: 'Delete', + // icon: 'trash-alt', + // params: { + // id: '@id' + // }, + // thunk: ( config ) => ( dispatch, getState ) => { + // confirm('Are your sure you want to delete this page?') + // ? console.log('delete', getState()) + // : console.log(false); + // + // } + // }] + // }] } diff --git a/src/Renderer.js b/src/Renderer.js index 858146c..c5c1232 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -1,3 +1,4 @@ +import _ from 'lodash'; import React from 'react'; import Limiter from './Renderer/Pagination/Limiter'; @@ -26,46 +27,109 @@ import Selection from './Renderer/Body/Selection'; import HeaderCol from './Renderer/Header/Column'; import SelectAll from './Renderer/Header/Selection'; +import { COMPONENT } from './constants'; + +// const pack = ({ itemConfig, action }) => (Renderer, props = {}) => ({ +// Renderer, +// { ...props, itemConfig, action } +// }); + +// const pack = (props) => (renderer) => renderer(props) + const renderers = { - pagination: { - limiter: Limiter, - pages: Pages, - resultCount: ResultCount - }, - toolbar: { - button: Button, - print: Print, - columns: Columns, - resetFilters: ResetFilters, - editable: EditableButtons, - default: MassActions, - }, - filter: { - number: Number, - date: DateFilter, - options: FilterOptions, - default: String - }, - body: { - date: Date, - actions: Actions, - selection: Selection, - options: Options, - image: Image, - default: Text - }, - header: { - selection: SelectAll, - default: HeaderCol - } + [COMPONENT.LIMITER]: ({ paginationProps }) => ({ Limiter, ...paginationProps }), + [COMPONENT.PAGES]: ({ paginationProps }) => ({ Pages, ...paginationProps }), + [COMPONENT.RESULT_COUNT]: ({ paginationProps }) => ({ ResultCount, ...paginationProps }), + [COMPONENT.BUTTON]: ({ thunk, internalStateUpdater }) => ({ Button, props: { thunk, internalStateUpdater } }), + [COMPONENT.PRINT]: ({ internalStateUpdater }, pack) => ({ Print, props: { internalStateUpdater } }), + [COMPONENT.COLUMNS]: ({ columns, visibleColumns, internalStateUpdater }) => ( + { Columns, props: { columns, visibleColumns, internalStateUpdater } } + ), + [COMPONENT.RESULT_FILTERS]: (_, pack) => ({ ResetFilters }), + [COMPONENT.EDITABLE]: ({ isModified, isEditing, internalStateUpdater, thunk }, pack) => ( + { EditableButtons, props: { isModified, isEditing, internalStateUpdater, thunk } } + ), + [COMPONENT.MASS_ACTIONS]: ({ thunk }, pack) => ({ MassActions, props: { thunk } }), + [COMPONENT.TABLE]: (props) => ( + + {(item, index) => { + const { Renderer, props } = renderer(components)(props)(item); + return ; + }} + + ), + [COMPONENT.TABLE_HEAD]: (props) => ( + + {(item, index) => { + const { Renderer, props } = renderer(components)(props)(item); + return ; + }} + + ) }; -const getRenderers = ( ofType ) => renderers[ofType] || {}; +const render = (components) => ({ action, ...props }) => (item, index) => { + var id = item; + if (isObject(item)) { + id = item.type; + } -const Renderer = ({ ofType, forItem, ...props }) => { - const renderers = getRenderers(ofType); - const Renderer = renderers[forItem] || renderers['default']; - return ; -}; + if (!!id === false) { + throw '"type" is a required field in layout item object'; + } + + const componentConfig = _.get(components, id, false); + if (componentConfig !== false && !!componentConfig.renderer === true) { + return componentConfig.renderer({ ...props, componentConfig }); + } + + if (!!renderer[type] === false) { + throw `Component of type "${type}" is not defined`; + } + + return renderers[type](props); +} + +// const renderers = { +// pagination: { +// limiter: Limiter, +// pages: Pages, +// resultCount: ResultCount +// }, +// toolbar: { +// button: Button, +// print: Print, +// columns: Columns, +// resetFilters: ResetFilters, +// editable: EditableButtons, +// default: MassActions, +// }, +// filter: { +// number: Number, +// date: DateFilter, +// options: FilterOptions, +// default: String +// }, +// body: { +// date: Date, +// actions: Actions, +// selection: Selection, +// options: Options, +// image: Image, +// default: Text +// }, +// header: { +// selection: SelectAll, +// default: HeaderCol +// } +// }; +// +// const getRenderers = ( ofType ) => renderers[ofType] || {}; +// +// const Renderer = ({ ofType, forItem, ...props }) => { +// const renderers = getRenderers(ofType); +// const Renderer = renderers[forItem] || renderers['default']; +// return ; +// }; export default Renderer; diff --git a/src/Renderer/Toolbar/Button.js b/src/Renderer/Toolbar/Button.js deleted file mode 100644 index a196fb5..0000000 --- a/src/Renderer/Toolbar/Button.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import StyledButton from '../../components/Button'; - -const Button = ({ itemConfig, thunk }) => { - const { thunk: cb, label, name } = itemConfig; - return ( - - { label } - - ); -}; - -export default Button; diff --git a/src/Renderer/Toolbar/Print.js b/src/Renderer/Toolbar/Print.js deleted file mode 100644 index 62948dc..0000000 --- a/src/Renderer/Toolbar/Print.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import { SET_IS_PRINTING } from '../../constants'; -import Button from '../../components/Button'; - -const Print = ({ itemConfig, internalStateUpdater }) => { - const printTable = () => internalStateUpdater({ type: SET_IS_PRINTING, value: true }); - return ( - - ); -}; - -export default Print; diff --git a/src/TableProvider.js b/src/TableProvider.js index 585136d..22ab9a2 100644 --- a/src/TableProvider.js +++ b/src/TableProvider.js @@ -1,42 +1,69 @@ -import React, { Component } from 'react'; import _ from 'lodash'; +import React, { Component, useState } from 'react'; +import { getInitialVisibleColumns, calculatePaginationProps, calculateWidth } from './utils'; -const ConfigContext = React.createContext({}); +const TableContext = React.createContext(null); -const TableProvider = ({ config, children }) => ( - { children } -); +export const TableProvider = ({ config = {}, tableData = {}, action, thunk, children }) => { + const [ isPrinting, setIsPrinting ] = useState(false); + const [ visibleColumnIds, setVisibleColumnIds ] = useState(getInitialVisibleColumns(config.components.table)); + const [ isEditing, setIsEditing ] = useState(!!config.isEditing); + const [ minWidth ] = useState(calculateWidth(config.components.table)); -export const TableConsumer = ({ children }) => ( - - { (config) => ( - children({ config }) - )} - -); + return ( + + { children } + + ) +} -export const withTableConfig = ( paths ) => ( WrappedComponent ) => { - const ComponentWithConfig = ( props ) => ( - - { (config) => { - var tableConfig = {}; - if(_.isObject(paths)) { - _.forEach(paths, ( value, key ) => { - tableConfig = { - ...tableConfig, - [key]: _.get(config.config, value) - }; - }); - } else { - tableConfig = paths ? _.get(config.config, paths, false) : config; - } - return ; - } } - - ); +// const ConfigContext = React.createContext({}); - return ComponentWithConfig; -}; +// const TableProvider = ({ config, children }) => ( +// { children } +// ); +// +// export const TableConsumer = ({ children }) => ( +// +// { (config) => ( +// children({ config }) +// )} +// +// ); -export default TableProvider; +// export const withTableConfig = ( paths ) => ( WrappedComponent ) => { +// const ComponentWithConfig = ( props ) => ( +// +// { (config) => { +// var tableConfig = {}; +// if(_.isObject(paths)) { +// _.forEach(paths, ( value, key ) => { +// tableConfig = { +// ...tableConfig, +// [key]: _.get(config.config, value) +// }; +// }); +// } else { +// tableConfig = paths ? _.get(config.config, paths, false) : config; +// } +// +// return ; +// } } +// +// ); +// +// return ComponentWithConfig; +// }; +// +export default TableContext; diff --git a/src/Renderer/Body/Actions.js b/src/components/Body/Actions.js similarity index 94% rename from src/Renderer/Body/Actions.js rename to src/components/Body/Actions.js index 3b4fbb5..4674186 100644 --- a/src/Renderer/Body/Actions.js +++ b/src/components/Body/Actions.js @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import React, { Component } from 'react'; import { deleteData } from '../../actions'; import { paramsResolver, prepareActionPayload, isUndefined } from '../../utils'; -import Button from '../../components/Button'; +import Button from '../../styled-components/Button'; const Actions = ({ extra, diff --git a/src/Renderer/Body/Date.js b/src/components/Body/Date.js similarity index 90% rename from src/Renderer/Body/Date.js rename to src/components/Body/Date.js index 88a2668..0705afb 100644 --- a/src/Renderer/Body/Date.js +++ b/src/components/Body/Date.js @@ -1,8 +1,8 @@ import _ from 'lodash'; import Time, { format as formatDate } from 'react-pure-time'; import React, { Fragment } from 'react'; -import Field from '../../components/Field'; -import Row from '../../components/Row'; +import Field from '../../styled-components/Field'; +import Row from '../../styled-components/Row'; const Date = ({ data, diff --git a/src/Renderer/Body/Image.js b/src/components/Body/Image.js similarity index 100% rename from src/Renderer/Body/Image.js rename to src/components/Body/Image.js diff --git a/src/Renderer/Body/Options.js b/src/components/Body/Options.js similarity index 92% rename from src/Renderer/Body/Options.js rename to src/components/Body/Options.js index 49559eb..b581c78 100644 --- a/src/Renderer/Body/Options.js +++ b/src/components/Body/Options.js @@ -1,8 +1,8 @@ import _ from 'lodash'; import Time from 'react-pure-time'; import React, { Fragment } from 'react'; -import Field from '../../components/Field'; -import Row from '../../components/Row'; +import Field from '../../styled-components/Field'; +import Row from '../../styled-components/Row'; const Options = ({ data, diff --git a/src/Renderer/Body/Selection.js b/src/components/Body/Selection.js similarity index 95% rename from src/Renderer/Body/Selection.js rename to src/components/Body/Selection.js index 899e20f..2e21cd2 100644 --- a/src/Renderer/Body/Selection.js +++ b/src/components/Body/Selection.js @@ -3,7 +3,7 @@ import React from 'react'; import { SET_SELECTION } from '../../actions'; import { getParam, getConfigParam } from '../../utils'; import { SELECT_ALL } from '../../constants'; -import Field from '../../components/Field'; +import Field from '../../styled-components/Field'; const handleSelection = ({ data, indexField, action }, event ) => { let paramKey = getConfigParam(indexField); diff --git a/src/Renderer/Body/Text.js b/src/components/Body/Text.js similarity index 88% rename from src/Renderer/Body/Text.js rename to src/components/Body/Text.js index b907cfb..d8a0c09 100644 --- a/src/Renderer/Body/Text.js +++ b/src/components/Body/Text.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import React, { Fragment } from 'react'; -import Field from '../../components/Field'; -import Row from '../../components/Row'; +import Field from '../../styled-components/Field'; +import Row from '../../styled-components/Row'; const Text = ({ data, diff --git a/src/components/Body/index.js b/src/components/Body/index.js new file mode 100644 index 0000000..273aeb9 --- /dev/null +++ b/src/components/Body/index.js @@ -0,0 +1,6 @@ +export Actions from './Actions'; +export Date from './Date'; +export Image from './Image'; +export Options from './Options'; +export Selection from './Selection'; +export Text from './Text'; diff --git a/src/components/Button.js b/src/components/Button.js index 59102ff..4a6ab17 100644 --- a/src/components/Button.js +++ b/src/components/Button.js @@ -1,72 +1,19 @@ import React from 'react'; -import styled, { css } from 'styled-components'; - -const Button = styled.button ` - display: inline-block; - transition: color 0.15s ease-in-out, - background-color 0.15s ease-in-out, - border-color 0.15s ease-in-out, - box-shadow 0.15s ease-in-out; - vertical-align: middle; - white-space: nowrap; - - ${({ - background = '#fff', - border = '1px solid rgba(34,36,38,.15)', - fontWeight = 400, - lineHeight = 1.5, - fontSize = '14px', - borderRadius = 0, - color = '#6c757d', - padding = '0.375rem 0.75rem', - dropdownToggle = false, - hover = {}, - active, - disabled = false, - }) => css ` - background: ${background}; - border: ${border}; - font-weight: ${fontWeight}; - line-height: ${lineHeight}; - font-size: ${fontSize}; - border-radius: ${borderRadius}; - color: ${color}; - padding: ${padding}; - - ${dropdownToggle && ` - &::after { - display: inline-block; - width: 0; - height: 0; - vertical-align: middle; - content: ''; - border-top: 0.3em solid; - border-right: 0.3rem solid transparent; - border-bottom: 0; - border-left: 0.3rem solid transparent; - margin-left: 0.255rem; - } - `}; - - ${!disabled && !active && css ` - cursor: pointer; - - &:hover { - color: ${hover.color || '#fff'}; - background-color: ${hover.backgroundColor || '#5a6268'}; - } - `}; - - ${active && css ` - background: ${props => props.activeBackground || '#007bff'}; - color: ${props => props.activeColor || '#fff'}; - font-weight: ${props => props.activeFontWeight || 'normal'}; - `}; - - ${disabled && css ` - opacity: 0.5; - `}; - `} -`; +import StyledButton from '../styled-components/Button'; + +const Button = (props) => { + const { config, thunk } = props; + const { thunk: cb, label, name } = config; + return ( + + { label } + + ); +}; + +Button.mapPropsToComponent = ({ thunk }) => ({ thunk }); export default Button; diff --git a/src/Renderer/Toolbar/Columns.js b/src/components/Columns.js similarity index 91% rename from src/Renderer/Toolbar/Columns.js rename to src/components/Columns.js index 6350a1c..422241b 100644 --- a/src/Renderer/Toolbar/Columns.js +++ b/src/components/Columns.js @@ -1,8 +1,8 @@ import ReactDOM from 'react-dom'; import React, { Component } from 'react'; -import Button from '../../components/Button'; -import Dropdown from '../../components/Dropdown'; -import { ADD_COLUMN, REMOVE_COLUMN } from '../../constants'; +import Button from '../styled-components/Button'; +import Dropdown from '../styled-components/Dropdown'; +import { ADD_COLUMN, REMOVE_COLUMN } from '../constants'; class Columns extends Component { constructor(props) { @@ -71,7 +71,7 @@ class Columns extends Component { render() { const { - itemConfig: { style = {} }, + config: { style = {} }, columns = [], visibleColumns = [] } = this.props; @@ -99,4 +99,9 @@ class Columns extends Component { } } +Columns.mapPropsToComponent = ({ + config: { columns }, + visibleColumns +}) => ({ columns, }); + export default Columns; diff --git a/src/Renderer/Toolbar/EditableButtons.js b/src/components/Editable.js similarity index 51% rename from src/Renderer/Toolbar/EditableButtons.js rename to src/components/Editable.js index 4aad242..f60fda1 100644 --- a/src/Renderer/Toolbar/EditableButtons.js +++ b/src/components/Editable.js @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; -import Button from '../../components/Button'; -import { TOGGLE_EDITABLE } from '../../constants'; +import Button from '../styled-components/Button'; +import { TOGGLE_EDITABLE } from '../constants'; const defaultLabels = { show: 'Make editable', @@ -8,12 +8,12 @@ const defaultLabels = { save: 'Save' }; -const EditableButtons = ({ itemConfig, isModified, isEditable, isEditing, internalStateUpdater, thunk }) => { - const { save } = itemConfig; - const labels = _.merge(defaultLabels, itemConfig.labels); - const toggleEditable = () => internalStateUpdater({ type: TOGGLE_EDITABLE }); +const Editable = ({ config, isModified, isEditing, setIsEditing, thunk }) => { + const { save } = config; + const labels = _.merge(defaultLabels, config.labels); + const toggleEditable = () => setIsEditing(state => !state); const getEditableLabel = () => !isEditing ? labels.show : labels.hide; - return isEditable && ( + return ( { !isModified && ( )} { isModified && ( - )} @@ -29,4 +29,10 @@ const EditableButtons = ({ itemConfig, isModified, isEditable, isEditing, intern ); }; -export default EditableButtons; +Editable.mapPropsToComponent = ({ + thunk, + tableData, + editing: [ isEditing, setIsEditing ] +}) => ({ isEditing, setIsEditing, thunk, isModified: tableData && !_.isEmpty(tableData.modified) }); + +export default Editable; diff --git a/src/Renderer/Filter/Date.js b/src/components/Filter/Date.js similarity index 93% rename from src/Renderer/Filter/Date.js rename to src/components/Filter/Date.js index 0e5a85c..c32c2ca 100644 --- a/src/Renderer/Filter/Date.js +++ b/src/components/Filter/Date.js @@ -1,7 +1,7 @@ import React, { Fragment } from 'react'; import { OPERATOR } from '../../constants'; -import Row from '../../components/Row'; -import Field from '../../components/Field'; +import Row from '../../styled-components/Row'; +import Field from '../../styled-components/Field'; var dateFrom = null; var dateTo = null; diff --git a/src/Renderer/Filter/Number.js b/src/components/Filter/Number.js similarity index 93% rename from src/Renderer/Filter/Number.js rename to src/components/Filter/Number.js index 3565fe9..a3c953a 100644 --- a/src/Renderer/Filter/Number.js +++ b/src/components/Filter/Number.js @@ -1,7 +1,7 @@ import React, { Fragment } from 'react'; import { OPERATOR } from '../../constants'; -import Row from '../../components/Row'; -import Field from '../../components/Field'; +import Row from '../../styled-components/Row'; +import Field from '../../styled-components/Field'; var valFrom = null; var valTo = null; diff --git a/src/Renderer/Filter/Options.js b/src/components/Filter/Options.js similarity index 94% rename from src/Renderer/Filter/Options.js rename to src/components/Filter/Options.js index 4946e3a..c90f7b8 100644 --- a/src/Renderer/Filter/Options.js +++ b/src/components/Filter/Options.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import React from 'react'; import { OPERATOR } from '../../constants'; -import Field from '../../components/Field'; +import Field from '../../styled-components/Field'; const applyFilter = ( filterer, event ) => { let filter = {}; diff --git a/src/Renderer/Filter/String.js b/src/components/Filter/String.js similarity index 92% rename from src/Renderer/Filter/String.js rename to src/components/Filter/String.js index c5e1d06..b3c79cb 100644 --- a/src/Renderer/Filter/String.js +++ b/src/components/Filter/String.js @@ -1,6 +1,6 @@ import React from 'react'; import { OPERATOR } from '../../constants'; -import Field from '../../components/Field'; +import Field from '../../styled-components/Field'; const applyFilter = ( filterer, event ) => { let filter = {}; diff --git a/src/components/Filter/index.js b/src/components/Filter/index.js new file mode 100644 index 0000000..759209c --- /dev/null +++ b/src/components/Filter/index.js @@ -0,0 +1,4 @@ +export Date from './Date'; +export Number from './Number'; +export Options from './Options'; +export String from './String'; diff --git a/src/Renderer/Header/Column.js b/src/components/Header/Column.js similarity index 86% rename from src/Renderer/Header/Column.js rename to src/components/Header/Column.js index 1f27a55..eb07bb3 100644 --- a/src/Renderer/Header/Column.js +++ b/src/components/Header/Column.js @@ -1,5 +1,5 @@ import React from 'react'; -import Sortable from '../../components/Sortable'; +import Sortable from '../../styled-components/Sortable'; const Column = ({ name, label, sortable, sort, dir }) => ( { let paramKey = getConfigParam(indexField); diff --git a/src/components/Header/index.js b/src/components/Header/index.js new file mode 100644 index 0000000..06bc4c6 --- /dev/null +++ b/src/components/Header/index.js @@ -0,0 +1,2 @@ +export Column from './Column'; +export Selection from './Selection'; diff --git a/src/Renderer/Pagination/Limiter.js b/src/components/Limiter.js similarity index 64% rename from src/Renderer/Pagination/Limiter.js rename to src/components/Limiter.js index 99ff17d..09465a7 100644 --- a/src/Renderer/Pagination/Limiter.js +++ b/src/components/Limiter.js @@ -1,10 +1,14 @@ import React from 'react'; -import { SET_LIMIT } from '../../actions'; -import Field from '../../components/Field'; -import Label from '../../components/Label'; -import { isUndefined } from '../../utils'; +import { SET_LIMIT } from '../actions'; +import Field from '../styled-components/Field'; +import Label from '../styled-components/Label'; +import { isUndefined } from '../utils'; -const Limiter = ({ options, limit, action, style }) => { +const Limiter = ({ + config: { options }, + limit, + action +}) => { const setLimit = ( limit ) => action(SET_LIMIT)({ limit }); return (