Skip to content

Commit

Permalink
Merge branch 'forestgeo-app-development'
Browse files Browse the repository at this point in the history
  • Loading branch information
siddheshraze committed Dec 3, 2024
2 parents 243592b + b6d3a47 commit f7adc95
Show file tree
Hide file tree
Showing 98 changed files with 6,504 additions and 9,428 deletions.
101 changes: 101 additions & 0 deletions .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Build, Test, and Deploy Writerside Documentation

on:
push:
branches: # Trigger on push to any branch
- "*"
paths:
- "frontend/documentation/**" # Only run on changes in the documentation folder
workflow_dispatch:

permissions:
id-token: write
pages: write

env:
INSTANCE: 'documentation/fad'
ARTIFACT: 'webHelpFAD2-all.zip'
DOCKER_VERSION: '243.21565' # Writerside's recommended Docker version

jobs:
build:
runs-on: ubuntu-latest
steps:
# Step 1: Checkout repository
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

# Step 2: Build Writerside documentation
- name: Build docs using Writerside Docker builder
uses: JetBrains/writerside-github-action@v4
with:
instance: ${{ env.INSTANCE }}
artifact: ${{ env.ARTIFACT }}
docker-version: ${{ env.DOCKER_VERSION }}
args: --verbose

# Debug: List artifacts directory
- name: List artifacts directory
run: ls -la artifacts/

# Step 3: Save artifact with build results
- name: Save artifact with build results
uses: actions/upload-artifact@v4
with:
name: docs
path: |
artifacts/${{ env.ARTIFACT }}
artifacts/report.json
retention-days: 7

test:
needs: build
runs-on: ubuntu-latest
steps:
# Step 1: Download artifacts
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: docs
path: artifacts

# Step 2: Test Writerside documentation
- name: Test documentation
uses: JetBrains/writerside-checker-action@v1
with:
instance: ${{ env.INSTANCE }}

deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: [build, test]
runs-on: ubuntu-latest
steps:
# Step 1: Download artifacts
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: docs

# Step 2: Unzip the artifact
- name: Unzip artifact
run: unzip -O UTF-8 -qq '${{ env.ARTIFACT }}' -d dir

# Step 3: Set up GitHub Pages
- name: Setup Pages
uses: actions/configure-pages@v4

# Step 4: Package and upload Pages artifact
- name: Package and upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: dir

# Step 5: Deploy to GitHub Pages
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

145 changes: 54 additions & 91 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,99 +1,62 @@
# The ForestGEO Data Entry App
# ForestGEO Census Management Application

liquibase generate-changelog --exclude-objects="\b\w*view\w*\b"
A cloud-native web application built to accelerate the pace of research for the Smithsonian
Institution's Forest Global Earth Observatory (ForestGEO). ForestGEO is a global forest research
network, unparalleled in size and scope, comprised of ecologists and research sites dedicated to
advancing long-term study of the world's forests. The ForestGEO app aims to empower researchers with
an efficient means of recording, validating, and publishing forest health data.
Learn more about ForestGEO [at their website](https://www.forestgeo.si.edu/).

This application was built using Next.js 13 (app directory) and NextUI (v2).

### Technical documentation:

Please see the
documentation [here](https://github.com/ForestGeoHack/ForestGEO/wiki/ForestGEO-App-Specification)

## Project Structure

- `prev_app/`: previous iteration of the ForestGEO app, which uses the
Next.js v12 Pages router system. You can step into this directory to run the previous iteration of
the application
- `app/`: the primary routing structure and setup for the primary application
- `components/`: requisite react components that are used within the application and icon
information
- `config/`: fonts information and general site information -- endpoint names, plot names, plot
interface, etc.
- `styles/`: tailwindcss formatting files and dropzone/validation table custom formatting files
- `types/`: additional set up for SVG formatting

### Running the project

1. Before running the project, you must create an `.env.local` file in the overhead directory with
the following values:
- `AZURE_AD_CLIENT_ID`
- `AZURE_AD_CLIENT_SECRET`
- `AZURE_AD_TENANT_ID`
- `NEXTAUTH_SECRET`
- `NEXTAUTH_URL`
- all `AZURE_` values must be created/populated from Azure's App Registration portal
2. Once `.env.local` is made, run `npm install` from the overhead directory to install dependencies
3. Run `npm run build` to compile/optimize the application for running
4. Run `npm run dev` to create a dev instance of the application locally on your machine
5. Navigate to `http://localhost:3000` to access the application

---

### Understanding Next.JS Dynamic Routing

Next.js's dynamic routing setup allows for built-in endpoint data processing. By using this, passing
data from a component or root layout to a page/endpoint is simplified (rather than using useCallback
or a React function). As a brief reminder, remember that when using Next.js 13, writing something
like `app/example/filehandling.tsx` will generate a route pointing to `... /example` instead
of `.../example/page`, and nesting successive folders will create a route with those
folders: `app/example1/example2/example3/filehandling.tsx` has the
route `... /example1/example2/example3/`.

For a better explanation of how this works, please observe the browse
endpoint: `app/(endpoints)/browse/[plotKey]/[plotNum]/filehandling.tsx`<br />
In order from left to right, please note the following points of interest:

- `(endpoints)`: wrapping a folder in parentheses allows for better organization w/o using the
wrapped folder name in the path. For example, accessing the Browse page locally does not require
adding `/endpoints/` to the URL
- `[plotKey]`: this is the first required variable when accessing this endpoint -- you will have to
add some string `plotKey` to the end of the URL: `.../browse/[your plot key]` in order to
successfully view the page.
- wrapping a folder in `[]` will designate that folder as a **required** dynamic parameter
- wrapping in `[...folderName]` designates `folderName` as a catch-all route. All following
values after `folderName` (i.e., `.../a/b` will return `folderName = [a, b]` )
- wrapping in `[[...folderName]]` designates `folderName` as an _optional_ catch-all route. As
expected, all values for/after `folderName` will be returned as part of the dynamic route,
but `undefined` will also be returned if no value is entered at all (instead of a 404 error)
- `[plotNum]`: second required variable when accessing this endpoint - your resulting endpoint will
look like (example) `http://localhost:3000/browse/plotKey/plotNum`.

---

### Release Notes (v0.1.0):

- endpoints have been added and routed to require a plot key/number combination for access
- initial state has been converted to new `Plot {key: 'none', num: 0}` instead of `''`
- MUI JoyUI has been partially implemented as a replacement for MaterialUI. However, due to time
limitations, MaterialUI has still been incorporated into converted sections from ForestGeoHack
- The current plan is to solely implement either NextUI or ChakraUI instead of either of these
options, and future updates will include this information.
- `SelectPlotProps` has been removed and replaced with NextJS dynamic routing (each endpoint will
dynamically retrieve plot information). Endpoints have been updated to reflect dynamic param-based
retrieval
- The navigation bar has been updated to use useEffect to push live endpoint updates when the
plot is changed (if you are at an endpoint and the plot is changed, the page will be reloaded
to reflect that)
- New components/moved-over information:
- `Fileuploadcomponents` --> css code has been udpated to be dark theme-friendly
- `FileList` --> moved over
- `Loginlogout` --> created component, login/logout process has been relegated to avatar icon
dropdown menu
- `Plotselection` --> partially created from SelectPlot, changed to utilize dynamic
routing/selection instead of requiring a new dropdown in each page
## Setting up for Local Development

This project uses NextJS v14(+), and server interactions and setup are handled through their interface. Please note
that for local development, you will **not** be able to use the NextJS-provided `next start` command due to the way that
the application is packaged for Azure deployment. Instead, please use the `next dev` command to start the local
development server to use the application.

> Note: the development server compiles and loads the application in real time as you interact with the website.
> Accordingly, **load times for API endpoints and other components will be much longer than the actual site's.** Please
> do not use these load times as an indicator of load times within the deployed application instance!
### Production vs Development Branches

The `main` branch of this repository is the production branch, and the `forestgeo-app-development` is the deployed
development branch. When adding new features or making changes to the application, please branch off of the
`forestgeo-app-development` branch instead of `main`. The production branch should not be used as a baseline and should
only be modified via approved PRs.

### Azure-side Setup Requirements

The application maintains a live connection to an Azure Storage and a Azure MySQL server instance. Before you can use
the application, please ensure that you work with a ForestGEO administrator to:

1. add your email address to the managing database,
2. provide you with a role and,
3. assign the testing schemas to your account

> It is critical that live sites actively being used by researchers are not mistakenly modified or damaged!
### Setting up the Environment

> **Note:** The following instructions assume that you have `NodeJS` and `npm` installed on your local machine.
After cloning the repository, please run `npm install` to install required dependencies.

The application requires a set of environmental variables stored in a `.env.local` file in order to run locally. Please
contact a repository administrator to request access to the key-vault storage, named `forestgeo-app-key-vault`. Once you
can access it, please retrieve all noted secrets in the repository and place them in your `.env.local` file. The name of
the secret corresponds to the name of the environmental variable. Please use the following example as a template:

Let's assume that the keyvault storage has a secret named `EXAMPLE-SECRET`, with a corresponding value of `1234`.
In order to use this secret in your local environment, add it to your `.env.local` file like this:

`EXAMPLE_SECRET=1234`

Please note that the name of the secret in the keyvault uses **hyphens**, while the name of the environmental variable
uses **underscores**. Please ensure you **replace all hyphens with underscores** when adding the secret to your
`.env.local` file.

Once you have successfully created your `.env.local` file, please run `npm run dev` to start the local development
server.

> **Ensure that you have port 3000 open and available on your local machine before starting the server!**
9 changes: 0 additions & 9 deletions frontend/app/(hub)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ export default function DashboardPage() {
try {
setIsLoading(true);

// Check if the required data is available, otherwise return a padded array
if (!currentSite || !currentPlot || !currentCensus) {
setChangelogHistory(Array(5).fill({}));
return;
Expand Down Expand Up @@ -161,14 +160,6 @@ export default function DashboardPage() {
</Typography>
</ListItemContent>
</ListItem>
<ListItem>
<ListItemContent>
<Typography level="body-md">
<strong>Plot-Species List</strong> - See existing taxonomy information for stems in your plot and census here.{' '}
<strong>Requires a census.</strong>
</Typography>
</ListItemContent>
</ListItem>
</List>
</ListItem>
</List>
Expand Down
16 changes: 0 additions & 16 deletions frontend/app/(hub)/fixeddatainput/stemtaxonomies/error.tsx

This file was deleted.

7 changes: 0 additions & 7 deletions frontend/app/(hub)/fixeddatainput/stemtaxonomies/page.tsx

This file was deleted.

3 changes: 1 addition & 2 deletions frontend/app/(hub)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import dynamic from 'next/dynamic';
import { Box, IconButton, Stack, Typography } from '@mui/joy';
import Divider from '@mui/joy/Divider';
import { useLoading } from '@/app/contexts/loadingprovider';
import { getAllSchemas } from '@/components/processors/processorhelperfunctions';
import { useOrgCensusContext, usePlotContext, useSiteContext } from '@/app/contexts/userselectionprovider';
import { useOrgCensusListDispatch, usePlotListDispatch, useQuadratListDispatch, useSiteListDispatch } from '@/app/contexts/listselectionprovider';
import { getEndpointHeaderName, siteConfig } from '@/config/macros/siteconfigs';
Expand Down Expand Up @@ -96,7 +95,7 @@ export default function HubLayout({ children }: { children: React.ReactNode }) {
}
}
} catch (e: any) {
const allsites = await getAllSchemas();
const allsites = await (await fetch(`/api/fetchall/sites?schema=${currentSite?.schemaName ?? ''}`)).json();
if (siteListDispatch) await siteListDispatch({ siteList: allsites });
} finally {
setLoading(false);
Expand Down
26 changes: 15 additions & 11 deletions frontend/app/api/auth/[[...nextauth]]/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import NextAuth, { AzureADProfile } from 'next-auth';
import AzureADProvider from 'next-auth/providers/azure-ad';
import { getAllowedSchemas, getAllSchemas } from '@/components/processors/processorhelperfunctions';
import { UserAuthRoles } from '@/config/macros';
import { SitesRDS } from '@/config/sqlrdsdefinitions/zones';
import { getConn, runQuery } from '@/components/processors/processormacros';
import { SitesRDS, SitesResult } from '@/config/sqlrdsdefinitions/zones';
import ConnectionManager from '@/config/connectionmanager';
import MapperFactory from '@/config/datamapper';

const handler = NextAuth({
secret: process.env.NEXTAUTH_SECRET!,
Expand All @@ -28,11 +28,11 @@ const handler = NextAuth({
return false; // Email is not a valid string, abort sign-in
}
if (userEmail) {
let conn, emailVerified, userStatus;
const connectionManager = new ConnectionManager();
let emailVerified, userStatus, userID;
try {
conn = await getConn();
const query = `SELECT UserStatus FROM catalog.users WHERE Email = '${userEmail}' LIMIT 1`;
const results = await runQuery(conn, query);
const query = `SELECT UserID, UserStatus FROM catalog.users WHERE Email = '${userEmail}' LIMIT 1`;
const results = await connectionManager.executeQuery(query);

// emailVerified is true if there is at least one result
emailVerified = results.length > 0;
Expand All @@ -41,17 +41,21 @@ const handler = NextAuth({
return false;
}
userStatus = results[0].UserStatus;
userID = results[0].UserID;
} catch (e: any) {
console.error('Error fetching user status:', e);
throw new Error('Failed to fetch user status.');
} finally {
if (conn) conn.release();
}
user.userStatus = userStatus as UserAuthRoles;
user.email = userEmail;
// console.log('getting all sites: ');
const allSites = await getAllSchemas();
const allowedSites = await getAllowedSchemas(userEmail);
const allSites = MapperFactory.getMapper<SitesRDS, SitesResult>('sites').mapData(await connectionManager.executeQuery(`SELECT * FROM catalog.sites`));
const allowedSites = MapperFactory.getMapper<SitesRDS, SitesResult>('sites').mapData(
await connectionManager.executeQuery(
`SELECT s.* FROM catalog.sites AS s JOIN catalog.usersiterelations AS usr ON s.SiteID = usr.SiteID WHERE usr.UserID = ?`,
[userID]
)
);
if (!allowedSites || !allSites) {
console.error('User does not have any allowed sites.');
return false;
Expand Down
Loading

0 comments on commit f7adc95

Please sign in to comment.