Skip to content

Commit c10cc4d

Browse files
committed
chore: enabled filter mapping
1 parent 9acc2bb commit c10cc4d

File tree

3 files changed

+100
-22
lines changed

3 files changed

+100
-22
lines changed

ichub-backend/controllers/fastapi/routers/provider/v1/twin_management.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,41 @@ async def twin_management_share_catalog_part_twin(catalog_part_twin_share: Catal
8080
return JSONResponse(status_code=204, content={"description":"Catalog part twin already shared"})
8181

8282
@router.get("/serialized-part-twin", response_model=List[SerializedPartTwinRead], responses=exception_responses)
83-
async def twin_management_get_all_serialized_part_twins(include_data_exchange_agreements: bool = False) -> List[SerializedPartTwinRead]:
84-
return twin_management_service.get_serialized_part_twins(include_data_exchange_agreements=include_data_exchange_agreements)
83+
async def twin_management_get_all_serialized_part_twins(
84+
include_data_exchange_agreements: bool = False,
85+
manufacturerId: Optional[str] = None,
86+
manufacturerPartId: Optional[str] = None,
87+
customerPartId: Optional[str] = None,
88+
partInstanceId: Optional[str] = None,
89+
van: Optional[str] = None,
90+
businessPartnerNumber: Optional[str] = None
91+
) -> List[SerializedPartTwinRead]:
92+
from models.services.provider.part_management import SerializedPartQuery
93+
94+
# Create a dynamic query object using all provided filter parameters
95+
query_data = {}
96+
97+
# Map API parameter names to Pydantic field aliases
98+
filter_mapping = {
99+
"manufacturerId": manufacturerId,
100+
"manufacturerPartId": manufacturerPartId,
101+
"customerPartId": customerPartId,
102+
"partInstanceId": partInstanceId,
103+
"van": van,
104+
"businessPartnerNumber": businessPartnerNumber
105+
}
106+
107+
# Only include non-None values in the query
108+
for field_name, value in filter_mapping.items():
109+
if value is not None:
110+
query_data[field_name] = value
111+
112+
query = SerializedPartQuery(**query_data)
113+
114+
return twin_management_service.get_serialized_part_twins(
115+
serialized_part_query=query,
116+
include_data_exchange_agreements=include_data_exchange_agreements
117+
)
85118

86119
@router.get("/serialized-part-twin/{global_id}", response_model=Optional[SerializedPartTwinDetailsRead], responses=exception_responses)
87120
async def twin_management_get_serialized_part_twin(global_id: UUID) -> Optional[SerializedPartTwinDetailsRead]:

ichub-frontend/src/features/serialized-parts/api.ts

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ const SERIALIZED_PART_READ_BASE_PATH = '/part-management/serialized-part';
2929
const SERIALIZED_PART_TWIN_BASE_PATH = '/twin-management/serialized-part-twin';
3030
const backendUrl = getIchubBackendUrl();
3131

32+
// Simple cache for twins to avoid redundant API calls
33+
const twinsCache = new Map<string, { data: SerializedPartTwinRead[]; timestamp: number }>();
34+
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
35+
36+
const getCacheKey = (manufacturerId?: string, manufacturerPartId?: string) => {
37+
return `${manufacturerId || 'all'}-${manufacturerPartId || 'all'}`;
38+
};
39+
3240
export const fetchAllSerializedParts = async (): Promise<SerializedPart[]> => {
3341
const response = await axios.get<SerializedPart[]>(`${backendUrl}${SERIALIZED_PART_READ_BASE_PATH}`);
3442
return response.data;
@@ -77,20 +85,39 @@ export const fetchAllSerializedPartTwins = async (
7785
manufacturerId?: string,
7886
manufacturerPartId?: string
7987
): Promise<SerializedPartTwinRead[]> => {
80-
const response = await axios.get<SerializedPartTwinRead[]>(
81-
`${backendUrl}${SERIALIZED_PART_TWIN_BASE_PATH}?include_data_exchange_agreements=true`
82-
);
88+
// Check cache first
89+
const cacheKey = getCacheKey(manufacturerId, manufacturerPartId);
90+
const cached = twinsCache.get(cacheKey);
91+
const now = Date.now();
92+
93+
if (cached && (now - cached.timestamp) < CACHE_DURATION) {
94+
console.log('Returning cached twins data for:', cacheKey);
95+
return cached.data;
96+
}
97+
98+
// Build query parameters to filter on the server side
99+
const params = new URLSearchParams();
100+
params.append('include_data_exchange_agreements', 'true');
83101

84-
// Filter twins by manufacturerId and manufacturerPartId if provided
85-
let twins = response.data;
86102
if (manufacturerId) {
87-
twins = twins.filter(twin => twin.manufacturerId === manufacturerId);
103+
params.append('manufacturerId', manufacturerId);
88104
}
89105
if (manufacturerPartId) {
90-
twins = twins.filter(twin => twin.manufacturerPartId === manufacturerPartId);
106+
params.append('manufacturerPartId', manufacturerPartId);
91107
}
92108

93-
return twins;
109+
console.log('Fetching twins from API for:', cacheKey);
110+
const response = await axios.get<SerializedPartTwinRead[]>(
111+
`${backendUrl}${SERIALIZED_PART_TWIN_BASE_PATH}?${params.toString()}`
112+
);
113+
114+
// Cache the result
115+
twinsCache.set(cacheKey, {
116+
data: response.data,
117+
timestamp: now
118+
});
119+
120+
return response.data;
94121
};
95122

96123
export const unshareSerializedPartTwin = async (

ichub-frontend/src/features/serialized-parts/components/SerializedPartsTable.tsx

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import CloudUploadIcon from '@mui/icons-material/CloudUpload';
3535
import IosShare from '@mui/icons-material/IosShare';
3636
import LinkOffIcon from '@mui/icons-material/LinkOff';
3737
import DeleteIcon from '@mui/icons-material/Delete';
38-
import { useEffect, useState } from 'react';
38+
import { useEffect, useState, useCallback } from 'react';
3939
import { SerializedPart } from '../types';
4040
import { SerializedPartTwinRead } from '../types/twin-types';
4141
import { createSerializedPartTwin, shareSerializedPartTwin, unshareSerializedPartTwin, deleteSerializedPart, fetchAllSerializedPartTwins } from '../api';
@@ -61,6 +61,23 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
6161
const [twinUnsharingId, setTwinUnsharingId] = useState<number | null>(null);
6262
const [partDeletingId, setPartDeletingId] = useState<number | null>(null);
6363

64+
// Helper function to fetch twins for all unique parts in the table
65+
const fetchTwinsForParts = useCallback(async (): Promise<SerializedPartTwinRead[]> => {
66+
const uniqueParts = Array.from(
67+
new Set(parts.map(p => `${p.manufacturerId}-${p.manufacturerPartId}`))
68+
).map(key => {
69+
const [manufacturerId, manufacturerPartId] = key.split('-');
70+
return { manufacturerId, manufacturerPartId };
71+
});
72+
73+
const allTwins: SerializedPartTwinRead[] = [];
74+
for (const { manufacturerId, manufacturerPartId } of uniqueParts) {
75+
const twins = await fetchAllSerializedPartTwins(manufacturerId, manufacturerPartId);
76+
allTwins.push(...twins);
77+
}
78+
return allTwins;
79+
}, [parts]);
80+
6481
// Determine twin status based on twin data
6582
const determineTwinStatus = (serializedPart: SerializedPart, twins: SerializedPartTwinRead[]): { status: StatusVariants; globalId?: string } => {
6683
const twin = twins.find(
@@ -83,12 +100,12 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
83100
useEffect(() => {
84101
const loadTwinData = async () => {
85102
try {
86-
// Fetch all twins to determine status
87-
const twins = await fetchAllSerializedPartTwins();
103+
// Fetch twins for the specific parts being displayed
104+
const allTwins = await fetchTwinsForParts();
88105

89106
// Merge serialized parts with twin status
90107
const rowsWithStatus = parts.map((serializedPart, index) => {
91-
const { status, globalId } = determineTwinStatus(serializedPart, twins);
108+
const { status, globalId } = determineTwinStatus(serializedPart, allTwins);
92109
return {
93110
...serializedPart,
94111
id: serializedPart.id || index,
@@ -115,7 +132,7 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
115132
};
116133

117134
loadTwinData();
118-
}, [parts]);
135+
}, [parts, fetchTwinsForParts]);
119136

120137
const handleCreateTwin = async (row: SerializedPartWithStatus) => {
121138
setTwinCreatingId(row.id);
@@ -126,10 +143,11 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
126143
partInstanceId: row.partInstanceId,
127144
});
128145

129-
// Refresh twin data after successful creation
130-
const twins = await fetchAllSerializedPartTwins();
146+
// Refresh twin data after successful creation - reload all twins for this table
147+
const allTwins = await fetchTwinsForParts();
148+
131149
const rowsWithStatus = parts.map((serializedPart, index) => {
132-
const { status, globalId } = determineTwinStatus(serializedPart, twins);
150+
const { status, globalId } = determineTwinStatus(serializedPart, allTwins);
133151
return {
134152
...serializedPart,
135153
id: serializedPart.id || index,
@@ -159,7 +177,7 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
159177
});
160178

161179
// Refresh twin data after successful share
162-
const twins = await fetchAllSerializedPartTwins();
180+
const twins = await fetchTwinsForParts();
163181
const rowsWithStatus = parts.map((serializedPart, index) => {
164182
const { status, globalId } = determineTwinStatus(serializedPart, twins);
165183
return {
@@ -185,7 +203,7 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
185203
setTwinUnsharingId(row.id);
186204
try {
187205
// Find the twin to get the AAS ID
188-
const twins = await fetchAllSerializedPartTwins();
206+
const twins = await fetchTwinsForParts();
189207
const twin = twins.find(
190208
(t) => t.manufacturerId === row.manufacturerId &&
191209
t.manufacturerPartId === row.manufacturerPartId &&
@@ -207,7 +225,7 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
207225
});
208226

209227
// Refresh twin data after successful unshare
210-
const updatedTwins = await fetchAllSerializedPartTwins();
228+
const updatedTwins = await fetchTwinsForParts();
211229
const rowsWithStatus = parts.map((serializedPart, index) => {
212230
const { status, globalId } = determineTwinStatus(serializedPart, updatedTwins);
213231
return {
@@ -243,7 +261,7 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
243261
console.log("Delete API call successful");
244262

245263
// Refresh data after successful deletion
246-
const twins = await fetchAllSerializedPartTwins();
264+
const twins = await fetchTwinsForParts();
247265
const rowsWithStatus = parts.map((serializedPart, index) => {
248266
const { status, globalId } = determineTwinStatus(serializedPart, twins);
249267
return {

0 commit comments

Comments
 (0)