diff --git a/src/components/CippComponents/CippAutocomplete.jsx b/src/components/CippComponents/CippAutocomplete.jsx
index 8cef03878f94..741fa8deec11 100644
--- a/src/components/CippComponents/CippAutocomplete.jsx
+++ b/src/components/CippComponents/CippAutocomplete.jsx
@@ -1,9 +1,9 @@
import { ArrowDropDown } from "@mui/icons-material";
import { Autocomplete, CircularProgress, createFilterOptions, TextField } from "@mui/material";
-import { ApiGetCall } from "../../api/ApiCall";
import { useEffect, useState } from "react";
import { useSettings } from "../../hooks/use-settings";
import { getCippError } from "../../utils/get-cipp-error";
+import { ApiGetCallWithPagination } from "../../api/ApiCall";
export const CippAutoComplete = (props) => {
const {
@@ -25,15 +25,29 @@ export const CippAutoComplete = (props) => {
sx,
...other
} = props;
- const filter = createFilterOptions({ stringify: (option) => JSON.stringify(option) });
+
const [usedOptions, setUsedOptions] = useState(options);
const [getRequestInfo, setGetRequestInfo] = useState({ url: "", waiting: false, queryKey: "" });
+ const filter = createFilterOptions({
+ stringify: (option) => JSON.stringify(option),
+ });
- const actionGetRequest = ApiGetCall({
+ // This is our paginated call
+ const actionGetRequest = ApiGetCallWithPagination({
...getRequestInfo,
});
const currentTenant = api?.tenantFilter ? api.tenantFilter : useSettings().currentTenant;
+ useEffect(() => {
+ if (actionGetRequest.isSuccess && !actionGetRequest.isFetching) {
+ const lastPage = actionGetRequest.data?.pages[actionGetRequest.data.pages.length - 1];
+ const nextLinkExists = lastPage?.Metadata?.nextLink;
+ if (nextLinkExists) {
+ actionGetRequest.fetchNextPage();
+ }
+ }
+ }, [actionGetRequest.data?.pages?.length, actionGetRequest.isFetching, api?.queryKey]);
+
useEffect(() => {
if (api) {
setGetRequestInfo({
@@ -46,52 +60,87 @@ export const CippAutoComplete = (props) => {
queryKey: api.queryKey,
});
}
+ }, [api, currentTenant]);
+ // After the data is fetched, combine and map it
+ useEffect(() => {
if (actionGetRequest.isSuccess) {
- const dataToMap = api.dataKey ? actionGetRequest.data?.[api.dataKey] : actionGetRequest.data;
- if (!Array.isArray(dataToMap)) {
+ // E.g., allPages is an array of pages returned by the pagination
+ const allPages = actionGetRequest.data?.pages || [];
+
+ // Helper to get nested data if you have something like "response.data.items"
+ const getNestedValue = (obj, path) => {
+ if (!path) return obj;
+ const keys = path.split(".");
+ let result = obj;
+ for (const key of keys) {
+ if (result && typeof result === "object" && key in result) {
+ result = result[key];
+ } else {
+ return undefined;
+ }
+ }
+ return result;
+ };
+
+ // Flatten the results from all pages
+ const combinedResults = allPages.flatMap((page) => {
+ const nestedData = getNestedValue(page, api?.dataKey);
+ return nestedData !== undefined ? nestedData : [];
+ });
+
+ if (!Array.isArray(combinedResults)) {
setUsedOptions([
{
label: "Error: The API returned data we cannot map to this field",
- value: "Error: The API returned data we cannot map to this field",
+ value: "Error",
},
]);
- return;
+ } else {
+ // Convert each item into your { label, value, addedFields } shape
+ const convertedOptions = combinedResults.map((option) => {
+ const addedFields = {};
+ if (api?.addedField) {
+ Object.keys(api.addedField).forEach((key) => {
+ addedFields[key] = option[api.addedField[key]];
+ });
+ }
+
+ return {
+ label:
+ typeof api?.labelField === "function"
+ ? api.labelField(option)
+ : option[api?.labelField],
+ value:
+ typeof api?.valueField === "function"
+ ? api.valueField(option)
+ : option[api?.valueField],
+ addedFields,
+ };
+ });
+ setUsedOptions(convertedOptions);
}
- const convertedOptions = dataToMap.map((option) => {
- const addedFields = {};
- if (api.addedField) {
- Object.keys(api.addedField).forEach((key) => {
- addedFields[key] = option[api.addedField[key]];
- });
- }
- return {
- label:
- typeof api.labelField === "function" ? api.labelField(option) : option[api.labelField],
- value:
- typeof api.valueField === "function" ? api.valueField(option) : option[api.valueField],
- addedFields: addedFields,
- };
- });
- setUsedOptions(convertedOptions);
}
+
if (actionGetRequest.isError) {
setUsedOptions([{ label: getCippError(actionGetRequest.error), value: "error" }]);
}
- }, [api, actionGetRequest.data]);
+ }, [api, actionGetRequest.data, actionGetRequest.isSuccess, actionGetRequest.isError]);
+
const rand = Math.random().toString(36).substring(5);
+
return (
) : (
)
}
- isOptionEqualToValue={(option, value) => option.value === value.value}
+ isOptionEqualToValue={(option, val) => option.value === val.value}
value={typeof value === "string" ? { label: value, value: value } : value}
filterSelectedOptions
disableClearable={disableClearable}
@@ -100,12 +149,11 @@ export const CippAutoComplete = (props) => {
filterOptions={(options, params) => {
const filtered = filter(options, params);
const isExisting =
- options !== undefined &&
- options !== null &&
options?.length > 0 &&
- options?.some(
+ options.some(
(option) => params.inputValue === option.value || params.inputValue === option.label
);
+
if (params.inputValue !== "" && creatable && !isExisting) {
filtered.push({
label: `Add option: "${params.inputValue}"`,
@@ -126,6 +174,7 @@ export const CippAutoComplete = (props) => {
onChange={(event, newValue) => {
if (Array.isArray(newValue)) {
newValue = newValue.map((item) => {
+ // If user typed a new item or missing label
if (item?.manual || !item?.label) {
item = {
label: item?.label ? item.value : item,