Settings UI tweaks (#22722)

* set edgetpu for multi-instance

* improve error messages when mixing/matching detectors

* allow custom add button text via uiSchema

* clarify language in docs for configuring detectors via the UI
This commit is contained in:
Josh Hawkins
2026-04-01 10:23:42 -05:00
committed by GitHub
parent f1983b25ca
commit adc8c2a6e8
5 changed files with 118 additions and 46 deletions

View File

@@ -16,7 +16,7 @@ const detectors: SectionConfigOverrides = {
uiSchema: {
"ui:field": "DetectorHardwareField",
"ui:options": {
multiInstanceTypes: ["cpu", "onnx", "openvino"],
multiInstanceTypes: ["cpu", "onnx", "openvino", "edgetpu"],
typeOrder: ["onnx", "openvino", "edgetpu"],
hiddenByType: {},
hiddenFields: detectorHiddenFields,

View File

@@ -60,7 +60,9 @@ export function AddPropertyButton({
className="gap-2"
>
<LuPlus className="h-4 w-4" />
{t("button.add", { ns: "common", defaultValue: "Add" })}
{typeof uiSchema?.["ui:options"]?.addButtonText === "string"
? uiSchema["ui:options"].addButtonText
: t("button.add", { ns: "common", defaultValue: "Add" })}
</Button>
);
}

View File

@@ -374,6 +374,18 @@ export function DetectorHardwareField(props: FieldProps) {
[detectors],
);
const getExistingType = useCallback(
(excludeKey?: string): string | undefined => {
for (const [key, value] of Object.entries(detectors)) {
if (excludeKey && key === excludeKey) continue;
const type = getInstanceType(value);
if (type) return type;
}
return undefined;
},
[detectors],
);
const handleAdd = useCallback(() => {
if (!addType) {
setAddError(
@@ -400,6 +412,28 @@ export function DetectorHardwareField(props: FieldProps) {
return;
}
const existingType = getExistingType();
if (existingType && existingType !== addType) {
const canAddExisting =
multiInstanceSet.has(existingType) ||
!resolveDuplicateType(existingType);
setAddError(
canAddExisting
? t("configMessages.detectors.mixedTypesSuggestion", {
ns: "views/settings",
defaultValue:
"All detectors must use the same type. Remove existing detectors or select {{type}}.",
type: getTypeLabel(existingType),
})
: t("configMessages.detectors.mixedTypes", {
ns: "views/settings",
defaultValue:
"All detectors must use the same type. Remove existing detectors to use a different type.",
}),
);
return;
}
const baseKey = addType;
let nextKey = baseKey;
let index = 2;
@@ -427,8 +461,10 @@ export function DetectorHardwareField(props: FieldProps) {
configNamespace,
detectors,
getDetectorDefaults,
getExistingType,
getTypeLabel,
isSingleInstanceType,
multiInstanceSet,
resolveDuplicateType,
updateDetectors,
]);
@@ -523,6 +559,29 @@ export function DetectorHardwareField(props: FieldProps) {
return;
}
const existingType = getExistingType(key);
if (existingType && existingType !== nextType) {
const canAddExisting =
multiInstanceSet.has(existingType) ||
!resolveDuplicateType(existingType, key);
setTypeErrors((prev) => ({
...prev,
[key]: canAddExisting
? t("configMessages.detectors.mixedTypesSuggestion", {
ns: "views/settings",
defaultValue:
"All detectors must use the same type. Remove existing detectors or select {{type}}.",
type: getTypeLabel(existingType),
})
: t("configMessages.detectors.mixedTypes", {
ns: "views/settings",
defaultValue:
"All detectors must use the same type. Remove existing detectors to use a different type.",
}),
}));
return;
}
setTypeErrors((prev) => {
const { [key]: _, ...rest } = prev;
return rest;
@@ -538,8 +597,10 @@ export function DetectorHardwareField(props: FieldProps) {
[
detectors,
getDetectorDefaults,
getExistingType,
getTypeLabel,
isSingleInstanceType,
multiInstanceSet,
resolveDuplicateType,
t,
updateDetectors,
@@ -556,6 +617,10 @@ export function DetectorHardwareField(props: FieldProps) {
const nestedOverrides = {
"ui:options": {
disableNestedCard: true,
addButtonText: t("configForm.detectors.addCustomKey", {
ns: "views/settings",
defaultValue: "Add custom key",
}),
},
} as UiSchema;
@@ -567,7 +632,7 @@ export function DetectorHardwareField(props: FieldProps) {
);
return mergeUiSchema(withTypeHiddenAndOptions, nestedOverrides);
},
[globalHiddenFields, hiddenByType, uiSchema?.additionalProperties],
[globalHiddenFields, hiddenByType, t, uiSchema?.additionalProperties],
);
const renderInstanceForm = useCallback(