Skip to content

Commit

Permalink
Merge pull request #739 from wri/feat/TM-1402-tree-species-design-int…
Browse files Browse the repository at this point in the history
…egration

[TM-1402] Wire up the new tree species BE systems with the updated tree species input.
  • Loading branch information
roguenet authored Dec 13, 2024
2 parents eab3706 + f0cae93 commit 2250727
Show file tree
Hide file tree
Showing 24 changed files with 753 additions and 279 deletions.
1 change: 0 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 Down
20 changes: 14 additions & 6 deletions openapi-codegen.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,34 @@ type EnvironmentName = (typeof ENVIRONMENT_NAMES)[number];
type Environment = {
apiBaseUrl: string;
userServiceUrl: string;
entityServiceUrl: string;
};

const ENVIRONMENTS: { [Property in EnvironmentName]: Environment } = {
local: {
apiBaseUrl: "http://localhost:8080",
userServiceUrl: "http://localhost:4010"
userServiceUrl: "http://localhost:4010",
entityServiceUrl: "http://localhost:4050"
},
dev: {
apiBaseUrl: "https://api-dev.terramatch.org",
userServiceUrl: "https://api-dev.terramatch.org"
userServiceUrl: "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",
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",
entityServiceUrl: "https://api-staging.terramatch.org"
},
prod: {
apiBaseUrl: "https://api.terramatch.org",
userServiceUrl: "https://api.terramatch.org"
userServiceUrl: "https://api.terramatch.org",
entityServiceUrl: "https://api.terramatch.org"
}
};

Expand All @@ -60,13 +66,15 @@ 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 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,
"entity-service": entityServiceUrl
};

const config: Record<string, Config> = {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"build-storybook": "storybook build",
"generate:api": "openapi-codegen gen api",
"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",
"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
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ChangeEvent, forwardRef, Fragment, Ref, useState } from "react";
import { Else, If, Then } from "react-if";

import { useDebounce } from "@/hooks/useDebounce";
import { useValueChanged } from "@/hooks/useValueChanged";

import Text from "../../Text/Text";
import Input, { InputProps } from "../Input/Input";
Expand All @@ -13,17 +14,18 @@ export interface AutoCompleteInputProps extends InputProps {
onSearch: (query: string) => Promise<string[]>;
disableAutoComplete?: boolean;
classNameMenu?: string;
onSelected?: (item: string) => void;
}

const SEARCH_RESET = { list: [], query: "" };

//TODO: Bugfix: Users can enter space in this input
const AutoCompleteInput = forwardRef(
(
{ onSearch, disableAutoComplete, classNameMenu, onSelected, ...inputProps }: AutoCompleteInputProps,
{ onSearch, disableAutoComplete, classNameMenu, ...inputProps }: AutoCompleteInputProps,
ref?: Ref<HTMLInputElement>
) => {
const t = useT();
const [list, setList] = useState<string[]>([]);
const [searchResult, setSearchResult] = useState<{ list: string[]; query: string }>(SEARCH_RESET);
const [loading, setLoading] = useState(false);

const onSelect = (item: string) => {
Expand All @@ -33,37 +35,34 @@ const AutoCompleteInput = forwardRef(
inputProps.onChange?.({ target: { name: inputProps.name, value: item } } as ChangeEvent<HTMLInputElement>);
}

onSelected?.(item);

setList([]);
// Avoid showing the search result list unless the name changes again.
setSearchResult({ list: [], query: item });
};

const search = useDebounce(async (query: string) => {
if (query === searchResult.query) return;

setLoading(true);

onSearch(query)
.then(resp => {
setList(resp);
setLoading(false);
})
.catch(() => {
setList([]);
setLoading(false);
});
try {
setSearchResult({ list: await onSearch(query), query });
setLoading(false);
} catch {
setSearchResult(SEARCH_RESET);
setLoading(false);
}
});

useValueChanged(inputProps.value, () => search(String(inputProps.value ?? "")));

return (
<Popover as="div" className="w-full">
<Popover.Button as={Fragment}>
<Input
{...inputProps}
ref={ref}
onChangeCapture={e => !disableAutoComplete && search(e.currentTarget.value)}
/>
<Input {...inputProps} ref={ref} />
</Popover.Button>

<Transition
show={list.length > 0 || !!loading}
show={searchResult.list.length > 0 || !!loading}
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
Expand All @@ -82,7 +81,7 @@ const AutoCompleteInput = forwardRef(
</Text>
</Then>
<Else>
{list.map(item => (
{searchResult.list.map(item => (
<Text
key={item}
variant="text-body-600"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ exports[`Storyshots Components/Elements/Inputs/AutoComplete Default 1`] = `
className="w-full outline-none transition-all duration-300 ease-in-out focus:ring-transparent px-3 py-[9px] rounded-lg focus:border-primary-500 border border-neutral-200"
data-headlessui-state=""
id=":r9:"
onChangeCapture={[Function]}
onClick={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
Expand Down
Loading

0 comments on commit 2250727

Please sign in to comment.