Config ui section is coming along
This commit is contained in:
4
ui/src/utils/basic.ts
Normal file
4
ui/src/utils/basic.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const objectCopy = <T>(obj: T): T => {
|
||||
return JSON.parse(JSON.stringify(obj)) as T;
|
||||
};
|
||||
|
||||
84
ui/src/utils/hooks.tsx
Normal file
84
ui/src/utils/hooks.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Updates a deeply nested value in an object using a string path
|
||||
* @param obj The object to update
|
||||
* @param value The new value to set
|
||||
* @param path String path to the property (e.g. 'config.process[0].model.name_or_path')
|
||||
* @returns A new object with the updated value
|
||||
*/
|
||||
export function setNestedValue<T, V>(obj: T, value: V, path?: string): T {
|
||||
// Create a copy of the original object to maintain immutability
|
||||
const result = { ...obj };
|
||||
|
||||
// if path is not provided, be root path
|
||||
if (!path) {
|
||||
path = '';
|
||||
}
|
||||
|
||||
// Split the path into segments
|
||||
const pathArray = path.split('.').flatMap(segment => {
|
||||
// Handle array notation like 'process[0]'
|
||||
const arrayMatch = segment.match(/^([^\[]+)(\[\d+\])+/);
|
||||
if (arrayMatch) {
|
||||
const propName = arrayMatch[1];
|
||||
const indices = segment
|
||||
.substring(propName.length)
|
||||
.match(/\[(\d+)\]/g)
|
||||
?.map(idx => parseInt(idx.substring(1, idx.length - 1)));
|
||||
|
||||
// Return property name followed by array indices
|
||||
return [propName, ...(indices || [])];
|
||||
}
|
||||
return segment;
|
||||
});
|
||||
|
||||
// Navigate to the target location
|
||||
let current: any = result;
|
||||
for (let i = 0; i < pathArray.length - 1; i++) {
|
||||
const key = pathArray[i];
|
||||
|
||||
// If current key is a number, treat it as an array index
|
||||
if (typeof key === 'number') {
|
||||
if (!Array.isArray(current)) {
|
||||
throw new Error(`Cannot access index ${key} of non-array`);
|
||||
}
|
||||
// Create a copy of the array to maintain immutability
|
||||
current = [...current];
|
||||
} else {
|
||||
// For object properties, create a new object if it doesn't exist
|
||||
if (current[key] === undefined) {
|
||||
// Check if the next key is a number, if so create an array, otherwise an object
|
||||
const nextKey = pathArray[i + 1];
|
||||
current[key] = typeof nextKey === 'number' ? [] : {};
|
||||
} else {
|
||||
// Create a shallow copy to maintain immutability
|
||||
current[key] = Array.isArray(current[key]) ? [...current[key]] : { ...current[key] };
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the next level
|
||||
current = current[key];
|
||||
}
|
||||
|
||||
// Set the value at the final path segment
|
||||
const finalKey = pathArray[pathArray.length - 1];
|
||||
current[finalKey] = value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook for managing a complex state object with string path updates
|
||||
* @param initialState The initial state object
|
||||
* @returns [state, setValue] tuple
|
||||
*/
|
||||
export function useNestedState<T>(initialState: T): [T, (value: any, path?: string) => void] {
|
||||
const [state, setState] = React.useState<T>(initialState);
|
||||
|
||||
const setValue = React.useCallback((value: any, path?: string) => {
|
||||
setState(prevState => setNestedValue(prevState, value, path));
|
||||
}, []);
|
||||
|
||||
return [state, setValue];
|
||||
}
|
||||
Reference in New Issue
Block a user