Skip to content

Commit

Permalink
Merge pull request #761 from wri/release/utltimate-ulmus
Browse files Browse the repository at this point in the history
[RELEASE] Utltimate Ulmus
  • Loading branch information
roguenet authored Dec 20, 2024
2 parents bcb0891 + ec1104e commit 348b037
Show file tree
Hide file tree
Showing 206 changed files with 7,807 additions and 1,320 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/deploy-github-storybook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Workflow taken from the Storybook docs: https://storybook.js.org/docs/sharing/publish-storybook#github-pages
name: Build and Publish Storybook to GitHub Pages

on:
push:
branches:
- 'staging'

permissions:
contents: read
pages: write
id-token: write

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20.x'

- uses: bitovi/[email protected]
with:
install_command: yarn install
build_command: yarn build-storybook
path: storybook-static
checkout: false
3 changes: 2 additions & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: pull-request
on:
pull_request:
branches: [main, staging, release/**]
jobs:
test:
runs-on: ubuntu-latest
Expand All @@ -14,3 +13,5 @@ jobs:
run: yarn
- name: Test
run: yarn run jest --ci
- name: Build
run: NEXT_PUBLIC_TARGET_ENV=staging yarn build
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# 🌲 Terramatch Web Platform 🌲

### Storybook
We host the `staging` build of Storybook on [Github Pages](https://wri.github.io/wri-terramatch-website/)

### Installation

```
Expand Down
4 changes: 2 additions & 2 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ const userSentryWebpackPluginOptions = {
// Suppresses source map uploading logs during build
silent: true,

org: process.env.SENTRY_ORG || "3-sided-cube",
project: process.env.SENTRY_PROJECT || "wri-web-platform-version-2",
org: process.env.SENTRY_ORG ?? "wri-terramatch",
project: process.env.SENTRY_PROJECT ?? "terramatch-frontend",
authToken: process.env.SENTRY_AUTH_TOKEN
};

Expand Down
28 changes: 22 additions & 6 deletions openapi-codegen.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,40 @@ type EnvironmentName = (typeof ENVIRONMENT_NAMES)[number];
type Environment = {
apiBaseUrl: string;
userServiceUrl: string;
jobServiceUrl: string;
entityServiceUrl: string;
};

const ENVIRONMENTS: { [Property in EnvironmentName]: Environment } = {
local: {
apiBaseUrl: "http://localhost:8080",
userServiceUrl: "http://localhost:4010"
userServiceUrl: "http://localhost:4010",
jobServiceUrl: "http://localhost:4020",
entityServiceUrl: "http://localhost:4050"
},
dev: {
apiBaseUrl: "https://api-dev.terramatch.org",
userServiceUrl: "https://api-dev.terramatch.org"
userServiceUrl: "https://api-dev.terramatch.org",
jobServiceUrl: "https://api-dev.terramatch.org",
entityServiceUrl: "https://api-dev.terramatch.org"
},
test: {
apiBaseUrl: "https://api-test.terramatch.org",
userServiceUrl: "https://api-test.terramatch.org"
userServiceUrl: "https://api-test.terramatch.org",
jobServiceUrl: "https://api-test.terramatch.org",
entityServiceUrl: "https://api-test.terramatch.org"
},
staging: {
apiBaseUrl: "https://api-staging.terramatch.org",
userServiceUrl: "https://api-staging.terramatch.org"
userServiceUrl: "https://api-staging.terramatch.org",
jobServiceUrl: "https://api-staging.terramatch.org",
entityServiceUrl: "https://api-staging.terramatch.org"
},
prod: {
apiBaseUrl: "https://api.terramatch.org",
userServiceUrl: "https://api.terramatch.org"
userServiceUrl: "https://api.terramatch.org",
jobServiceUrl: "https://api.terramatch.org",
entityServiceUrl: "https://api.terramatch.org"
}
};

Expand All @@ -60,13 +72,17 @@ if (!ENVIRONMENT_NAMES.includes(declaredEnv as EnvironmentName)) {
const DEFAULTS = ENVIRONMENTS[declaredEnv];
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL ?? DEFAULTS.apiBaseUrl;
const userServiceUrl = process.env.NEXT_PUBLIC_USER_SERVICE_URL ?? DEFAULTS.userServiceUrl;
const jobServiceUrl = process.env.NEXT_PUBLIC_JOB_SERVICE_URL ?? DEFAULTS.jobServiceUrl;
const entityServiceUrl = process.env.NEXT_PUBLIC_ENTITY_SERVICE_URL ?? DEFAULTS.entityServiceUrl;

// The services defined in the v3 Node BE codebase. Although the URL path for APIs in the v3 space
// are namespaced by feature set rather than service (a service may contain multiple namespaces), we
// isolate the generated API integration by service to make it easier for a developer to find where
// the associated BE code is for a given FE API integration.
const SERVICES = {
"user-service": userServiceUrl
"user-service": userServiceUrl,
"job-service": jobServiceUrl,
"entity-service": entityServiceUrl
};

const config: Record<string, Config> = {
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"generate:api": "openapi-codegen gen api",
"generate:jobService": "openapi-codegen gen jobService",
"generate:userService": "openapi-codegen gen userService",
"generate:services": "npm run generate:userService",
"generate:entityService": "openapi-codegen gen entityService",
"generate:services": "yarn generate:userService && yarn generate:entityService && yarn generate:jobService",
"tx:push": "eval $(grep '^TRANSIFEX_TOKEN' .env) && eval $(grep '^TRANSIFEX_SECRET' .env) && txjs-cli push --key-generator=hash src/ --token=$TRANSIFEX_TOKEN --secret=$TRANSIFEX_SECRET",
"tx:pull": "eval $(grep '^TRANSIFEX_TOKEN' .env) && eval $(grep '^TRANSIFEX_SECRET' .env) && txjs-cli pull --token=$TRANSIFEX_TOKEN --secret=$TRANSIFEX_SECRET"
},
Expand Down
Binary file modified public/images/graphic-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions public/images/graphic-8.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/images/map-img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/monitoring-graph-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/monitoring-graph-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/monitoring-graph-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/monitoring-graph-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/monitoring-graph-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 80 additions & 0 deletions src/admin/components/Alerts/DelayedJobsProgressAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Alert, AlertTitle, CircularProgress } from "@mui/material";
import { FC, useEffect, useState } from "react";
import { useStore } from "react-redux";

import ApiSlice from "@/store/apiSlice";
import { AppStore } from "@/store/store";

type DelayedJobsProgressAlertProps = {
show: boolean;
title?: string;
setIsLoadingDelayedJob?: (value: boolean) => void;
};

const DelayedJobsProgressAlert: FC<DelayedJobsProgressAlertProps> = ({ show, title, setIsLoadingDelayedJob }) => {
const [delayedJobProcessing, setDelayedJobProcessing] = useState<number>(0);
const [delayedJobTotal, setDalayedJobTotal] = useState<number>(0);
const [progressMessage, setProgressMessage] = useState<string>("Running 0 out of 0 polygons (0%)");

const store = useStore<AppStore>();
useEffect(() => {
let intervalId: any;
if (show) {
intervalId = setInterval(() => {
const { total_content, processed_content, progress_message } = store.getState().api;
setDalayedJobTotal(total_content);
setDelayedJobProcessing(processed_content);
if (progress_message != "") {
setProgressMessage(progress_message);
}
}, 1000);
}

return () => {
if (intervalId) {
setDelayedJobProcessing(0);
setDalayedJobTotal(0);
setProgressMessage("Running 0 out of 0 polygons (0%)");
clearInterval(intervalId);
}
};
}, [show]);

const abortDelayedJob = () => {
ApiSlice.abortDelayedJob(true);
ApiSlice.addTotalContent(0);
ApiSlice.addProgressContent(0);
ApiSlice.addProgressMessage("Running 0 out of 0 polygons (0%)");
setDelayedJobProcessing(0);
setDalayedJobTotal(0);
setIsLoadingDelayedJob?.(false);
};

if (!show) return null;

const calculatedProgress = delayedJobTotal! > 0 ? Math.round((delayedJobProcessing! / delayedJobTotal!) * 100) : 0;

const severity = calculatedProgress >= 75 ? "success" : calculatedProgress >= 50 ? "info" : "warning";

return (
<div className="fixed bottom-5 left-0 z-50 flex w-full items-center justify-center">
<Alert
severity={severity}
icon={<CircularProgress size={18} color="inherit" />}
action={
<button
onClick={abortDelayedJob}
className="ml-2 rounded px-2 py-1 text-sm font-medium text-red-200 hover:bg-red-300"
>
Cancel
</button>
}
>
<AlertTitle>{title}</AlertTitle>
{progressMessage ?? "Running 0 out of 0 polygons (0%)"}
</Alert>
</div>
);
};

export default DelayedJobsProgressAlert;
53 changes: 28 additions & 25 deletions src/admin/components/EntityEdit/EntityEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useNavigate, useParams } from "react-router-dom";
import modules from "@/admin/modules";
import WizardForm from "@/components/extensive/WizardForm";
import LoadingContainer from "@/components/generic/Loading/LoadingContainer";
import EntityProvider from "@/context/entity.provider";
import FrameworkProvider, { Framework } from "@/context/framework.provider";
import {
GetV2FormsENTITYUUIDResponse,
Expand Down Expand Up @@ -73,31 +74,33 @@ export const EntityEdit = () => {
<div className="mx-auto w-full max-w-7xl">
<LoadingContainer loading={isLoading}>
<FrameworkProvider frameworkKey={framework}>
<WizardForm
steps={formSteps!}
errors={error}
onBackFirstStep={() => navigate("..")}
onChange={data =>
updateEntity({
pathParams: { uuid: entityUUID, entity: entityName },
body: { answers: normalizedFormData(data, formSteps!) }
})
}
formStatus={isSuccess ? "saved" : isUpdating ? "saving" : undefined}
onSubmit={() => navigate(createPath({ resource, id, type: "show" }))}
defaultValues={defaultValues}
title={title}
tabOptions={{
markDone: true,
disableFutureTabs: true
}}
summaryOptions={{
title: "Review Details",
downloadButtonText: "Download"
}}
roundedCorners
hideSaveAndCloseButton
/>
<EntityProvider entityUuid={entityUUID} entityName={entityName}>
<WizardForm
steps={formSteps!}
errors={error}
onBackFirstStep={() => navigate("..")}
onChange={data =>
updateEntity({
pathParams: { uuid: entityUUID, entity: entityName },
body: { answers: normalizedFormData(data, formSteps!) }
})
}
formStatus={isSuccess ? "saved" : isUpdating ? "saving" : undefined}
onSubmit={() => navigate(createPath({ resource, id, type: "show" }))}
defaultValues={defaultValues}
title={title}
tabOptions={{
markDone: true,
disableFutureTabs: true
}}
summaryOptions={{
title: "Review Details",
downloadButtonText: "Download"
}}
roundedCorners
hideSaveAndCloseButton
/>
</EntityProvider>
</FrameworkProvider>
</LoadingContainer>
</div>
Expand Down
18 changes: 15 additions & 3 deletions src/admin/components/Fields/CustomChipField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,36 @@ const STATUS_CLASSNAME_MAP: { [key: string]: string } = {
Approved: "bg-green-30 text-green-100",
Rejected: "bg-yellow-300 text-yellow-700",
"Under Review": "bg-yellow-300 text-yellow-700",
Submitted: "bg-blue-200 text-blue",
"Awaiting approval": "bg-blue-200 text-blue",
"Awaiting Review": "bg-blue-200 text-blue",
"Planting In Progress": "bg-yellow-300 text-yellow-700",
"Restoration in progress": "bg-green-30 text-green-100",
Draft: "bg-grey-200 text-grey-500",
Started: "bg-grey-200 text-grey-500",
Unknown: "bg-grey-200 text-grey-500",
"Needs Info": "bg-tertiary-50 text-tertiary-650",
"Needs more information": "bg-tertiary-50 text-tertiary-650",
"More info requested": "bg-tertiary-50 text-tertiary-650",
"No Update": "bg-grey-200 text-grey-500"
"No Update": "bg-grey-200 text-grey-500",
approved: "bg-green-30 text-green-100",
submitted: "bg-blue-200 text-blue",
"needs-more-information": "bg-tertiary-50 text-tertiary-650"
};

const CustomChipField = ({ label = "" }: { label: string | undefined }) => {
const CustomChipField = ({
label = "",
classNameChipField
}: {
label: string | undefined;
classNameChipField?: string;
}) => {
return (
<div
className={classNames(
"text-14 w-fit-content whitespace-nowrap rounded-[3px] px-2 capitalize",
STATUS_CLASSNAME_MAP[label] ?? "bg-grey-200 text-grey-500"
STATUS_CLASSNAME_MAP[label] ?? "bg-grey-200 text-grey-500",
classNameChipField
)}
>
{label == "Unknown" ? "Started" : label}
Expand Down
31 changes: 31 additions & 0 deletions src/admin/components/ResourceTabs/AuditLogTab/AuditLogTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { NURSERY_REPORT, PROJECT_REPORT, SITE_REPORT } from "@/constants/entitie
import useAuditLogActions from "@/hooks/AuditStatus/useAuditLogActions";

import AuditLogSiteTabSelection from "./components/AuditLogSiteTabSelection";
import AuditLogTable from "./components/AuditLogTable";
import SiteAuditLogEntityStatus from "./components/SiteAuditLogEntityStatus";
import SiteAuditLogEntityStatusSide from "./components/SiteAuditLogEntityStatusSide";
import SiteAuditLogProjectStatus from "./components/SiteAuditLogProjectStatus";
Expand Down Expand Up @@ -58,6 +59,10 @@ const AuditLogTab: FC<IProps> = ({ label, entity, ...rest }) => {
loadEntityList();
}, [buttonToggle]);

const isSite = buttonToggle === AuditLogButtonStates.SITE;
const redirectTo = `${basename}/${modules.site.ResourceName}/${selected?.uuid}/show/6`;
const title = () => selected?.title ?? selected?.name;

const verifyEntity = ["reports", "nursery"].some(word => ReverseButtonStates2[entity!].includes(word));

const verifyEntityReport = () => {
Expand Down Expand Up @@ -133,6 +138,32 @@ const AuditLogTab: FC<IProps> = ({ label, entity, ...rest }) => {
/>
</Grid>
</Grid>
<div className="px-2 py-2">
<When condition={buttonToggle === AuditLogButtonStates.PROJECT && !record?.project}>
<Text variant="text-16-bold" className="mb-6">
History and Discussion for {record && record?.name}
</Text>
{auditLogData && <AuditLogTable auditLogData={auditLogData} auditData={auditData} refresh={refetch} />}
</When>
<When condition={buttonToggle !== AuditLogButtonStates.PROJECT || verifyEntity}>
<>
<div className="mb-6">
{!isSite && !verifyEntity && <Text variant="text-16-bold">History and Discussion for {title()}</Text>}
{(isSite || verifyEntity) && (
<Text variant="text-16-bold">
History and Discussion for{" "}
<Link className="text-16-bold !text-[#000000DD]" to={redirectTo}>
{title()}
</Link>
</Text>
)}
</div>
<When condition={!!auditLogData}>
<AuditLogTable auditLogData={auditLogData!} auditData={auditData} refresh={refetch} />
</When>
</>
</When>
</div>
</TabbedShowLayout.Tab>
</When>
);
Expand Down
Loading

0 comments on commit 348b037

Please sign in to comment.