├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── index.ts └── providers │ ├── authProvider.ts │ └── dataProvider.ts ├── tsconfig.json ├── tsconfig.node.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | *.env 15 | *.db-shm 16 | *.db-wal 17 | 18 | # Editor directories and files 19 | .vscode/* 20 | !.vscode/extensions.json 21 | .idea 22 | .DS_Store 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 2.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 4 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION 5 | OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial content 12 | Distributed under this Agreement, and 13 | 14 | b) in the case of each subsequent Contributor: 15 | i) changes to the Program, and 16 | ii) additions to the Program; 17 | where such changes and/or additions to the Program originate from 18 | and are Distributed by that particular Contributor. A Contribution 19 | "originates" from a Contributor if it was added to the Program by 20 | such Contributor itself or anyone acting on such Contributor's behalf. 21 | Contributions do not include changes or additions to the Program that 22 | are not Modified Works. 23 | 24 | "Contributor" means any person or entity that Distributes the Program. 25 | 26 | "Licensed Patents" mean patent claims licensable by a Contributor which 27 | are necessarily infringed by the use or sale of its Contribution alone 28 | or when combined with the Program. 29 | 30 | "Program" means the Contributions Distributed in accordance with this 31 | Agreement. 32 | 33 | "Recipient" means anyone who receives the Program under this Agreement 34 | or any Secondary License (as applicable), including Contributors. 35 | 36 | "Derivative Works" shall mean any work, whether in Source Code or other 37 | form, that is based on (or derived from) the Program and for which the 38 | editorial revisions, annotations, elaborations, or other modifications 39 | represent, as a whole, an original work of authorship. 40 | 41 | "Modified Works" shall mean any work in Source Code or other form that 42 | results from an addition to, deletion from, or modification of the 43 | contents of the Program, including, for purposes of clarity any new file 44 | in Source Code form that contains any contents of the Program. Modified 45 | Works shall not include works that contain only declarations, 46 | interfaces, types, classes, structures, or files of the Program solely 47 | in each case in order to link to, bind by name, or subclass the Program 48 | or Modified Works thereof. 49 | 50 | "Distribute" means the acts of a) distributing or b) making available 51 | in any manner that enables the transfer of a copy. 52 | 53 | "Source Code" means the form of a Program preferred for making 54 | modifications, including but not limited to software source code, 55 | documentation source, and configuration files. 56 | 57 | "Secondary License" means either the GNU General Public License, 58 | Version 2.0, or any later versions of that license, including any 59 | exceptions or additional permissions as identified by the initial 60 | Contributor. 61 | 62 | 2. GRANT OF RIGHTS 63 | 64 | a) Subject to the terms of this Agreement, each Contributor hereby 65 | grants Recipient a non-exclusive, worldwide, royalty-free copyright 66 | license to reproduce, prepare Derivative Works of, publicly display, 67 | publicly perform, Distribute and sublicense the Contribution of such 68 | Contributor, if any, and such Derivative Works. 69 | 70 | b) Subject to the terms of this Agreement, each Contributor hereby 71 | grants Recipient a non-exclusive, worldwide, royalty-free patent 72 | license under Licensed Patents to make, use, sell, offer to sell, 73 | import and otherwise transfer the Contribution of such Contributor, 74 | if any, in Source Code or other form. This patent license shall 75 | apply to the combination of the Contribution and the Program if, at 76 | the time the Contribution is added by the Contributor, such addition 77 | of the Contribution causes such combination to be covered by the 78 | Licensed Patents. The patent license shall not apply to any other 79 | combinations which include the Contribution. No hardware per se is 80 | licensed hereunder. 81 | 82 | c) Recipient understands that although each Contributor grants the 83 | licenses to its Contributions set forth herein, no assurances are 84 | provided by any Contributor that the Program does not infringe the 85 | patent or other intellectual property rights of any other entity. 86 | Each Contributor disclaims any liability to Recipient for claims 87 | brought by any other entity based on infringement of intellectual 88 | property rights or otherwise. As a condition to exercising the 89 | rights and licenses granted hereunder, each Recipient hereby 90 | assumes sole responsibility to secure any other intellectual 91 | property rights needed, if any. For example, if a third party 92 | patent license is required to allow Recipient to Distribute the 93 | Program, it is Recipient's responsibility to acquire that license 94 | before distributing the Program. 95 | 96 | d) Each Contributor represents that to its knowledge it has 97 | sufficient copyright rights in its Contribution, if any, to grant 98 | the copyright license set forth in this Agreement. 99 | 100 | e) Notwithstanding the terms of any Secondary License, no 101 | Contributor makes additional grants to any Recipient (other than 102 | those set forth in this Agreement) as a result of such Recipient's 103 | receipt of the Program under the terms of a Secondary License 104 | (if permitted under the terms of Section 3). 105 | 106 | 3. REQUIREMENTS 107 | 108 | 3.1 If a Contributor Distributes the Program in any form, then: 109 | 110 | a) the Program must also be made available as Source Code, in 111 | accordance with section 3.2, and the Contributor must accompany 112 | the Program with a statement that the Source Code for the Program 113 | is available under this Agreement, and informs Recipients how to 114 | obtain it in a reasonable manner on or through a medium customarily 115 | used for software exchange; and 116 | 117 | b) the Contributor may Distribute the Program under a license 118 | different than this Agreement, provided that such license: 119 | i) effectively disclaims on behalf of all other Contributors all 120 | warranties and conditions, express and implied, including 121 | warranties or conditions of title and non-infringement, and 122 | implied warranties or conditions of merchantability and fitness 123 | for a particular purpose; 124 | 125 | ii) effectively excludes on behalf of all other Contributors all 126 | liability for damages, including direct, indirect, special, 127 | incidental and consequential damages, such as lost profits; 128 | 129 | iii) does not attempt to limit or alter the recipients' rights 130 | in the Source Code under section 3.2; and 131 | 132 | iv) requires any subsequent distribution of the Program by any 133 | party to be under a license that satisfies the requirements 134 | of this section 3. 135 | 136 | 3.2 When the Program is Distributed as Source Code: 137 | 138 | a) it must be made available under this Agreement, or if the 139 | Program (i) is combined with other material in a separate file or 140 | files made available under a Secondary License, and (ii) the initial 141 | Contributor attached to the Source Code the notice described in 142 | Exhibit A of this Agreement, then the Program may be made available 143 | under the terms of such Secondary Licenses, and 144 | 145 | b) a copy of this Agreement must be included with each copy of 146 | the Program. 147 | 148 | 3.3 Contributors may not remove or alter any copyright, patent, 149 | trademark, attribution notices, disclaimers of warranty, or limitations 150 | of liability ("notices") contained within the Program from any copy of 151 | the Program which they Distribute, provided that Contributors may add 152 | their own appropriate notices. 153 | 154 | 4. COMMERCIAL DISTRIBUTION 155 | 156 | Commercial distributors of software may accept certain responsibilities 157 | with respect to end users, business partners and the like. While this 158 | license is intended to facilitate the commercial use of the Program, 159 | the Contributor who includes the Program in a commercial product 160 | offering should do so in a manner which does not create potential 161 | liability for other Contributors. Therefore, if a Contributor includes 162 | the Program in a commercial product offering, such Contributor 163 | ("Commercial Contributor") hereby agrees to defend and indemnify every 164 | other Contributor ("Indemnified Contributor") against any losses, 165 | damages and costs (collectively "Losses") arising from claims, lawsuits 166 | and other legal actions brought by a third party against the Indemnified 167 | Contributor to the extent caused by the acts or omissions of such 168 | Commercial Contributor in connection with its distribution of the Program 169 | in a commercial product offering. The obligations in this section do not 170 | apply to any claims or Losses relating to any actual or alleged 171 | intellectual property infringement. In order to qualify, an Indemnified 172 | Contributor must: a) promptly notify the Commercial Contributor in 173 | writing of such claim, and b) allow the Commercial Contributor to control, 174 | and cooperate with the Commercial Contributor in, the defense and any 175 | related settlement negotiations. The Indemnified Contributor may 176 | participate in any such claim at its own expense. 177 | 178 | For example, a Contributor might include the Program in a commercial 179 | product offering, Product X. That Contributor is then a Commercial 180 | Contributor. If that Commercial Contributor then makes performance 181 | claims, or offers warranties related to Product X, those performance 182 | claims and warranties are such Commercial Contributor's responsibility 183 | alone. Under this section, the Commercial Contributor would have to 184 | defend claims against the other Contributors related to those performance 185 | claims and warranties, and if a court requires any other Contributor to 186 | pay any damages as a result, the Commercial Contributor must pay 187 | those damages. 188 | 189 | 5. NO WARRANTY 190 | 191 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 192 | PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" 193 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 194 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF 195 | TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 196 | PURPOSE. Each Recipient is solely responsible for determining the 197 | appropriateness of using and distributing the Program and assumes all 198 | risks associated with its exercise of rights under this Agreement, 199 | including but not limited to the risks and costs of program errors, 200 | compliance with applicable laws, damage to or loss of data, programs 201 | or equipment, and unavailability or interruption of operations. 202 | 203 | 6. DISCLAIMER OF LIABILITY 204 | 205 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 206 | PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS 207 | SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 208 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST 209 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 210 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 211 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 212 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE 213 | POSSIBILITY OF SUCH DAMAGES. 214 | 215 | 7. GENERAL 216 | 217 | If any provision of this Agreement is invalid or unenforceable under 218 | applicable law, it shall not affect the validity or enforceability of 219 | the remainder of the terms of this Agreement, and without further 220 | action by the parties hereto, such provision shall be reformed to the 221 | minimum extent necessary to make such provision valid and enforceable. 222 | 223 | If Recipient institutes patent litigation against any entity 224 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 225 | Program itself (excluding combinations of the Program with other software 226 | or hardware) infringes such Recipient's patent(s), then such Recipient's 227 | rights granted under Section 2(b) shall terminate as of the date such 228 | litigation is filed. 229 | 230 | All Recipient's rights under this Agreement shall terminate if it 231 | fails to comply with any of the material terms or conditions of this 232 | Agreement and does not cure such failure in a reasonable period of 233 | time after becoming aware of such noncompliance. If all Recipient's 234 | rights under this Agreement terminate, Recipient agrees to cease use 235 | and distribution of the Program as soon as reasonably practicable. 236 | However, Recipient's obligations under this Agreement and any licenses 237 | granted by Recipient relating to the Program shall continue and survive. 238 | 239 | Everyone is permitted to copy and distribute copies of this Agreement, 240 | but in order to avoid inconsistency the Agreement is copyrighted and 241 | may only be modified in the following manner. The Agreement Steward 242 | reserves the right to publish new versions (including revisions) of 243 | this Agreement from time to time. No one other than the Agreement 244 | Steward has the right to modify this Agreement. The Eclipse Foundation 245 | is the initial Agreement Steward. The Eclipse Foundation may assign the 246 | responsibility to serve as the Agreement Steward to a suitable separate 247 | entity. Each new version of the Agreement will be given a distinguishing 248 | version number. The Program (including Contributions) may always be 249 | Distributed subject to the version of the Agreement under which it was 250 | received. In addition, after a new version of the Agreement is published, 251 | Contributor may elect to Distribute the Program (including its 252 | Contributions) under the new version. 253 | 254 | Except as expressly stated in Sections 2(a) and 2(b) above, Recipient 255 | receives no rights or licenses to the intellectual property of any 256 | Contributor under this Agreement, whether expressly, by implication, 257 | estoppel or otherwise. All rights in the Program not expressly granted 258 | under this Agreement are reserved. Nothing in this Agreement is intended 259 | to be enforceable by any entity that is not a Contributor or Recipient. 260 | No third-party beneficiary rights are created under this Agreement. 261 | 262 | Exhibit A - Form of Secondary Licenses Notice 263 | 264 | "This Source Code may also be made available under the following 265 | Secondary Licenses when the conditions for such availability set forth 266 | in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), 267 | version(s), and exceptions or additional permissions here}." 268 | 269 | Simply including a copy of this Agreement, including this Exhibit A 270 | is not sufficient to license the Source Code under Secondary Licenses. 271 | 272 | If it is not possible or desirable to put the notice in a particular 273 | file, then You may include the notice in a location (such as a LICENSE 274 | file in a relevant directory) where a recipient would be likely to 275 | look for such a notice. 276 | 277 | You may add additional accurate notices of copyright ownership. 278 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## RA-Soul-Provider 2 | 3 | ### Description 4 | 5 | `RA-Soul` is a data provider that helps you connect React Admin with [`Soul`](https://github.com/thevahidal/soul), a REST server that uses SQLite. This provider exports a list of auth provider methods and data provider methods that you can use to connect your React Admin application with `Soul`. 6 | 7 | ### Provider Methods 8 | 9 | #### Data Providers 10 | 11 | ``` 12 | - getList 13 | - getOne 14 | - getMany 15 | - getManyReference 16 | - create 17 | - update 18 | - updateMany 19 | - delete 20 | - deleteMany 21 | ``` 22 | 23 | #### Auth Providers 24 | 25 | ``` 26 | - login 27 | - logout 28 | - checkAuth 29 | - checkError 30 | - getPermissions 31 | - changePassword 32 | ``` 33 | 34 | ### Usage 35 | 36 | #### 1. Start the `Soul` server 37 | 38 | Clone the `Soul` repository and follow the instructions in the [README](https://github.com/thevahidal/soul/blob/main/README.md) to run the server. 39 | 40 | #### 2. Install the `ra-soul` provider 41 | 42 | ``` 43 | npm i ra-soul 44 | ``` 45 | 46 | #### 3. Use the provider in your React Admin application 47 | 48 | ```js 49 | import { Admin, Resource } from "react-admin"; 50 | import { dataProvider, authProvider } from "ra-soul"; 51 | 52 | import { 53 | AlbumList, 54 | AlbumShow, 55 | AlbumEdit, 56 | AlbumCreate, 57 | } from "./components/Album"; 58 | 59 | import { 60 | GenreList, 61 | GenreShow, 62 | GenreEdit, 63 | GenreCreate, 64 | } from "./components/Genre"; 65 | 66 | import { ChangePassword, Login } from "./components/auth/ChangePassword"; 67 | 68 | /** React Admin expects an id field for each resource, but if your database doesn't have an id 69 | * field in each table, then you should map your primary key for each resource 70 | **/ 71 | 72 | const primaryKeyDictionary = { 73 | albums: "AlbumId", 74 | tracks: "TrackId", 75 | genres: "GenreId", 76 | playlists: "PlayListId", 77 | }; 78 | 79 | const soulApiUrl = "http://soul.api.url/api"; 80 | 81 | function App() { 82 | return ( 83 | 88 | 95 | 96 | 103 | 104 | 105 | 106 | ); 107 | } 108 | ``` 109 | 110 | ## Running a Compiled React Admin App with Soul 111 | 112 | Soul provides a way to run a compiled version of your `React Admin` application using its `extensions` feature. To do this, build your `React Admin` app and place the compiled application inside a folder named `_extensions`. This setup will expose your compiled `React Admin` app with an endpoint accessible to the outside world. For more details about this feature, refer to [this page](https://github.com/thevahidal/soul/blob/main/docs/self-hosting.md). 113 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ra-soul", 3 | "private": false, 4 | "author": { 5 | "name": "Ian Mayo" 6 | }, 7 | "contributors": [ 8 | { 9 | "name": "Ian Mayo" 10 | } 11 | ], 12 | "description": "Data and Auth Providers to allow Soul to be used as backend for React-Admin", 13 | "version": "1.0.1", 14 | "keywords": [ 15 | "react-admin", 16 | "soul", 17 | "data-provider", 18 | "auth-provider" 19 | ], 20 | "license": "EPL-2.0", 21 | "type": "module", 22 | "module": "src/index.ts", 23 | "main": "src/index.ts", 24 | "scripts": { 25 | "start": "tsc --watch", 26 | "build": "tsc", 27 | "prepublish": "npm run build" 28 | }, 29 | "dependencies": { 30 | "axios": "^1.2.0", 31 | "jsdoc": "^4.0.0", 32 | "query-string": "^7.1.1", 33 | "react": "^18.2.0", 34 | "react-admin": "^4.16.18", 35 | "react-dom": "^18.2.0", 36 | "react-router-dom": "^6.23.1", 37 | "typescript": "^4.9.3" 38 | }, 39 | "devDependencies": { 40 | "@types/react": "^18.0.24", 41 | "@types/react-dom": "^18.0.8", 42 | "@vitejs/plugin-react": "^2.2.0", 43 | "cross-var": "^1.1.0", 44 | "dotenv-cli": "^7.2.1", 45 | "vite": "^3.2.3" 46 | }, 47 | "bugs": { 48 | "url": "https://github.com/DeepBlueCLtd/RA-Soul/issues" 49 | }, 50 | "homepage": "https://github.com/DeepBlueCLtd/RA-Soul" 51 | } 52 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { authProvider } from "./providers/authProvider"; 2 | import { dataProvider } from "./providers/dataProvider"; 3 | 4 | export { authProvider, dataProvider }; 5 | -------------------------------------------------------------------------------- /src/providers/authProvider.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { AuthProvider } from "ra-core"; 3 | 4 | const refreshToken = async (apiUrl: string) => { 5 | const url = `${apiUrl}/auth/token/refresh`; 6 | await axios.get(url, { withCredentials: true }); 7 | }; 8 | 9 | export const authProvider = (apiUrl: any): AuthProvider => ({ 10 | login: ({ username, password }) => { 11 | const url = `${apiUrl}/auth/token/obtain`; 12 | 13 | return axios 14 | .post(url, { fields: { username, password } }, { withCredentials: true }) 15 | .then((response) => { 16 | return Promise.resolve(); 17 | }) 18 | .catch((error) => { 19 | return Promise.reject(error); 20 | }); 21 | }, 22 | 23 | logout: () => { 24 | const url = `${apiUrl}/auth/logout`; 25 | 26 | return axios 27 | .get(url, { withCredentials: true }) 28 | .then((response) => { 29 | return Promise.resolve(); 30 | }) 31 | .catch((error) => { 32 | return Promise.resolve(); 33 | }); 34 | }, 35 | 36 | checkAuth: () => { 37 | return Promise.resolve(); 38 | }, 39 | 40 | checkError: async (error) => { 41 | const status = error.response.status; 42 | 43 | if (status === 401 || status === 403) { 44 | //if access token is expired then send a request to refresh the access token 45 | try { 46 | await refreshToken(apiUrl); 47 | return Promise.resolve(); 48 | } catch (err) { 49 | return Promise.reject(); 50 | } 51 | } 52 | 53 | return Promise.resolve(); 54 | }, 55 | 56 | getPermissions: () => Promise.resolve(), 57 | 58 | changePassword: (currentPassword: string, newPassword: string) => { 59 | const url = `${apiUrl}/auth/change-password`; 60 | 61 | return axios 62 | .put( 63 | url, 64 | { fields: { currentPassword, newPassword } }, 65 | { withCredentials: true }, 66 | ) 67 | .then((response) => { 68 | return { success: true, message: "Password changed successfully" }; 69 | }) 70 | .catch((error) => { 71 | return { success: false, message: "Password change failed" }; 72 | }); 73 | }, 74 | }); 75 | -------------------------------------------------------------------------------- /src/providers/dataProvider.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { stringify } from "query-string"; 3 | import { DataProvider } from "ra-core"; 4 | 5 | export const dataProvider = ( 6 | pkDictionary: any, 7 | apiUrl: string, 8 | ): DataProvider => ({ 9 | getList: (resource: string, params: any) => { 10 | const { page, perPage } = params.pagination; 11 | let { field, order } = params.sort; 12 | 13 | field = field === "id" ? pkDictionary[resource] : field; 14 | const ordering = order === "ASC" ? `${field}` : `-${field}`; 15 | 16 | //since the soul api requires comma separated filters, remove the quotes and curly braces from the filter 17 | const filter = JSON.stringify(params.filter).replace(/[{} ""]/g, ""); 18 | 19 | /** 20 | NOTE: If you want to use the _extend query when you send a request to soul 21 | you should pass the extend keys dynamically from the UI by using the "meta" attribute in the component 22 | https://marmelab.com/react-admin/List.html#adding-meta-to-the-dataprovider-call 23 | */ 24 | 25 | const query = { 26 | _page: page, 27 | _limit: perPage, 28 | _ordering: ordering, 29 | _filters: filter ? filter : undefined, 30 | _extend: params.meta?.extend, //Add the _extend query to get many data by using a foreign key 31 | }; 32 | 33 | const url = `${apiUrl}/tables/${resource}/rows?${stringify(query)}`; 34 | 35 | return axios.get(url, { withCredentials: true }).then((response) => { 36 | const { data } = response.data; 37 | 38 | //manually add an id key 39 | const modifiedData = []; 40 | for (let i = 0; i < data.length; i++) { 41 | const item = data[i]; 42 | const primaryKey = pkDictionary[resource]; 43 | 44 | if (primaryKey !== undefined) { 45 | item.id = item[primaryKey]; 46 | delete item[primaryKey]; 47 | } 48 | 49 | modifiedData.push(item); 50 | } 51 | 52 | return { data: modifiedData, total: response.data.total }; 53 | }); 54 | }, 55 | 56 | getOne: (resource: string, params: any) => { 57 | const url = `${apiUrl}/tables/${resource}/rows/${params.id}`; 58 | 59 | return axios.get(url, { withCredentials: true }).then((response) => { 60 | let { data } = response.data; 61 | data = data[0]; 62 | 63 | const primaryKey = pkDictionary[resource]; 64 | if (primaryKey !== undefined) { 65 | data.id = data[primaryKey]; 66 | delete data[primaryKey]; 67 | } 68 | 69 | return { data }; 70 | }); 71 | }, 72 | 73 | getMany: (resource: string, params: any) => { 74 | const url = `${apiUrl}/tables/${resource}/rows/${params.ids.toString()}`; 75 | 76 | return axios.get(url, { withCredentials: true }).then((response) => { 77 | const { data } = response.data; 78 | 79 | //manually add an id key 80 | const modifiedData = []; 81 | for (let i = 0; i < data.length; i++) { 82 | const item = data[i]; 83 | const primaryKey = pkDictionary[resource]; 84 | 85 | if (primaryKey !== undefined) { 86 | item.id = item[primaryKey]; 87 | delete item[primaryKey]; 88 | } 89 | 90 | modifiedData.push(item); 91 | } 92 | 93 | return { data: modifiedData, total: response.data.total }; 94 | }); 95 | }, 96 | 97 | getManyReference: (resource: string, params: any) => { 98 | const { page, perPage } = params.pagination; 99 | const { field, order } = params.sort; 100 | 101 | const ordering = order === "ASC" ? `${field}` : `-${field}`; 102 | const filter = JSON.stringify(params.filter).replace(/[{} ""]/g, ""); 103 | 104 | const query = { 105 | _page: page, 106 | _limit: perPage, 107 | _ordering: field !== "id" ? ordering : undefined, 108 | _filters: filter ? `${filter},${params.target}:${params.id}` : undefined, 109 | }; 110 | 111 | const url = `${apiUrl}/tables/${resource}/rows?${stringify(query)}`; 112 | 113 | return axios.get(url, { withCredentials: true }).then((response) => { 114 | const { data } = response.data; 115 | 116 | //manually add an id key 117 | const modifiedData = []; 118 | for (let i = 0; i < data.length; i++) { 119 | const item = data[i]; 120 | const primaryKey = pkDictionary[resource]; 121 | 122 | if (primaryKey !== undefined) { 123 | item.id = item[primaryKey]; 124 | delete item[primaryKey]; 125 | } 126 | 127 | modifiedData.push(item); 128 | } 129 | 130 | return { data: modifiedData, total: response.data.total }; 131 | }); 132 | }, 133 | 134 | create: (resource: string, params: any) => { 135 | const url = `${apiUrl}/tables/${resource}/rows`; 136 | 137 | return axios 138 | .post(url, { fields: params.data }, { withCredentials: true }) 139 | .then((response) => { 140 | return { data: { id: response.data.lastInsertRowId, ...params.data } }; 141 | }); 142 | }, 143 | 144 | update: (resource: string, params: any) => { 145 | const url = `${apiUrl}/tables/${resource}/rows/${params.id}`; 146 | 147 | // remove the id property 148 | const { id, ...editData } = params.data; 149 | 150 | return axios 151 | .put(url, { fields: editData }, { withCredentials: true }) 152 | .then((response) => { 153 | return { data: { id: response.data.lastInsertRowId, ...params.data } }; 154 | }); 155 | }, 156 | 157 | updateMany: (resource: string, params: any) => { 158 | const url = `${apiUrl}/tables/${resource}/rows/${params.ids.toString()}`; 159 | 160 | // remove the id property 161 | const { id, ...editData } = params.data; 162 | return axios 163 | .put(url, { fields: editData }, { withCredentials: true }) 164 | .then(async (response) => { 165 | return { data: params.ids }; 166 | }); 167 | }, 168 | 169 | delete: (resource: string, params: any) => { 170 | const url = `${apiUrl}/tables/${resource}/rows/${params.id}`; 171 | 172 | return axios.delete(url, { withCredentials: true }).then((response) => { 173 | return { data: params.id }; 174 | }); 175 | }, 176 | 177 | deleteMany: (resource: string, params: any) => { 178 | const ids = params.ids.toString(); 179 | const url = `${apiUrl}/tables/${resource}/rows/${ids}`; 180 | 181 | return axios.delete(url, { withCredentials: true }).then((response) => { 182 | return { data: params.ids }; 183 | }); 184 | }, 185 | }); 186 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | --------------------------------------------------------------------------------