{"id":20349406,"url":"https://github.com/rootinc/crudable","last_synced_at":"2026-04-22T03:32:55.441Z","repository":{"id":42637291,"uuid":"133552490","full_name":"rootinc/CRUDable","owner":"rootinc","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-02T13:32:16.000Z","size":262,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-04-21T03:55:15.912Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rootinc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-15T17:46:01.000Z","updated_at":"2021-05-26T13:05:49.000Z","dependencies_parsed_at":"2025-01-14T23:42:12.467Z","dependency_job_id":null,"html_url":"https://github.com/rootinc/CRUDable","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/rootinc/CRUDable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rootinc%2FCRUDable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rootinc%2FCRUDable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rootinc%2FCRUDable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rootinc%2FCRUDable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rootinc","download_url":"https://codeload.github.com/rootinc/CRUDable/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rootinc%2FCRUDable/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32119868,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T00:31:26.853Z","status":"online","status_checked_at":"2026-04-22T02:00:05.693Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T22:25:47.408Z","updated_at":"2026-04-22T03:32:55.422Z","avatar_url":"https://github.com/rootinc.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CRUDable\n\nProvides CRUDable interfaces with React.\n\n## Installation\n\n1. `npm i github:rootinc/CRUDable`\n2. :shipit:\n\n## Usage\n\n### User Example\n\n**User.js**\n```\nimport React, { Component } from 'react';\n\nimport {CRUDable, defaultPlaceholderId} from 'CRUDable';\n\nexport default class User extends CRUDable {\n  renderReadOnly = () =\u003e {\n    return (\n      \u003ctr\n        onClick={(e) =\u003e {\n          const key = e.target.getAttribute('data-key');\n          this.switchToWriteOnly(key);\n        }}\n      \u003e\n        \u003ctd data-key=\"email\"\u003e{this.props.data.email}\u003c/td\u003e\n        \u003ctd data-key=\"first_name\"\u003e{this.props.data.first_name}\u003c/td\u003e\n        \u003ctd data-key=\"last_name\"\u003e{this.props.data.last_name}\u003c/td\u003e\n        \u003ctd /\u003e\n      \u003c/tr\u003e\n    );\n  }\n\n  renderWriteOnly = (e) =\u003e {\n    return (\n      \u003ctr\u003e\n        \u003ctd\u003e\n          \u003cinput\n            autoFocus={this.state.autoFocusKey === \"email\"}\n            value={this.props.data.email}\n            onFocus={this.handleFocus}\n            onChange={(e) =\u003e {this.handleChange(e, 'email'); }}\n            onBlur={(e) =\u003e {this.handleBlur(e, 'email'); }}\n            onClick={this.handleClick}\n          /\u003e\n        \u003c/td\u003e\n        \u003ctd\u003e\n          \u003cinput\n            autoFocus={!this.state.autoFocusKey || this.state.autoFocusKey === \"name\"}\n            value={this.props.data.first_name}\n            onFocus={this.handleFocus}\n            onChange={(e) =\u003e {this.handleChange(e, 'first_name'); }}\n            onBlur={(e) =\u003e {this.handleBlur(e, 'first_name'); }}\n            onClick={this.handleClick}\n          /\u003e\n        \u003c/td\u003e\n        \u003ctd\u003e\n          \u003cinput\n            value={this.props.data.last_name}\n            onFocus={this.handleFocus}\n            onChange={(e) =\u003e {this.handleChange(e, 'last_name'); }}\n            onBlur={(e) =\u003e {this.handleBlur(e, 'last_name'); }}\n            onClick={this.handleClick}\n          /\u003e\n        \u003c/td\u003e\n        \u003ctd\u003e\n          {\n            this.props.data.id \u003c defaultPlaceholderId ? null : this.renderCreateButton(\"Create User\")\n          }\n\n          {\n            this.props.data.id \u003c defaultPlaceholderId ? this.renderDeleteButton(\"Delete User\") : null\n          }\n        \u003c/td\u003e\n      \u003c/tr\u003e\n    );\n  }\n}\n```\n\n**UserManagement.js**\n```\nimport React, { Component } from 'react';\n\nimport User from './User';\n\nimport {CRUDableManagement} from 'CRUDable';\n\nexport default class UserManagement extends CRUDableManagement {\n  renderList = () =\u003e {\n    return this.props.list.map((user)=\u003e{\n      return (\n        \u003cUser\n          key={user.id}\n          data={user}\n          createObject={this.createObject}\n          cancelObject={this.cancelObject}\n          updateObject={this.updateObject}\n          deleteObject={this.deleteObject}\n        /\u003e\n      );\n    });\n  }\n\n  renderContainer = () =\u003e {\n    return (\n      \u003ctable className=\"table table-striped\"\u003e\n        \u003ctbody\u003e\n          \u003ctr\u003e\n            \u003cth\u003eEmail\u003c/th\u003e\n            \u003cth\u003eFirst Name\u003c/th\u003e\n            \u003cth\u003eLast Name\u003c/th\u003e\n          \u003c/tr\u003e\n          {this.renderList()}\n        \u003c/tbody\u003e\n      \u003c/table\u003e\n    );\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        {this.renderAddButton(\"Add User\")}\n\n        {this.renderContainer()}\n      \u003c/div\u003e\n    );\n  }\n}\n\n```\n\n**UserManagementContainer.js**\n```\nimport React, { Component } from 'react';\nimport ReactDOM from 'react-dom';\n\nimport update from 'immutability-helper';\n\nimport UserManagement from './UserManagement';\n\nclass UserManagementContainer extends Component {\n  constructor(props) {\n    super(props);\n\n    this.state = {\n      users: []\n    };\n  }\n\n  componentWillMount() {\n    this.fetchUsers();\n  }\n\n  fetchUsers = () =\u003e {\n    window.axios.get(\"/api/users\")\n      .then((response) =\u003e {\n        this.setState({\n          users: response.data.payload.users\n        });\n      })\n      .catch((error) =\u003e {\n        console.error(error);\n      });\n  }\n\n  revertUsers = (index) =\u003e {\n    return update(this.state.users, {\n      $splice: [[index, 1]]\n    });\n  }\n\n  modifyList = (type, users, user, index) =\u003e {\n    switch (type)\n    {\n      case 'POST':\n        this.postData(user, index);\n        break;\n      case 'PUT':\n        this.putData(user);\n        break;\n      case 'DELETE':\n        this.deleteData(user);\n        break;\n    }\n\n    this.setState({users: users});\n  }\n\n  postData = (postData, index) =\u003e {\n    window.axios.post(\"/api/users\", postData)\n      .then((response) =\u003e {\n        if (response.data.status === \"error\")\n        {\n          console.error(response);\n\n          this.setState({\n            users: this.revertUsers(index)\n          });\n        }\n        else\n        {\n          const usersWithNewUser = update(this.state.users, {\n            [index]: {\n              $merge: response.data.payload.user\n            }\n          });\n\n          this.setState({users: usersWithNewUser});\n        }\n      })\n      .catch((error) =\u003e {\n        console.error(error);\n\n        this.setState({\n          users: this.revertUsers(index)\n        });\n      });\n  }\n\n  putData = (putData) =\u003e {\n    window.axios.put(\"/api/users/\" + putData.id, putData)\n      .then((response) =\u003e {\n        if (response.data.status === \"error\")\n        {\n          console.error(response);\n        }\n      })\n      .catch((error) =\u003e {\n        console.error(error);\n      });\n  }\n\n  deleteData = (deleteData) =\u003e {\n    window.axios.delete(\"/api/users/\" + deleteData.id, deleteData)\n      .then((response) =\u003e {\n        if (response.data.status === \"error\")\n        {\n          console.error(response);\n        }\n      })\n      .catch((error) =\u003e {\n        console.error(error);\n      });\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cUserManagement\n          defaultData={{\n            first_name: \"Firstname\",\n            last_name: \"Lastname\",\n            email: \"email@domain.com\",\n          }}\n          list={this.state.users}\n          modifyList={this.modifyList}\n          fetchUsers={this.fetchUsers}\n        /\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n\nexport default UserManagementContainer;\nconst usersElement = document.getElementById('users');\n\nif (usersElement) {\n  ReactDOM.render(\u003cUserManagementContainer /\u003e, usersElement);\n}\n```\n\n### Another (More Complicated) Example\n\n**Commitment.js**\n```\nimport React, { Component } from 'react';\n\nimport {CRUDable, defaultPlaceholderId} from 'CRUDable';\n\nexport default class Commitment extends CRUDable {\n  renderReadOnly = () =\u003e {\n    let className = \"\";\n\n    if (!this.props.data.favorite) {\n      className = \"-o\";\n    }\n\n    return (\n      \u003cdiv style={{ display: \"flex\", alignItems: \"center\", marginBottom: \"0.5rem\" }}\u003e\n        \u003cdiv\u003e\n          \u003ci\n            className={\"fa fa-star\" + className}\n            onClick={() =\u003e {\n              this.handleChange({target: {value: !this.props.data.favorite}}, 'favorite', true)\n            }}\n            style={{\n              color: \"goldenrod\",\n              fontSize: \"1rem\"\n            }}\n          /\u003e\n        \u003c/div\u003e\n        \u003cdiv\n          onClick={(e) =\u003e {\n            if (this.props.canEdit)\n            {\n              const key = e.target.getAttribute('data-key');\n              this.switchToWriteOnly(key);\n            }\n          }}\n          style={{\n            flex: \"1\",\n            backgroundColor: this.props.color || this.props.data.compass_module.color,\n            color: \"white\",\n            borderRadius: \"0.25rem\",\n            marginLeft: \"0.25rem\",\n            padding: \"0.5rem\"\n          }}\n          title=\"Click to edit\"\n          data-key=\"text\"\n        \u003e\n          \u003cspan data-key=\"text\"\u003e{this.props.data.text}\u003c/span\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    );\n  }\n\n  renderWriteOnly = () =\u003e {\n    return (\n      \u003cdiv\u003e\n        \u003cdiv style={{ display: \"flex\" }}\u003e\n          \u003ctextarea\n            autoFocus={this.state.autoFocusKey === \"text\"}\n            placeholder=\"+ Add commitment\"\n            value={this.props.data.text}\n            onFocus={this.handleFocus}\n            onChange={(e) =\u003e {this.handleChange(e, 'text'); }}\n            onBlur={(e) =\u003e {this.handleBlur(e, 'text'); }}\n            onClick={this.handleClick}\n            onKeyDown={(e) =\u003e {\n              if (e.keyCode === 13)\n              {\n                e.preventDefault();\n\n                if (this.props.data.text != \"\")\n                {\n                  this.handleCreate();\n                }\n              }\n            }}\n          /\u003e\n          {\n            this.props.data.id \u003c defaultPlaceholderId ? (\n              \u003cdiv\u003e{this.renderDeleteButton(\"Delete\")}\u003c/div\u003e\n            ) : null\n          }\n        \u003c/div\u003e\n\n        \u003cp\n          style={{\n            margin: \"4px 0 10px 4px\",\n            fontSize: \".75rem\",\n            color: \"gray\"\n          }}\n        \u003e\n          Hit Enter to Submit\n        \u003c/p\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n**CommitmentManagement.js**\n```\nimport React, { Component } from 'react';\n\nimport { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';\n\nimport Commitment from './Commitment';\n\nimport {CRUDableManagement} from 'CRUDable';\n\nconst reorder = (list, startIndex, endIndex) =\u003e {\n  const result = Array.from(list);\n  const [removed] = result.splice(startIndex, 1);\n  result.splice(endIndex, 0, removed);\n\n  return result;\n};\n\nexport default class CommitmentManagement extends CRUDableManagement {\n  droppedOutsideOfList = (result) =\u003e {\n    return !result.destination;\n  }\n\n  onDragEnd = (result) =\u003e {\n    if (this.droppedOutsideOfList(result)) {\n      return;\n    }\n\n    let list = reorder(this.props.list, result.source.index, result.destination.index);\n\n    for (let i=0; i\u003clist.length; i++)\n    {\n      list[i].sequence = i;\n    }\n\n    this.props.updateFavoriteCommitmentsOrder(list);\n  }\n\n  renderCommitment = (commitment, canEdit) =\u003e {\n    return (\n      \u003cCommitment\n        key={commitment.id}\n        data={commitment}\n        color={this.props.color}\n        createObject={this.createObject}\n        cancelObject={this.cancelObject}\n        updateObject={this.updateObject}\n        deleteObject={this.deleteObject}\n        canEdit={canEdit}\n      /\u003e\n    );\n  }\n\n  renderDraggableList = () =\u003e {\n    return this.props.list.map((commitment, index)=\u003e{\n      return (\n        \u003cDraggable\n          key={commitment.id}\n          draggableId={'' + commitment.id}\n          index={index}\n        \u003e\n          {(provided, snapshot) =\u003e (\n            \u003cdiv\n              ref={provided.innerRef}\n              {...provided.draggableProps}\n            \u003e\n              \u003cdiv\n                style={{\n                  display: \"flex\",\n                  alignItems: \"center\"\n                }}\n              \u003e\n                \u003ci\n                  {...provided.dragHandleProps}\n                  className=\"fa fa-ellipsis-h\"\n                  aria-hidden=\"true\"\n                  style={{\n                    marginRight: \"15px\",\n                    marginBottom: \"0.5rem\"\n                  }}\n                /\u003e\n                \u003cdiv style={{flex: 1}}\u003e\n                  {this.renderCommitment(commitment, false)}\n                \u003c/div\u003e\n              \u003c/div\u003e\n            \u003c/div\u003e\n          )}\n        \u003c/Draggable\u003e\n      );\n    });\n  }\n\n  renderDnDContainer = () =\u003e {\n    return (\n      \u003cDragDropContext\n        onDragEnd={this.onDragEnd}\n      \u003e\n        \u003cDroppable\n          droppableId=\"1\"\n        \u003e\n          {(provided, snapshot) =\u003e (\n            \u003cdiv\n              ref={provided.innerRef}\n            \u003e\n              {this.renderDraggableList()}\n            \u003c/div\u003e\n          )}\n        \u003c/Droppable\u003e\n      \u003c/DragDropContext\u003e\n    );\n  }\n\n  renderList = () =\u003e {\n    return this.props.list.map((commitment)=\u003e{\n      return this.renderCommitment(commitment, true);\n    });\n  }\n\n  renderContainer = () =\u003e {\n    return (\n      \u003cdiv\u003e\n        {this.renderList()}\n      \u003c/div\u003e\n    );\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        {this.props.orderable ? this.renderDnDContainer() : this.renderContainer()}\n      \u003c/div\u003e\n    );\n  }\n}\n\n```\n\n**Commitments.js**\n```\nimport React, { Component } from 'react';\n\nimport update from 'immutability-helper';\n\nimport CommitmentManagement from './CommitmentManagement';\n\nimport {defaultPlaceholderId, getKey} from 'CRUDable';\n\nexport default class Commitments extends Component {\n  modifyList = (type, commitments, commitment, index) =\u003e {\n    this.props.modifyCommitments(commitments);\n\n    switch (type)\n    {\n      case 'POST':\n        this.postData(commitment, index);\n        break;\n      case 'PUT':\n        this.putData(commitment);\n        break;\n      case 'DELETE':\n        this.deleteData(commitment);\n        break;\n    }\n  }\n\n  postData = (postData, index) =\u003e {\n    window.axios.post(\"/api/commitments\", postData)\n      .then((response) =\u003e {\n        let type;\n\n        if (this.props.addPlaceholderTo == \"top\")\n        {\n          type = \"$unshift\";\n        }\n        else if (this.props.addPlaceholderTo == \"bottom\")\n        {\n          type = \"$push\";\n        }\n        else\n        {\n          type = \"$unshift\";\n        }\n\n        let commitmentsWithNewCommitmentAndPlaceholder = update(this.props.commitments, {\n          [index]: {\n            $merge: response.data.payload.commitment,\n          },\n          [type]: [{ //prepend or append placeholder commitments since there is no add button\n            id: getKey(),\n            compass_module_id: this.props.compass_module_id,\n            text: \"\"\n          }]\n        });\n\n        this.props.modifyCommitments(commitmentsWithNewCommitmentAndPlaceholder);\n      })\n      .catch(function (error) {\n        console.error(error);\n      });\n  }\n\n  putData = (putData) =\u003e {\n    window.axios.put(\"/api/commitments/\" + putData.id, putData)\n      .then(() =\u003e {\n        this.props.refreshFavorites \u0026\u0026 this.props.refreshFavorites();\n      })\n      .catch(function (error) {\n        console.error(error);\n      });\n  }\n\n  deleteData = (deleteData) =\u003e {\n    window.axios.delete(\"/api/commitments/\" + deleteData.id)\n      .catch(function (error) {\n        console.error(error);\n      });\n  }\n\n  render() {\n    return (\n      \u003cdiv\n        className={this.props.className}\n      \u003e\n        \u003cdiv style={{backgroundColor: this.props.color}}\u003e\n          \u003cstrong\u003e{this.props.title}\u003c/strong\u003e\n          \u003cCommitmentManagement\n            list={this.props.commitments}\n            modifyList={this.modifyList}\n            addPlaceholderTo={this.props.addPlaceholderTo}\n            color={this.props.color}\n          /\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n**CommitmentsContainer.js**\n```\nimport React, { Component } from 'react';\nimport ReactDOM from 'react-dom';\n\nimport update from 'immutability-helper';\n\nimport styled from 'styled-components';\n\nimport Commitments from './commitments/Commitments';\nimport CommitmentManagement from './commitments/CommitmentManagement';\n\nimport {defaultPlaceholderId, getKey} from 'CRUDable';\n\nclass CommitmentsContainer extends Component {\n  constructor(props) {\n    super(props);\n\n    this.state = {\n      compassModulesWithCommitments: [],\n      favoriteCommitments: [],\n    };\n  }\n\n  componentWillMount() {\n    this.fetchCompassModulesWithCommitments();\n    this.fetchFavoriteCommitments();\n  }\n\n  fetchCompassModulesWithCommitments = () =\u003e {\n    window.axios.get(\"/api/commitments\")\n      .then((response) =\u003e {\n        this.prependPlacholderCommitments(response.data.payload.compass_modules);\n\n        this.setState({\n          compassModulesWithCommitments: response.data.payload.compass_modules,\n        });\n      })\n      .catch((error) =\u003e {\n        console.error(error);\n      });\n  }\n\n  fetchFavoriteCommitments = () =\u003e {\n    window.axios.get(\"/api/commitments/favorites\")\n      .then((response) =\u003e {\n        this.setState({\n          favoriteCommitments: response.data.payload.commitments,\n        });\n      })\n      .catch((error) =\u003e {\n        console.error(error);\n      });\n  }\n\n  prependPlacholderCommitments = (compassModules) =\u003e {\n    for (let i=0; i\u003ccompassModules.length; i++)\n    {\n      let commitments = compassModules[i].commitments;\n\n      commitments.unshift({\n        id: getKey(),\n        compass_module_id: compassModules[i].id,\n        text: \"\"\n      })\n    }\n  }\n\n  findCompassModuleIndex = (moduleId) =\u003e {\n    return this.state.compassModulesWithCommitments.findIndex((cm) =\u003e {\n      return moduleId === cm.id;\n    });\n  }\n\n  modifyCommitments = (moduleId, commitments) =\u003e {\n    var index = this.findCompassModuleIndex(moduleId);\n\n    let commitmentsMerged = update(this.state.compassModulesWithCommitments, {\n      [index]: {\n        commitments: {\n          $set: commitments\n        }\n      }\n    });\n\n    this.setState({compassModulesWithCommitments: commitmentsMerged});\n  }\n\n  modifyFavoriteCommitments = (type, favoriteCommitments, favoriteCommitment, index) =\u003e {\n    window.axios.put(\"/api/commitments/\" + favoriteCommitment.id, favoriteCommitment)\n      .then(() =\u003e {\n        this.fetchCompassModulesWithCommitments();\n      })\n      .catch(function (error) {\n        alert(window._genericErrorMessage);\n      });\n\n    const listRemovedObject = update(favoriteCommitments, {\n      $splice: [[index, 1]]\n    });\n\n    this.setState({favoriteCommitments: listRemovedObject});\n  }\n\n  updateFavoriteCommitmentsOrder = (list) =\u003e {\n    window.axios.post(\"/api/commitments/favorites/reorder\", {list: list})\n      .catch(function (error) {\n        alert(window._genericErrorMessage);\n      });\n\n    this.setState({favoriteCommitments: list});\n  }\n\n  renderFavoriteCommitments = () =\u003e {\n    return (\n      \u003cdiv\u003e\n        \u003cdiv\u003e\n          \u003ch2\u003eFavorites\u003c/h2\u003e\n          \u003cCommitmentManagement\n            list={this.state.favoriteCommitments}\n            modifyList={this.modifyFavoriteCommitments}\n            orderable={true}\n            updateFavoriteCommitmentsOrder={this.updateFavoriteCommitmentsOrder}\n          /\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    );\n  }\n\n  renderCommitments = () =\u003e {\n    return this.state.compassModulesWithCommitments.map((compassModule) =\u003e {\n      return (\n        \u003cCommitments\n          key={compassModule.id}\n          title={compassModule.title}\n          compass_module_id={compassModule.id}\n          commitments={compassModule.commitments}\n          modifyCommitments={(commitments) =\u003e {\n            this.modifyCommitments(compassModule.id, commitments);\n          }}\n          refreshFavorites={this.fetchFavoriteCommitments}\n          addPlaceholderTo=\"top\"\n          className=\"className\"\n          color={compassModule.color}\n        /\u003e\n      );\n    });\n  }\n\n  render() {\n    return (\n      \u003cdiv className=\"compass-module-detail bx-container\"\u003e\n        \u003ch1 className=\"card first\"\u003eCommitments\u003c/h1\u003e\n        \u003cdiv className=\"bx-grid\"\u003e\n          {this.renderFavoriteCommitments()}\n          \u003cdiv style={{ margin: \"0\" }}\u003e\n            {this.renderCommitments()}\n          \u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n\nexport default CommitmentsContainer;\nconst commitmentElement = document.getElementById('commitments');\n\nif (commitmentElement) {\n  ReactDOM.render(\u003cCommitmentsContainer /\u003e, commitmentElement);\n}\n```\n\n## Contributing\n\nThank you for considering contributing to CRUDable! To encourage active collaboration, we encourage pull requests, not just issues.\n\nIf you file an issue, the issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible and a code sample that demonstrates the issue. The goal of a issue is to make it easy for yourself - and others - to replicate the bug and develop a fix.\n\n## License\n\nCRUDable is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frootinc%2Fcrudable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frootinc%2Fcrudable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frootinc%2Fcrudable/lists"}