tested appender service to events
This commit is contained in:
parent
0cde34a9bc
commit
dd707b2463
|
|
@ -49,21 +49,27 @@ class EventCluster:
|
|||
endpoint_uu_id=str(to_save_endpoint.uu_id),
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
include_args=[
|
||||
Events.function_code,
|
||||
Events.function_class,
|
||||
Events.endpoint_code,
|
||||
Events.endpoint_uu_id,
|
||||
]
|
||||
)
|
||||
event_to_save_database = Events.find_or_create(**event_dict_to_save)
|
||||
if event_to_save_database.meta_data.created:
|
||||
print(f"UUID: {event_to_save_database.uu_id} event is saved to {to_save_endpoint.uu_id}")
|
||||
event_found = Events.filter_one(
|
||||
Events.function_code == event_dict_to_save["function_code"],
|
||||
db=db_session,
|
||||
).data
|
||||
if event_found:
|
||||
event_found.update(**event_dict_to_save)
|
||||
event_found.save(db=db_session)
|
||||
else:
|
||||
event_to_save_database.update(**event_dict_to_save)
|
||||
if event_to_save_database.meta_data.updated:
|
||||
print(f"UUID: {event_to_save_database.uu_id} event is updated to {to_save_endpoint.uu_id}")
|
||||
event_to_save_database.save(db=db_session)
|
||||
event_to_save_database = Events.find_or_create(
|
||||
**event_dict_to_save,
|
||||
include_args=[
|
||||
Events.function_code,
|
||||
Events.function_class,
|
||||
Events.endpoint_code,
|
||||
Events.endpoint_uu_id,
|
||||
]
|
||||
)
|
||||
if event_to_save_database.meta_data.created:
|
||||
print(f"UUID: {event_to_save_database.uu_id} event is saved to {to_save_endpoint.uu_id}")
|
||||
event_to_save_database.save(db=db_session)
|
||||
|
||||
def match_event(self, event_key: str) -> "Event":
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -23,17 +23,24 @@ class RouteRegisterController:
|
|||
for route_method in [
|
||||
method.lower() for method in getattr(route, "methods")
|
||||
]:
|
||||
restriction = EndpointRestriction.find_or_create(
|
||||
add_or_update_dict = dict(
|
||||
endpoint_method=route_method,
|
||||
endpoint_name=route_path,
|
||||
endpoint_desc=route_summary.replace("_", " "),
|
||||
endpoint_function=route_summary,
|
||||
operation_uu_id=operation_id, # UUID of the endpoint
|
||||
operation_uu_id=operation_id,
|
||||
is_confirmed=True,
|
||||
db=db_session,
|
||||
)
|
||||
if restriction.meta_data.created:
|
||||
restriction.save(db=db_session)
|
||||
endpoint_restriction_found = EndpointRestriction.filter_one_system(
|
||||
EndpointRestriction.operation_uu_id == operation_id, db=db_session,
|
||||
).data
|
||||
if endpoint_restriction_found:
|
||||
endpoint_restriction_found.update(**add_or_update_dict, db=db_session)
|
||||
endpoint_restriction_found.save(db=db_session)
|
||||
else:
|
||||
restriction = EndpointRestriction.find_or_create(**add_or_update_dict, db=db_session)
|
||||
if restriction.meta_data.created:
|
||||
restriction.save(db=db_session)
|
||||
|
||||
def register_routes(self):
|
||||
for router in self.router_list:
|
||||
|
|
|
|||
|
|
@ -5,18 +5,39 @@ from ApiControllers.abstracts.default_validations import CommonHeaders
|
|||
from ApiControllers.providers.token_provider import TokenProvider
|
||||
from Controllers.Postgres.pagination import PaginateOnly, Pagination, PaginationResult
|
||||
from Controllers.Postgres.response import EndpointResponse
|
||||
from Validations.service_endpoints.validations import Event2Employee, Event2Occupant
|
||||
from Validations.service_endpoints.validations import Event2Employee, Event2Occupant, AddRemoveService
|
||||
from Events.event_endpoints.cluster import EventsEndpointRouterCluster
|
||||
|
||||
# Create API router
|
||||
event_endpoint_route = APIRouter(prefix="/events", tags=["Event Actions"])
|
||||
|
||||
|
||||
@event_endpoint_route.post(
|
||||
path="/list",
|
||||
description="List events endpoint",
|
||||
path="/list/available",
|
||||
description="List available events endpoint",
|
||||
operation_id="0659d5e4-671f-466c-a84f-47a1290a6f0d",
|
||||
)
|
||||
def event_list_route(
|
||||
def event_list_available_route(
|
||||
data: PaginateOnly,
|
||||
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
|
||||
):
|
||||
"""
|
||||
List available events with pagination and filtering options
|
||||
"""
|
||||
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
|
||||
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
|
||||
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventsListAvailable")
|
||||
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
|
||||
return event_cluster_matched.event_callable(list_options=data)
|
||||
|
||||
|
||||
@event_endpoint_route.post(
|
||||
path="/list/appended",
|
||||
description="List appended events endpoint",
|
||||
operation_id="4d563973-cdcd-44e1-94e0-4262ffb456a1",
|
||||
)
|
||||
def event_list_appended_route(
|
||||
data: PaginateOnly,
|
||||
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
|
||||
):
|
||||
|
|
@ -26,10 +47,10 @@ def event_list_route(
|
|||
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
|
||||
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
|
||||
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventsList")
|
||||
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventsListAppended")
|
||||
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
|
||||
return event_cluster_matched.event_callable(data=data)
|
||||
|
||||
return event_cluster_matched.event_callable(list_options=data)
|
||||
|
||||
|
||||
@event_endpoint_route.post(
|
||||
path="/register/service",
|
||||
|
|
@ -37,7 +58,7 @@ def event_list_route(
|
|||
operation_id="c89a2150-db4d-4a8f-b6ec-9e0f09625f76",
|
||||
)
|
||||
def event_register_service_route(
|
||||
data: Any,
|
||||
data: AddRemoveService,
|
||||
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
|
||||
):
|
||||
"""
|
||||
|
|
@ -46,7 +67,27 @@ def event_register_service_route(
|
|||
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
|
||||
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
|
||||
FoundCluster = EventEndpointRouterCluster.get_event_cluster("EventRegisterService")
|
||||
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventRegisterService")
|
||||
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
|
||||
return event_cluster_matched.event_callable(data=data)
|
||||
|
||||
|
||||
@event_endpoint_route.post(
|
||||
path="/unregister/service",
|
||||
description="Unregister event from service endpoint",
|
||||
operation_id="2f16dc9e-de02-449d-9c3f-1a21f87e8794",
|
||||
)
|
||||
def event_unregister_service_route(
|
||||
data: AddRemoveService,
|
||||
headers: CommonHeaders = Depends(CommonHeaders.as_dependency),
|
||||
):
|
||||
"""
|
||||
Unregister event from service
|
||||
"""
|
||||
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
|
||||
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
|
||||
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventUnregisterService")
|
||||
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
|
||||
return event_cluster_matched.event_callable(data=data)
|
||||
|
||||
|
|
@ -66,7 +107,7 @@ def event_bind_employee_extra_route(
|
|||
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
|
||||
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
|
||||
FoundCluster = EventEndpointRouterCluster.get_event_cluster("EventBindEmployeeExtra")
|
||||
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventBindEmployeeExtra")
|
||||
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
|
||||
return event_cluster_matched.event_callable(data=data)
|
||||
|
||||
|
|
@ -86,6 +127,6 @@ def event_bind_occupant_extra_route(
|
|||
token_object = TokenProvider.get_dict_from_redis(token=headers.token)
|
||||
event_founder_dict = dict(endpoint_code=headers.operation_id, token=token_object)
|
||||
event_key = TokenProvider.retrieve_event_codes(**event_founder_dict)
|
||||
FoundCluster = EventEndpointRouterCluster.get_event_cluster("EventBindOccupantExtra")
|
||||
FoundCluster = EventsEndpointRouterCluster.get_event_cluster("EventBindOccupantExtra")
|
||||
event_cluster_matched = FoundCluster.match_event(event_key=event_key)
|
||||
return event_cluster_matched.event_callable(data=data)
|
||||
|
|
|
|||
|
|
@ -1,23 +1,35 @@
|
|||
from ApiControllers.abstracts.event_clusters import EventCluster, RouterCluster
|
||||
from .supers_events import (
|
||||
EventsListEvent,
|
||||
EventsListAvailableEvent,
|
||||
EventsListAppendedEvent,
|
||||
EventRegisterServiceEvent,
|
||||
EventUnRegisterServiceEvent,
|
||||
EventBindEmployeeExtraEvent,
|
||||
EventBindOccupantExtraEvent,
|
||||
)
|
||||
|
||||
EventsEndpointRouterCluster = RouterCluster(name="EventsEndpointRouterCluster")
|
||||
|
||||
EventsEndpointEventClusterList = EventCluster(
|
||||
name="EventsList", endpoint_uu_id="0659d5e4-671f-466c-a84f-47a1290a6f0d"
|
||||
EventsEndpointEventClusterListAvailable = EventCluster(
|
||||
name="EventsListAvailable", endpoint_uu_id="0659d5e4-671f-466c-a84f-47a1290a6f0d"
|
||||
)
|
||||
EventsEndpointEventClusterList.add_event(EventsListEvent)
|
||||
EventsEndpointEventClusterListAvailable.add_event(EventsListAvailableEvent)
|
||||
|
||||
EventsEndpointEventClusterListAppended = EventCluster(
|
||||
name="EventsListAppended", endpoint_uu_id="4d563973-cdcd-44e1-94e0-4262ffb456a1"
|
||||
)
|
||||
EventsEndpointEventClusterListAppended.add_event(EventsListAppendedEvent)
|
||||
|
||||
EventsEndpointEventClusterRegisterService = EventCluster(
|
||||
name="EventRegisterService", endpoint_uu_id="c89a2150-db4d-4a8f-b6ec-9e0f09625f76"
|
||||
)
|
||||
EventsEndpointEventClusterRegisterService.add_event(EventRegisterServiceEvent)
|
||||
|
||||
EventsEndpointEventClusterUnregisterService = EventCluster(
|
||||
name="EventUnregisterService", endpoint_uu_id="2f16dc9e-de02-449d-9c3f-1a21f87e8794"
|
||||
)
|
||||
EventsEndpointEventClusterUnregisterService.add_event(EventUnRegisterServiceEvent)
|
||||
|
||||
EventsEndpointEventClusterBindEmployeeExtra = EventCluster(
|
||||
name="EventBindEmployeeExtra", endpoint_uu_id="58ef3640-04ec-43f9-8f3e-f86be3ce4a24"
|
||||
)
|
||||
|
|
@ -28,8 +40,9 @@ EventsEndpointEventClusterBindOccupantExtra = EventCluster(
|
|||
)
|
||||
EventsEndpointEventClusterBindOccupantExtra.add_event(EventBindOccupantExtraEvent)
|
||||
|
||||
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterList)
|
||||
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterListAvailable)
|
||||
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterListAppended)
|
||||
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterRegisterService)
|
||||
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterUnregisterService)
|
||||
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterBindEmployeeExtra)
|
||||
EventsEndpointRouterCluster.set_event_cluster(EventsEndpointEventClusterBindOccupantExtra)
|
||||
|
||||
|
|
@ -9,28 +9,45 @@ from Schemas import (
|
|||
Event2EmployeeExtra,
|
||||
Event2OccupantExtra,
|
||||
Service2Events,
|
||||
Services,
|
||||
)
|
||||
|
||||
|
||||
# List endpoint
|
||||
EventsListEvent = Event(
|
||||
name="service_endpoint_list",
|
||||
key="0a08c64b-ce20-4791-b1e9-014db6b75ea7",
|
||||
# List available events endpoint
|
||||
EventsListAvailableEvent = Event(
|
||||
name="event_endpoint_list_available",
|
||||
key="d39af512-ec71-4c0f-9b35-e53b0d06d3a4",
|
||||
request_validator=None, # TODO: Add request validator
|
||||
response_validator=None, # TODO: Add response validator
|
||||
description="Super Users List services endpoint",
|
||||
description="Super Users List available events endpoint",
|
||||
)
|
||||
|
||||
# List appended events endpoint
|
||||
EventsListAppendedEvent = Event(
|
||||
name="event_endpoint_list_appended",
|
||||
key="bea77d6a-d99f-468b-9002-b3bda6bb6ad0",
|
||||
request_validator=None, # TODO: Add request validator
|
||||
response_validator=None, # TODO: Add response validator
|
||||
description="Super Users List appended events endpoint",
|
||||
)
|
||||
|
||||
# Event Register endpoint
|
||||
EventRegisterServiceEvent = Event(
|
||||
name="service_endpoint_register_service",
|
||||
name="event_endpoint_register_service",
|
||||
key="e18e7f89-5708-4a15-9258-99b0903ed43d",
|
||||
request_validator=None, # TODO: Add request validator
|
||||
response_validator=None, # TODO: Add response validator
|
||||
description="Super Users Register service endpoint",
|
||||
)
|
||||
|
||||
# Event Unregister endpoint
|
||||
EventUnRegisterServiceEvent = Event(
|
||||
name="service_endpoint_unregister_service",
|
||||
key="4d693774-4857-435b-a63c-c39baebfe916",
|
||||
request_validator=None, # TODO: Add request validator
|
||||
response_validator=None, # TODO: Add response validator
|
||||
description="Super Users Unregister service endpoint",
|
||||
)
|
||||
|
||||
# Bind employee extra endpoint
|
||||
EventBindEmployeeExtraEvent = Event(
|
||||
name="service_endpoint_bind_employee_extra",
|
||||
|
|
@ -50,58 +67,196 @@ EventBindOccupantExtraEvent = Event(
|
|||
)
|
||||
|
||||
|
||||
def events_list_callable(list_options: PaginateOnly):
|
||||
def events_list_available_callable(list_options: PaginateOnly):
|
||||
"""
|
||||
Example callable method
|
||||
List available events with pagination and filtering options
|
||||
"""
|
||||
list_options = PaginateOnly(**list_options.model_dump())
|
||||
with Services.new_session() as db_session:
|
||||
service_uu_id = list_options.query.get('service_uu_id__ilike', None)
|
||||
if not service_uu_id:
|
||||
return {
|
||||
"message": "MSG0003-PARAM-MISSING",
|
||||
"data": list_options.query,
|
||||
"completed": False,
|
||||
}
|
||||
with Events.new_session() as db_session:
|
||||
service2events = Service2Events.filter_all(*Service2Events.convert(list_options.query), db=db_session)
|
||||
already_events = [service_to_event.event_id for service_to_event in service2events.data]
|
||||
list_options.query.pop('service_uu_id__ilike', None)
|
||||
list_options.query.pop('service_uu_id', None)
|
||||
if list_options.query:
|
||||
services_list = Services.filter_all(
|
||||
*Services.convert(list_options.query), db=db_session
|
||||
)
|
||||
events_list = Events.filter_all(*Events.convert(list_options.query), Events.id.not_in(already_events), db=db_session)
|
||||
else:
|
||||
services_list = Services.filter_all(db=db_session)
|
||||
pagination = Pagination(data=services_list)
|
||||
events_list = Events.filter_all(Events.id.not_in(already_events), db=db_session)
|
||||
pagination = Pagination(data=events_list)
|
||||
pagination.change(**list_options.model_dump())
|
||||
pagination_result = PaginationResult(
|
||||
data=services_list,
|
||||
pagination=pagination,
|
||||
# response_model="",
|
||||
).pagination.as_dict
|
||||
pagination_result = PaginationResult(data=events_list, pagination=pagination)
|
||||
return EndpointResponse(
|
||||
message="MSG0003-LIST",
|
||||
pagination_result=pagination_result,
|
||||
).response
|
||||
|
||||
EventsListEvent.event_callable = events_list_callable
|
||||
|
||||
EventsListAvailableEvent.event_callable = events_list_available_callable
|
||||
|
||||
|
||||
def events_list_appended_callable(list_options: PaginateOnly):
|
||||
"""
|
||||
List appended events with pagination and filtering options
|
||||
"""
|
||||
list_options = PaginateOnly(**list_options.model_dump())
|
||||
service_uu_id = list_options.query.get('service_uu_id__ilike', None)
|
||||
if not service_uu_id:
|
||||
return {
|
||||
"message": "MSG0003-PARAM-MISSING",
|
||||
"data": list_options.query,
|
||||
"completed": False,
|
||||
}
|
||||
with Events.new_session() as db_session:
|
||||
service2events = Service2Events.filter_all(*Service2Events.convert(list_options.query), db=db_session)
|
||||
already_events = [service_to_event.event_id for service_to_event in service2events.data]
|
||||
list_options.query.pop('service_uu_id__ilike', None)
|
||||
list_options.query.pop('service_uu_id', None)
|
||||
if list_options.query:
|
||||
events_list = Events.filter_all(*Events.convert(list_options.query), Events.id.in_(already_events), db=db_session)
|
||||
else:
|
||||
events_list = Events.filter_all(Events.id.in_(already_events), db=db_session)
|
||||
pagination = Pagination(data=events_list)
|
||||
pagination.change(**list_options.model_dump())
|
||||
pagination_result = PaginationResult(data=events_list, pagination=pagination)
|
||||
return EndpointResponse(
|
||||
message="MSG0003-LIST",
|
||||
pagination_result=pagination_result,
|
||||
).response
|
||||
|
||||
|
||||
EventsListAppendedEvent.event_callable = events_list_appended_callable
|
||||
|
||||
|
||||
def event_register_service_callable(data: Any):
|
||||
"""
|
||||
Example callable method
|
||||
Register event to service
|
||||
"""
|
||||
return EndpointResponse(
|
||||
message="MSG0003-REGISTER",
|
||||
).response
|
||||
with Events.new_session() as db_session:
|
||||
event = Events.filter_one_system(
|
||||
Events.uu_id == data.event_uu_id,
|
||||
db=db_session
|
||||
)
|
||||
print('event', event.data)
|
||||
if not event.data:
|
||||
return {
|
||||
"message": "MSG0003-NOT-FOUND",
|
||||
"data": data.model_dump(),
|
||||
"completed": False,
|
||||
}
|
||||
service = Services.filter_one_system(
|
||||
Services.uu_id == data.service_uu_id,
|
||||
db=db_session
|
||||
)
|
||||
print('service', service.data)
|
||||
if not service.data:
|
||||
return {
|
||||
"message": "MSG0003-NOT-FOUND",
|
||||
"data": data.model_dump(),
|
||||
"completed": False,
|
||||
}
|
||||
service_to_event = Service2Events.find_or_create(
|
||||
db=db_session,
|
||||
include_args=[
|
||||
Service2Events.service_uu_id,
|
||||
Service2Events.event_uu_id,
|
||||
],
|
||||
service_id=service.data.id,
|
||||
event_id=event.data.id,
|
||||
is_confirmed=True,
|
||||
service_uu_id=str(service.data.uu_id),
|
||||
event_uu_id=str(event.data.uu_id),
|
||||
)
|
||||
print('service_to_event', service_to_event)
|
||||
if not service_to_event.meta_data.created:
|
||||
return {
|
||||
"message": "MSG0003-ALREADY-FOUND",
|
||||
"data": data.model_dump(),
|
||||
"completed": False,
|
||||
}
|
||||
service_to_event.save(db=db_session)
|
||||
return {
|
||||
"message": "MSG0003-REGISTER",
|
||||
"data": data.model_dump(),
|
||||
"completed": True,
|
||||
}
|
||||
|
||||
|
||||
EventRegisterServiceEvent.event_callable = event_register_service_callable
|
||||
|
||||
|
||||
def event_unregister_service_callable(data: Any):
|
||||
"""
|
||||
Unregister event from service
|
||||
"""
|
||||
with Events.new_session() as db_session:
|
||||
event = Events.filter_one_system(
|
||||
Events.uu_id == data.event_uu_id, db=db_session
|
||||
)
|
||||
if not event.data:
|
||||
return {
|
||||
"message": "MSG0003-NOT-FOUND",
|
||||
"data": data.model_dump(),
|
||||
"completed": False,
|
||||
}
|
||||
service = Services.filter_one_system(
|
||||
Services.uu_id == data.service_uu_id, db=db_session
|
||||
)
|
||||
if not service.data:
|
||||
return {
|
||||
"message": "MSG0003-NOT-FOUND",
|
||||
"data": data.model_dump(),
|
||||
"completed": False,
|
||||
}
|
||||
service_to_event = Service2Events.filter_one_system(
|
||||
Service2Events.service_id==service.data.id,
|
||||
Service2Events.event_id==event.data.id,
|
||||
db=db_session,
|
||||
)
|
||||
if not service_to_event.data:
|
||||
return {
|
||||
"message": "MSG0003-NOT-FOUND",
|
||||
"data": data.model_dump(),
|
||||
"completed": False,
|
||||
}
|
||||
service_to_event.query.delete()
|
||||
db_session.commit()
|
||||
return {
|
||||
"message": "MSG0003-UNREGISTER",
|
||||
"data": data.model_dump(),
|
||||
"completed": True,
|
||||
}
|
||||
|
||||
|
||||
EventUnRegisterServiceEvent.event_callable = event_unregister_service_callable
|
||||
|
||||
|
||||
def event_bind_employee_extra_callable(data: Any):
|
||||
"""
|
||||
Example callable method
|
||||
Bind event to employee extra
|
||||
"""
|
||||
return EndpointResponse(
|
||||
message="MSG0003-BIND",
|
||||
).response
|
||||
return {
|
||||
"message": "MSG0003-BIND",
|
||||
"data": data.model_dump(),
|
||||
"completed": True,
|
||||
}
|
||||
|
||||
|
||||
EventBindEmployeeExtraEvent.event_callable = event_bind_employee_extra_callable
|
||||
|
||||
|
||||
def event_bind_occupant_extra_callable(data: Any):
|
||||
"""
|
||||
Example callable method
|
||||
Bind event to occupant extra
|
||||
"""
|
||||
return EndpointResponse(
|
||||
message="MSG0003-BIND",
|
||||
).response
|
||||
|
||||
|
||||
EventBindOccupantExtraEvent.event_callable = event_bind_occupant_extra_callable
|
||||
|
|
|
|||
|
|
@ -16,3 +16,4 @@ ServiceEndpointEventClusterToService = EventCluster(
|
|||
ServiceEndpointEventClusterToService.add_event(ServiceEndpointToEventsEvent)
|
||||
|
||||
ServiceEndpointRouterCluster.set_event_cluster(ServiceEndpointEventClusterList)
|
||||
ServiceEndpointRouterCluster.set_event_cluster(ServiceEndpointEventClusterToService)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Event2Employee:
|
||||
class Event2Employee(BaseModel):
|
||||
pass
|
||||
|
||||
|
||||
class Event2Occupant:
|
||||
class Event2Occupant(BaseModel):
|
||||
pass
|
||||
|
||||
|
||||
class AddRemoveService(BaseModel):
|
||||
event_uu_id: str
|
||||
service_uu_id: str
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@ class CRUDModel:
|
|||
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
print('e', e)
|
||||
cls.raise_exception(
|
||||
f"Failed to find or create record: {str(e)}", status_code=500
|
||||
)
|
||||
|
|
|
|||
|
|
@ -78,18 +78,13 @@ async function coreFetch<T>(
|
|||
signal,
|
||||
};
|
||||
|
||||
// Add body if needed
|
||||
if (method !== "GET" && payload) {
|
||||
fetchOptions.body = JSON.stringify(
|
||||
// Handle special case for updateDataWithToken
|
||||
payload.payload ? payload.payload : payload
|
||||
);
|
||||
}
|
||||
|
||||
// Create timeout promise
|
||||
const timeoutPromise = createTimeoutPromise(timeout, controller);
|
||||
|
||||
// Race between fetch and timeout
|
||||
const response = (await Promise.race([
|
||||
fetch(url, fetchOptions),
|
||||
timeoutPromise,
|
||||
|
|
@ -99,7 +94,7 @@ async function coreFetch<T>(
|
|||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
console.log("Fetching:", url, fetchOptions);
|
||||
console.log("Response:", responseJson);
|
||||
// console.log("Response:", responseJson);
|
||||
}
|
||||
|
||||
return prepareResponse(responseJson, response.status);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ async function listApplications(payload: PaginationParams): Promise<PaginatedApi
|
|||
false
|
||||
);
|
||||
|
||||
// Format the response to match the expected PaginatedApiResponse format
|
||||
if (response?.status === 200 || response?.status === 202) {
|
||||
const responseData = response.data as any;
|
||||
return {
|
||||
|
|
@ -64,7 +63,6 @@ async function listApplications(payload: PaginationParams): Promise<PaginatedApi
|
|||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching application list:", error);
|
||||
// Return a default empty response instead of null to match the expected return type
|
||||
return {
|
||||
data: [],
|
||||
pagination: {
|
||||
|
|
|
|||
|
|
@ -3,82 +3,151 @@
|
|||
import { fetchDataWithToken } from "../api-fetcher";
|
||||
import { baseUrlApplication } from "../basics";
|
||||
import { PaginationParams } from "../schemas/list";
|
||||
import type { PaginatedApiResponse } from "@/app/api/utils/types";
|
||||
import { PaginatedApiResponse, collectPaginationFromApiResponse, defaultPaginationResponse } from "@/app/api/utils/types";
|
||||
|
||||
const eventsListEndpoint = `${baseUrlApplication}/events/list`;
|
||||
const eventsListAvailableEndpoint = `${baseUrlApplication}/events/list/available`;
|
||||
const eventsListAppendedEndpoint = `${baseUrlApplication}/events/list/appended`;
|
||||
const appendEventToServiceEndpoint = `${baseUrlApplication}/events/register/service`;
|
||||
const removeEventFromServiceEndpoint = `${baseUrlApplication}/events/unregister/service`;
|
||||
|
||||
interface AppendEventToService {
|
||||
service_uu_id: string;
|
||||
event_uu_id: string;
|
||||
}
|
||||
|
||||
interface RemoveEventFromService extends AppendEventToService { }
|
||||
|
||||
|
||||
async function list_events_available(payload: PaginationParams): Promise<PaginatedApiResponse<any>> {
|
||||
if (!payload.query.service_uu_id__ilike) {
|
||||
console.warn('Missing service_uu_id in query parameters');
|
||||
return {
|
||||
data: [],
|
||||
pagination: defaultPaginationResponse,
|
||||
};
|
||||
}
|
||||
|
||||
async function listEvents(payload: PaginationParams): Promise<PaginatedApiResponse<any>> {
|
||||
try {
|
||||
const requestBody = {
|
||||
page: payload.page,
|
||||
size: payload.size,
|
||||
order_field: payload.orderField,
|
||||
order_type: payload.orderType,
|
||||
query: payload.query,
|
||||
};
|
||||
|
||||
console.log('Sending request to backend with service_uu_id:', payload.query.service_uu_id);
|
||||
console.log('Full request body:', JSON.stringify(requestBody, null, 2));
|
||||
|
||||
const response = await fetchDataWithToken(
|
||||
eventsListEndpoint,
|
||||
{
|
||||
page: payload.page,
|
||||
size: payload.size,
|
||||
order_field: payload.orderField,
|
||||
order_type: payload.orderType,
|
||||
query: payload.query,
|
||||
},
|
||||
eventsListAvailableEndpoint,
|
||||
requestBody,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
|
||||
if (response?.status === 200 || response?.status === 202) {
|
||||
const responseData = response.data as PaginatedApiResponse<any>;
|
||||
console.log('list_events_available responseData:', JSON.stringify(responseData, null, 2));
|
||||
return {
|
||||
data: responseData.data || [],
|
||||
pagination: {
|
||||
page: responseData.pagination?.page || 1,
|
||||
size: responseData.pagination?.size || 10,
|
||||
totalCount: responseData.pagination?.totalCount || 0,
|
||||
totalItems: responseData.pagination?.totalItems || 0,
|
||||
totalPages: responseData.pagination?.totalPages || 0,
|
||||
pageCount: responseData.pagination?.pageCount || 0,
|
||||
orderField: responseData.pagination?.orderField || ['name'],
|
||||
orderType: responseData.pagination?.orderType || ['asc'],
|
||||
query: responseData.pagination?.query || {},
|
||||
next: responseData.pagination?.next || false,
|
||||
back: responseData.pagination?.back || false
|
||||
}
|
||||
pagination: collectPaginationFromApiResponse(responseData)
|
||||
};
|
||||
}
|
||||
return {
|
||||
data: [],
|
||||
pagination: {
|
||||
page: 1,
|
||||
size: 10,
|
||||
totalCount: 0,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
pageCount: 0,
|
||||
orderField: ['name'],
|
||||
orderType: ['asc'],
|
||||
query: {},
|
||||
next: false,
|
||||
back: false
|
||||
}
|
||||
pagination: defaultPaginationResponse,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching events list:", error);
|
||||
// Return a default empty response instead of null to match the expected return type
|
||||
return {
|
||||
data: [],
|
||||
pagination: {
|
||||
page: 1,
|
||||
size: 10,
|
||||
totalCount: 0,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
pageCount: 0,
|
||||
orderField: ['name'],
|
||||
orderType: ['asc'],
|
||||
query: {},
|
||||
next: false,
|
||||
back: false
|
||||
}
|
||||
pagination: defaultPaginationResponse,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function list_events_appended(payload: PaginationParams): Promise<PaginatedApiResponse<any>> {
|
||||
|
||||
if (!payload.query.service_uu_id__ilike) {
|
||||
console.warn('Missing service_uu_id in query parameters for list_events_appended');
|
||||
return {
|
||||
data: [],
|
||||
pagination: defaultPaginationResponse,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const requestBody = {
|
||||
page: payload.page,
|
||||
size: payload.size,
|
||||
order_field: payload.orderField,
|
||||
order_type: payload.orderType,
|
||||
query: payload.query,
|
||||
};
|
||||
|
||||
console.log('Sending request to backend with service_uu_id:', payload.query.service_uu_id);
|
||||
console.log('Full request body:', JSON.stringify(requestBody, null, 2));
|
||||
|
||||
const response = await fetchDataWithToken(
|
||||
eventsListAppendedEndpoint,
|
||||
requestBody,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
|
||||
if (response?.status === 200 || response?.status === 202) {
|
||||
const responseData = response.data as PaginatedApiResponse<any>;
|
||||
console.log('list_events_appended responseData:', JSON.stringify(responseData, null, 2));
|
||||
return {
|
||||
data: responseData.data || [],
|
||||
pagination: collectPaginationFromApiResponse(responseData)
|
||||
};
|
||||
}
|
||||
return {
|
||||
data: [],
|
||||
pagination: defaultPaginationResponse,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching events list:", error);
|
||||
return {
|
||||
data: [],
|
||||
pagination: defaultPaginationResponse,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function appendEventToService(payload: AppendEventToService) {
|
||||
try {
|
||||
const response = await fetchDataWithToken(
|
||||
appendEventToServiceEndpoint,
|
||||
payload,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return response?.status === 200 || response?.status === 202 ? response.data : null;
|
||||
} catch (error) {
|
||||
console.error("Error appending event to service:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async function removeEventFromService(payload: RemoveEventFromService) {
|
||||
try {
|
||||
const response = await fetchDataWithToken(
|
||||
removeEventFromServiceEndpoint,
|
||||
payload,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return response?.status === 200 || response?.status === 202 ? response.data : null;
|
||||
} catch (error) {
|
||||
console.error("Error removing event from service:", error);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
listEvents,
|
||||
list_events_available,
|
||||
list_events_appended,
|
||||
appendEventToService,
|
||||
removeEventFromService,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
import { appendEventToService } from "@/apicalls/events/endpoints";
|
||||
import { NextRequest } from "next/server";
|
||||
import { withErrorHandling } from "@/app/api/utils/requestHandlers";
|
||||
import {
|
||||
successResponse,
|
||||
errorResponse,
|
||||
} from "@/app/api/utils/responseHandlers";
|
||||
|
||||
export const POST = withErrorHandling(
|
||||
async (request: NextRequest, body: any) => {
|
||||
const payload = {
|
||||
event_uu_id: body.event_uu_id,
|
||||
service_uu_id: body.service_uu_id,
|
||||
};
|
||||
const result = await appendEventToService(payload);
|
||||
if (!result) {
|
||||
return errorResponse("Error appending event to service");
|
||||
} else {
|
||||
return successResponse(result);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { removeEventFromService } from "@/apicalls/events/endpoints";
|
||||
import { NextRequest } from "next/server";
|
||||
import { withErrorHandling } from "@/app/api/utils/requestHandlers";
|
||||
import {
|
||||
successResponse,
|
||||
errorResponse,
|
||||
} from "@/app/api/utils/responseHandlers";
|
||||
|
||||
export const POST = withErrorHandling(
|
||||
async (request: NextRequest, body: any) => {
|
||||
const payload = {
|
||||
event_uu_id: body.event_uu_id,
|
||||
service_uu_id: body.service_uu_id,
|
||||
};
|
||||
const result = await removeEventFromService(payload);
|
||||
if (!result) {
|
||||
return errorResponse("Error removing event from service");
|
||||
} else {
|
||||
return successResponse(result);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { listEventsToService } from "@/apicalls/services/endpoints";
|
||||
import { createListHandler } from "@/app/api/utils";
|
||||
import { list_events_appended } from "@/apicalls/events/endpoints";
|
||||
import { createListHandler } from "@/app/api/utils/apiOperations";
|
||||
|
||||
export const POST = createListHandler(listEventsToService);
|
||||
export const POST = createListHandler(list_events_appended);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { listEvents } from "@/apicalls/events/endpoints";
|
||||
import { createListHandler } from "@/app/api/utils";
|
||||
import { list_events_available } from "@/apicalls/events/endpoints";
|
||||
import { createListHandler } from "@/app/api/utils/apiOperations";
|
||||
|
||||
export const POST = createListHandler(listEvents);
|
||||
export const POST = createListHandler(list_events_available);
|
||||
|
|
|
|||
|
|
@ -28,18 +28,11 @@ export async function handleListOperation(
|
|||
body: any,
|
||||
listFunction: ListFunction
|
||||
) {
|
||||
// Extract pagination parameters with defaults
|
||||
const page = body.page || 1;
|
||||
const size = body.size || 10;
|
||||
|
||||
// Extract sorting parameters with defaults
|
||||
const orderField = body.orderField || ["name"];
|
||||
const orderField = body.orderField || ["uu_id"];
|
||||
const orderType = body.orderType || ["asc"];
|
||||
|
||||
// Extract query filters
|
||||
const query = body.query || {};
|
||||
|
||||
// Call the actual API function for listing
|
||||
const response = await listFunction({
|
||||
page,
|
||||
size,
|
||||
|
|
@ -47,8 +40,6 @@ export async function handleListOperation(
|
|||
orderType,
|
||||
query,
|
||||
} as PaginationParams);
|
||||
|
||||
// Return the list response
|
||||
return paginationResponse(response.data, response.pagination);
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +55,6 @@ export async function handleCreateOperation(
|
|||
createFunction?: CreateFunction,
|
||||
requiredFields: string[] = []
|
||||
) {
|
||||
// Validate required fields if specified
|
||||
if (requiredFields.length > 0) {
|
||||
const validation = validateRequiredFields(body, requiredFields);
|
||||
if (!validation.valid) {
|
||||
|
|
@ -72,13 +62,11 @@ export async function handleCreateOperation(
|
|||
}
|
||||
}
|
||||
|
||||
// If a create function is provided, call it
|
||||
if (createFunction) {
|
||||
const result = await createFunction(body);
|
||||
return createResponse(result);
|
||||
}
|
||||
|
||||
// Otherwise return a mock response
|
||||
return createResponse({
|
||||
id: Math.floor(Math.random() * 1000),
|
||||
...body,
|
||||
|
|
@ -96,26 +84,15 @@ export async function handleUpdateOperation(
|
|||
body: any,
|
||||
updateFunction?: UpdateFunction
|
||||
) {
|
||||
// Skip validation as it's handled at the page level with Yup
|
||||
// and IDs are extracted from URL paths for update/delete operations
|
||||
|
||||
// Get UUID from query string. This is the value of the "uuid" query
|
||||
// string parameter, e.g. if the URL is "?uuid=SOMEUUID", this will
|
||||
// be "SOMEUUID".
|
||||
const uuid = request.nextUrl.searchParams.get("uuid");
|
||||
console.log("UUID:", uuid);
|
||||
|
||||
if (!uuid) {
|
||||
return errorResponse("UUID not found", 400);
|
||||
}
|
||||
|
||||
if (updateFunction) {
|
||||
console.log("Body:", body);
|
||||
const result = await updateFunction(body, uuid);
|
||||
return updateResponse(result);
|
||||
}
|
||||
|
||||
// Otherwise return a mock response
|
||||
return updateResponse(body);
|
||||
}
|
||||
|
||||
|
|
@ -128,14 +105,7 @@ export async function handleDeleteOperation(
|
|||
request: NextRequest,
|
||||
deleteFunction?: DeleteFunction
|
||||
) {
|
||||
// Skip ID validation as it's handled at the page level
|
||||
// and IDs are typically extracted from URL paths
|
||||
|
||||
// Get UUID from query string. This is the value of the "uuid" query
|
||||
// string parameter, e.g. if the URL is "?uuid=SOMEUUID", this will
|
||||
// be "SOMEUUID".
|
||||
const uuid = request.nextUrl.searchParams.get("uuid");
|
||||
|
||||
if (!uuid) {
|
||||
return errorResponse("UUID not found", 400);
|
||||
}
|
||||
|
|
@ -143,8 +113,6 @@ export async function handleDeleteOperation(
|
|||
if (deleteFunction) {
|
||||
await deleteFunction(uuid);
|
||||
}
|
||||
|
||||
// Return a success response
|
||||
return deleteResponse();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,20 @@ export interface PaginationResponse {
|
|||
back: boolean;
|
||||
}
|
||||
|
||||
export const defaultPaginationResponse: PaginationResponse = {
|
||||
page: 1,
|
||||
size: 10,
|
||||
totalCount: 0,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
pageCount: 0,
|
||||
orderField: ["uu_id"],
|
||||
orderType: ["asc"],
|
||||
query: {},
|
||||
next: false,
|
||||
back: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* API response interface
|
||||
*/
|
||||
|
|
@ -57,6 +71,24 @@ export interface PaginatedApiResponse<T> {
|
|||
pagination: PaginationResponse;
|
||||
}
|
||||
|
||||
export const collectPaginationFromApiResponse = (
|
||||
response: PaginatedApiResponse<any>
|
||||
): PaginationResponse => {
|
||||
return {
|
||||
page: response.pagination?.page || 1,
|
||||
size: response.pagination?.size || 10,
|
||||
totalCount: response.pagination?.totalCount || 0,
|
||||
totalItems: response.pagination?.totalItems || 0,
|
||||
totalPages: response.pagination?.totalPages || 0,
|
||||
pageCount: response.pagination?.pageCount || 0,
|
||||
orderField: response.pagination?.orderField || ["uu_id"],
|
||||
orderType: response.pagination?.orderType || ["asc"],
|
||||
query: response.pagination?.query || {},
|
||||
next: response.pagination?.next || false,
|
||||
back: response.pagination?.back || false,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* API handler function type
|
||||
*/
|
||||
|
|
@ -65,7 +97,9 @@ export type ApiHandler = (request: NextRequest, body: any) => Promise<Response>;
|
|||
/**
|
||||
* List function type
|
||||
*/
|
||||
export type ListFunction = (params: PaginationParams) => Promise<PaginatedApiResponse<any>>;
|
||||
export type ListFunction = (
|
||||
params: PaginationParams
|
||||
) => Promise<PaginatedApiResponse<any>>;
|
||||
|
||||
/**
|
||||
* Create function type
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export function CardDisplay<T>({
|
|||
showUpdateIcon = false,
|
||||
onViewClick,
|
||||
onUpdateClick,
|
||||
size = "lg",
|
||||
}: CardDisplayProps<T>) {
|
||||
if (error) {
|
||||
return (
|
||||
|
|
@ -44,7 +45,7 @@ export function CardDisplay<T>({
|
|||
/>
|
||||
))
|
||||
) : data.length === 0 ? (
|
||||
<div className="col-span-full text-center py-6">
|
||||
<div className="col-span-full text-center py-1">
|
||||
{translations[lang].noData || "No data found"}
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -64,6 +65,7 @@ export function CardDisplay<T>({
|
|||
onViewClick={onViewClick}
|
||||
onUpdateClick={onUpdateClick}
|
||||
getFieldValue={getFieldValue}
|
||||
size={size}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
"use client";
|
||||
import React from "react";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
} from "@/components/ui/card";
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Eye, Edit } from "lucide-react";
|
||||
import { CardItemProps, CardActionsProps, CardFieldProps } from "./schema";
|
||||
|
|
@ -23,17 +19,108 @@ export function CardItem<T>({
|
|||
onViewClick,
|
||||
onUpdateClick,
|
||||
getFieldValue,
|
||||
size = "lg",
|
||||
}: CardItemProps<T>) {
|
||||
|
||||
return (
|
||||
const getCardHeight = () => {
|
||||
switch (size) {
|
||||
case "xs": return "h-16 max-h-16";
|
||||
case "sm": return "h-20 max-h-20";
|
||||
case "md": return "h-24 max-h-24";
|
||||
case "lg":
|
||||
default: return "h-full";
|
||||
}
|
||||
};
|
||||
|
||||
const getCardStyle = () => {
|
||||
switch (size) {
|
||||
case "xs": return "!py-0 !gap-0 !flex !flex-col";
|
||||
case "sm": return "!py-1 !gap-1 !flex !flex-col";
|
||||
case "md": return "!py-2 !gap-2 !flex !flex-col";
|
||||
case "lg":
|
||||
default: return "";
|
||||
}
|
||||
};
|
||||
|
||||
const getTitleSize = () => {
|
||||
switch (size) {
|
||||
case "xs": return "text-xs";
|
||||
case "sm": return "text-sm";
|
||||
case "md": return "text-base";
|
||||
case "lg":
|
||||
default: return "text-lg";
|
||||
}
|
||||
};
|
||||
|
||||
const getContentPadding = () => {
|
||||
switch (size) {
|
||||
case "xs": return "p-1 py-1";
|
||||
case "sm": return "p-1 py-1";
|
||||
case "md": return "p-2 py-1";
|
||||
case "lg":
|
||||
default: return "p-3";
|
||||
}
|
||||
};
|
||||
|
||||
if (size === "xs" || size === "sm") {
|
||||
return (
|
||||
<div key={index} className="w-full p-1">
|
||||
<div
|
||||
className={`border rounded-lg shadow-sm ${getCardHeight()} ${onCardClick ? 'cursor-pointer hover:shadow-md transition-shadow' : ''} overflow-hidden flex flex-col bg-card text-card-foreground relative`}
|
||||
onClick={onCardClick ? () => onCardClick(item) : undefined}
|
||||
>
|
||||
{showViewIcon && (
|
||||
<button
|
||||
className="absolute top-1 right-1 h-5 w-5 inline-flex items-center justify-center rounded-full bg-white/80 hover:bg-white z-10"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (onViewClick) onViewClick(item);
|
||||
}}
|
||||
>
|
||||
<Eye className="h-3 w-3" />
|
||||
</button>
|
||||
)}
|
||||
{showUpdateIcon && (
|
||||
<button
|
||||
className="absolute top-1 right-7 h-5 w-5 inline-flex items-center justify-center rounded-full bg-white/80 hover:bg-white z-10"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (onUpdateClick) onUpdateClick(item);
|
||||
}}
|
||||
>
|
||||
<Edit className="h-3 w-3" />
|
||||
</button>
|
||||
)}
|
||||
<div className="px-2 pt-1 pb-1">
|
||||
<h3 className={`${getTitleSize()} font-semibold truncate pr-6`}>{getFieldValue(item, titleField)}</h3>
|
||||
<div className="flex flex-col justify-start mt-1">
|
||||
{showFields.map((field) => (
|
||||
<CardField
|
||||
key={`${index}-${field}`}
|
||||
item={item}
|
||||
field={field}
|
||||
lang={lang}
|
||||
translations={translations}
|
||||
renderCustomField={renderCustomField}
|
||||
getFieldValue={getFieldValue}
|
||||
size={size}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={index} className="w-full p-1">
|
||||
<Card
|
||||
className={`h-full ${onCardClick ? 'cursor-pointer hover:shadow-md transition-shadow' : ''}`}
|
||||
className={`${getCardHeight()} ${onCardClick ? 'cursor-pointer hover:shadow-md transition-shadow' : ''} overflow-hidden flex flex-col`}
|
||||
onClick={onCardClick ? () => onCardClick(item) : undefined}
|
||||
>
|
||||
<CardHeader className="p-3 pb-0 flex justify-between items-start">
|
||||
<h3 className="text-lg font-semibold">{getFieldValue(item, titleField)}</h3>
|
||||
<CardHeader className={`${getContentPadding()} pb-0 flex justify-between items-start`}>
|
||||
<h3 className={`${getTitleSize()} font-semibold`}>{getFieldValue(item, titleField)}</h3>
|
||||
<CardActions
|
||||
item={item}
|
||||
showViewIcon={showViewIcon}
|
||||
|
|
@ -42,7 +129,7 @@ export function CardItem<T>({
|
|||
onUpdateClick={onUpdateClick}
|
||||
/>
|
||||
</CardHeader>
|
||||
<CardContent className="p-3">
|
||||
<CardContent className={`${getContentPadding()} flex-1 overflow-hidden`}>
|
||||
<div className="space-y-2">
|
||||
{showFields.map((field) => (
|
||||
<CardField
|
||||
|
|
@ -53,6 +140,7 @@ export function CardItem<T>({
|
|||
translations={translations}
|
||||
renderCustomField={renderCustomField}
|
||||
getFieldValue={getFieldValue}
|
||||
size={size}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -62,8 +150,6 @@ export function CardItem<T>({
|
|||
);
|
||||
}
|
||||
|
||||
// Interface moved to schema.ts
|
||||
|
||||
function CardActions<T>({
|
||||
item,
|
||||
showViewIcon,
|
||||
|
|
@ -105,8 +191,6 @@ function CardActions<T>({
|
|||
);
|
||||
}
|
||||
|
||||
// Interface moved to schema.ts
|
||||
|
||||
function CardField<T>({
|
||||
item,
|
||||
field,
|
||||
|
|
@ -114,17 +198,48 @@ function CardField<T>({
|
|||
translations,
|
||||
renderCustomField,
|
||||
getFieldValue,
|
||||
size = "lg",
|
||||
}: CardFieldProps<T>) {
|
||||
const getTextSize = () => {
|
||||
switch (size) {
|
||||
case "xs": return "text-xs";
|
||||
case "sm": return "text-xs";
|
||||
case "md": return "text-sm";
|
||||
case "lg":
|
||||
default: return "text-base";
|
||||
}
|
||||
};
|
||||
|
||||
const getLabelWidth = () => {
|
||||
switch (size) {
|
||||
case "xs": return "w-16";
|
||||
case "sm": return "w-20";
|
||||
case "md": return "w-24";
|
||||
case "lg":
|
||||
default: return "w-32";
|
||||
}
|
||||
};
|
||||
|
||||
if (renderCustomField) {
|
||||
return renderCustomField(item, field);
|
||||
}
|
||||
|
||||
const label = translations?.[field]?.[lang] || field;
|
||||
const value = getFieldValue(item, field);
|
||||
|
||||
if (size === "xs" || size === "sm") {
|
||||
return (
|
||||
<div className={`flex items-center ${getTextSize()} py-0 my-0 leading-tight`}>
|
||||
<span className={`${getLabelWidth()} font-medium truncate mr-1`}>{label}:</span>
|
||||
<span className="truncate max-w-[60%]">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex">
|
||||
<span className="font-medium mr-2 min-w-[80px]">
|
||||
{translations[field]?.[lang] || field}:
|
||||
</span>
|
||||
<span className="flex-1">
|
||||
{renderCustomField
|
||||
? renderCustomField(item, field)
|
||||
: getFieldValue(item, field)}
|
||||
</span>
|
||||
<div className={`flex items-center ${getTextSize()}`}>
|
||||
<span className={`${getLabelWidth()} font-medium truncate`}>{label}:</span>
|
||||
<span className="truncate">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { GridSize } from "../HeaderSelections/GridSelectionComponent";
|
||||
|
||||
export type CardSize = "xs" | "sm" | "md" | "lg";
|
||||
|
||||
export interface CardDisplayProps<T> {
|
||||
showFields: string[];
|
||||
data: T[];
|
||||
|
|
@ -15,6 +17,7 @@ export interface CardDisplayProps<T> {
|
|||
showUpdateIcon?: boolean;
|
||||
onViewClick?: (item: T) => void;
|
||||
onUpdateClick?: (item: T) => void;
|
||||
size?: CardSize;
|
||||
}
|
||||
|
||||
export interface CardItemProps<T> {
|
||||
|
|
@ -31,6 +34,7 @@ export interface CardItemProps<T> {
|
|||
onViewClick?: (item: T) => void;
|
||||
onUpdateClick?: (item: T) => void;
|
||||
getFieldValue: (item: any, field: string) => any;
|
||||
size?: CardSize;
|
||||
}
|
||||
|
||||
export interface CardActionsProps<T> {
|
||||
|
|
@ -47,6 +51,7 @@ export interface CardFieldProps<T> {
|
|||
translations: Record<string, any>;
|
||||
renderCustomField?: (item: T, field: string) => React.ReactNode;
|
||||
getFieldValue: (item: any, field: string) => any;
|
||||
size?: CardSize;
|
||||
}
|
||||
|
||||
export interface CardSkeletonProps {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export interface ViewComponentProps<T> extends BaseFormProps<T> {
|
|||
export interface FormDisplayProps<T> {
|
||||
mode: FormMode | FormModeView;
|
||||
initialData?: T;
|
||||
refetch?: () => void;
|
||||
refetch?: (additionalParams?: Record<string, any>) => void;
|
||||
setMode: React.Dispatch<React.SetStateAction<FormModeView | FormMode>>;
|
||||
setSelectedItem: React.Dispatch<React.SetStateAction<T | null>>;
|
||||
onCancel: () => void;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ export function useApiData<T>(
|
|||
} catch (error) {
|
||||
console.error("Error fetching data from API:", error);
|
||||
|
||||
// Return empty data with pagination info on error
|
||||
return {
|
||||
data: [],
|
||||
pagination: {
|
||||
|
|
@ -60,6 +59,5 @@ export function useApiData<T>(
|
|||
}
|
||||
};
|
||||
|
||||
// Use the generic data fetching hook with our API-specific fetch function
|
||||
return useDataFetching<T>(fetchFromApi, initialParams);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export function useDataFetching<T>(
|
|||
const [requestParams, setRequestParams] = useState<RequestParams>({
|
||||
page: initialParams.page || 1,
|
||||
size: initialParams.size || 10,
|
||||
orderField: initialParams.orderField || ["name"],
|
||||
orderField: initialParams.orderField || ["uu_id"],
|
||||
orderType: initialParams.orderType || ["asc"],
|
||||
query: initialParams.query || {},
|
||||
});
|
||||
|
|
@ -85,14 +85,10 @@ export function useDataFetching<T>(
|
|||
requestParams.query,
|
||||
]);
|
||||
|
||||
// Track if this is the initial mount
|
||||
const initialMountRef = useRef(true);
|
||||
|
||||
// Track previous request params to avoid unnecessary fetches
|
||||
const prevRequestParamsRef = useRef<RequestParams>(requestParams);
|
||||
|
||||
useEffect(() => {
|
||||
// Only fetch on mount or when request params actually change
|
||||
const paramsChanged =
|
||||
JSON.stringify(prevRequestParamsRef.current) !==
|
||||
JSON.stringify(requestParams);
|
||||
|
|
@ -102,19 +98,17 @@ export function useDataFetching<T>(
|
|||
fetchDataFromApi();
|
||||
initialMountRef.current = false;
|
||||
prevRequestParamsRef.current = { ...requestParams };
|
||||
}, 300); // Debounce
|
||||
}, 300);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [fetchDataFromApi, requestParams]);
|
||||
|
||||
const updatePagination = useCallback((updates: Partial<RequestParams>) => {
|
||||
// Transform query parameters to use __ilike with %value% format
|
||||
if (updates.query) {
|
||||
const transformedQuery: Record<string, any> = {};
|
||||
|
||||
Object.entries(updates.query).forEach(([key, value]) => {
|
||||
// Only transform string values that aren't already using a special operator
|
||||
if (
|
||||
typeof value === "string" &&
|
||||
!key.includes("__") &&
|
||||
|
|
@ -127,13 +121,9 @@ export function useDataFetching<T>(
|
|||
});
|
||||
|
||||
updates.query = transformedQuery;
|
||||
|
||||
// Always reset to page 1 when search query changes
|
||||
if (!updates.hasOwnProperty("page")) {
|
||||
updates.page = 1;
|
||||
}
|
||||
|
||||
// Reset response metadata when search changes to avoid stale pagination data
|
||||
setResponseMetadata({
|
||||
totalCount: 0,
|
||||
totalItems: 0,
|
||||
|
|
@ -153,7 +143,6 @@ export function useDataFetching<T>(
|
|||
|
||||
// Create a combined refetch function
|
||||
const refetch = useCallback(() => {
|
||||
// Reset pagination to page 1 when manually refetching
|
||||
setRequestParams((prev) => ({
|
||||
...prev,
|
||||
page: 1,
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import { Card, CardContent } from '@/components/ui/card';
|
|||
import { TextQueryModifier } from '@/components/common/QueryModifiers/TextQueryModifier';
|
||||
import { PaginationToolsComponent } from '@/components/common/PaginationModifiers/PaginationToolsComponent';
|
||||
import { CardDisplay } from '@/components/common/CardDisplay/CardDisplay';
|
||||
import { ListComponentApplicationProps, ListComponentServiceProps } from './type';
|
||||
import { ListComponentEventsProps, ListComponentServicesProps } from './type';
|
||||
|
||||
const ListComponentServices: React.FC<ListComponentServiceProps> = ({
|
||||
const ListComponentServices: React.FC<ListComponentServicesProps> = ({
|
||||
lang,
|
||||
loading,
|
||||
error,
|
||||
|
|
@ -17,6 +17,7 @@ const ListComponentServices: React.FC<ListComponentServiceProps> = ({
|
|||
showFields,
|
||||
gridCols,
|
||||
titleField,
|
||||
size,
|
||||
handleQueryChange,
|
||||
updatePagination,
|
||||
handleCardClick,
|
||||
|
|
@ -75,6 +76,7 @@ const ListComponentServices: React.FC<ListComponentServiceProps> = ({
|
|||
titleField={titleField}
|
||||
onCardClick={handleCardClick}
|
||||
gridCols={gridCols}
|
||||
size={size}
|
||||
showViewIcon={true}
|
||||
onViewClick={handleViewClick}
|
||||
/>
|
||||
|
|
@ -83,7 +85,7 @@ const ListComponentServices: React.FC<ListComponentServiceProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
const ListComponentEvents: React.FC<ListComponentApplicationProps> = ({
|
||||
const ListComponentEvents: React.FC<ListComponentEventsProps> = ({
|
||||
lang,
|
||||
loading,
|
||||
error,
|
||||
|
|
@ -91,6 +93,7 @@ const ListComponentEvents: React.FC<ListComponentApplicationProps> = ({
|
|||
pagination,
|
||||
showFields,
|
||||
gridCols,
|
||||
size,
|
||||
handleQueryChange,
|
||||
updatePagination,
|
||||
handleCardClick,
|
||||
|
|
@ -151,6 +154,57 @@ const ListComponentEvents: React.FC<ListComponentApplicationProps> = ({
|
|||
gridCols={gridCols}
|
||||
showViewIcon={true}
|
||||
onViewClick={handleViewClick}
|
||||
size={size}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ListComponentAppenders: React.FC<ListComponentEventsProps> = ({
|
||||
lang,
|
||||
loading,
|
||||
error,
|
||||
data,
|
||||
pagination,
|
||||
showFields,
|
||||
gridCols,
|
||||
size,
|
||||
handleQueryChange,
|
||||
updatePagination,
|
||||
handleCardClick,
|
||||
handleViewClick,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{/* Pagination Tools Component */}
|
||||
<Card className="my-4">
|
||||
<CardContent className="pt-6">
|
||||
<PaginationToolsComponent
|
||||
pagination={pagination}
|
||||
updatePagination={updatePagination}
|
||||
loading={loading}
|
||||
lang={lang}
|
||||
translations={translations}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Card Display Component */}
|
||||
<div className="mt-6">
|
||||
<CardDisplay
|
||||
showFields={showFields}
|
||||
data={data}
|
||||
lang={lang}
|
||||
translations={translations}
|
||||
error={error}
|
||||
loading={loading}
|
||||
titleField="name"
|
||||
onCardClick={handleCardClick}
|
||||
gridCols={gridCols}
|
||||
showViewIcon={true}
|
||||
onViewClick={handleViewClick}
|
||||
size={size}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
@ -160,4 +214,5 @@ const ListComponentEvents: React.FC<ListComponentApplicationProps> = ({
|
|||
export {
|
||||
ListComponentEvents,
|
||||
ListComponentServices,
|
||||
ListComponentAppenders,
|
||||
};
|
||||
|
|
@ -7,9 +7,15 @@ import {
|
|||
serviceViewFieldDefinitions,
|
||||
ServiceFieldDefinitionsType,
|
||||
ServiceSchema,
|
||||
serviceFieldsByMode,
|
||||
} from "./schemaList/services";
|
||||
import * as schema from "./schemaList/schema";
|
||||
|
||||
import {
|
||||
EventData,
|
||||
eventFlatFieldDefinitions,
|
||||
EventFieldDefinitionsType,
|
||||
EventSchema,
|
||||
eventFieldsByMode
|
||||
} from "./schemaList/events";
|
||||
import { ListComponentEvents, ListComponentServices } from "./listComponent";
|
||||
import { translations, translationsServices, translationsAppenders, translationsEvents } from "./language";
|
||||
|
||||
|
|
@ -21,6 +27,7 @@ import { useApiData } from "@/components/common";
|
|||
import { Language } from "@/components/common/schemas";
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { CardSize } from "@/components/common/CardDisplay/schema";
|
||||
|
||||
const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language }) => {
|
||||
|
||||
|
|
@ -39,7 +46,7 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
error: errorEvents,
|
||||
updatePagination: updatePaginationEvents,
|
||||
refetch: refetchEvents
|
||||
} = useApiData<schema.ApplicationData>('/api/events');
|
||||
} = useApiData<EventData>('/api/events');
|
||||
const {
|
||||
data: dataAppenders,
|
||||
pagination: paginationAppenders,
|
||||
|
|
@ -47,18 +54,18 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
error: errorAppenders,
|
||||
updatePagination: updatePaginationAppenders,
|
||||
refetch: refetchAppenders
|
||||
} = useApiData<schema.ApplicationData>('/api/appenders');
|
||||
} = useApiData<EventData>('/api/appenders');
|
||||
|
||||
const [mode, setMode] = useState<FormModeView | FormMode>("list");
|
||||
const [gridCols, setGridCols] = useState<GridSize>(3);
|
||||
|
||||
const [selectedItemServices, setSelectedItemServices] = useState<ServiceData | null>(null);
|
||||
const [selectedItemEvents, setSelectedItemEvents] = useState<schema.ApplicationData | null>(null);
|
||||
const [selectedItemAppenders, setSelectedItemAppenders] = useState<schema.ApplicationData | null>(null);
|
||||
const [selectedItemEvents, setSelectedItemEvents] = useState<EventData | null>(null);
|
||||
const [selectedItemAppenders, setSelectedItemAppenders] = useState<EventData | null>(null);
|
||||
|
||||
const [fieldDefinitionsServices, setFieldDefinitionsServices] = useState<ServiceFieldDefinitionsType | null>(null);
|
||||
const [fieldDefinitionsEvents, setFieldDefinitionsEvents] = useState<schema.FieldDefinitionsType | null>(null);
|
||||
const [fieldDefinitionsAppenders, setFieldDefinitionsAppenders] = useState<schema.FieldDefinitionsType | null>(null);
|
||||
const [fieldDefinitionsEvents, setFieldDefinitionsEvents] = useState<EventFieldDefinitionsType | null>(null);
|
||||
const [fieldDefinitionsAppenders, setFieldDefinitionsAppenders] = useState<EventFieldDefinitionsType | null>(null);
|
||||
|
||||
const [validationSchemaServices, setValidationSchemaServices] = useState<z.ZodSchema | null>(null);
|
||||
const [validationSchemaEvents, setValidationSchemaEvents] = useState<z.ZodSchema | null>(null);
|
||||
|
|
@ -69,23 +76,127 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
|
||||
useEffect(() => {
|
||||
setFieldDefinitionsServices(serviceViewFieldDefinitions); setValidationSchemaServices(ServiceSchema);
|
||||
setFieldDefinitionsEvents(schema.viewFieldDefinitions); setValidationSchemaEvents(schema.ViewApplicationSchema);
|
||||
setFieldDefinitionsAppenders(schema.viewFieldDefinitions); setValidationSchemaAppenders(schema.ViewApplicationSchema);
|
||||
setFieldDefinitionsEvents(eventFlatFieldDefinitions); setValidationSchemaEvents(EventSchema);
|
||||
setFieldDefinitionsAppenders(eventFlatFieldDefinitions); setValidationSchemaAppenders(EventSchema);
|
||||
}, [lang]);
|
||||
|
||||
const handleQueryChange = (key: string, value: string | null) => {
|
||||
useEffect(() => {
|
||||
if (selectedItemServices && selectedItemServices?.uu_id) {
|
||||
updatePaginationAppenders({
|
||||
page: paginationAppenders.page,
|
||||
size: paginationAppenders.size,
|
||||
orderField: paginationAppenders.orderField,
|
||||
orderType: paginationAppenders.orderType,
|
||||
query: {
|
||||
...paginationAppenders.query,
|
||||
service_uu_id: selectedItemServices.uu_id
|
||||
}
|
||||
});
|
||||
|
||||
updatePaginationEvents({
|
||||
page: paginationEvents.page,
|
||||
size: paginationEvents.size,
|
||||
orderField: paginationEvents.orderField,
|
||||
orderType: paginationEvents.orderType,
|
||||
query: {
|
||||
...paginationEvents.query,
|
||||
service_uu_id: selectedItemServices.uu_id
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [selectedItemServices]);
|
||||
|
||||
const handleQueryChangeServices = (key: string, value: string | null) => {
|
||||
const newQuery = { ...paginationServices.query };
|
||||
if (value === null) { delete newQuery[key] } else if (value.trim() === "") { delete newQuery[key] } else { newQuery[key] = value }
|
||||
updatePaginationServices({ page: 1, query: newQuery })
|
||||
};
|
||||
|
||||
const handleQueryChangeEvents = (key: string, value: string | null) => {
|
||||
const newQuery = { ...paginationEvents.query };
|
||||
if (value === null) { delete newQuery[key] } else if (value.trim() === "") { delete newQuery[key] } else { newQuery[key] = value }
|
||||
|
||||
if (selectedItemServices?.uu_id) {
|
||||
newQuery.service_uu_id = selectedItemServices.uu_id;
|
||||
}
|
||||
updatePaginationEvents({ page: 1, query: newQuery });
|
||||
};
|
||||
|
||||
const handleQueryChangeAppenders = (key: string, value: string | null) => {
|
||||
const newQuery = { ...paginationAppenders.query };
|
||||
if (value === null) { delete newQuery[key] } else if (value.trim() === "") { delete newQuery[key] } else { newQuery[key] = value }
|
||||
if (selectedItemServices?.uu_id) {
|
||||
newQuery.service_uu_id = selectedItemServices.uu_id;
|
||||
}
|
||||
updatePaginationAppenders({ page: 1, query: newQuery });
|
||||
};
|
||||
|
||||
const appendServiceEvent = async (event: EventData) => {
|
||||
if (!selectedItemServices?.uu_id) {
|
||||
throw new Error("Service not selected");
|
||||
}
|
||||
const payload = { event_uu_id: event.uu_id, service_uu_id: selectedItemServices.uu_id }
|
||||
fetch('/api/appenders/create', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
}).then((res) => {
|
||||
if (res.ok) {
|
||||
updatePaginationAppenders({
|
||||
...paginationAppenders,
|
||||
query: {
|
||||
...paginationAppenders.query,
|
||||
service_uu_id: selectedItemServices.uu_id
|
||||
}
|
||||
});
|
||||
updatePaginationEvents({
|
||||
...paginationEvents,
|
||||
query: {
|
||||
...paginationEvents.query,
|
||||
service_uu_id: selectedItemServices.uu_id
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const removeServiceEvent = async (event: EventData) => {
|
||||
if (!selectedItemServices?.uu_id) {
|
||||
throw new Error("Service not selected");
|
||||
}
|
||||
const payload = { event_uu_id: event.uu_id, service_uu_id: selectedItemServices.uu_id }
|
||||
fetch('/api/appenders/delete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
}).then((res) => {
|
||||
if (res.ok) {
|
||||
updatePaginationAppenders({
|
||||
...paginationAppenders,
|
||||
query: {
|
||||
...paginationAppenders.query,
|
||||
service_uu_id: selectedItemServices.uu_id
|
||||
}
|
||||
});
|
||||
updatePaginationEvents({
|
||||
...paginationEvents,
|
||||
query: {
|
||||
...paginationEvents.query,
|
||||
service_uu_id: selectedItemServices.uu_id
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleServicesCardClick = (item: ServiceData) => { setSelectedItemServices(item); setMode("list"); };
|
||||
const handleServicesViewClick = (item: ServiceData) => { setSelectedItemServices(item); setMode("view"); };
|
||||
|
||||
const handleEventsCardClick = (item: schema.ApplicationData) => { console.log("Events Card clicked:", item) };
|
||||
const handleEventsViewClick = (item: schema.ApplicationData) => { setSelectedItemEvents(item); setMode("view"); };
|
||||
const handleEventsCardClick = (item: EventData) => { appendServiceEvent(item); };
|
||||
const handleEventsViewClick = (item: EventData) => { setSelectedItemEvents(item); setMode("view"); };
|
||||
|
||||
const handleAppendersCardClick = (item: schema.ApplicationData) => { console.log("Appenders Card clicked:", item) };
|
||||
const handleAppendersViewClick = (item: schema.ApplicationData) => { setSelectedItemAppenders(item); setMode("view"); };
|
||||
const handleAppendersCardClick = (item: EventData) => { removeServiceEvent(item); };
|
||||
const handleAppendersViewClick = (item: EventData) => { setSelectedItemAppenders(item); setMode("view"); };
|
||||
|
||||
const cancelAllSelections = () => {
|
||||
setMode("list");
|
||||
|
|
@ -103,7 +214,8 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
showFields: showFieldsServices,
|
||||
gridCols: gridCols,
|
||||
titleField: "service_name",
|
||||
handleQueryChange: handleQueryChange,
|
||||
size: "lg" as CardSize,
|
||||
handleQueryChange: handleQueryChangeServices,
|
||||
updatePagination: updatePaginationServices,
|
||||
handleCardClick: handleServicesCardClick,
|
||||
handleViewClick: handleServicesViewClick
|
||||
|
|
@ -118,7 +230,8 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
showFields: showFieldsEvents,
|
||||
gridCols: 1,
|
||||
titleField: "description",
|
||||
handleQueryChange: handleQueryChange,
|
||||
size: "sm" as CardSize,
|
||||
handleQueryChange: handleQueryChangeEvents,
|
||||
updatePagination: updatePaginationEvents,
|
||||
handleCardClick: handleEventsCardClick,
|
||||
handleViewClick: handleEventsViewClick
|
||||
|
|
@ -133,7 +246,8 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
showFields: showFieldsEvents,
|
||||
gridCols: 1,
|
||||
titleField: "description",
|
||||
handleQueryChange: handleQueryChange,
|
||||
size: "sm" as CardSize,
|
||||
handleQueryChange: handleQueryChangeAppenders,
|
||||
updatePagination: updatePaginationAppenders,
|
||||
handleCardClick: handleAppendersCardClick,
|
||||
handleViewClick: handleAppendersViewClick
|
||||
|
|
@ -152,7 +266,7 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
formProps: {
|
||||
fieldDefinitions: fieldDefinitionsServices,
|
||||
validationSchema: validationSchemaServices,
|
||||
fieldsByMode: schema.fieldsByMode
|
||||
fieldsByMode: serviceFieldsByMode
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -169,14 +283,10 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
formProps: {
|
||||
fieldDefinitions: fieldDefinitionsEvents,
|
||||
validationSchema: validationSchemaEvents,
|
||||
fieldsByMode: schema.fieldsByMode
|
||||
fieldsByMode: eventFieldsByMode,
|
||||
}
|
||||
};
|
||||
|
||||
const removeAppendersFromEvents = (events: schema.ApplicationData[], appenders: schema.ApplicationData[]) => {
|
||||
|
||||
}
|
||||
|
||||
const appendersFormProps = {
|
||||
initialData: selectedItemAppenders || undefined,
|
||||
mode: mode,
|
||||
|
|
@ -190,7 +300,7 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
formProps: {
|
||||
fieldDefinitions: fieldDefinitionsAppenders,
|
||||
validationSchema: validationSchemaAppenders,
|
||||
fieldsByMode: schema.fieldsByMode
|
||||
fieldsByMode: eventFieldsByMode,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -202,25 +312,26 @@ const AppendersServicePage: React.FC<PageProps> = ({ lang }: { lang: Language })
|
|||
</div>
|
||||
{mode === "list" ? (
|
||||
<div className="flex flex-col space-y-4">
|
||||
{!selectedItemServices ? <div className="w-full h-1/2"><ListComponentServices {...serviceListProps} /></div> :
|
||||
<div className="w-full h-1/2">
|
||||
<Button onClick={cancelAllSelections}>{translations[lang].cancel}</Button>
|
||||
<Card className="my-5">
|
||||
<CardHeader>{translations[lang].serviceSelectedTitle}</CardHeader>
|
||||
<CardContent>{selectedItemServices?.service_name}{" "}{translations[lang].serviceSelectedContent}</CardContent>
|
||||
</Card>
|
||||
<div className="flex flex-row space-x-4">
|
||||
<div className="flex-1"><ListComponentEvents {...eventsListProps} /></div>
|
||||
<div className="flex-1"><ListComponentEvents {...appendersListProps} /></div>
|
||||
{
|
||||
!selectedItemServices ? <div className="w-full h-1/2"><ListComponentServices {...serviceListProps} /></div> :
|
||||
<div className="w-full h-1/2">
|
||||
<Button onClick={cancelAllSelections}>{translations[lang].cancel}</Button>
|
||||
<Card className="my-5">
|
||||
<CardHeader>{translations[lang].serviceSelectedTitle}</CardHeader>
|
||||
<CardContent>{selectedItemServices.uu_id}{" "}{selectedItemServices?.service_name}{" "}{translations[lang].serviceSelectedContent}</CardContent>
|
||||
</Card>
|
||||
<div className="flex flex-row space-x-4">
|
||||
<div className="flex-1"><ListComponentEvents {...eventsListProps} /></div>
|
||||
<div className="flex-1"><ListComponentEvents {...appendersListProps} /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col space-y-4">
|
||||
{selectedItemServices && <FormDisplay<ServiceData> {...serviceFormProps} />}
|
||||
{selectedItemEvents && <FormDisplay<schema.ApplicationData> {...eventsFormProps} />}
|
||||
{selectedItemAppenders && <FormDisplay<schema.ApplicationData> {...appendersFormProps} />}
|
||||
{selectedItemEvents && <FormDisplay<EventData> {...eventsFormProps} />}
|
||||
{selectedItemAppenders && <FormDisplay<EventData> {...appendersFormProps} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -161,6 +161,9 @@ const appenderFlatFieldDefinitions = flattenFieldDefinitions(
|
|||
serviceBaseFieldDefinitions
|
||||
);
|
||||
type AppenderFieldDefinitionsType = typeof appenderFlatFieldDefinitions;
|
||||
const appenderFieldsByMode = {
|
||||
view: Object.keys(serviceBaseFieldDefinitions),
|
||||
};
|
||||
|
||||
export type { AppendersData, AppenderFieldDefinitionsType };
|
||||
export {
|
||||
|
|
@ -168,4 +171,5 @@ export {
|
|||
appenderFlatFieldDefinitions,
|
||||
AppenderBaseTranslationEn,
|
||||
AppenderBaseTranslationTr,
|
||||
appenderFieldsByMode,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,270 @@
|
|||
import { z } from "zod";
|
||||
import { flattenFieldDefinitions } from "@/eventRouters/schemas/zodSchemas";
|
||||
|
||||
interface EventData {
|
||||
uu_id: string;
|
||||
function_code: string;
|
||||
function_class: string;
|
||||
description?: string;
|
||||
property_description?: string;
|
||||
marketing_layer?: string;
|
||||
cost?: number;
|
||||
unit_price?: number;
|
||||
endpoint_code: string;
|
||||
endpoint_uu_id: string;
|
||||
is_confirmed: boolean;
|
||||
active: boolean;
|
||||
deleted?: boolean;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
const errorMessages = {
|
||||
en: {
|
||||
function_code: "Function code is required",
|
||||
function_class: "Function class is required",
|
||||
endpoint_code: "Endpoint code is required",
|
||||
endpoint_uu_id: "Endpoint UUID is required",
|
||||
},
|
||||
tr: {
|
||||
function_code: "Fonksiyon kodu gereklidir",
|
||||
function_class: "Fonksiyon sınıfı gereklidir",
|
||||
endpoint_code: "Endpoint kodu gereklidir",
|
||||
endpoint_uu_id: "Endpoint UUID gereklidir",
|
||||
},
|
||||
};
|
||||
|
||||
const getEventBaseSchema = (lang: "en" | "tr" = "en") =>
|
||||
z.object({
|
||||
uu_id: z.string().optional(),
|
||||
function_code: z.string().min(1, errorMessages[lang].function_code),
|
||||
function_class: z.string().min(1, errorMessages[lang].function_class),
|
||||
description: z.string().optional(),
|
||||
property_description: z.string().optional(),
|
||||
marketing_layer: z.string().optional(),
|
||||
cost: z.number().optional(),
|
||||
unit_price: z.number().optional(),
|
||||
endpoint_code: z.string().min(1, errorMessages[lang].endpoint_code),
|
||||
endpoint_uu_id: z.string().min(1, errorMessages[lang].endpoint_uu_id),
|
||||
is_confirmed: z.boolean().default(false),
|
||||
active: z.boolean().default(true),
|
||||
deleted: z.boolean().default(false),
|
||||
created_at: z.string().optional(),
|
||||
updated_at: z.string().optional(),
|
||||
});
|
||||
|
||||
const EventBaseSchema = getEventBaseSchema("en");
|
||||
|
||||
const EventBaseTranslationTr = {
|
||||
uu_id: "UUID",
|
||||
function_code: "Fonksiyon kodu",
|
||||
function_class: "Fonksiyon sınıfı",
|
||||
description: "Açıklama",
|
||||
property_description: "Özellik açıklama",
|
||||
marketing_layer: "Pazarlama katmanı",
|
||||
cost: "Maliyet",
|
||||
unit_price: "Birim fiyatı",
|
||||
endpoint_code: "Endpoint kodu",
|
||||
endpoint_uu_id: "Endpoint UUID",
|
||||
is_confirmed: "Onaylandı",
|
||||
active: "Active",
|
||||
deleted: "Deleted",
|
||||
created_at: "Created At",
|
||||
updated_at: "Updated At",
|
||||
};
|
||||
|
||||
const EventBaseTranslationEn = {
|
||||
uu_id: "UUID",
|
||||
function_code: "Function code",
|
||||
function_class: "Function class",
|
||||
description: "Description",
|
||||
property_description: "Property description",
|
||||
marketing_layer: "Marketing layer",
|
||||
cost: "Cost",
|
||||
unit_price: "Unit price",
|
||||
endpoint_code: "Endpoint code",
|
||||
endpoint_uu_id: "Endpoint UUID",
|
||||
is_confirmed: "Confirmed",
|
||||
active: "Active",
|
||||
deleted: "Deleted",
|
||||
created_at: "Created At",
|
||||
updated_at: "Updated At",
|
||||
};
|
||||
|
||||
const eventBaseFieldDefinitions = {
|
||||
identificationInfo: {
|
||||
title: "Event Information",
|
||||
order: 1,
|
||||
fields: {
|
||||
uu_id: {
|
||||
type: "text",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.uu_id,
|
||||
en: EventBaseTranslationEn.uu_id,
|
||||
},
|
||||
readOnly: true,
|
||||
required: false,
|
||||
},
|
||||
function_code: {
|
||||
type: "text",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.function_code,
|
||||
en: EventBaseTranslationEn.function_code,
|
||||
},
|
||||
readOnly: false,
|
||||
required: true,
|
||||
},
|
||||
function_class: {
|
||||
type: "text",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.function_class,
|
||||
en: EventBaseTranslationEn.function_class,
|
||||
},
|
||||
readOnly: false,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: "text",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.description,
|
||||
en: EventBaseTranslationEn.description,
|
||||
},
|
||||
readOnly: false,
|
||||
required: false,
|
||||
},
|
||||
property_description: {
|
||||
type: "text",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.property_description,
|
||||
en: EventBaseTranslationEn.property_description,
|
||||
},
|
||||
readOnly: false,
|
||||
required: false,
|
||||
},
|
||||
marketing_layer: {
|
||||
type: "text",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.marketing_layer,
|
||||
en: EventBaseTranslationEn.marketing_layer,
|
||||
},
|
||||
readOnly: false,
|
||||
required: false,
|
||||
},
|
||||
cost: {
|
||||
type: "number",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.cost,
|
||||
en: EventBaseTranslationEn.cost,
|
||||
},
|
||||
readOnly: false,
|
||||
required: false,
|
||||
},
|
||||
unit_price: {
|
||||
type: "number",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.unit_price,
|
||||
en: EventBaseTranslationEn.unit_price,
|
||||
},
|
||||
readOnly: false,
|
||||
required: false,
|
||||
},
|
||||
endpoint_code: {
|
||||
type: "text",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.endpoint_code,
|
||||
en: EventBaseTranslationEn.endpoint_code,
|
||||
},
|
||||
readOnly: false,
|
||||
required: true,
|
||||
},
|
||||
endpoint_uu_id: {
|
||||
type: "text",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.endpoint_uu_id,
|
||||
en: EventBaseTranslationEn.endpoint_uu_id,
|
||||
},
|
||||
readOnly: false,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
statusInfo: {
|
||||
title: "Status Information",
|
||||
order: 3,
|
||||
fields: {
|
||||
active: {
|
||||
type: "checkbox",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.active,
|
||||
en: EventBaseTranslationEn.active,
|
||||
},
|
||||
readOnly: false,
|
||||
required: false,
|
||||
defaultValue: true,
|
||||
},
|
||||
deleted: {
|
||||
type: "checkbox",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.deleted,
|
||||
en: EventBaseTranslationEn.deleted,
|
||||
},
|
||||
readOnly: true,
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
},
|
||||
is_confirmed: {
|
||||
type: "checkbox",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.is_confirmed,
|
||||
en: EventBaseTranslationEn.is_confirmed,
|
||||
},
|
||||
readOnly: false,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
systemInfo: {
|
||||
title: "System Information",
|
||||
order: 4,
|
||||
fields: {
|
||||
created_at: {
|
||||
type: "date",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.created_at,
|
||||
en: EventBaseTranslationEn.created_at,
|
||||
},
|
||||
readOnly: true,
|
||||
required: false,
|
||||
},
|
||||
updated_at: {
|
||||
type: "date",
|
||||
label: {
|
||||
tr: EventBaseTranslationTr.updated_at,
|
||||
en: EventBaseTranslationEn.updated_at,
|
||||
},
|
||||
readOnly: true,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const ViewEventSchema = EventBaseSchema;
|
||||
const EventSchema = EventBaseSchema;
|
||||
const eventFlatFieldDefinitions = flattenFieldDefinitions(
|
||||
eventBaseFieldDefinitions
|
||||
);
|
||||
type EventFieldDefinitionsType = typeof eventFlatFieldDefinitions;
|
||||
const eventFieldsByMode = {
|
||||
view: Object.keys(eventBaseFieldDefinitions),
|
||||
};
|
||||
|
||||
export type { EventData, EventFieldDefinitionsType };
|
||||
export {
|
||||
EventSchema,
|
||||
eventFlatFieldDefinitions,
|
||||
EventBaseTranslationEn,
|
||||
EventBaseTranslationTr,
|
||||
eventFieldsByMode,
|
||||
};
|
||||
|
|
@ -291,4 +291,5 @@ export {
|
|||
serviceViewFieldDefinitions,
|
||||
ServiceBaseTranslationEn,
|
||||
ServiceBaseTranslationTr,
|
||||
serviceFieldsByMode,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,24 +1,10 @@
|
|||
import { Language } from "@/components/common/schemas";
|
||||
import { GridSize } from "@/components/common/HeaderSelections/GridSelectionComponent";
|
||||
import * as schema from "./schemaList/schema";
|
||||
import { CardSize } from "@/components/common/CardDisplay/schema";
|
||||
import * as schemaServices from "./schemaList/services";
|
||||
import * as schemaEvents from "./schemaList/events";
|
||||
|
||||
export interface ListComponentApplicationProps {
|
||||
lang: Language;
|
||||
loading: boolean;
|
||||
error: any;
|
||||
data: schema.ApplicationData[];
|
||||
pagination: any;
|
||||
showFields: string[];
|
||||
gridCols: GridSize | number;
|
||||
titleField: string;
|
||||
handleQueryChange: (key: string, value: string | null) => void;
|
||||
updatePagination: (pagination: any) => void;
|
||||
handleCardClick: (item: schema.ApplicationData) => void;
|
||||
handleViewClick: (item: schema.ApplicationData) => void;
|
||||
}
|
||||
|
||||
export interface ListComponentServiceProps {
|
||||
export interface ListComponentServicesProps {
|
||||
lang: Language;
|
||||
loading: boolean;
|
||||
error: any;
|
||||
|
|
@ -27,8 +13,25 @@ export interface ListComponentServiceProps {
|
|||
showFields: string[];
|
||||
gridCols: GridSize | number;
|
||||
titleField: string;
|
||||
size: CardSize;
|
||||
handleQueryChange: (key: string, value: string | null) => void;
|
||||
updatePagination: (pagination: any) => void;
|
||||
handleCardClick: (item: schemaServices.ServiceData) => void;
|
||||
handleViewClick: (item: schemaServices.ServiceData) => void;
|
||||
}
|
||||
|
||||
export interface ListComponentEventsProps {
|
||||
lang: Language;
|
||||
loading: boolean;
|
||||
error: any;
|
||||
data: schemaEvents.EventData[];
|
||||
pagination: any;
|
||||
showFields: string[];
|
||||
gridCols: GridSize | number;
|
||||
titleField: string;
|
||||
size: CardSize;
|
||||
handleQueryChange: (key: string, value: string | null) => void;
|
||||
updatePagination: (pagination: any) => void;
|
||||
handleCardClick: (item: schemaEvents.EventData) => void;
|
||||
handleViewClick: (item: schemaEvents.EventData) => void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,17 +152,17 @@ services:
|
|||
# mem_limit: 512m
|
||||
# cpus: 0.5
|
||||
|
||||
# dealer_service:
|
||||
# container_name: dealer_service
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: ApiServices/DealerService/Dockerfile
|
||||
# networks:
|
||||
# - wag-services
|
||||
# env_file:
|
||||
# - api_env.env
|
||||
# mem_limit: 512m
|
||||
# cpus: 0.5
|
||||
dealer_service:
|
||||
container_name: dealer_service
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ApiServices/DealerService/Dockerfile
|
||||
networks:
|
||||
- wag-services
|
||||
env_file:
|
||||
- api_env.env
|
||||
mem_limit: 512m
|
||||
cpus: 0.5
|
||||
|
||||
networks:
|
||||
wag-services:
|
||||
|
|
|
|||
Loading…
Reference in New Issue