From 747c4a54fa4529ff309d8343c104ed7e3a2cd095 Mon Sep 17 00:00:00 2001 From: Jorge Monroy Date: Tue, 28 Jan 2025 15:40:07 -0400 Subject: [PATCH 01/14] [TM-1545] fix messages (#843) --- .../components/ValidationPolygonFileShow.tsx | 4 +++- .../elements/Map-mapbox/MapControls/PolygonHandler.tsx | 4 +++- .../elements/MapPolygonPanel/VersionInformation.tsx | 4 +++- src/pages/site/[uuid]/tabs/Overview.tsx | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/admin/modules/validationPolygonFile/components/ValidationPolygonFileShow.tsx b/src/admin/modules/validationPolygonFile/components/ValidationPolygonFileShow.tsx index 1ffd9336c..bec6d42a5 100644 --- a/src/admin/modules/validationPolygonFile/components/ValidationPolygonFileShow.tsx +++ b/src/admin/modules/validationPolygonFile/components/ValidationPolygonFileShow.tsx @@ -15,6 +15,7 @@ import { fetchPostV2TerrafundUploadShapefileValidate } from "@/generated/apiComponents"; import { FileType, UploadedFile } from "@/types/common"; +import { getErrorMessageFromPayload } from "@/utils/errors"; const ValidatePolygonFileShow: FC = () => { const { openModal, closeModal } = useModalContext(); @@ -95,7 +96,8 @@ const ValidatePolygonFileShow: FC = () => { } openNotification("error", errorMessage, t("Error uploading file")); } else { - openNotification("error", t("An unknown error occurred"), t("Error uploading file")); + const errorMessage = getErrorMessageFromPayload(error); + openNotification("error", t("Error uploading file"), t(errorMessage)); } } hideLoader(); diff --git a/src/components/elements/Map-mapbox/MapControls/PolygonHandler.tsx b/src/components/elements/Map-mapbox/MapControls/PolygonHandler.tsx index 30708dfd8..78565d6fb 100644 --- a/src/components/elements/Map-mapbox/MapControls/PolygonHandler.tsx +++ b/src/components/elements/Map-mapbox/MapControls/PolygonHandler.tsx @@ -17,6 +17,7 @@ import { fetchPostV2TerrafundUploadShapefileProject } from "@/generated/apiComponents"; import { FileType, UploadedFile } from "@/types/common"; +import { getErrorMessageFromPayload } from "@/utils/errors"; import Button from "../../Button/Button"; @@ -98,7 +99,8 @@ export const PolygonHandler = () => { } openNotification("error", errorMessage, t("Error uploading file")); } else { - openNotification("error", t("An unknown error occurred"), t("Error uploading file")); + const errorMessage = getErrorMessageFromPayload(error); + openNotification("error", t("Error uploading file"), t(errorMessage)); } } hideLoader(); diff --git a/src/components/elements/MapPolygonPanel/VersionInformation.tsx b/src/components/elements/MapPolygonPanel/VersionInformation.tsx index 3a1bc49eb..3441e2211 100644 --- a/src/components/elements/MapPolygonPanel/VersionInformation.tsx +++ b/src/components/elements/MapPolygonPanel/VersionInformation.tsx @@ -23,6 +23,7 @@ import { } from "@/generated/apiComponents"; import { SitePolygon, SitePolygonsDataResponse } from "@/generated/apiSchemas"; import { FileType, UploadedFile } from "@/types/common"; +import { getErrorMessageFromPayload } from "@/utils/errors"; import Menu from "../Menu/Menu"; import { MENU_PLACEMENT_RIGHT_BOTTOM } from "../Menu/MenuVariant"; @@ -147,7 +148,8 @@ const VersionInformation = ({ } openNotification("error", t("Error uploading file"), errorMessage); } else { - openNotification("error", t("Error uploading file"), t("An unknown error occurred")); + const errorMessage = getErrorMessageFromPayload(error); + openNotification("error", t("Error uploading file"), t(errorMessage)); } } }; diff --git a/src/pages/site/[uuid]/tabs/Overview.tsx b/src/pages/site/[uuid]/tabs/Overview.tsx index a265e61bd..9a9b16eb5 100644 --- a/src/pages/site/[uuid]/tabs/Overview.tsx +++ b/src/pages/site/[uuid]/tabs/Overview.tsx @@ -40,6 +40,7 @@ import { SitePolygonsDataResponse, SitePolygonsLoadedDataResponse } from "@/gene import { getEntityDetailPageLink } from "@/helpers/entity"; import { statusActionsMap } from "@/hooks/AuditStatus/useAuditLogActions"; import { FileType, UploadedFile } from "@/types/common"; +import { getErrorMessageFromPayload } from "@/utils/errors"; import Log from "@/utils/log"; import SiteArea from "../components/SiteArea"; @@ -172,7 +173,8 @@ const SiteOverviewTab = ({ site, refetch: refetchEntity }: SiteOverviewTabProps) } openNotification("error", t("Error uploading file"), errorMessage); } else { - openNotification("error", t("Error uploading file"), t("An unknown error occurred")); + const errorMessage = getErrorMessageFromPayload(error); + openNotification("error", t("Error uploading file"), t(errorMessage)); } } finally { hideLoader(); From e0dc965840e83a167ab63384fdf62f560f873da3 Mon Sep 17 00:00:00 2001 From: Jorge Monroy Date: Tue, 28 Jan 2025 16:16:15 -0400 Subject: [PATCH 02/14] [TM-1651] add context within country (#844) --- src/hooks/useMessageValidations.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/hooks/useMessageValidations.ts b/src/hooks/useMessageValidations.ts index f88dc552a..84b088c1d 100644 --- a/src/hooks/useMessageValidations.ts +++ b/src/hooks/useMessageValidations.ts @@ -59,6 +59,30 @@ export const useMessageValidators = () => { }, [t] ); + const getTargetCountryMessage = useMemo( + () => + (extraInfo: any): string[] => { + if (!extraInfo) return []; + + try { + const infoObject = JSON.parse(extraInfo); + if (infoObject && typeof infoObject === "object" && "country_name" in infoObject) { + const countryName = infoObject.country_name || "Unknown Country"; + return [ + t("Target Country: The polygon should be located inside {country}", { + country: countryName + }) + ]; + } else { + return [t("Error: Country information is missing in extra info.")]; + } + } catch (error) { + Log.error("Failed to get target country message", error); + return [t("Error parsing extra info.")]; + } + }, + [t] + ); const getDataMessage = useMemo( () => (extraInfo: string | undefined) => { if (!extraInfo) return []; @@ -159,11 +183,13 @@ export const useMessageValidators = () => { return getIntersectionMessages(extraInfo); } else if (criteria_id === 14) { return getDataMessage(extraInfo); + } else if (criteria_id === 7) { + return getTargetCountryMessage(extraInfo); } else { return []; } }, - [getProjectGoalMessage, getIntersectionMessages, getDataMessage] + [getProjectGoalMessage, getIntersectionMessages, getDataMessage, getTargetCountryMessage] ); return { From 78f24c63fd709cf05a17b0864a571e5567c8ccf2 Mon Sep 17 00:00:00 2001 From: Jose Carlos Laura Ramirez Date: Tue, 28 Jan 2025 16:40:14 -0400 Subject: [PATCH 03/14] [TM-1637] allow framework admins to create edit users (#845) --- .../Actions/ListActionsCreateFilter.tsx | 6 +++--- src/admin/hooks/useGetUserRole.ts | 3 ++- src/admin/modules/user/components/UserCreate.tsx | 16 +++++++++++++--- src/admin/modules/user/components/UserEdit.tsx | 14 +++++++++++--- src/admin/modules/user/components/UserList.tsx | 7 +++++-- src/admin/modules/user/const.ts | 11 +++++++++++ 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/admin/components/Actions/ListActionsCreateFilter.tsx b/src/admin/components/Actions/ListActionsCreateFilter.tsx index d47a81d90..1873d21b8 100644 --- a/src/admin/components/Actions/ListActionsCreateFilter.tsx +++ b/src/admin/components/Actions/ListActionsCreateFilter.tsx @@ -3,13 +3,13 @@ import { Button, CreateButton, FilterButton, TopToolbar } from "react-admin"; import { When } from "react-if"; interface ListActionsCreateFilterProps { - isSuperAdmin?: boolean; + canCreateUser?: boolean; onExport?: () => void; } -const ListActionsCreateFilter = ({ isSuperAdmin, onExport }: ListActionsCreateFilterProps) => ( +const ListActionsCreateFilter = ({ canCreateUser, onExport }: ListActionsCreateFilterProps) => ( - + diff --git a/src/admin/hooks/useGetUserRole.ts b/src/admin/hooks/useGetUserRole.ts index f9d485a73..51fba7984 100644 --- a/src/admin/hooks/useGetUserRole.ts +++ b/src/admin/hooks/useGetUserRole.ts @@ -8,6 +8,7 @@ export const useGetUserRole = () => { role: user.primaryRole, isSuperAdmin: user.primaryRole === "admin-super", isPPCAdmin: user.primaryRole === "admin-ppc", - isPPCTerrafundAdmin: user.primaryRole === "admin-terrafund" + isPPCTerrafundAdmin: user.primaryRole === "admin-terrafund", + isFrameworkAdmin: user.primaryRole && user.primaryRole.includes("admin-") }; }; diff --git a/src/admin/modules/user/components/UserCreate.tsx b/src/admin/modules/user/components/UserCreate.tsx index c1b3526dc..0efae8f5b 100644 --- a/src/admin/modules/user/components/UserCreate.tsx +++ b/src/admin/modules/user/components/UserCreate.tsx @@ -1,3 +1,4 @@ +import { useMemo } from "react"; import { AutocompleteInput, Create, @@ -13,6 +14,7 @@ import { useGetUserRole } from "@/admin/hooks/useGetUserRole"; import { countriesChoices, directFrameworkChoices, + frameworkAdminPrimaryRoleChoices, frameworkChoices, userPrimaryRoleChoices } from "@/admin/modules/user/const"; @@ -21,7 +23,7 @@ import { validateForm } from "@/admin/utils/forms"; import modules from "../.."; const UserCreate = () => { - const { isSuperAdmin } = useGetUserRole(); + const { isFrameworkAdmin, isSuperAdmin, role } = useGetUserRole(); const schemaObject: any = { first_name: yup.string().nullable().required("First Name is required"), @@ -34,10 +36,18 @@ const UserCreate = () => { country: yup.string().nullable() }; - if (isSuperAdmin) { + if (isFrameworkAdmin) { schemaObject.role = yup.string().required("Role is required"); } + const roleChoices = useMemo(() => { + if (isSuperAdmin) { + return userPrimaryRoleChoices; + } + + return [...frameworkAdminPrimaryRoleChoices, userPrimaryRoleChoices.find(choice => choice.id === role)]; + }, [isFrameworkAdmin]); + return ( @@ -56,7 +66,7 @@ const UserCreate = () => { - {isSuperAdmin && } + {isFrameworkAdmin && } diff --git a/src/admin/modules/user/components/UserEdit.tsx b/src/admin/modules/user/components/UserEdit.tsx index 2623f6ac6..c1694ea63 100644 --- a/src/admin/modules/user/components/UserEdit.tsx +++ b/src/admin/modules/user/components/UserEdit.tsx @@ -1,3 +1,4 @@ +import { useMemo } from "react"; import { AutocompleteInput, Edit, @@ -13,6 +14,7 @@ import { useGetUserRole } from "@/admin/hooks/useGetUserRole"; import { countriesChoices, directFrameworkChoices, + frameworkAdminPrimaryRoleChoices, frameworkChoices, userPrimaryRoleChoices } from "@/admin/modules/user/const"; @@ -22,7 +24,7 @@ import modules from "../.."; import UserTitle from "./UserTitle"; const UserEdit = () => { - const { isSuperAdmin } = useGetUserRole(); + const { isFrameworkAdmin, isSuperAdmin, role } = useGetUserRole(); const schemaObject: any = { first_name: yup.string().nullable().required(), last_name: yup.string().nullable().required(), @@ -32,7 +34,13 @@ const UserEdit = () => { organisation: yup.object() }; - if (isSuperAdmin) schemaObject.role = yup.string().required(); + const roleChoices = useMemo(() => { + if (isSuperAdmin) { + return userPrimaryRoleChoices; + } + + return [...frameworkAdminPrimaryRoleChoices, userPrimaryRoleChoices.find(choice => choice.id === role)]; + }, [isFrameworkAdmin]); return ( } mutationMode="pessimistic" actions={false}> @@ -51,7 +59,7 @@ const UserEdit = () => { - {isSuperAdmin && } + {isFrameworkAdmin && } { export const UserList = () => { const [exporting, setExporting] = useState(false); - const { isSuperAdmin } = useGetUserRole(); + const { isFrameworkAdmin } = useGetUserRole(); const userDataProvider = useDataProvider(); @@ -108,7 +108,10 @@ export const UserList = () => { - } filters={filters}> + } + filters={filters} + > diff --git a/src/admin/modules/user/const.ts b/src/admin/modules/user/const.ts index f49448787..b68e08244 100644 --- a/src/admin/modules/user/const.ts +++ b/src/admin/modules/user/const.ts @@ -1,6 +1,17 @@ import { getCountriesOptions } from "@/constants/options/countries"; import { Framework } from "@/context/framework.provider"; +export const frameworkAdminPrimaryRoleChoices = [ + { + id: "project-developer", + name: "Project Developer" + }, + { + id: "project-manager", + name: "Project Manager" + } +]; + export const userPrimaryRoleChoices = [ { id: "admin-ppc", From 738e0f473605a9a4fd8359f0ad85b54cea197488 Mon Sep 17 00:00:00 2001 From: Nathan Curtis Date: Tue, 28 Jan 2025 12:57:56 -0800 Subject: [PATCH 04/14] [TM-1640] Avoid overlapping and superfluous form updates. --- .../components/EntityEdit/EntityEdit.tsx | 16 +--- src/hooks/useFormUpdate.ts | 78 +++++++++++++++++++ .../edit/[uuid]/EditEntityForm.tsx | 17 ++-- 3 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 src/hooks/useFormUpdate.ts diff --git a/src/admin/components/EntityEdit/EntityEdit.tsx b/src/admin/components/EntityEdit/EntityEdit.tsx index 81ef49f10..a7f271d0c 100644 --- a/src/admin/components/EntityEdit/EntityEdit.tsx +++ b/src/admin/components/EntityEdit/EntityEdit.tsx @@ -7,13 +7,10 @@ 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, - useGetV2FormsENTITYUUID, - usePutV2FormsENTITYUUID -} from "@/generated/apiComponents"; +import { GetV2FormsENTITYUUIDResponse, useGetV2FormsENTITYUUID } from "@/generated/apiComponents"; import { normalizedFormData } from "@/helpers/customForms"; import { pluralEntityNameToSingular } from "@/helpers/entity"; +import { useFormUpdate } from "@/hooks/useFormUpdate"; import { useGetCustomFormSteps, useNormalizedFormDefaultValue @@ -39,7 +36,7 @@ export const EntityEdit = () => { const entityName = ResourceEntityMapping[resource] as EntityName; const entityUUID = id as string; - const { mutate: updateEntity, error, isSuccess, isLoading: isUpdating } = usePutV2FormsENTITYUUID({}); + const { updateEntity, error, isSuccess, isUpdating } = useFormUpdate(entityName, entityUUID); const { data: formResponse, @@ -79,12 +76,7 @@ export const EntityEdit = () => { steps={formSteps!} errors={error} onBackFirstStep={() => navigate("..")} - onChange={data => - updateEntity({ - pathParams: { uuid: entityUUID, entity: entityName }, - body: { answers: normalizedFormData(data, formSteps!) } - }) - } + onChange={data => updateEntity({ answers: normalizedFormData(data, formSteps!) })} formStatus={isSuccess ? "saved" : isUpdating ? "saving" : undefined} onSubmit={() => navigate(createPath({ resource, id, type: "show" }))} defaultValues={defaultValues} diff --git a/src/hooks/useFormUpdate.ts b/src/hooks/useFormUpdate.ts new file mode 100644 index 000000000..87df51a1d --- /dev/null +++ b/src/hooks/useFormUpdate.ts @@ -0,0 +1,78 @@ +import { isEqual } from "lodash"; +import { useEffect, useReducer } from "react"; +import { v4 as uuidv4 } from "uuid"; + +import { + PutV2FormsENTITYUUIDRequestBody, + PutV2FormsENTITYUUIDResponse, + usePutV2FormsENTITYUUID +} from "@/generated/apiComponents"; +import { EntityName } from "@/types/common"; +import Log from "@/utils/log"; + +type FormUpdateState = { + id: string; + started: boolean; + body: PutV2FormsENTITYUUIDRequestBody; +}[]; +type AddUpdateAction = { + type: "addUpdate"; + body: PutV2FormsENTITYUUIDRequestBody; +}; +type UpdateStartedAction = { + type: "updateStarted"; + id: string; +}; +type FormUpdateAction = AddUpdateAction | UpdateStartedAction; + +function reducer(state: FormUpdateState, action: FormUpdateAction): FormUpdateState { + if (action.type === "addUpdate") { + // If the body is the same as the front of the queue, ignore this update. The front of the + // queue is either the update in progress, or the update most recently sent. + if (isEqual(state[0]?.body, action.body)) return state; + return [{ id: uuidv4(), started: false, body: action.body }, ...state]; + } else if (action.type === "updateStarted") { + const idx = state.findIndex(({ id }) => id === action.id); + if (idx < 0) { + Log.error("Update not found in reducer state", { action, state }); + return state; + } + + // If we just started one, we no longer care about the rest of the queue. + return [...state.slice(0, idx), { ...state[idx], started: true }]; + } + + Log.warn("Unrecognized action", { action }); + return state; +} + +/** + * A hook to make calling the form update endpoint cleaner. Two factors are important that this fixes: + * 1) The WizardForm calls onChange really aggressively, and sometimes with the same data multiple times in a row. + * 2) When using usePutV2FormsENTITTYUUID directly in the form edit components, it was easily possible to issue + * multiple update requests to the BE in parallel, which has some hard to diagnose downstream effects (like + * duplicate Workdays getting created on reports) when the BE processes two identical updates at the same + * time from different threads. As such, this hook prevents two update requests from happening at the same time. + */ +export const useFormUpdate = (entityName: EntityName, entityUUID: string) => { + const { mutate, error, isSuccess, isLoading: isUpdating } = usePutV2FormsENTITYUUID({}); + const [updateState, dispatch] = useReducer(reducer, []); + + useEffect(() => { + if (isUpdating || updateState.length === 0 || updateState[0].started) return; + + // Pull the update from the front of the queue and send it. + const { id, body } = updateState[0]; + dispatch({ type: "updateStarted", id }); + mutate({ + pathParams: { uuid: entityUUID, entity: entityName }, + body + }); + }, [entityName, entityUUID, isUpdating, mutate, updateState]); + + const updateEntity = (body: PutV2FormsENTITYUUIDResponse) => { + dispatch({ type: "addUpdate", body }); + }; + + return { updateEntity, error, isSuccess, isUpdating }; +}; diff --git a/src/pages/entity/[entityName]/edit/[uuid]/EditEntityForm.tsx b/src/pages/entity/[entityName]/edit/[uuid]/EditEntityForm.tsx index c6832cb0d..248cd25b9 100644 --- a/src/pages/entity/[entityName]/edit/[uuid]/EditEntityForm.tsx +++ b/src/pages/entity/[entityName]/edit/[uuid]/EditEntityForm.tsx @@ -5,13 +5,10 @@ import { useMemo } from "react"; import WizardForm from "@/components/extensive/WizardForm"; import EntityProvider from "@/context/entity.provider"; import { useFrameworkContext } from "@/context/framework.provider"; -import { - GetV2FormsENTITYUUIDResponse, - usePutV2FormsENTITYUUID, - usePutV2FormsENTITYUUIDSubmit -} from "@/generated/apiComponents"; +import { GetV2FormsENTITYUUIDResponse, usePutV2FormsENTITYUUIDSubmit } from "@/generated/apiComponents"; import { normalizedFormData } from "@/helpers/customForms"; import { getEntityDetailPageLink, isEntityReport, pluralEntityNameToSingular } from "@/helpers/entity"; +import { useFormUpdate } from "@/hooks/useFormUpdate"; import { useGetCustomFormSteps, useNormalizedFormDefaultValue @@ -34,7 +31,7 @@ const EditEntityForm = ({ entityName, entityUUID, entity, formData }: EditEntity const mode = router.query.mode as string | undefined; //edit, provide-feedback-entity, provide-feedback-change-request const isReport = isEntityReport(entityName); - const { mutate: updateEntity, error, isSuccess, isLoading: isUpdating } = usePutV2FormsENTITYUUID({}); + const { updateEntity, error, isSuccess, isUpdating } = useFormUpdate(entityName, entityUUID); const { mutate: submitEntity, isLoading: isSubmitting } = usePutV2FormsENTITYUUIDSubmit({ onSuccess() { if (mode === "edit" || mode?.includes("provide-feedback")) { @@ -102,12 +99,8 @@ const EditEntityForm = ({ entityName, entityUUID, entity, formData }: EditEntity onCloseForm={() => router.push("/home")} onChange={(data, closeAndSave?: boolean) => updateEntity({ - pathParams: { uuid: entityUUID, entity: entityName }, - // @ts-ignore - body: { - answers: normalizedFormData(data, formSteps!), - ...(closeAndSave ? { continue_later_action: true } : {}) - } + answers: normalizedFormData(data, formSteps!), + ...(closeAndSave ? { continue_later_action: true } : {}) }) } formStatus={isSuccess ? "saved" : isUpdating ? "saving" : undefined} From 80fdffaeeead8ddb444fcd9b91423ea92a3f7edd Mon Sep 17 00:00:00 2001 From: Nathan Curtis Date: Tue, 28 Jan 2025 15:28:16 -0800 Subject: [PATCH 05/14] [TM-1658] Use different column headers for nursery seedlings. --- .../Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/elements/Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx b/src/components/elements/Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx index cb9b7aed2..ff6453114 100644 --- a/src/components/elements/Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx +++ b/src/components/elements/Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx @@ -78,6 +78,16 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => { props.withPreviousCounts && (isReport || (isEntity && ["sites", "nurseries"].includes(entityName))); const displayPreviousCounts = props.withPreviousCounts && isReport; const hasCountActive = props.withNumbers; + const totalReportedColumn = + collection === "nursery-seedling" + ? t("NEW SEEDLINGS PRODUCED THIS REPORT:") + : isReport + ? t("TOTAL PLANTED THIS REPORT:") + : hasCountActive + ? t("TREES TO BE PLANTED:") + : ""; + const totalToDateColumn = + collection === "nursery-seedling" ? t("TOTAL SEEDLINGS PRODUCED TO DATE:") : t("TOTAL PLANTED TO DATE:"); const entity = (handleBaseEntityTrees ? entityName : undefined) as EstablishmentEntityType; const uuid = handleBaseEntityTrees ? entityUuid : undefined; @@ -304,7 +314,7 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
- {isReport ? t("TOTAL PLANTED THIS REPORT:") : hasCountActive ? t("TREES TO BE PLANTED:") : ""} + {totalReportedColumn} {hasCountActive @@ -317,7 +327,7 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
- {t("TOTAL PLANTED TO DATE:")} + {totalToDateColumn} {totalWithPrevious.toLocaleString()} From eabefeaa82cee6d64503c098cf5b55b0c735de66 Mon Sep 17 00:00:00 2001 From: Nathan Curtis Date: Tue, 28 Jan 2025 16:33:01 -0800 Subject: [PATCH 06/14] [TM-1638][TM-1639] Fix use of detailed intervention types on project details. --- src/pages/project/[uuid]/tabs/Details.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/project/[uuid]/tabs/Details.tsx b/src/pages/project/[uuid]/tabs/Details.tsx index 89280b44a..4e51a4b0e 100644 --- a/src/pages/project/[uuid]/tabs/Details.tsx +++ b/src/pages/project/[uuid]/tabs/Details.tsx @@ -76,7 +76,9 @@ const ProjectDetailTab = ({ project }: ProjectDetailsTabProps) => { options={restorationStrategyOptions} selectedValues={project.restoration_strategy} /> - {project.history} + + {project.detailed_intervention_types} + {format(project.planting_start_date)} {format(project.planting_end_date)} From aa19da0534aa2f39ec800b5ed3efb6d8a1c33322 Mon Sep 17 00:00:00 2001 From: Limber Mamani <154026979+LimberHope@users.noreply.github.com> Date: Wed, 29 Jan 2025 12:39:36 -0400 Subject: [PATCH 07/14] [TM-1514] update banner progress goals (#850) * [TM-1514] update banner progress goals * [TM-1514] remove comment --- src/pages/project/[uuid]/tabs/GoalsAndProgress.tsx | 1 - src/pages/site/[uuid]/tabs/GoalsAndProgress.tsx | 12 +++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pages/project/[uuid]/tabs/GoalsAndProgress.tsx b/src/pages/project/[uuid]/tabs/GoalsAndProgress.tsx index b92131721..5b89fa106 100644 --- a/src/pages/project/[uuid]/tabs/GoalsAndProgress.tsx +++ b/src/pages/project/[uuid]/tabs/GoalsAndProgress.tsx @@ -311,7 +311,6 @@ const GoalsAndProgressTab = ({ project }: GoalsAndProgressProps) => { frameworksShow={[Framework.HBF]} label={t("workdays CREATED")} value={205} - totalValue={"no data"} classNameLabel="text-neutral-650 uppercase mb-3" labelVariant="text-14" classNameCard="text-center flex flex-col items-center" diff --git a/src/pages/site/[uuid]/tabs/GoalsAndProgress.tsx b/src/pages/site/[uuid]/tabs/GoalsAndProgress.tsx index 41a13cb4f..6c4aa4bf2 100644 --- a/src/pages/site/[uuid]/tabs/GoalsAndProgress.tsx +++ b/src/pages/site/[uuid]/tabs/GoalsAndProgress.tsx @@ -114,7 +114,6 @@ const GoalsAndProgressTab = ({ site }: GoalsAndProgressTabProps) => { frameworksShow={[Framework.HBF]} label={t("workdays CREATED")} value={205} - totalValue={"no data"} classNameLabel="text-neutral-650 uppercase mb-3" labelVariant="text-14" classNameCard="text-center flex flex-col items-center" @@ -123,7 +122,13 @@ const GoalsAndProgressTab = ({ site }: GoalsAndProgressTabProps) => { { label={t("Trees Restored")} frameworksHide={[Framework.HBF]} value={113250} - totalValue={ - site.framework_key === Framework.TF || site.framework_key === Framework.PPC ? "no data" : "300,000" - } classNameLabel="text-neutral-650 uppercase mb-3" labelVariant="text-14" classNameCard="text-center flex flex-col items-center" From 89e5aac185d9eac9c29b31bd3742350130c21555 Mon Sep 17 00:00:00 2001 From: cesarLima1 <105736261+cesarLima1@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:23:44 -0400 Subject: [PATCH 08/14] [TM-1606] add reference for tree species tables in site report landing page project dev view (#849) --- src/pages/reports/site-report/[uuid].page.tsx | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/pages/reports/site-report/[uuid].page.tsx b/src/pages/reports/site-report/[uuid].page.tsx index eeaf3f95c..1b8109003 100644 --- a/src/pages/reports/site-report/[uuid].page.tsx +++ b/src/pages/reports/site-report/[uuid].page.tsx @@ -222,7 +222,7 @@ const SiteReportDetailPage = () => { variantLabel: "text-14", classNameLabel: " text-neutral-650 uppercase !w-auto", classNameLabelValue: "!justify-start ml-2 !text-2xl items-baseline", - value: 100000 + value: siteReport.total_trees_planted_count } ]} className="mb-5 mt-4 pr-[41px] lg:pr-[150px]" @@ -232,8 +232,7 @@ const SiteReportDetailPage = () => { modelName="site-report" modelUUID={siteReportUUID} collection="tree-planted" - typeTable="treeCount" - data={dataTreeCount} + framework={siteReport.framework_key} />
@@ -276,7 +275,7 @@ const SiteReportDetailPage = () => { variantLabel: "text-14", classNameLabel: " text-neutral-650 uppercase !w-auto", classNameLabelValue: "!justify-start ml-2 !text-2xl items-baseline", - value: 5250 + value: siteReport.total_seeds_planted_count } ]} className="mb-5 mt-4 pr-[41px] lg:pr-[150px]" @@ -285,9 +284,8 @@ const SiteReportDetailPage = () => {
@@ -303,7 +301,7 @@ const SiteReportDetailPage = () => { variantLabel: "text-14", classNameLabel: " text-neutral-650 uppercase !w-auto", classNameLabelValue: "!justify-start ml-2 !text-2xl items-baseline", - value: 5250 + value: siteReport.total_non_tree_species_planted_count } ]} className="mb-5 mt-4 pr-[41px] lg:pr-[150px]" @@ -313,8 +311,7 @@ const SiteReportDetailPage = () => { modelName="site-report" modelUUID={siteReportUUID} collection="non-tree" - typeTable="nonTreeCount" - data={dataNonTreeCount} + framework={siteReport.framework_key} /> @@ -382,18 +379,16 @@ const SiteReportDetailPage = () => { variantLabel: "text-14", classNameLabel: " text-neutral-650 uppercase !w-auto", classNameLabelValue: "!justify-start ml-2 !text-2xl items-baseline", - value: 3200 + value: siteReport.num_trees_regenerating } ]} className="mb-5 mt-4 pr-[41px] lg:pr-[150px]" /> - {t("Description of AND Activities:")} + {t("Description of ANR Activities:")} - {t( - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum imperdiet consequat nulla, a dapibus nunc ultricies eget. Aliquam facilisis luctus nibh. Vivamus a lobortis nisl, scelerisque porttitor velit. Phasellus nec hendrerit felis. Proin commodo tortor consequat tortor pulvinar auctor. Nam rhoncus urna dolor, nec scelerisque elit blandit quis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam sollicitudin lobortis leo, eget laoreet magna fermentum ut. Suspendisse volutpat scelerisque felis, non commodo arcu laoreet vel. Sed facilisis volutpat est, a venenatis orci rhoncus cursus." - )} + {t(siteReport.regeneration_description ?? "No description")} {/* From 9bf62dc905a439924487f65b06a240b0d7470fb9 Mon Sep 17 00:00:00 2001 From: cesarLima1 <105736261+cesarLima1@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:25:55 -0400 Subject: [PATCH 09/14] [TM-1615] add references for terrafund site report landing page (#851) * [TM-1606] add reference for tree species tables in site report landing page project dev view * [TM-1615] add references for terrafund site report landing page --- src/pages/reports/site-report/[uuid].page.tsx | 87 ++++--------------- 1 file changed, 16 insertions(+), 71 deletions(-) diff --git a/src/pages/reports/site-report/[uuid].page.tsx b/src/pages/reports/site-report/[uuid].page.tsx index 1b8109003..51f922bce 100644 --- a/src/pages/reports/site-report/[uuid].page.tsx +++ b/src/pages/reports/site-report/[uuid].page.tsx @@ -100,41 +100,6 @@ const SiteReportDetailPage = () => { } ]; - const dataNonTreeCount = [ - { - name: ["Species scientific name", "tree"], - nonTreeCount: "45,000" - }, - { - name: ["Species scientific name", "Native species"], - nonTreeCount: "45,000" - }, - { - name: ["Species scientific name", "tree"], - nonTreeCount: "10,350" - }, - { - name: ["Species scientific name", "tree"], - nonTreeCount: "7,500" - }, - { - name: ["Non-scientific name", "tree"], - nonTreeCount: "4,040" - }, - { - name: ["Species scientific name", "tree"], - nonTreeCount: "3,200" - }, - { - name: ["Species scientific name", "new"], - nonTreeCount: "3,000" - }, - { - name: ["Species scientific name", "tree"], - nonTreeCount: "0" - } - ]; - return ( @@ -204,11 +169,17 @@ const SiteReportDetailPage = () => { {siteReport.technical_narrative} {siteReport.public_narrative} - - N/A - N/A - N/A - N/A + + {siteReport.pct_survival_to_date} + + {siteReport.survival_calculation} + + + {siteReport.survival_description} + + + {siteReport.maintenance_activities} + {t("Trees Planted")} @@ -263,7 +234,7 @@ const SiteReportDetailPage = () => { /> - + {t("Seeds Planted")} { /> - + {t("Tree Replanting")} { variantLabel: "text-14", classNameLabel: " text-neutral-650 uppercase !w-auto", classNameLabelValue: "!justify-start ml-2 !text-2xl items-baseline", - value: 5250 - } - ]} - className="mb-5 mt-4 pr-[41px] lg:pr-[150px]" - /> -
- -
- {t("Assisted Natural Regeneration")} - {
From 422bd0093ec8b914cf61850761d097aa3602b61f Mon Sep 17 00:00:00 2001 From: cesarLima1 <105736261+cesarLima1@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:47:31 -0400 Subject: [PATCH 10/14] [TM-1616] add references for hbf site report landing page (#852) --- src/pages/reports/site-report/[uuid].page.tsx | 42 ++----------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/src/pages/reports/site-report/[uuid].page.tsx b/src/pages/reports/site-report/[uuid].page.tsx index 51f922bce..6eb8f0ce8 100644 --- a/src/pages/reports/site-report/[uuid].page.tsx +++ b/src/pages/reports/site-report/[uuid].page.tsx @@ -65,41 +65,6 @@ const SiteReportDetailPage = () => { "Site Workdays" ); - const dataTreeCount = [ - { - name: ["Species scientific name", "tree"], - treeCount: "45,000" - }, - { - name: ["Species scientific name", "Native species"], - treeCount: "45,000" - }, - { - name: ["Species scientific name", "tree"], - treeCount: "10,350" - }, - { - name: ["Species scientific name", "tree"], - treeCount: "7,500" - }, - { - name: ["Non-scientific name", "tree"], - treeCount: "4,040" - }, - { - name: ["Species scientific name", "tree"], - treeCount: "3,200" - }, - { - name: ["Species scientific name", "new"], - treeCount: "3,000" - }, - { - name: ["Species scientific name", "tree"], - treeCount: "0" - } - ]; - return ( @@ -219,7 +184,7 @@ const SiteReportDetailPage = () => { variantLabel: "text-14", classNameLabel: " text-neutral-650 uppercase !w-auto", classNameLabelValue: "!justify-start ml-2 !text-2xl items-baseline", - value: 100000 + value: siteReport.total_trees_planted_count } ]} className="mb-5 mt-4 pr-[41px] lg:pr-[150px]" @@ -228,9 +193,8 @@ const SiteReportDetailPage = () => {
From 562bddbb180527ac1a40582f1c0835cca0d915a2 Mon Sep 17 00:00:00 2001 From: Jorge Monroy Date: Wed, 29 Jan 2025 15:29:10 -0400 Subject: [PATCH 11/14] [TM-1634] add landscape borders and titles (#853) --- src/components/elements/Map-mapbox/Map.tsx | 31 +++++++++++++- src/components/elements/Map-mapbox/utils.ts | 41 +++++++++++++++++++ src/constants/layers.ts | 18 +++++++- .../dashboard/components/ContentOverview.tsx | 6 +++ src/pages/dashboard/index.page.tsx | 33 ++++++++++++--- 5 files changed, 121 insertions(+), 8 deletions(-) diff --git a/src/components/elements/Map-mapbox/Map.tsx b/src/components/elements/Map-mapbox/Map.tsx index 1f3ea3267..2deefdf8a 100644 --- a/src/components/elements/Map-mapbox/Map.tsx +++ b/src/components/elements/Map-mapbox/Map.tsx @@ -58,6 +58,7 @@ import ViewImageCarousel from "./MapControls/ViewImageCarousel"; import { ZoomControl } from "./MapControls/ZoomControl"; import { addBorderCountry, + addBorderLandscape, addDeleteLayer, addFilterOnLayer, addGeojsonToDraw, @@ -67,6 +68,7 @@ import { addSourcesToLayers, drawTemporaryPolygon, removeBorderCountry, + removeBorderLandscape, removeMediaLayer, removePopups, startDrawing, @@ -121,6 +123,7 @@ interface MapProps extends Omit listViewProjects?: any; role?: any; selectedCountry?: string | null; + selectedLandscapes?: string[]; setLoader?: (value: boolean) => void; setIsLoadingDelayedJob?: (value: boolean) => void; isLoadingDelayedJob?: boolean; @@ -172,7 +175,16 @@ export const MapContainer = ({ const [sourcesAdded, setSourcesAdded] = useState(false); const [viewImages, setViewImages] = useState(false); const [currentStyle, setCurrentStyle] = useState(MapStyle.Satellite); - const { polygonsData, bbox, setPolygonFromMap, polygonFromMap, sitePolygonData, selectedCountry, setLoader } = props; + const { + polygonsData, + bbox, + setPolygonFromMap, + polygonFromMap, + sitePolygonData, + selectedCountry, + selectedLandscapes, + setLoader + } = props; const context = useSitePolygonData(); const contextMapArea = useMapAreaContext(); const dashboardContext = useDashboardContext(); @@ -311,6 +323,23 @@ export const MapContainer = ({ }); } }, [selectedCountry, styleLoaded, sourcesAdded]); + useEffect(() => { + if (!map.current || !sourcesAdded) return; + const setupBorders = () => { + if (selectedLandscapes && selectedLandscapes.length > 0) { + addBorderLandscape(map.current, selectedLandscapes); + } else { + removeBorderLandscape(map.current); + } + }; + if (map.current.isStyleLoaded()) { + setupBorders(); + } else { + map.current.once("render", () => { + setupBorders(); + }); + } + }, [selectedLandscapes, styleLoaded, sourcesAdded]); useEffect(() => { const projectUUID = router.query.uuid as string; const isProjectPath = router.isReady && router.asPath.includes("project"); diff --git a/src/components/elements/Map-mapbox/utils.ts b/src/components/elements/Map-mapbox/utils.ts index a22a4a04e..cd1feccdf 100644 --- a/src/components/elements/Map-mapbox/utils.ts +++ b/src/components/elements/Map-mapbox/utils.ts @@ -704,6 +704,10 @@ export const setFilterCountry = (map: mapboxgl.Map, layerName: string, country: const filter = ["==", ["get", "iso"], country]; map.setFilter(layerName, filter); }; +export const setFilterLandscape = (map: mapboxgl.Map, layerName: string, landscapes: string[]) => { + const filter = ["in", ["get", "landscape"], ["literal", landscapes]]; + map.setFilter(layerName, filter); +}; export const addBorderCountry = (map: mapboxgl.Map, country: string) => { if (!country || !map) return; @@ -732,6 +736,43 @@ export const addBorderCountry = (map: mapboxgl.Map, country: string) => { } as mapboxgl.AnyLayer); setFilterCountry(map, sourceName, country); }; +export const addBorderLandscape = (map: mapboxgl.Map, landscapes: string[]) => { + if (!landscapes || !map) return; + + const styleName = `${LAYERS_NAMES.LANDSCAPES}`; + const landscapeLayer = layersList.find(layer => layer.name === styleName); + if (!landscapeLayer) return; + const countryStyles = landscapeLayer.styles || []; + const sourceName = landscapeLayer.name; + const GEOSERVER_TILE_URL = getGeoserverURL(landscapeLayer.geoserverLayerName); + + if (!map.getSource(sourceName)) { + map.addSource(sourceName, { + type: "vector", + tiles: [GEOSERVER_TILE_URL] + }); + } + if (map.getLayer(sourceName)) { + map.removeLayer(sourceName); + } + const style = countryStyles[0]; + map.addLayer({ + ...style, + id: sourceName, + source: sourceName, + "source-layer": landscapeLayer.geoserverLayerName + } as mapboxgl.AnyLayer); + setFilterLandscape(map, sourceName, landscapes); +}; +export const removeBorderLandscape = (map: mapboxgl.Map) => { + const layerName = `${LAYERS_NAMES.LANDSCAPES}`; + if (map.getLayer(layerName)) { + map.removeLayer(layerName); + } + if (map.getSource(layerName)) { + map.removeSource(layerName); + } +}; export const removeBorderCountry = (map: mapboxgl.Map) => { const layerName = `${LAYERS_NAMES.WORLD_COUNTRIES}-line`; diff --git a/src/constants/layers.ts b/src/constants/layers.ts index a975bfd1f..4cbf9f0c3 100644 --- a/src/constants/layers.ts +++ b/src/constants/layers.ts @@ -9,7 +9,8 @@ export const LAYERS_NAMES = { POLYGON_GEOMETRY: "polygon_geometry", MEDIA_IMAGES: "media_images", DELETED_GEOMETRIES: "deleted_geometries", - CENTROIDS: "centroids" + CENTROIDS: "centroids", + LANDSCAPES: "landscape_geom" }; export const layersList: LayerType[] = [ { @@ -184,6 +185,21 @@ export const layersList: LayerType[] = [ ], hover: false }, + { + geoserverLayerName: LAYERS_NAMES.LANDSCAPES, + name: `${LAYERS_NAMES.LANDSCAPES}`, + styles: [ + { + type: "line", + layout: {}, + paint: { + "line-color": "#F0AD11", + "line-width": 2 + } + } + ], + hover: false + }, { name: LAYERS_NAMES.CENTROIDS, geoserverLayerName: "", diff --git a/src/pages/dashboard/components/ContentOverview.tsx b/src/pages/dashboard/components/ContentOverview.tsx index 3f4c60440..87b9718d9 100644 --- a/src/pages/dashboard/components/ContentOverview.tsx +++ b/src/pages/dashboard/components/ContentOverview.tsx @@ -78,12 +78,16 @@ const ContentOverview = (props: ContentOverviewProps) => { const { openModal, closeModal, setModalLoading } = useModalContext(); const { filters, setFilters, dashboardCountries } = useDashboardContext(); const [selectedCountry, setSelectedCountry] = useState(undefined); + const [selectedLandscapes, setSelectedLandscapes] = useState(undefined); const [dashboardMapLoaded, setDashboardMapLoaded] = useState(false); const [modalMapLoaded, setModalMapLoaded] = useState(false); useEffect(() => { setSelectedCountry(filters.country.country_slug); }, [filters.country]); + useEffect(() => { + setSelectedLandscapes(filters.landscapes || []); + }, [filters.landscapes]); const [currentBbox, setCurrentBbox] = useState(initialBbox); useEffect(() => { if (initialBbox) { @@ -143,6 +147,7 @@ const ContentOverview = (props: ContentOverviewProps) => { showImagesButton={showImagesButton} bbox={dashboardBbox} selectedCountry={selectedCountry} + selectedLandscapes={selectedLandscapes} setLoader={setModalMapLoaded} /> @@ -242,6 +247,7 @@ const ContentOverview = (props: ContentOverviewProps) => { bbox={currentBbox} selectedCountry={selectedCountry} setLoader={setDashboardMapLoaded} + selectedLandscapes={selectedLandscapes} />
diff --git a/src/pages/dashboard/index.page.tsx b/src/pages/dashboard/index.page.tsx index ccb068c1b..c644279ed 100644 --- a/src/pages/dashboard/index.page.tsx +++ b/src/pages/dashboard/index.page.tsx @@ -292,17 +292,38 @@ const Dashboard = () => {
- + 0) && !filters.uuid}>
- + {t("results for:")} - flag - - {t(filters.country?.data.label)} - + + + flag + + {t(filters.country?.data.label)} + + + + + + {filters.landscapes[0]} + + + + 1 && filters.country.id === 0) || + (filters.landscapes.length > 0 && filters.country.id !== 0) + } + > + + {filters.country.id === 0 ? t("Multiple Landscapes") : t("Multiple Countries/Landscapes")} + +
+
Date: Wed, 29 Jan 2025 16:03:17 -0400 Subject: [PATCH 12/14] [TM-1603] change the quantity of elements shown in tables in site reports landing pages (#854) --- .../elements/ImageGallery/ImageGallery.tsx | 2 +- src/components/elements/Table/Table.tsx | 5 ++++- src/components/extensive/Pagination/index.tsx | 18 ++++++++++++++++-- .../extensive/Tables/TreeSpeciesTablePD.tsx | 3 +++ src/pages/reports/site-report/[uuid].page.tsx | 10 ++++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/components/elements/ImageGallery/ImageGallery.tsx b/src/components/elements/ImageGallery/ImageGallery.tsx index f6277c5dd..adf161e34 100644 --- a/src/components/elements/ImageGallery/ImageGallery.tsx +++ b/src/components/elements/ImageGallery/ImageGallery.tsx @@ -428,7 +428,7 @@ const ImageGallery = ({ defaultPageSize={defaultPageSize} hasPageSizeSelector invertSelect - isImageGallery + galleryType={"imageGallery"} />
diff --git a/src/components/elements/Table/Table.tsx b/src/components/elements/Table/Table.tsx index 8c1148e52..d2b5844c4 100644 --- a/src/components/elements/Table/Table.tsx +++ b/src/components/elements/Table/Table.tsx @@ -57,6 +57,7 @@ export interface TableProps onRowClick?: (row: TData) => void; contentClassName?: string; classNameTableWrapper?: string; + galleryType?: string; } export interface TableState { @@ -91,6 +92,7 @@ function Table({ resetOnDataChange = true, // maintains default behavior onRowClick, contentClassName, + galleryType, ...props }: TableProps) { const t = useT(); @@ -300,10 +302,11 @@ function Table({ previousPage={previousPage} setPageIndex={setPageIndex} setPageSize={setPageSize} - defaultPageSize={initialTableState?.pagination?.pageSize || 5} + defaultPageSize={galleryType === "treeSpeciesPD" ? 8 : initialTableState?.pagination?.pageSize || 5} containerClassName="mt-6" hasPageSizeSelector invertSelect={invertSelectPagination} + galleryType={galleryType} /> )}
diff --git a/src/components/extensive/Pagination/index.tsx b/src/components/extensive/Pagination/index.tsx index 131eca585..a2b5f9bbf 100644 --- a/src/components/extensive/Pagination/index.tsx +++ b/src/components/extensive/Pagination/index.tsx @@ -12,11 +12,25 @@ export interface PaginationProps extends PageSelectorProps { setPageSize?: (count: number) => void; variant?: VariantPagination; invertSelect?: boolean; - isImageGallery?: boolean; + galleryType?: string; +} + +function getPageSizeOptions(galleryType?: string) { + if (galleryType === undefined) { + return [5, 10, 15, 20, 50]; + } + if (galleryType === "imageGallery") { + return [3, 6, 12, 30, 60]; + } + if (galleryType === "treeSpeciesPD") { + return [8, 16, 24, 40, 56]; + } + return [5, 10, 15, 20, 50]; } function Pagination(props: PaginationProps) { const t = useT(); + const pageSizeOptions = getPageSizeOptions(props.galleryType); return (
{ const queryParams: any = {}; @@ -436,6 +438,7 @@ const TreeSpeciesTablePD = ({ hasPagination invertSelectPagination visibleRows={visibleRows} + galleryType={galleryType} />
); diff --git a/src/pages/reports/site-report/[uuid].page.tsx b/src/pages/reports/site-report/[uuid].page.tsx index 6eb8f0ce8..55478e65e 100644 --- a/src/pages/reports/site-report/[uuid].page.tsx +++ b/src/pages/reports/site-report/[uuid].page.tsx @@ -169,6 +169,8 @@ const SiteReportDetailPage = () => { modelUUID={siteReportUUID} collection="tree-planted" framework={siteReport.framework_key} + visibleRows={8} + galleryType={"treeSpeciesPD"} />
@@ -195,6 +197,8 @@ const SiteReportDetailPage = () => { modelUUID={siteReportUUID} collection="tree-planted" framework={siteReport.framework_key} + visibleRows={8} + galleryType={"treeSpeciesPD"} />
@@ -221,6 +225,8 @@ const SiteReportDetailPage = () => { modelUUID={siteReportUUID} collection="seeding" framework={siteReport.framework_key} + visibleRows={8} + galleryType={"treeSpeciesPD"} />
@@ -247,6 +253,8 @@ const SiteReportDetailPage = () => { modelUUID={siteReportUUID} collection="non-tree" framework={siteReport.framework_key} + visibleRows={8} + galleryType={"treeSpeciesPD"} /> @@ -273,6 +281,8 @@ const SiteReportDetailPage = () => { modelUUID={siteReportUUID} collection="replanting" framework={siteReport.framework_key} + visibleRows={8} + galleryType={"treeSpeciesPD"} /> From 4c48e313fcfcbad60a9bbfd9502d5799b7b21f32 Mon Sep 17 00:00:00 2001 From: Jose Carlos Laura Ramirez Date: Thu, 30 Jan 2025 10:23:49 -0400 Subject: [PATCH 13/14] [TM-1637] fix permissions with edit user (#855) --- src/admin/components/Actions/ShowActions.tsx | 26 +++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/admin/components/Actions/ShowActions.tsx b/src/admin/components/Actions/ShowActions.tsx index 60fb4e3d9..87b9da18c 100644 --- a/src/admin/components/Actions/ShowActions.tsx +++ b/src/admin/components/Actions/ShowActions.tsx @@ -1,5 +1,6 @@ import { Box, Typography } from "@mui/material"; import { get } from "lodash"; +import { useMemo } from "react"; import { Button, DeleteWithConfirmButton, @@ -13,6 +14,7 @@ import { } from "react-admin"; import { When } from "react-if"; +import { useGetUserRole } from "@/admin/hooks/useGetUserRole"; import Icon, { IconNames } from "@/components/extensive/Icon/Icon"; import ShowTitle from "../ShowTitle"; @@ -38,6 +40,7 @@ const ShowActions = ({ toggleTestStatus, deleteProps = {} }: IProps) => { + const { isFrameworkAdmin, isSuperAdmin, role } = useGetUserRole(); const record = useRecordContext(); const resource = useResourceContext(); @@ -48,6 +51,27 @@ const ShowActions = ({ deleteProps.confirmContent = `You are about to delete this ${resourceName}. This action will permanently remove the item from the system, and it cannot be undone. Are you sure you want to delete this item?`; } + const showEdit = useMemo(() => { + if (resource === "user") { + if (isSuperAdmin) { + return true; + } + if (record?.role === "admin-super") { + return false; + } + if (record?.role === "project-developer" || record?.role === "project-manager") { + return true; + } + if (isFrameworkAdmin) { + if (record?.role === role) { + return true; + } + return false; + } + } + return record && hasEdit; + }, [record, resource, hasEdit, isFrameworkAdmin, isSuperAdmin]); + return ( @@ -78,7 +102,7 @@ const ShowActions = ({ icon={} /> )} - {record && hasEdit && ( + {showEdit && ( } From 275f9d716da605b2084eb2f00e6fa1369915b978 Mon Sep 17 00:00:00 2001 From: cesarLima1 <105736261+cesarLima1@users.noreply.github.com> Date: Thu, 30 Jan 2025 10:58:07 -0400 Subject: [PATCH 14/14] [TM-1615] hide counter rows per page and pagination label when count is less than the default value (#856) --- src/components/elements/Table/Table.tsx | 6 ++++-- src/components/extensive/Pagination/index.tsx | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/elements/Table/Table.tsx b/src/components/elements/Table/Table.tsx index d2b5844c4..e04925083 100644 --- a/src/components/elements/Table/Table.tsx +++ b/src/components/elements/Table/Table.tsx @@ -141,6 +141,8 @@ function Table({ }); const tableState = getState(); + const defaultPageSize = galleryType === "treeSpeciesPD" ? 8 : initialTableState?.pagination?.pageSize || 5; + const rowCount = Object.keys(getRowModel().rowsById).length; useEffect(() => { setSorting(initialTableState?.sorting ?? []); @@ -302,9 +304,9 @@ function Table({ previousPage={previousPage} setPageIndex={setPageIndex} setPageSize={setPageSize} - defaultPageSize={galleryType === "treeSpeciesPD" ? 8 : initialTableState?.pagination?.pageSize || 5} + defaultPageSize={defaultPageSize} containerClassName="mt-6" - hasPageSizeSelector + hasPageSizeSelector={rowCount > defaultPageSize} invertSelect={invertSelectPagination} galleryType={galleryType} /> diff --git a/src/components/extensive/Pagination/index.tsx b/src/components/extensive/Pagination/index.tsx index a2b5f9bbf..5cc601af0 100644 --- a/src/components/extensive/Pagination/index.tsx +++ b/src/components/extensive/Pagination/index.tsx @@ -52,7 +52,11 @@ function Pagination(props: PaginationProps) { ) : (
)} - + {props.hasPageSizeSelector ? ( + + ) : ( +
+ )}
); }