diff --git a/forms-flow-api/migrations/versions/77d8b68e6c1f_users_table.py b/forms-flow-api/migrations/versions/77d8b68e6c1f_users_table.py new file mode 100644 index 0000000000..76e8cd7a82 --- /dev/null +++ b/forms-flow-api/migrations/versions/77d8b68e6c1f_users_table.py @@ -0,0 +1,69 @@ +"""Users table + +Revision ID: 77d8b68e6c1f +Revises: f1599a5bd658 +Create Date: 2024-05-30 16:01:37.273907 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '77d8b68e6c1f' +down_revision = 'f1599a5bd658' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('user', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('user_name', sa.String(length=50), nullable=False), + sa.Column('default_filter', sa.Integer(), nullable=True), + sa.Column('locale', sa.String(), nullable=True, comment='language code'), + sa.Column('tenant', sa.String(), nullable=True, comment='tenant key'), + sa.Column('created', sa.DateTime(), nullable=False), + sa.Column('modified', sa.DateTime(), nullable=True), + sa.Column('created_by', sa.String(), nullable=False), + sa.Column('modified_by', sa.String(), nullable=True), + sa.ForeignKeyConstraint(['default_filter'], ['filter.id'], ondelete='SET NULL'), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('user_name', 'tenant', name='uq_tenant_user_name') + ) + op.alter_column('themes', 'logo_type', + existing_type=sa.VARCHAR(length=100), + type_=sa.String(length=50), + existing_nullable=False) + op.alter_column('themes', 'logo_data', + existing_type=sa.VARCHAR(), + comment='logo_data contain a base64 or a URL.', + existing_nullable=False) + op.alter_column('themes', 'theme', + existing_type=postgresql.JSON(astext_type=sa.Text()), + comment='Json data', + existing_nullable=False) + op.create_unique_constraint('uq_tenant', 'themes', ['tenant']) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('uq_tenant', 'themes', type_='unique') + op.alter_column('themes', 'theme', + existing_type=postgresql.JSON(astext_type=sa.Text()), + comment=None, + existing_comment='Json data', + existing_nullable=False) + op.alter_column('themes', 'logo_data', + existing_type=sa.VARCHAR(), + comment=None, + existing_comment='logo_data contain a base64 or a URL.', + existing_nullable=False) + op.alter_column('themes', 'logo_type', + existing_type=sa.String(length=50), + type_=sa.VARCHAR(length=100), + existing_nullable=False) + op.drop_table('user') + # ### end Alembic commands ### diff --git a/forms-flow-api/src/formsflow_api/models/__init__.py b/forms-flow-api/src/formsflow_api/models/__init__.py index 8f97294d70..7989f4948a 100644 --- a/forms-flow-api/src/formsflow_api/models/__init__.py +++ b/forms-flow-api/src/formsflow_api/models/__init__.py @@ -11,6 +11,7 @@ from .form_process_mapper import FormProcessMapper from .process import Process, ProcessStatus, ProcessType from .theme import Themes +from .user import User __all__ = [ "db", @@ -28,4 +29,5 @@ "ProcessType", "ProcessStatus", "Themes", + "User", ] diff --git a/forms-flow-api/src/formsflow_api/models/theme.py b/forms-flow-api/src/formsflow_api/models/theme.py index b0f09bb317..34a7afb929 100644 --- a/forms-flow-api/src/formsflow_api/models/theme.py +++ b/forms-flow-api/src/formsflow_api/models/theme.py @@ -1,6 +1,6 @@ """This manages theme Database Models.""" -from sqlalchemy import JSON +from sqlalchemy import JSON, UniqueConstraint from .audit_mixin import AuditDateTimeMixin, AuditUserMixin from .base_model import BaseModel @@ -18,7 +18,8 @@ class Themes(AuditDateTimeMixin, AuditUserMixin, BaseModel, db.Model): ) application_title = db.Column(db.String(50), nullable=False) theme = db.Column(JSON, nullable=False, comment="Json data") - tenant = db.Column(db.String(20), nullable=True, unique=True) + tenant = db.Column(db.String(20), nullable=True) + __table_args__ = (UniqueConstraint("tenant", name="uq_tenant"),) @classmethod def create_theme(cls, theme_info: dict): diff --git a/forms-flow-api/src/formsflow_api/models/user.py b/forms-flow-api/src/formsflow_api/models/user.py new file mode 100644 index 0000000000..492601a312 --- /dev/null +++ b/forms-flow-api/src/formsflow_api/models/user.py @@ -0,0 +1,70 @@ +"""This manages User Database Models.""" + +from flask_sqlalchemy.query import Query +from formsflow_api_utils.utils.user_context import UserContext, user_context +from sqlalchemy import UniqueConstraint + +from .audit_mixin import AuditDateTimeMixin, AuditUserMixin +from .base_model import BaseModel +from .db import db + + +class User(AuditDateTimeMixin, AuditUserMixin, BaseModel, db.Model): + """This class manages user information.""" + + id = db.Column(db.Integer, primary_key=True) + user_name = db.Column(db.String(50), nullable=False) + default_filter = db.Column( + db.Integer, db.ForeignKey("filter.id", ondelete="SET NULL"), nullable=True + ) + locale = db.Column(db.String(), nullable=True, comment="language code") + tenant = db.Column(db.String(), nullable=True, comment="tenant key") + __table_args__ = ( + UniqueConstraint("user_name", "tenant", name="uq_tenant_user_name"), + ) + + @classmethod + def create_user(cls, user_data: dict): + """Create new user.""" + assert user_data is not None + user = cls() + user.created_by = user_data.get("created_by") + user.user_name = user_data.get("user_name") + user.locale = user_data.get("locale") + user.tenant = user_data.get("tenant") + user.default_filter = user_data.get("default_filter") + user.save() + return user + + def update(self, user_data: dict): + """Update user data.""" + self.update_from_dict( + [ + "locale", + "tenant", + "default_filter", + ], + user_data, + ) + self.commit() + + @classmethod + @user_context + def tenant_authorization(cls, query: Query, **kwargs): + """Modifies the query to include tenant check if needed.""" + tenant_auth_query: Query = query + user: UserContext = kwargs["user"] + tenant_key: str = user.tenant_key + if not isinstance(query, Query): + raise TypeError("Query object must be of type Query") + if tenant_key is not None: + tenant_auth_query = tenant_auth_query.filter(cls.tenant == tenant_key) + return tenant_auth_query + + @classmethod + def get_user_by_user_name(cls, user_name: str = None): + """Find user data by username.""" + assert user_name is not None + query = cls.query.filter(cls.user_name == user_name) + query = cls.tenant_authorization(query) + return query.one_or_none() diff --git a/forms-flow-api/src/formsflow_api/resources/filter.py b/forms-flow-api/src/formsflow_api/resources/filter.py index e8312d075b..d776372028 100644 --- a/forms-flow-api/src/formsflow_api/resources/filter.py +++ b/forms-flow-api/src/formsflow_api/resources/filter.py @@ -71,6 +71,14 @@ }, ) +filter_response_with_default_filter = API.model( + "FilterResponse", + { + "filters": fields.List(fields.Nested(filter_response)), + "defaultFilter": fields.String(description="Default filter"), + }, +) + @cors_preflight("GET, POST, OPTIONS") @API.route("", methods=["GET", "POST", "OPTIONS"]) @@ -158,7 +166,7 @@ class UsersFilterList(Resource): 200: "OK:- Successful request.", 403: "FORBIDDEN:- Permission denied", }, - model=[filter_response], + model=filter_response_with_default_filter, ) def get(): """ diff --git a/forms-flow-api/src/formsflow_api/resources/user.py b/forms-flow-api/src/formsflow_api/resources/user.py index 3a2fe7dea2..2ab094d530 100644 --- a/forms-flow-api/src/formsflow_api/resources/user.py +++ b/forms-flow-api/src/formsflow_api/resources/user.py @@ -6,6 +6,7 @@ from flask_restx import Namespace, Resource, fields from formsflow_api_utils.utils import ( ADMIN_GROUP, + REVIEWER_GROUP, auth, cors_preflight, profiletime, @@ -15,6 +16,7 @@ TenantUserAddSchema, UserlocaleReqSchema, UserPermissionUpdateSchema, + UserSchema, UsersListSchema, ) from formsflow_api.services import KeycloakAdminAPIService, UserService @@ -67,6 +69,7 @@ ) locale_put_model = API.model("Locale", {"locale": fields.String()}) +default_filter_model = API.model("DefaulFilter", {"defaultFilter": fields.String()}) @cors_preflight("PUT, OPTIONS") @@ -115,6 +118,29 @@ def put(self) -> dict: response = self.client.update_request(url_path=f"users/{user['id']}", data=user) if response is None: return {"message": "User not found"}, HTTPStatus.NOT_FOUND + # Capture "locale" changes in user table + UserService.update_user_data({"locale": dict_data["locale"]}) + return response, HTTPStatus.OK + + +@cors_preflight("POST, OPTIONS") +@API.route("/default-filter", methods=["OPTIONS", "POST"]) +class UserDefaultFilter(Resource): + """Resource to create or update user's default filter.""" + + @staticmethod + @auth.has_one_of_roles([ADMIN_GROUP, REVIEWER_GROUP]) + @profiletime + @API.doc(body=default_filter_model) + @API.response(200, "OK:- Successful request.") + @API.response( + 400, + "BAD_REQUEST:- Invalid request.", + ) + def post(): + """Update the user's default task filter.""" + data = UserSchema().load(request.get_json()) + response = UserService().update_user_data(data=data) return response, HTTPStatus.OK diff --git a/forms-flow-api/src/formsflow_api/schemas/__init__.py b/forms-flow-api/src/formsflow_api/schemas/__init__.py index 6d12c08401..caa9488fb8 100644 --- a/forms-flow-api/src/formsflow_api/schemas/__init__.py +++ b/forms-flow-api/src/formsflow_api/schemas/__init__.py @@ -25,6 +25,7 @@ TenantUserAddSchema, UserlocaleReqSchema, UserPermissionUpdateSchema, + UserSchema, UsersListSchema, ) diff --git a/forms-flow-api/src/formsflow_api/schemas/process.py b/forms-flow-api/src/formsflow_api/schemas/process.py index 9e242a8721..addb8e1396 100644 --- a/forms-flow-api/src/formsflow_api/schemas/process.py +++ b/forms-flow-api/src/formsflow_api/schemas/process.py @@ -2,8 +2,9 @@ import json -from marshmallow import EXCLUDE, Schema, fields, validates from formsflow_api_utils.exceptions import BusinessException +from marshmallow import EXCLUDE, Schema, fields, validates + from formsflow_api.constants import BusinessErrorCode from formsflow_api.models import FormProcessMapper diff --git a/forms-flow-api/src/formsflow_api/schemas/user.py b/forms-flow-api/src/formsflow_api/schemas/user.py index 611bed0855..cfd503ebea 100644 --- a/forms-flow-api/src/formsflow_api/schemas/user.py +++ b/forms-flow-api/src/formsflow_api/schemas/user.py @@ -60,3 +60,17 @@ class Meta: # pylint: disable=too-few-public-methods user = fields.Str(data_key="user", required=True) roles = fields.List(fields.Nested(AddUserRoleSchema)) + + +class UserSchema(Schema): + """Schema for user data.""" + + class Meta: # pylint: disable=too-few-public-methods + """Exclude unknown fields in the deserialized output.""" + + unknown = EXCLUDE + + default_filter = fields.Int(data_key="defaultFilter", allow_none=True) + locale = fields.Str(data_key="locale") + user_name = fields.Str(data_key="userName", dump_only=True) + # tenant = fields.Str(data_key="tenantKey", dump_only=True) diff --git a/forms-flow-api/src/formsflow_api/services/filter.py b/forms-flow-api/src/formsflow_api/services/filter.py index 4726d02af3..95651962eb 100644 --- a/forms-flow-api/src/formsflow_api/services/filter.py +++ b/forms-flow-api/src/formsflow_api/services/filter.py @@ -6,7 +6,7 @@ from formsflow_api_utils.utils.user_context import UserContext, user_context from formsflow_api.constants import BusinessErrorCode -from formsflow_api.models import Filter +from formsflow_api.models import Filter, User from formsflow_api.schemas import FilterSchema filter_schema = FilterSchema() @@ -121,7 +121,11 @@ def get_user_filters(**kwargs): filter_item["variables"] += [ var for var in default_variables if var not in filter_item["variables"] ] - return filter_data + response = {"filters": filter_data} + # get user default filter + user_data = User.get_user_by_user_name(user_name=user.user_name) + response["defaultFilter"] = user_data.default_filter if user_data else None + return response @staticmethod @user_context diff --git a/forms-flow-api/src/formsflow_api/services/user.py b/forms-flow-api/src/formsflow_api/services/user.py index 96601bd0b0..464d654fcc 100644 --- a/forms-flow-api/src/formsflow_api/services/user.py +++ b/forms-flow-api/src/formsflow_api/services/user.py @@ -2,6 +2,11 @@ from typing import Dict, List +from formsflow_api_utils.utils.user_context import UserContext, user_context + +from formsflow_api.models import User +from formsflow_api.schemas import UserSchema + class UserService: """This class manages keycloak user service.""" @@ -84,3 +89,20 @@ def paginate(self, data, page_number, page_size): start_index = (page_number - 1) * page_size end_index = start_index + page_size return data[start_index:end_index] + + @staticmethod + @user_context + def update_user_data(data, **kwargs): + """Update user data.""" + user: UserContext = kwargs["user"] + user_data = User.get_user_by_user_name(user_name=user.user_name) + if user_data: + if user_data.tenant is None and user.tenant_key: + data["tenant"] = user.tenant_key + user_data.update(data) + else: + data["user_name"] = user.user_name + data["tenant"] = user.tenant_key + data["created_by"] = user.user_name + user_data = User.create_user(data) + return UserSchema().dump(user_data) diff --git a/forms-flow-api/tests/unit/api/test_filter.py b/forms-flow-api/tests/unit/api/test_filter.py index 3c4d5b94ce..bab37995d4 100644 --- a/forms-flow-api/tests/unit/api/test_filter.py +++ b/forms-flow-api/tests/unit/api/test_filter.py @@ -37,9 +37,9 @@ def test_get_user_filters(app, client, session, jwt): # Since reviewer created both filters response will include both. response = client.get("/filter/user", headers=headers) assert response.status_code == 200 - assert len(response.json) == 2 - assert response.json[0].get("name") == "Clerk Task" - assert response.json[1].get("name") == "Reviewer Task" + assert len(response.json.get("filters")) == 2 + assert response.json.get("filters")[0].get("name") == "Clerk Task" + assert response.json.get("filters")[1].get("name") == "Reviewer Task" def test_filter_update(app, client, session, jwt): diff --git a/forms-flow-api/tests/unit/api/test_user.py b/forms-flow-api/tests/unit/api/test_user.py index a27213b84a..4480aecdf2 100644 --- a/forms-flow-api/tests/unit/api/test_user.py +++ b/forms-flow-api/tests/unit/api/test_user.py @@ -1,7 +1,13 @@ """Test suite for keycloak user API endpoint.""" # from tests import skip_in_ci -from tests.utilities.base_test import get_locale_update_valid_payload, get_token +import json + +from tests.utilities.base_test import ( + get_filter_payload, + get_locale_update_valid_payload, + get_token, +) class TestKeycloakUserServiceResource: @@ -68,3 +74,23 @@ def test_keycloak_users_list_invalid_group(app, client, session, jwt): headers = {"Authorization": f"Bearer {token}", "content-type": "application/json"} rv = client.get("/user?memberOfGroup=test123", headers=headers) assert rv.status_code == 400 + + +def test_default_filter(app, client, session, jwt): + """Test create a filter and update default filter of a user.""" + token = get_token(jwt, role="formsflow-reviewer", username="reviewer") + headers = {"Authorization": f"Bearer {token}", "content-type": "application/json"} + # Create filter for clerk role + response = client.post( + "/filter", + headers=headers, + json=get_filter_payload(name="Clerk Task", roles=["clerk"]), + ) + assert response.status_code == 201 + response = client.post( + "/user/default-filter", + headers=headers, + data=json.dumps({"defaultFilter": response.json.get("id")}), + content_type="application/json", + ) + assert response.status_code == 200 diff --git a/forms-flow-web/src/actions/actionConstants.js b/forms-flow-web/src/actions/actionConstants.js index e55c25a4df..534172bc40 100644 --- a/forms-flow-web/src/actions/actionConstants.js +++ b/forms-flow-web/src/actions/actionConstants.js @@ -116,6 +116,7 @@ const ACTION_CONSTANTS = { IS_BPM_TASK_DETAIL_LOADING: "IS_BPM_TASK_DETAIL_LOADING", IS_BPM_TASK_DETAIL_UPDATING: "IS_BPM_TASK_DETAIL_UPDATING", BPM_FILTER_LIST: "BPM_FILTER_LIST", + DEFAULT_FILTER: "DEFAULT_FILTER", IS_BPM_FILTERS_LOADING: "IS_BPM_FILTERS_LOADING", BPM_SELECTED_FILTER: "BPM_SELECTED_FILTER", SELECTED_TASK_ID: "SELECTED_TASK_ID", diff --git a/forms-flow-web/src/actions/bpmTaskActions.js b/forms-flow-web/src/actions/bpmTaskActions.js index 3989c47c6d..cba643c191 100644 --- a/forms-flow-web/src/actions/bpmTaskActions.js +++ b/forms-flow-web/src/actions/bpmTaskActions.js @@ -101,6 +101,13 @@ export const setBPMFilterList = (data) => (dispatch) => { }); }; +export const setDefaultFilter = (data) => (dispatch) => { + dispatch({ + type: ACTION_CONSTANTS.DEFAULT_FILTER, + payload: data, + }); +}; + export const setSelectedBPMFilter = (data) => (dispatch) => { dispatch({ type: ACTION_CONSTANTS.BPM_SELECTED_FILTER, diff --git a/forms-flow-web/src/apiManager/endpoints/index.js b/forms-flow-web/src/apiManager/endpoints/index.js index db909cb84b..583cda16e0 100644 --- a/forms-flow-web/src/apiManager/endpoints/index.js +++ b/forms-flow-web/src/apiManager/endpoints/index.js @@ -40,6 +40,7 @@ const API = { GET_BPM_PROCESS_LIST: `${BPM_BASE_URL_EXT}/v1/process-definition`, GET_DMN_PROCESS_LIST: `${BPM_BASE_URL_EXT}/v1/decision-definition`, GET_API_USER_LIST: `${WEB_BASE_URL}/user`, + UPDATE_DEFAULT_FILTER: `${WEB_BASE_URL}/user/default-filter`, GET_BPM_FILTERS: `${BPM_BASE_URL_EXT}/v1/filter`, GET_BPM_TASK_LIST_WITH_FILTER: `${BPM_BASE_URL_EXT}/v1/filter//list`, GET_BPM_TASK_LIST_COUNT_WITH_FILTER: `${BPM_BASE_URL_EXT}/v1/filter//count`, diff --git a/forms-flow-web/src/apiManager/services/bpmTaskServices.js b/forms-flow-web/src/apiManager/services/bpmTaskServices.js index 87d23450bf..9f7b45f7fd 100644 --- a/forms-flow-web/src/apiManager/services/bpmTaskServices.js +++ b/forms-flow-web/src/apiManager/services/bpmTaskServices.js @@ -18,6 +18,7 @@ import { bpmActionError, setBPMTaskList, setVisibleAttributes, + setDefaultFilter, } from "../../actions/bpmTaskActions"; import { replaceUrl } from "../../helper/helper"; import axios from "axios"; @@ -194,7 +195,8 @@ export const fetchFilterList = (...rest) => { ) .then((res) => { if (res.data) { - dispatch(setBPMFilterList(res.data)); + dispatch(setDefaultFilter(res.data.defaultFilter)); + dispatch(setBPMFilterList(res.data.filters)); //dispatch(setBPMLoader(false)); done(null, res.data); } else { diff --git a/forms-flow-web/src/apiManager/services/userservices.js b/forms-flow-web/src/apiManager/services/userservices.js index 6b55dc54e7..ec4c8b9727 100644 --- a/forms-flow-web/src/apiManager/services/userservices.js +++ b/forms-flow-web/src/apiManager/services/userservices.js @@ -57,3 +57,11 @@ export const fetchUsers = ( return RequestService.httpGETRequest(url); }; + + +export const updateDefaultFilter = (defaultFilter) => { + return RequestService.httpPOSTRequest( + API.UPDATE_DEFAULT_FILTER, + {defaultFilter} + ); +}; \ No newline at end of file diff --git a/forms-flow-web/src/components/ServiceFlow/index.js b/forms-flow-web/src/components/ServiceFlow/index.js index ecc7bc69c3..5bfd2afb21 100644 --- a/forms-flow-web/src/components/ServiceFlow/index.js +++ b/forms-flow-web/src/components/ServiceFlow/index.js @@ -67,6 +67,7 @@ export default React.memo(() => { const taskListRef = useRef(taskList); const tenantKey = useSelector((state) => state.tenants?.tenantId); const cardView = useSelector((state) => state.bpmTasks.viewType); + const defaultFilter = useSelector((state)=> state.user.defaultFilter); const [expandedTasks, setExpandedTasks] = useState({}); const redirectUrl = useRef( MULTITENANCY_ENABLED ? `/tenant/${tenantKey}/` : "/" @@ -114,7 +115,7 @@ export default React.memo(() => { dispatch( fetchFilterList((err, data) => { if (data) { - fetchBPMTaskCount(data) + fetchBPMTaskCount(data.filters) .then((res) => { dispatch(setBPMFiltersAndCount(res.data)); }) @@ -133,7 +134,7 @@ export default React.memo(() => { let filterSelected; if (filterList.length > 1) { filterSelected = filterList?.find( - (filter) => filter.name === ALL_TASKS + (filter) => filter.id === defaultFilter || filter.name === ALL_TASKS ); if (!filterSelected) { filterSelected = filterList[0]; diff --git a/forms-flow-web/src/components/ServiceFlow/list/sort/CreateNewFilter.js b/forms-flow-web/src/components/ServiceFlow/list/sort/CreateNewFilter.js index f7c271d23d..2e455c3ee6 100644 --- a/forms-flow-web/src/components/ServiceFlow/list/sort/CreateNewFilter.js +++ b/forms-flow-web/src/components/ServiceFlow/list/sort/CreateNewFilter.js @@ -304,7 +304,7 @@ export default function CreateNewFilterDrawer({ dispatch( fetchFilterList((err, data) => { if (data) { - fetchBPMTaskCount(data) + fetchBPMTaskCount(data.filters) .then((res) => { dispatch(setBPMFiltersAndCount(res.data)); }) @@ -451,10 +451,11 @@ export default function CreateNewFilterDrawer({ dispatch( fetchFilterList((err, data) => { if (data) { - fetchBPMTaskCount(data) + fetchBPMTaskCount(data.filters) .then((res) => { dispatch(setBPMFiltersAndCount(res.data)); - dispatch(fetchServiceTaskList(data[0], null, firstResult)); + dispatch(fetchServiceTaskList(data.defaultFilter || data.filters[0] + , null, firstResult)); }) .catch((err) => { if (err) { @@ -983,7 +984,7 @@ export default function CreateNewFilterDrawer({ toggleDrawer(); clearAllFilters(); }} - className="btn btn-link text-dark cursor-pointer" + className="btn btn-outline-primary" > {(t) => t("Create New Filter")} diff --git a/forms-flow-web/src/containers/TaskHead.js b/forms-flow-web/src/containers/TaskHead.js index 66f59a5e5e..7efa7e11c8 100644 --- a/forms-flow-web/src/containers/TaskHead.js +++ b/forms-flow-web/src/containers/TaskHead.js @@ -1,14 +1,16 @@ -import React, { useState } from "react"; +import React, { useCallback, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { push } from "connected-react-router"; import { NavDropdown } from "react-bootstrap"; import ServiceFlowFilterListDropDown from "../components/ServiceFlow/filter/ServiceTaskFilterListDropDown"; import { MULTITENANCY_ENABLED } from "../constants/constants"; -import { setBPMFilterLoader, setBPMFiltersAndCount, setSelectedTaskID, setViewType } from '../actions/bpmTaskActions'; +import { setBPMFilterLoader, setBPMFiltersAndCount, setDefaultFilter, setSelectedTaskID, setViewType } from '../actions/bpmTaskActions'; import CreateNewFilterDrawer from "../components/ServiceFlow/list/sort/CreateNewFilter"; import { useTranslation } from "react-i18next"; import { fetchBPMTaskCount } from "../apiManager/services/bpmTaskServices"; - +import { toast } from "react-toastify"; +import { updateDefaultFilter } from "../apiManager/services/userservices"; +import _ from "lodash"; function TaskHead() { const dispatch = useDispatch(); const { t } = useTranslation(); @@ -22,6 +24,7 @@ function TaskHead() { const isFilterLoading = useSelector((state) => state.bpmTasks.isFilterLoading); const filterListItems = useSelector((state) => state.bpmTasks.filterList); const isTaskListLoading = useSelector((state) => state.bpmTasks.isTaskListLoading); + const defaultFilter = useSelector((state)=> state.user.defaultFilter); const baseUrl = MULTITENANCY_ENABLED ? `/tenant/${tenantKey}/` : "/"; @@ -56,18 +59,32 @@ function TaskHead() { : text; }; + const defaultFilterChange = useCallback(()=>{ + updateDefaultFilter(selectedFilter.id == defaultFilter ? null : selectedFilter.id).then((res)=>{ + dispatch(setDefaultFilter(res.data.defaultFilter)); + if (selectedFilter.id == defaultFilter){ + toast.success(t(`Default filter removed`)); + }else{ + toast.success(t(`${_.startCase(selectedFilter.name)} added as default filter`)); + } + + }).catch((err)=>{ + console.error(err); + }); + },[selectedFilter,defaultFilter]); + return (
-
+
- {selectedFilter?.name ? - textTruncate(25, 23, `${selectedFilter?.name} ${count}`) : - filterListLoading() } + {selectedFilter?.name + ? textTruncate(25, 23, `${selectedFilter?.name} ${count}`) + : filterListLoading()} } onClick={goToTask} @@ -80,9 +97,30 @@ function TaskHead() { openFilterDrawer={setOpenFilterDrawer} /> - + + + + +
: null } +