From 656e4163cfcf66de212fd3b8a7c2abe9366c614e Mon Sep 17 00:00:00 2001 From: piouson Date: Mon, 27 Jul 2020 05:28:24 +0100 Subject: [PATCH 1/2] feat: add search function for all records - [x] add generic search function - [x] add generic pagination - [x] add applications record search - [x] add msadmins record search - [x] add organizations record search - [x] add plans record search - [x] add selectable rows in msadmins page - [x] add delete many function to msadmins page - [x] drop application record reference to organization - [x] drop record specific ssearching Resolve #54 --- .../applications/ApplicationFilter.js | 11 ++++++++ .../applications/ApplicationList.js | 27 +++++-------------- src/components/msadmins/AdminFilter.js | 12 +++++++++ src/components/msadmins/AdminList.js | 25 +++++------------ src/components/msadmins/AdminShow.js | 2 -- .../organizations/OrganizationFilter.js | 11 ++++++++ .../organizations/OrganizationList.js | 18 ++++--------- .../organizations/OrganizationShow.js | 4 +-- src/components/pagination/index.js | 6 +++++ src/components/plans/PlanFilter.js | 10 +++++++ src/components/plans/PlanList.js | 23 ++++------------ src/services/data-provider.js | 24 +++++++++++------ src/utils/data/admin-data.js | 6 ++++- src/utils/data/application-data.js | 8 +----- src/utils/data/organizations-data.js | 6 +---- src/utils/data/plans-data.js | 6 +---- src/utils/endpoints/admin-endpoints.js | 12 ++++----- src/utils/endpoints/application-endpoints.js | 6 ++--- .../endpoints/organizations-endpoints.js | 6 ++--- src/utils/pagination.js | 24 +++++++++++++++++ 20 files changed, 132 insertions(+), 115 deletions(-) create mode 100644 src/components/applications/ApplicationFilter.js create mode 100644 src/components/msadmins/AdminFilter.js create mode 100644 src/components/organizations/OrganizationFilter.js create mode 100644 src/components/pagination/index.js create mode 100644 src/components/plans/PlanFilter.js diff --git a/src/components/applications/ApplicationFilter.js b/src/components/applications/ApplicationFilter.js new file mode 100644 index 0000000..3f1dac1 --- /dev/null +++ b/src/components/applications/ApplicationFilter.js @@ -0,0 +1,11 @@ +import React from "react"; +import { Filter, TextInput } from "react-admin"; + +const ApplicationFilter = (props) => ( + + + + +); + +export default ApplicationFilter; diff --git a/src/components/applications/ApplicationList.js b/src/components/applications/ApplicationList.js index 72084a3..30fa7ba 100644 --- a/src/components/applications/ApplicationList.js +++ b/src/components/applications/ApplicationList.js @@ -1,17 +1,8 @@ import React from "react"; import { useMediaQuery } from "@material-ui/core"; -import { - List, - Datagrid, - TextField, - SimpleList, - Pagination, - ReferenceField, -} from "react-admin"; - -const ApplicationPagination = (props) => ( - -); +import { List, Datagrid, TextField, SimpleList } from "react-admin"; +import ApplicationFilter from "./ApplicationFilter"; +import Pagination from "../pagination"; const ApplicationList = (props) => { const isSmall = useMediaQuery((theme) => theme.breakpoints.down("sm")); @@ -20,7 +11,8 @@ const ApplicationList = (props) => { } + pagination={} + filters={} {...props} > {isSmall ? ( @@ -31,14 +23,7 @@ const ApplicationList = (props) => { ) : ( - - - + )} diff --git a/src/components/msadmins/AdminFilter.js b/src/components/msadmins/AdminFilter.js new file mode 100644 index 0000000..6860e74 --- /dev/null +++ b/src/components/msadmins/AdminFilter.js @@ -0,0 +1,12 @@ +import React from "react"; +import { Filter, TextInput } from "react-admin"; + +const AdminFilter = (props) => ( + + + + + +); + +export default AdminFilter; diff --git a/src/components/msadmins/AdminList.js b/src/components/msadmins/AdminList.js index 476130e..158a3e0 100644 --- a/src/components/msadmins/AdminList.js +++ b/src/components/msadmins/AdminList.js @@ -1,22 +1,8 @@ import React from "react"; import { useMediaQuery } from "@material-ui/core"; -import { - List, - Datagrid, - TextField, - EmailField, - SimpleList, - TopToolbar, - ExportButton, - CreateButton, -} from "react-admin"; - -const AdminListActions = ({ basePath, data, resource }) => ( - - - - -); +import { List, Datagrid, TextField, EmailField, SimpleList } from "react-admin"; +import Pagination from "../pagination"; +import AdminFilter from "./AdminFilter"; const AdminList = (props) => { const isSmall = useMediaQuery((theme) => theme.breakpoints.down("sm")); @@ -25,7 +11,8 @@ const AdminList = (props) => { } + pagination={} + filters={} {...props} > {isSmall ? ( @@ -36,7 +23,7 @@ const AdminList = (props) => { tertiaryText={(record) => record.role} /> ) : ( - false}> + diff --git a/src/components/msadmins/AdminShow.js b/src/components/msadmins/AdminShow.js index 6dccbf2..668f2cd 100644 --- a/src/components/msadmins/AdminShow.js +++ b/src/components/msadmins/AdminShow.js @@ -5,12 +5,10 @@ import { TextField, TopToolbar, DeleteButton, - EditButton, } from "react-admin"; const AdminShowActions = ({ basePath, data, resource }) => ( - ); diff --git a/src/components/organizations/OrganizationFilter.js b/src/components/organizations/OrganizationFilter.js new file mode 100644 index 0000000..826c24d --- /dev/null +++ b/src/components/organizations/OrganizationFilter.js @@ -0,0 +1,11 @@ +import React from "react"; +import { Filter, TextInput } from "react-admin"; + +const OrganizationFilter = (props) => ( + + + + +); + +export default OrganizationFilter; diff --git a/src/components/organizations/OrganizationList.js b/src/components/organizations/OrganizationList.js index 134a59d..25c3798 100644 --- a/src/components/organizations/OrganizationList.js +++ b/src/components/organizations/OrganizationList.js @@ -1,17 +1,8 @@ import React from "react"; import { useMediaQuery } from "@material-ui/core"; -import { - List, - Datagrid, - TextField, - EmailField, - SimpleList, - Pagination, -} from "react-admin"; - -const OrganizationPagination = (props) => ( - -); +import { List, Datagrid, TextField, EmailField, SimpleList } from "react-admin"; +import OrganizationFilter from "./OrganizationFilter"; +import Pagination from "../pagination"; const OrganizationList = (props) => { const isSmall = useMediaQuery((theme) => theme.breakpoints.down("sm")); @@ -20,7 +11,8 @@ const OrganizationList = (props) => { } + pagination={} + filters={} {...props} > {isSmall ? ( diff --git a/src/components/organizations/OrganizationShow.js b/src/components/organizations/OrganizationShow.js index 0991945..84110d5 100644 --- a/src/components/organizations/OrganizationShow.js +++ b/src/components/organizations/OrganizationShow.js @@ -38,8 +38,8 @@ const OrganizationShow = (props) => { ( + +); diff --git a/src/components/plans/PlanFilter.js b/src/components/plans/PlanFilter.js new file mode 100644 index 0000000..7593a85 --- /dev/null +++ b/src/components/plans/PlanFilter.js @@ -0,0 +1,10 @@ +import React from "react"; +import { Filter, TextInput } from "react-admin"; + +const PlanFilter = (props) => ( + + + +); + +export default PlanFilter; diff --git a/src/components/plans/PlanList.js b/src/components/plans/PlanList.js index 4b81685..d617c02 100644 --- a/src/components/plans/PlanList.js +++ b/src/components/plans/PlanList.js @@ -1,21 +1,8 @@ import React from "react"; import { useMediaQuery } from "@material-ui/core"; -import { - List, - Datagrid, - TextField, - SimpleList, - TopToolbar, - CreateButton, - ExportButton, -} from "react-admin"; - -const PlanListActions = ({ basePath, data, resource }) => ( - - - - -); +import { List, Datagrid, TextField, SimpleList } from "react-admin"; +import Pagination from "../pagination"; +import PlanFilter from "./PlanFilter"; const PlanList = (props) => { const isSmall = useMediaQuery((theme) => theme.breakpoints.down("sm")); @@ -24,8 +11,8 @@ const PlanList = (props) => { } - pagination={null} + pagination={} + filters={} {...props} > {isSmall ? ( diff --git a/src/services/data-provider.js b/src/services/data-provider.js index 6cbea3e..32dbe20 100644 --- a/src/services/data-provider.js +++ b/src/services/data-provider.js @@ -1,7 +1,7 @@ import { fetchUtils } from "react-admin"; import endpoints from "../utils/endpoints"; import { stringify } from "querystring"; -import getPaginateQuery from "../utils/pagination"; +import getPaginateQuery, { filter } from "../utils/pagination"; import handleProfileData from "../utils/data/profile-data"; import { GET_LIST, @@ -29,7 +29,7 @@ export default { const endpoint = endpoints(GET_LIST, resource, params); return httpClient(`${endpoint.url}?${stringify(query)}`).then( ({ json }) => ({ - data: endpoint.getData(json.data), + data: filter(endpoint.getData(json.data), params), total: json.data.pageInfo ? json.data.pageInfo.totalRecord : json.data.length, @@ -56,12 +56,20 @@ export default { getManyReference: (resource, params) => { const endpoint = endpoints(GET_MANY_REFERENCE, resource, params); - return httpClient(endpoint.url).then(({ json }) => ({ - data: endpoint.getData(json.data, endpoint.target, endpoint.targetId), - total: json.data.pageInfo - ? json.data.pageInfo.totalRecord - : json.data.length, - })); + console.log("REFERENCE", params); + const query = { + limit: 50, + sort: "ASC", + page: 1, + }; + return httpClient(`${endpoint.url}?${stringify(query)}`).then( + ({ json }) => ({ + data: endpoint.getData(json.data, endpoint.target, endpoint.targetId), + total: json.data.pageInfo + ? json.data.pageInfo.totalRecord + : json.data.length, + }) + ); }, update: (resource, params) => { diff --git a/src/utils/data/admin-data.js b/src/utils/data/admin-data.js index 211208f..dab7c5e 100644 --- a/src/utils/data/admin-data.js +++ b/src/utils/data/admin-data.js @@ -1,6 +1,10 @@ export default (data) => { if (data.records && Array.isArray(data.records)) { - return data.records.map((item) => ({ id: item.msAdminId, ...item })); + const profile = localStorage.getItem("profile"); + const currentUserId = JSON.parse(profile).msAdminId; + return data.records + .filter((admin) => admin.msAdminId !== currentUserId) + .map((item) => ({ id: item.msAdminId, ...item })); } else if (data.msAdminId) { return { id: data.msAdminId, ...data }; } diff --git a/src/utils/data/application-data.js b/src/utils/data/application-data.js index d2d7084..22d9fcc 100644 --- a/src/utils/data/application-data.js +++ b/src/utils/data/application-data.js @@ -1,14 +1,8 @@ -const getApplicationsData = (data, target, id) => { +const getApplicationsData = (data) => { let mappedData = data; if (Array.isArray(data.records) && data.records[0].applicationId) { mappedData = data.records.map(mapApplicationIdToId); - - if (target && id) { - mappedData = mappedData.filter((item) => { - return item[target]._id === id; - }); - } } return mappedData; diff --git a/src/utils/data/organizations-data.js b/src/utils/data/organizations-data.js index e0c2806..7674bb7 100644 --- a/src/utils/data/organizations-data.js +++ b/src/utils/data/organizations-data.js @@ -1,14 +1,10 @@ -const getOrganizationsData = (data, target, id) => { +const getOrganizationsData = (data) => { let mappedData = data; if (Array.isArray(data.records) && data.records[0].organizationId) { mappedData = data.records.map(mapOrganizationIdToId); } - if (target && id) { - mappedData = mappedData.filter((item) => item[target] === id); - } - return mappedData; }; diff --git a/src/utils/data/plans-data.js b/src/utils/data/plans-data.js index f88836f..6cfaa60 100644 --- a/src/utils/data/plans-data.js +++ b/src/utils/data/plans-data.js @@ -1,4 +1,4 @@ -const getPlansData = (data, target, id) => { +const getPlansData = (data) => { let mappedData = data; if (Array.isArray(data) && data[0].planId) { @@ -7,10 +7,6 @@ const getPlansData = (data, target, id) => { mappedData = mapPlanIdToId(data); } - if (target && id) { - mappedData = mappedData.filter((item) => item[target] === id); - } - return mappedData; }; diff --git a/src/utils/endpoints/admin-endpoints.js b/src/utils/endpoints/admin-endpoints.js index 821a484..8b00abc 100644 --- a/src/utils/endpoints/admin-endpoints.js +++ b/src/utils/endpoints/admin-endpoints.js @@ -6,7 +6,7 @@ import { UPDATE, DELETE, GET_MANY, - GET_MANY_REFERENCE, + DELETE_MANY, } from "react-admin"; const apiUrl = "https://comments-microservice.herokuapp.com/v1"; @@ -28,11 +28,6 @@ export default (type, params) => { url: `${apiUrl}/msadmins`, getData: getData, }; - case GET_MANY_REFERENCE: - return { - url: `${apiUrl}/msadmins`, - getData: getData, - }; case UPDATE: return { url: `${apiUrl}/msadmins`, @@ -57,6 +52,11 @@ export default (type, params) => { options: { method: "DELETE" }, getData: getData, }; + case DELETE_MANY: + return { + urls: params.ids.map((id) => `${apiUrl}/msadmins/${id}`), + getData: getData, + }; default: throw new Error(`Unsupported Admin Data Provider request type ${type}`); } diff --git a/src/utils/endpoints/application-endpoints.js b/src/utils/endpoints/application-endpoints.js index a8e8b2a..f074dcf 100644 --- a/src/utils/endpoints/application-endpoints.js +++ b/src/utils/endpoints/application-endpoints.js @@ -20,10 +20,8 @@ export default (type, params) => { }; case GET_MANY_REFERENCE: return { - url: `${apiUrl}/msadmins/applications`, - getData: (data) => { - return getData(data, params.target, params.id); - }, + url: `${apiUrl}/msadmins/applications/${params.id}`, + getData: getData, }; case GET_ONE: case DELETE: diff --git a/src/utils/endpoints/organizations-endpoints.js b/src/utils/endpoints/organizations-endpoints.js index b4c8889..a3d2111 100644 --- a/src/utils/endpoints/organizations-endpoints.js +++ b/src/utils/endpoints/organizations-endpoints.js @@ -19,10 +19,8 @@ export default (type, params) => { }; case GET_MANY_REFERENCE: return { - url: `${apiUrl}/msadmins/organizations`, - getData: (data) => { - return getData(data, params.target, params.id); - }, + url: `${apiUrl}/msadmins/organizations/${params.id}/applications`, + getData: getData, }; case GET_ONE: case DELETE: diff --git a/src/utils/pagination.js b/src/utils/pagination.js index ade1ae7..0040c41 100644 --- a/src/utils/pagination.js +++ b/src/utils/pagination.js @@ -8,3 +8,27 @@ export default (params) => { page: page, }; }; + +export const filter = (data, params) => { + const filter = params ? params.filter : {}; + if (Object.keys(filter).length) { + return Object.keys(filter).reduce( + (acc, key) => + acc.filter((item) => RegExp(filter[key], "i").test(item[key])), + data + ); + } + return data; +}; + +export const sortData = (data, params) => { + const sort = params.sort; + if (sort) { + return [].concat(data).sort((a, b) => { + return isNaN(a[sort.field]) + ? a[sort.field].localeCompare(b[sort.field]) + : a - b; + }); + } + return data; +}; From d6b3845fbc7d49a60febe4f78a3e53c08e509758 Mon Sep 17 00:00:00 2001 From: piouson Date: Mon, 27 Jul 2020 15:17:28 +0100 Subject: [PATCH 2/2] Add filter as reusable component --- .gitignore | 1 + .gitpod.yml | 18 ++++++++++++++++ .../applications/ApplicationFilter.js | 11 ---------- .../applications/ApplicationList.js | 17 ++++++++++++--- src/components/msadmins/AdminList.js | 21 ++++++++++++++++--- .../organizations/OrganizationList.js | 17 ++++++++++++--- src/components/pagination/Filter.js | 14 +++++++++++++ .../pagination/{index.js => Pagination.js} | 0 src/components/plans/PlanList.js | 17 ++++++++++++--- src/utils/data/admin-data.js | 2 +- 10 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 .gitpod.yml delete mode 100644 src/components/applications/ApplicationFilter.js create mode 100644 src/components/pagination/Filter.js rename src/components/pagination/{index.js => Pagination.js} (100%) diff --git a/.gitignore b/.gitignore index 5d716fe..dc128f0 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ .env.test.local .env.production.local +debug.log npm-debug.log* yarn-debug.log* yarn-error.log* diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..34905a3 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,18 @@ +tasks: + - init: npm install + command: echo DANGEROUSLY_DISABLE_HOST_CHECK=true >> .env + command: npm start +ports: + - port: 3000 + onOpen: open-preview +github: + prebuilds: + master: true + branches: true + pullRequests: true + pullRequestsFromForks: true + addCheck: true + addComment: true + addBadge: false + addLabel: false + \ No newline at end of file diff --git a/src/components/applications/ApplicationFilter.js b/src/components/applications/ApplicationFilter.js deleted file mode 100644 index 3f1dac1..0000000 --- a/src/components/applications/ApplicationFilter.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; -import { Filter, TextInput } from "react-admin"; - -const ApplicationFilter = (props) => ( - - - - -); - -export default ApplicationFilter; diff --git a/src/components/applications/ApplicationList.js b/src/components/applications/ApplicationList.js index 30fa7ba..9d60984 100644 --- a/src/components/applications/ApplicationList.js +++ b/src/components/applications/ApplicationList.js @@ -1,18 +1,29 @@ import React from "react"; import { useMediaQuery } from "@material-ui/core"; import { List, Datagrid, TextField, SimpleList } from "react-admin"; -import ApplicationFilter from "./ApplicationFilter"; -import Pagination from "../pagination"; +import Pagination from "../pagination/Pagination"; +import Filter from "../pagination/Filter"; const ApplicationList = (props) => { const isSmall = useMediaQuery((theme) => theme.breakpoints.down("sm")); + const filters = [ + { + label: "Filter by name", + source: "applicationName", + alwaysOn: true, + }, + { + label: "Filter by organization", + source: "organizationName", + }, + ]; return ( } - filters={} + filters={} {...props} > {isSmall ? ( diff --git a/src/components/msadmins/AdminList.js b/src/components/msadmins/AdminList.js index 158a3e0..942c9a8 100644 --- a/src/components/msadmins/AdminList.js +++ b/src/components/msadmins/AdminList.js @@ -1,18 +1,33 @@ import React from "react"; import { useMediaQuery } from "@material-ui/core"; import { List, Datagrid, TextField, EmailField, SimpleList } from "react-admin"; -import Pagination from "../pagination"; -import AdminFilter from "./AdminFilter"; +import Pagination from "../pagination/Pagination"; +import Filter from "../pagination/Filter"; const AdminList = (props) => { const isSmall = useMediaQuery((theme) => theme.breakpoints.down("sm")); + const filters = [ + { + label: "Filter by name", + source: "fullname", + alwaysOn: true, + }, + { + label: "Filter by email", + source: "email", + }, + { + label: "Filter by role", + source: "role", + }, + ]; return ( } - filters={} + filters={} {...props} > {isSmall ? ( diff --git a/src/components/organizations/OrganizationList.js b/src/components/organizations/OrganizationList.js index 25c3798..8ab488d 100644 --- a/src/components/organizations/OrganizationList.js +++ b/src/components/organizations/OrganizationList.js @@ -1,18 +1,29 @@ import React from "react"; import { useMediaQuery } from "@material-ui/core"; import { List, Datagrid, TextField, EmailField, SimpleList } from "react-admin"; -import OrganizationFilter from "./OrganizationFilter"; -import Pagination from "../pagination"; +import Pagination from "../pagination/Pagination"; +import Filter from "../pagination/Filter"; const OrganizationList = (props) => { const isSmall = useMediaQuery((theme) => theme.breakpoints.down("sm")); + const filters = [ + { + label: "Filter by name", + source: "organizationName", + alwaysOn: true, + }, + { + label: "Filter by email", + source: "organizationEmail", + }, + ]; return ( } - filters={} + filters={} {...props} > {isSmall ? ( diff --git a/src/components/pagination/Filter.js b/src/components/pagination/Filter.js new file mode 100644 index 0000000..30b81f1 --- /dev/null +++ b/src/components/pagination/Filter.js @@ -0,0 +1,14 @@ +import React from "react"; +import { Filter, TextInput } from "react-admin"; + +export default ({ filters, ...props }) => ( + + {filters.map((filter) => ( + + ))} + +); diff --git a/src/components/pagination/index.js b/src/components/pagination/Pagination.js similarity index 100% rename from src/components/pagination/index.js rename to src/components/pagination/Pagination.js diff --git a/src/components/plans/PlanList.js b/src/components/plans/PlanList.js index d617c02..d6b7edc 100644 --- a/src/components/plans/PlanList.js +++ b/src/components/plans/PlanList.js @@ -1,18 +1,29 @@ import React from "react"; import { useMediaQuery } from "@material-ui/core"; import { List, Datagrid, TextField, SimpleList } from "react-admin"; -import Pagination from "../pagination"; -import PlanFilter from "./PlanFilter"; +import Pagination from "../pagination/Pagination"; +import Filter from "../pagination/Filter"; const PlanList = (props) => { const isSmall = useMediaQuery((theme) => theme.breakpoints.down("sm")); + const filters = [ + { + label: "Filter by name", + source: "organizationName", + alwaysOn: true, + }, + { + label: "Filter by email", + source: "organizationEmail", + }, + ]; return ( } - filters={} + filters={} {...props} > {isSmall ? ( diff --git a/src/utils/data/admin-data.js b/src/utils/data/admin-data.js index dab7c5e..278d00f 100644 --- a/src/utils/data/admin-data.js +++ b/src/utils/data/admin-data.js @@ -1,5 +1,5 @@ export default (data) => { - if (data.records && Array.isArray(data.records)) { + if (Array.isArray(data.records)) { const profile = localStorage.getItem("profile"); const currentUserId = JSON.parse(profile).msAdminId; return data.records