NMDC Field Notes is a mobile app researchers can use to collect metadata in the field.
The app is currently in development.
Install Node.js v20, which includes npm.
Once you've done that, you'll be able to run Node.js via
$ node
and npm via$ npm
.
Install the Ionic CLI globally.
npm install -g @ionic/cli
The
-g
option tells npm you want it to install that package globally, which the Ionic CLI's authors recommend. Once you've done that, you'll be able to run the Ionic CLI via$ ionic
.
Install the npm packages upon which this project depends.
npm install
That tells npm you want it to install all the packages listed in the
package-lock.json
file, which was programmatically generated from the manually-maintainedpackage.json
file.
Capacitor is a library that gives the web application access to the device's native functionality (e.g. location, camera, and storage). Review the Capacitor environment setup documentation and make sure you have the necessary dependencies installed.
The application loads values from environment variables defined in a .env.local
file.
That file is intentionally not stored in the Git repository. That file is loaded automatically by Vite, which exposes the environment variables via the
import.meta.env
object. The application'sconfig.ts
file then uses that object to make aconfig
object—and the rest of the application uses thatconfig
object instead of directly accessing theimport.meta.env
object.
You can copy the .env.local.example
file to .env.local
to get started.
cp .env.local.example .env.local
Run the dev
script defined in package.json
.
npm run dev
That will start a development server, serving the web version of the mobile app.
The development server is powered by Vite.
If you want your local Field Notes instance to work with a local nmdc-server
instance, there are a few environment variables to set on the server side.
The NMDC_CORS_ALLOW_ORIGINS
variable controls which origins are allowed to make CORS requests to the server. It is a comma-separated list of origins. Add http://127.0.0.1:8100
to allow requests from the web-based interface. Add capacitor://localhost
and https://localhost
to allow requests from device simulators. So for example, in the nmdc-server
.env
file:
NMDC_CORS_ALLOW_ORIGINS=capacitor://localhost,https://localhost,http://127.0.0.1:8100
The NMDC_LOGIN_REDIRECT_ALLOW_ORIGINS
variable controls which origins are allowed to redirect to after login. It is a comma-separated list of origins. Add http://127.0.0.1:8100
to allow redirects to the web-based interface. Add org.microbiomedata.fieldnotes://
to allow redirects to mobile apps. So for example, in the nmdc-server
.env
file:
NMDC_LOGIN_REDIRECT_ALLOW_ORIGINS=http://127.0.0.1:8100,org.microbiomedata.fieldnotes://
Alternatively, you can have your local Field Notes instance talk to the dev nmdc-server
instance. In that case, you can set the NMDC_SERVER_URL
environment variable in your .env.local
file to https://data-dev.microbiomedata.org
.
We recommend you use your web browser's developer tools to decrease the size of your web browser's viewport so that it resembles the screen of a mobile device, then visit the development server.
You can visit the development server at:
By default, Ionic will use the web browser's user agent to determine whether to style the web app like an iOS app or an Android app. For most web browser user agents, it will style it like an Android app. You can force a particular style by adding the ionic:mode
query parameter to the URL, as shown below.
- http://127.0.0.1:8100/
+ http://127.0.0.1:8100/?ionic:mode=ios
- http://127.0.0.1:8100/
+ http://127.0.0.1:8100/?ionic:mode=md
The
md
stands for Material Design.
Run the linter.
npm run lint
That tells npm you want it to run the script named
lint
, defined in thepackage.json
file. At the time of this writing, that script runseslint src
.
Identify circular imports using the madge
package.
npm run check.imports
Run the unit tests.
npm run test.unit
That tells npm you want it to run the script named
test.unit
, defined in thepackage.json
file. At the time of this writing, that script runsvitest
.
Assuming the development server is running, you can run the end-to-end tests with:
npm run test.e2e
That tells npm you want it to run the script named
test.e2e
, defined in thepackage.json
file. At the time of this writing, that script runscypress run
.
Assuming you're using a Mac, here's how you can simulate the iOS version of the mobile app.
Download and install Xcode (if you haven't already).
If either (a) this is your first time running the simulator, or (b) you have added a Capacitor plugin since the last time you ran the simulator; run:
ionic capacitor sync ios
Start the simulator with live reloading enabled.
ionic cap run ios --livereload --external
The simulator may take a few minutes to start. Eventually, the console will say "Deploying App.app to <uuid>
" and the simulator will appear.
We use Prettier to ensure the files in this repository are formatted the way we want.
You can use it like this:
# Check whether any files are not formatted.
npm run check.format
# Format all files.
npm run format
The .prettierignore
file tells Prettier which files we want it to
ignore (i.e. to not format).
The
.prettierignore
file automatically inherits from the.gitignore
file.
The prettier.config.js
file can be used to override Prettier's
default configuration.
Also, the presence of the file signifies to code editors that this project uses Prettier; which may influence some features of the editor.
We use Storybook to preview UI components in isolation.
Storybook is an interactive directory of your UI components and their stories. In the past, you'd have to spin up the app, navigate to a page, and contort the UI into the right state. (...) With Storybook, you can skip all those steps and jump straight to working on a UI component in a specific state.
Source: Why Storybook?
You can start the Storybook web server by running:
npm run storybook
Once the Storybook web server is running, you will be able to access it at:
Here's how you can introduce a new environment variable to the code base:
- Add its TypeScript type information to the
ImportMetaEnv
interface insrc/vite-env.d.ts
- Add its name and an example value to
.env.local.example
- Add the variable to the
Config
interface and theconfig
object inconfig.ts
- Elsewhere in the code base, access the variable via the
config
object exported byconfig.ts
(instead of accessingimport.meta.env.{NAME}
directly)
Creating a release involves three steps:
- Increment the build number and optionally update the version number
- Create and distribute a new Android build
- Create and distribute a new iOS build
Decide: Are you releasing a new build or a new version?
How do I choose?
- A build release is a new testing release of the app. It may be thought of as a release candidate. It implies a new
buildNumber
inpackage.json
. This corresponds to a new "build number" in iOS terms or "versionCode" in Android terms. New builds (of already-released versions) do not go through Apple's approval process when released to TestFlight. - A version release is a new general release of the app. It implies a new
version
number inpackage.json
and newbuildNumber
. The commit where these numbers are updated is also tagged. The newversion
corresponds to a new "version number" in iOS terms or "versionName" in Android terms. There will typically be several build releases before a version release.
- Ensure you are on the main branch and have the latest changes.
git checkout main && git pull
- Update build and (optionally) version numbers.
- If this is a build release, run the following commands to increment the build number.
npm run release -- build git push
- If this is a version release, decide whether the new version will be a patch, minor, or major version. Then, run the following commands to create a new version commit and tag. NOTE: During the beta testing period, use only minor or patch versions.
npm run release -- patch # (or "minor" or "major") git push --follow-tags
- If this is a build release, run the following commands to increment the build number.
- If this is a version release, check GitHub Actions to ensure that pushing the version tag triggered the workflow that creates a new GitHub Release. Ensure that the workflow completed successfully.
One-time keystore setup
- Obtain two passwords from other developers: the keystore decryption password and the keystore password. Save these securely in a password manager.
- Download the encrypted keystore file from NERSC.
scp <user>@dtn01.nersc.gov:/global/cfs/cdirs/m3408/nmdc-field-notes/android-keystore/org.microbiomedata.fieldnotes.keystore.tar.gz.enc .
- Decrypt the keystore file into the
android
directory. Enter the keystore decryption password when prompted.openssl enc -d -aes256 -pbkdf2 -in ./org.microbiomedata.fieldnotes.keystore.tar.gz.enc | tar xz -C ./android
- Remove the encrypted keystore file.
rm org.microbiomedata.fieldnotes.keystore.tar.gz.enc
- Build the Android APK file.
- Open the Android project in Android Studio.
ionic capacitor open android
- In the toolbar, click
Build
>Generate Signed App Bundle / APK...
- Select "APK" and click "Next"
- Enter the following information and click "Next"
- Key store path:
<project root>/android/org.microbiomedata.fieldnotes.keystore
- Key store password:
<keystore password>
- Key alias:
nmdc field notes
- Key password:
<keystore password>
- Key store path:
- Select the "release" build variant and click "Create"
- Wait for the gradle build to complete. Look for notification saying "Build completed successfully for module 'android.app.main' with 1 build variant."
- Open the Android project in Android Studio.
- Distribute the APK file via the GitHub Release.
- Make a copy of the APK file with the version and build numbers in the filename.
npm run rename.apk
- Edit the vX.Y.Z GitHub Release and attach the
org.microbiomedata.fieldnotes-vX.Y.Z-build.N.apk
file to it. NOTE: If this is a build release there may be one or more existing APK files attached to the release. This is by design. - Deleted the APK file from your local project root.
rm org.microbiomedata.fieldnotes-*.apk
- Make a copy of the APK file with the version and build numbers in the filename.
Note
These instructions are based around distributing via TestFlight for the beta release period. These will be updated later to include App Store distribution once a stable release is ready.
- Create the iOS build:
- Open the iOS project in Xcode.
ionic capacitor open ios
- "Create an archive of the app" by clicking (in the toolbar)
Product
>Archive
- "Select the method of distribution" to be TestFlight & App Store
- Click the "Validate App" button to validate the build with respect to App Store Connect
- Click the "Distribute App" button to upload the build to App Store Connect
- Open the iOS project in Xcode.
- Distribute the iOS build via TestFlight:
- Log in to App Store Connect
- Go to
Apps
>NMDC Field Notes
>TestFlight
- Under "iOS Builds," find the newly-uploaded build (in the table of all builds)
- If it says "Missing Compliance", click "Manage", select "None of the algorithms mentioned above", and click "Save". The words "Ready to Submit" will take the place of the "Missing Compliance" message.
- In the sidebar, click on one of the tester groups (e.g. NMDC iOS Developers)
- Add the newly-uploaded build to this group (by clicking the
+
button next to "Builds"). At this point the people in that tester group will receive an email telling them that a new build is available to test (and that they can get it by opening the TestFlight app). - Repeat the previous two substeps for the other tester groups.
NMDC Field Notes Phone Application (NMDC Field Notes) Copyright (c) 2024, The Regents of the University of California, through Lawrence Berkeley National Laboratory, and Triad National Security, LLC through Los Alamos National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved.
If you have questions about your rights to use or distribute this software, please contact Berkeley Lab's Intellectual Property Office at [email protected].
NOTICE. This Software was developed under funding from the U.S. Department of Energy and the U.S. Government consequently retains certain rights. As such, the U.S. Government has been granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable, worldwide license in the Software to reproduce, distribute copies to the public, prepare derivative works, and perform publicly and display publicly, and to permit others to do so.