diff --git a/epictrack-api/src/api/resources/__init__.py b/epictrack-api/src/api/resources/__init__.py index 64bb6322d..57058a9ed 100644 --- a/epictrack-api/src/api/resources/__init__.py +++ b/epictrack-api/src/api/resources/__init__.py @@ -1,118 +1,122 @@ -# Copyright © 2019 Province of British Columbia -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Exposes all of the resource endpoints mounted in Flask-Blueprint style. - -Uses restplus namespaces to mount individual api endpoints into the service. - -All services have 2 defaults sets of endpoints: - - ops - - meta -That are used to expose operational health information about the service, and meta information. -""" - -from flask import Blueprint - -from .act_section import API as ACT_SECTION_API -from .apihelper import Api -from .code import API as CODES_API -from .event import API as EVENT_API -from .event_configuration import API as EVENT_CONFIGURATION_API -from .event_template import API as EVENT_TEMPLATE_API -from .indigenous_nation import API as INDIGENOUS_NATION_API -from .inspection import API as INSPECTION_API -from .lookup_data_generator import API as LOOKUP_API -from .meta import API as META_API -from .ops import API as OPS_API -from .outcome import API as OUTCOME_API -from .outcome_configuration import API as OUTCOME_CONFIGURATION_API -from .phase import API as PHASE_API -from .position import API as POSITION_API -from .project import API as PROJECTS_API -from .proponent import API as PROPONENT_API -from .reminder_configuration import API as REMINDER_CONFIGURATION_API -from .reports import API as REPORTS_API -from .responsibility import API as RESPONSIBILITY_API -from .special_field import API as SPECIAL_FIELD_API -from .staff import API as STAFF_API -from .sub_types import API as SUB_TYPES_API -from .sync_form_data import API as SYNC_FORM_DATA_API -from .task import API as TASK_API -from .task_template import API as TASK_TEMPLATE_API -from .user import API as USER_API -from .work import API as WORK_API -from .work_issues import API as WORK_ISSUES_API -from .work_status import API as WORK_STATUS_API -from .region import API as REGION_API -from .eao_team import API as EAO_TEAM_API - - -__all__ = ("API_BLUEPRINT", "OPS_BLUEPRINT") - -# This will add the Authorize button to the swagger docs -AUTHORIZATIONS = {"apikey": {"type": "apiKey", "in": "header", "name": "Authorization"}} - -OPS_BLUEPRINT = Blueprint("API_OPS", __name__, url_prefix="/ops") - -API_OPS = Api( - OPS_BLUEPRINT, - title="Service OPS API", - version="1.0", - description="The Core API for the Reports System", - security=["apikey"], - authorizations=AUTHORIZATIONS, -) - -API_OPS.add_namespace(OPS_API, path="/") - -API_BLUEPRINT = Blueprint("API", __name__, url_prefix="/api/v1") - -API = Api( - API_BLUEPRINT, - title="EAO Reports API", - version="1.0", - description="The Core API for the Reports System", - security=["apikey"], - authorizations=AUTHORIZATIONS, -) - -API.add_namespace(META_API, path="/meta") -API.add_namespace(CODES_API, path="/codes") -API.add_namespace(PROJECTS_API, path="/projects") -API.add_namespace(SYNC_FORM_DATA_API, path="/sync-form-data") -API.add_namespace(PHASE_API, path="/phases") -API.add_namespace(STAFF_API, path="/staffs") -API.add_namespace(OUTCOME_API, path="/outcomes") -API.add_namespace(SUB_TYPES_API, path="/sub-types") -API.add_namespace(INSPECTION_API, path="/inspections") -API.add_namespace(WORK_API, path="/works") -API.add_namespace(LOOKUP_API, path="/lookups") -API.add_namespace(REPORTS_API, path="/reports") -API.add_namespace(INDIGENOUS_NATION_API, path="/indigenous-nations") -API.add_namespace(PROPONENT_API, path="/proponents") -API.add_namespace(REMINDER_CONFIGURATION_API, path="/reminder-configurations") -API.add_namespace(USER_API, path='/users') -API.add_namespace(TASK_TEMPLATE_API, path="/task-templates") -API.add_namespace(EVENT_TEMPLATE_API, path="/event-templates") -API.add_namespace(TASK_API, path="/tasks") -API.add_namespace(EVENT_API, path="/milestones") -API.add_namespace(EVENT_CONFIGURATION_API, path="/event-configurations") -API.add_namespace(RESPONSIBILITY_API, path="/responsibilities") -API.add_namespace(OUTCOME_CONFIGURATION_API, path="/outcome-configurations") -API.add_namespace(ACT_SECTION_API, path="/act-sections") -API.add_namespace(WORK_STATUS_API, path='/work//statuses') -API.add_namespace(WORK_ISSUES_API, path='/work//issues') -API.add_namespace(SPECIAL_FIELD_API, path='/special-fields') -API.add_namespace(POSITION_API, path='/positions') -API.add_namespace(REGION_API, path='/regions') -API.add_namespace(EAO_TEAM_API, path='/eao-teams') +# Copyright © 2019 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Exposes all of the resource endpoints mounted in Flask-Blueprint style. + +Uses restplus namespaces to mount individual api endpoints into the service. + +All services have 2 defaults sets of endpoints: + - ops + - meta +That are used to expose operational health information about the service, and meta information. +""" + +from flask import Blueprint + +from .act_section import API as ACT_SECTION_API +from .apihelper import Api +from .code import API as CODES_API +from .event import API as EVENT_API +from .event_configuration import API as EVENT_CONFIGURATION_API +from .event_template import API as EVENT_TEMPLATE_API +from .indigenous_nation import API as INDIGENOUS_NATION_API +from .inspection import API as INSPECTION_API +from .lookup_data_generator import API as LOOKUP_API +from .meta import API as META_API +from .ops import API as OPS_API +from .outcome import API as OUTCOME_API +from .outcome_configuration import API as OUTCOME_CONFIGURATION_API +from .phase import API as PHASE_API +from .position import API as POSITION_API +from .project import API as PROJECTS_API +from .project_type import API as PROJECT_TYPES_API +from .proponent import API as PROPONENT_API +from .reminder_configuration import API as REMINDER_CONFIGURATION_API +from .reports import API as REPORTS_API +from .responsibility import API as RESPONSIBILITY_API +from .special_field import API as SPECIAL_FIELD_API +from .staff import API as STAFF_API +from .sub_types import API as SUB_TYPES_API +from .sync_form_data import API as SYNC_FORM_DATA_API +from .task import API as TASK_API +from .task_template import API as TASK_TEMPLATE_API +from .user import API as USER_API +from .work import API as WORK_API +from .work_issues import API as WORK_ISSUES_API +from .work_status import API as WORK_STATUS_API +from .work_type import API as WORK_TYPES_API +from .region import API as REGION_API +from .eao_team import API as EAO_TEAM_API + + +__all__ = ("API_BLUEPRINT", "OPS_BLUEPRINT") + +# This will add the Authorize button to the swagger docs +AUTHORIZATIONS = {"apikey": {"type": "apiKey", "in": "header", "name": "Authorization"}} + +OPS_BLUEPRINT = Blueprint("API_OPS", __name__, url_prefix="/ops") + +API_OPS = Api( + OPS_BLUEPRINT, + title="Service OPS API", + version="1.0", + description="The Core API for the Reports System", + security=["apikey"], + authorizations=AUTHORIZATIONS, +) + +API_OPS.add_namespace(OPS_API, path="/") + +API_BLUEPRINT = Blueprint("API", __name__, url_prefix="/api/v1") + +API = Api( + API_BLUEPRINT, + title="EAO Reports API", + version="1.0", + description="The Core API for the Reports System", + security=["apikey"], + authorizations=AUTHORIZATIONS, +) + +API.add_namespace(META_API, path="/meta") +API.add_namespace(CODES_API, path="/codes") +API.add_namespace(PROJECTS_API, path="/projects") +API.add_namespace(PROJECT_TYPES_API, path="/project-types") +API.add_namespace(SYNC_FORM_DATA_API, path="/sync-form-data") +API.add_namespace(PHASE_API, path="/phases") +API.add_namespace(STAFF_API, path="/staffs") +API.add_namespace(OUTCOME_API, path="/outcomes") +API.add_namespace(SUB_TYPES_API, path="/sub-types") +API.add_namespace(INSPECTION_API, path="/inspections") +API.add_namespace(WORK_API, path="/works") +API.add_namespace(LOOKUP_API, path="/lookups") +API.add_namespace(REPORTS_API, path="/reports") +API.add_namespace(INDIGENOUS_NATION_API, path="/indigenous-nations") +API.add_namespace(PROPONENT_API, path="/proponents") +API.add_namespace(REMINDER_CONFIGURATION_API, path="/reminder-configurations") +API.add_namespace(USER_API, path='/users') +API.add_namespace(TASK_TEMPLATE_API, path="/task-templates") +API.add_namespace(EVENT_TEMPLATE_API, path="/event-templates") +API.add_namespace(TASK_API, path="/tasks") +API.add_namespace(EVENT_API, path="/milestones") +API.add_namespace(EVENT_CONFIGURATION_API, path="/event-configurations") +API.add_namespace(RESPONSIBILITY_API, path="/responsibilities") +API.add_namespace(OUTCOME_CONFIGURATION_API, path="/outcome-configurations") +API.add_namespace(ACT_SECTION_API, path="/act-sections") +API.add_namespace(WORK_STATUS_API, path='/work//statuses') +API.add_namespace(WORK_TYPES_API, path='/work-types') +API.add_namespace(WORK_ISSUES_API, path='/work//issues') +API.add_namespace(SPECIAL_FIELD_API, path='/special-fields') +API.add_namespace(POSITION_API, path='/positions') +API.add_namespace(REGION_API, path='/regions') +API.add_namespace(EAO_TEAM_API, path='/eao-teams') diff --git a/epictrack-api/src/api/resources/project.py b/epictrack-api/src/api/resources/project.py index 5315c4323..6954caed4 100644 --- a/epictrack-api/src/api/resources/project.py +++ b/epictrack-api/src/api/resources/project.py @@ -21,7 +21,8 @@ from api.schemas import response as res from api.schemas.work_type import WorkTypeSchema from api.services import ProjectService -from api.utils import auth, profiletime +from api.utils import auth, constants, profiletime +from api.utils.caching import AppCache from api.utils.util import cors_preflight @@ -223,6 +224,7 @@ class ProjectTypes(Resource): @cors.crossdomain(origin="*") @auth.require @profiletime + @AppCache.cache.cached(timeout=constants.CACHE_DAY_TIMEOUT, query_string=True) def get(): """Return all project types.""" project_types = ProjectService.find_all_project_types() diff --git a/epictrack-api/src/api/resources/project_type.py b/epictrack-api/src/api/resources/project_type.py new file mode 100644 index 000000000..3e15d1b7c --- /dev/null +++ b/epictrack-api/src/api/resources/project_type.py @@ -0,0 +1,45 @@ +# Copyright © 2019 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Resource for work endpoints.""" +from http import HTTPStatus + +from flask import jsonify +from flask_restx import Namespace, Resource, cors + +from api.services import ProjectService +from api.utils import auth, constants, profiletime +from api.utils.caching import AppCache +from api.utils.util import cors_preflight + + +API = Namespace("project types", description="Project Types") + + +@cors_preflight("GET") +@API.route("", methods=["GET", "OPTIONS"]) +class ProjectTypes(Resource): + """Endpoint resource to manage project types.""" + + @staticmethod + @cors.crossdomain(origin="*") + @auth.require + @profiletime + @AppCache.cache.cached(timeout=constants.CACHE_DAY_TIMEOUT, query_string=True) + def get(): + """Return all project types.""" + project_types = ProjectService.find_all_project_types() + return ( + jsonify(project_types), + HTTPStatus.OK, + ) diff --git a/epictrack-api/src/api/resources/work.py b/epictrack-api/src/api/resources/work.py index bce81c7f4..5bee1a422 100644 --- a/epictrack-api/src/api/resources/work.py +++ b/epictrack-api/src/api/resources/work.py @@ -24,7 +24,8 @@ from api.schemas import response as res from api.services import WorkService from api.services.work_phase import WorkPhaseService -from api.utils import auth, profiletime +from api.utils import auth, constants, profiletime +from api.utils.caching import AppCache from api.utils.datetime_helper import get_start_of_day from api.utils.util import cors_preflight @@ -470,6 +471,7 @@ class WorkTypes(Resource): @staticmethod @cors.crossdomain(origin="*") @auth.require + @AppCache.cache.cached(timeout=constants.CACHE_DAY_TIMEOUT) @profiletime def get(): """Return all active works.""" diff --git a/epictrack-api/src/api/resources/work_type.py b/epictrack-api/src/api/resources/work_type.py new file mode 100644 index 000000000..7cfcd83c1 --- /dev/null +++ b/epictrack-api/src/api/resources/work_type.py @@ -0,0 +1,42 @@ +# Copyright © 2019 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Resource for work endpoints.""" +from http import HTTPStatus + +from flask import jsonify +from flask_restx import Namespace, Resource, cors + +from api.services import WorkService +from api.utils import auth, constants, profiletime +from api.utils.caching import AppCache +from api.utils.util import cors_preflight + + +API = Namespace("work-types", description="Work types") + + +@cors_preflight("GET") +@API.route("", methods=["GET", "OPTIONS"]) +class WorkTypes(Resource): + """Endpoint resource to manage works.""" + + @staticmethod + @cors.crossdomain(origin="*") + @auth.require + @AppCache.cache.cached(timeout=constants.CACHE_DAY_TIMEOUT) + @profiletime + def get(): + """Return all active work types.""" + work_types = WorkService.find_all_work_types() + return jsonify(work_types), HTTPStatus.OK diff --git a/epictrack-web/src/components/myWorkplans/Filters/NameFilter.tsx b/epictrack-web/src/components/myWorkplans/Filters/NameFilter.tsx index c14061b74..b37d54579 100644 --- a/epictrack-web/src/components/myWorkplans/Filters/NameFilter.tsx +++ b/epictrack-web/src/components/myWorkplans/Filters/NameFilter.tsx @@ -1,5 +1,11 @@ import React, { useState, useEffect, useContext } from "react"; -import { Autocomplete, Box, InputAdornment, TextField } from "@mui/material"; +import { + Autocomplete, + Box, + InputAdornment, + MenuItem, + TextField, +} from "@mui/material"; import { MyWorkplansContext, WorkPlanSearchOptions, @@ -84,7 +90,9 @@ export const NameFilter = () => { clearOnBlur noOptionsText="" renderOption={(props, option, state) => ( -
  • {highlightText(option, state.inputValue)}
  • + + {highlightText(option, state.inputValue)} + )} disabled={loading} /> diff --git a/epictrack-web/src/constants/api-endpoint.ts b/epictrack-web/src/constants/api-endpoint.ts index 04be6adfd..de0e2fb1b 100644 --- a/epictrack-web/src/constants/api-endpoint.ts +++ b/epictrack-web/src/constants/api-endpoint.ts @@ -9,12 +9,14 @@ const Endpoints = { }, Projects: { PROJECTS: "projects", - PROJECT_TYPES: "projects/types", WORK_TYPES: "projects/:project_id/work-types", FIRST_NATIONS: "projects/:project_id/first-nations", FIRST_NATION_AVAILABLE: "projects/:project_id/first-nation-available", PROJECT_ABBREVIATION: "projects/abbreviation", }, + ProjectTypes: { + GET_ALL: "project-types", + }, Codes: { GET_CODES: "codes", }, @@ -39,6 +41,9 @@ const Endpoints = { WORK_IMPORT_FIRST_NATIONS: "works/:work_id/first-nations/import", GET_ALL_WORK_TYPES: "works/types", }, + WorkTypes: { + GET_ALL: "work-types", + }, WorkIssues: { ISSUES: "work/:work_id/issues", UPDATE_ISSUE: "work/:work_id/issues/:issue_id", diff --git a/epictrack-web/src/services/projectService/projectService.ts b/epictrack-web/src/services/projectService/projectService.ts index 89461e595..17de6ee1a 100644 --- a/epictrack-web/src/services/projectService/projectService.ts +++ b/epictrack-web/src/services/projectService/projectService.ts @@ -79,7 +79,7 @@ class ProjectService implements ServiceBase { } async getProjectTypes() { - return await http.GetRequest(Endpoints.Projects.PROJECT_TYPES); + return await http.GetRequest(Endpoints.ProjectTypes.GET_ALL); } } diff --git a/epictrack-web/src/services/workService/workService.ts b/epictrack-web/src/services/workService/workService.ts index 8499d411b..74f02cce1 100644 --- a/epictrack-web/src/services/workService/workService.ts +++ b/epictrack-web/src/services/workService/workService.ts @@ -207,9 +207,7 @@ class WorkService implements ServiceBase { } async getWorkTypes() { - return await http.GetRequest( - Endpoints.Works.GET_ALL_WORK_TYPES - ); + return await http.GetRequest(Endpoints.WorkTypes.GET_ALL); } } export default new WorkService(); diff --git a/epictrack-web/src/utils/MatchingTextHighlight.tsx b/epictrack-web/src/utils/MatchingTextHighlight.tsx index 6e0d90dd4..33c759356 100644 --- a/epictrack-web/src/utils/MatchingTextHighlight.tsx +++ b/epictrack-web/src/utils/MatchingTextHighlight.tsx @@ -4,13 +4,13 @@ export const highlightText = (text: string, query: string) => { const index = text.toLowerCase().indexOf(query.toLowerCase()); if (index !== -1) { return ( - <> + {text.substring(0, index)} {text.substring(index, index + query.length)} {text.substring(index + query.length)} - + ); } return text;