{"id":23032003,"url":"https://github.com/uwrit/r2m2","last_synced_at":"2025-10-17T05:14:02.933Z","repository":{"id":39200061,"uuid":"244512878","full_name":"uwrit/r2m2","owner":"uwrit","description":null,"archived":false,"fork":false,"pushed_at":"2023-07-18T21:13:48.000Z","size":2809,"stargazers_count":0,"open_issues_count":30,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-08T12:13:18.960Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uwrit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2020-03-03T01:23:21.000Z","updated_at":"2020-03-26T18:17:07.000Z","dependencies_parsed_at":"2024-12-15T15:49:31.481Z","dependency_job_id":"c6d3f7ce-0bdb-4bed-9b50-dec5616655a6","html_url":"https://github.com/uwrit/r2m2","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uwrit%2Fr2m2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uwrit%2Fr2m2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uwrit%2Fr2m2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uwrit%2Fr2m2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uwrit","download_url":"https://codeload.github.com/uwrit/r2m2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246899625,"owners_count":20851893,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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-12-15T15:49:27.101Z","updated_at":"2025-10-17T05:13:57.888Z","avatar_url":"https://github.com/uwrit.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# R2M2\n\nWelcome to the Research Resource Maturity Models Survey app!\n\n- [Running the app locally](#running-the-app-locally)\n- [Adding Models](#adding-models)\n\n## Running the app locally\nThe R2M2 survey app uses a three-tiered architecture with a React web client, a small Python-Flask server API, and a REDCap project as a database.\n\nTo run it locally, do the following steps:\n\n### API Setup\n\n```bash\n# Clone the repo\n$ git clone git@github.com:uwrit/r2m2.git\n\n# Setup a python virtual environment\n$ cd r2m2/src/server\n$ python3 -m venv venv\n$ . venv/bin/activate\n\n# Install API dependencies\n$ python3 -m pip install Flask requests\n```\n\nNext, create a `config.json` file to tell the API the REDCap instance to point to under `/r2m2/src/server/flaskr/app/modules/services/config.json`.\n\n```json\n{\n    \"redcap\": {\n        \"token\": \"\u003cAPI_token\u003e\",\n        \"url\": \"https://redcap.example.org/api/\"\n    }\n}\n```\n\nRun the API\n```bash\n$ python3 server/run.py\n```\n\n### Web client setup\n\nNow that the API is running, you can setup the React web client. Make sure you have [NPM](https://www.npmjs.com/get-npm) installed first.\n\n```bash\n# Install client dependencies\n$ cd r2m2/src/ui-client\n$ npm install\n\n# Run the client\n$ npm start\n```\n\nNote that in order to be allowed into the app (even in development), you'll need a record in the REDCap project `User` form with your `email` address and `entry_code`.\n\n## Adding Models\n\nAdding models to the Research Resource Maturity Models Survey app is straightforward.\n\n1. Add a new `Form` to the [REDCap project](https://rcdev.iths.org/redcap_v9.4.2/Design/online_designer.php?pid=277) to represent the Model you'd like to add. \n\nName the variables in the project uses the convention `\u003cform_name\u003e_q\u003cquestion_num\u003e_\u003cshort_name\u003e`, and be sure to use `Multiple Radio Buttons (Single Answer)` as the type.\n\nSo for example, a form called `Example` could have variables of the form:\n- `example_complete` (REDCap automatically makes this field)\n- `example_q1_month_of_birth`\n- `example_q2_fav_monty_python_joke`\n- ...\n\n2. Next, add the model to the client app. Begin by adding the new variables you added to the REDCap project above to the existing `AnswerField` type in [r2m2/src/ui-client/src/model.User.ts](https://github.com/uwrit/r2m2/blob/master/src/ui-client/src/model/User.ts#L3).\n\n```typescript\nexport type AnswerField =\n\n    // User name\n    'user_fname' |\n    'user_lname' |\n    ...\n\n    // Example                             \u003c- These are new\n    `example_complete` |\n    `example_q1_month_of_birth` |\n    `example_q2_fav_monty_python_joke` |\n\n    ...\n```\n\n3. Create a new file for your Model under [r2m2/src/ui-client/src/model/Models/](https://github.com/uwrit/r2m2/tree/master/src/ui-client/src/model/Models). Inside the file, create a new `BaseModel` object. This is the data that will populate the form actually seen by users.\n\n```typescript\nimport React from \"react\";\nimport { BaseModel } from \"../ModelsState\";\nimport { UserAnswers } from \"../User\";\nimport { ExampleForm } from \"../../components/Models/Example/Example\"; // \u003c- Don't worry, this won't work yet but is the next step.\n\nexport const Example: BaseModel = \n{\n    completeField: 'example_complete',\n    name: 'The Super Awesome Example Survey (SAES)',\n    description: 'The Super Awesome Example Survey is just that, an example. But also super awesome.',\n    render: (dispatch: any, answers: UserAnswers) =\u003e \u003cExampleForm dispatch={dispatch} answers={answers} /\u003e,\n    questions: [\n        {\n            answerField: 'example_q1_month_of_birth',\n            text: 'Select the month of your birth:',\n            options: [\n                {\n                    text: 'January',\n                    value: '1'\n                },\n                {\n                    text: 'February',\n                    value: '2'\n                }\n            ]\n        },\n        {\n            answerField: 'example_q2_fav_monty_python_joke',\n            text: 'Select your favorite Monty Python joke:',\n            options: [\n                {\n                    text: 'The dead parrot one',\n                    value: '1'\n                },\n                {\n                    text: 'Tis but a scratch',\n                    value: '2'\n                }\n            ]\n        }\n    ],\n}\n```\n\nNote that the `import { ExampleForm } from ...` statement won't work yet, we'll do that next.\n\n4. Under [r2m2/src/ui-client/src/components/Models/](https://github.com/uwrit/r2m2/tree/master/src/ui-client/src/model/Models), add a new file called `Example.tsx`, subsituting \"Example\" for the actual name of your Model. This is the React component we want to render when your model is selected by the user. Most models can work using existing React components we've created (specifically [ModelForm](https://github.com/uwrit/r2m2/blob/master/src/ui-client/src/components/BaseForms/ModelForm/ModelForm.tsx)), so you should rarely need to do anything custom here.\n\n```typescript\nimport React from 'react';\nimport { Example } from '../../model/Models/Example';  // \u003c- This is the file created in step #3.\nimport { UserAnswers } from '../../model/User';\nimport { ModelForm } from '../BaseForms/ModelForm/ModelForm';\n\ninterface Props {\n    dispatch: any;\n    answers: UserAnswers;\n}\n\nexport class ExampleForm extends React.PureComponent\u003cProps\u003e {\n\n    public render() {\n        const { dispatch, answers } = this.props;\n        \n        return \u003cModelForm dispatch={dispatch} answers={answers} model={Example}/\u003e;\n    }\n}\n```\n\n5. Last step: add your Model to the `defaultModelState() function` under [r2m2/src/ui-client/src/reducers/model.ts](https://github.com/uwrit/r2m2/blob/master/src/ui-client/src/reducers/model.ts#L6). This \"officially\" adds the model to the list that users can select.\n\n```typescript\nimport { MODEL_SET_CURRENT, ModelAction, MODEL_SET_SELECTED } from '../actions/model';\nimport { ModelsState } from '../model/ModelsState';\nimport { RIOSM } from '../model/Models/RIOSM';\nimport { HIMSS_EMRAM } from '../model/Models/HIMSS_EMRAM';\nimport { Example } from '../model/Models/Example';         // \u003c- Import your Model first\n\nexport const defaultModelState = (): ModelsState =\u003e {\n    return {\n        all: [ RIOSM, HIMSS_EMRAM, Example ]               // \u003c- Then add it to the array here\n    };\n};\n```\n\nVoilà! ;)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuwrit%2Fr2m2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuwrit%2Fr2m2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuwrit%2Fr2m2/lists"}