From 40d0e061a4254b7c98ee1f79a539a4a27dea7c40 Mon Sep 17 00:00:00 2001 From: Kurt Nordstrom Date: Wed, 29 Jul 2026 16:45:39 -0400 Subject: [PATCH 1/2] Change lms config editor to be closer to existing settings behavior --- ui-rsdir/src/components/LMSConfigEditor.css | 10 ++ ui-rsdir/src/components/LMSConfigEditor.js | 143 ++++++++++++++++---- 2 files changed, 129 insertions(+), 24 deletions(-) create mode 100644 ui-rsdir/src/components/LMSConfigEditor.css diff --git a/ui-rsdir/src/components/LMSConfigEditor.css b/ui-rsdir/src/components/LMSConfigEditor.css new file mode 100644 index 0000000..f5b72f9 --- /dev/null +++ b/ui-rsdir/src/components/LMSConfigEditor.css @@ -0,0 +1,10 @@ +.fieldEditor { + display: flex; + align-items: flex-start; + gap: var(--gutter-static-one-third); +} + +.fieldInput { + flex: 1; + min-width: 0; +} diff --git a/ui-rsdir/src/components/LMSConfigEditor.js b/ui-rsdir/src/components/LMSConfigEditor.js index 9c11ff1..bb98c85 100644 --- a/ui-rsdir/src/components/LMSConfigEditor.js +++ b/ui-rsdir/src/components/LMSConfigEditor.js @@ -1,15 +1,17 @@ -import React, { useContext, useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import { useQueryClient } from 'react-query'; import { CalloutContext, useOkapiKy } from '@folio/stripes/core'; import { Button, - Col, - Row, + Card, + IconButton, Select, TextField, } from '@folio/stripes/components'; +import css from './LMSConfigEditor.css'; + const entryPath = id => `rsdir/entries/by-id/${id}`; const fieldLabelId = fieldName => `ui-rsdir.lmsConfig.${fieldName}`; @@ -68,8 +70,11 @@ const LMSConfigEditor = ({ id, entry: initialEntry, fieldMapping = [] }) => { const queryClient = useQueryClient(); const [entry, setEntry] = useState(initialEntry); const [values, setValues] = useState(() => valuesFromEntry(initialEntry, fieldMapping)); + const [editingFields, setEditingFields] = useState({}); const [savingFields, setSavingFields] = useState({}); const [fieldErrors, setFieldErrors] = useState({}); + const editingFieldsRef = useRef({}); + const previousIdRef = useRef(id); const booleanOptions = useMemo(() => [ { label: '', value: '' }, @@ -78,9 +83,43 @@ const LMSConfigEditor = ({ id, entry: initialEntry, fieldMapping = [] }) => { ], [intl]); useEffect(() => { + const nextValues = valuesFromEntry(initialEntry, fieldMapping); + const isNewEntry = previousIdRef.current !== id; + setEntry(initialEntry); - setValues(valuesFromEntry(initialEntry, fieldMapping)); - }, [fieldMapping, initialEntry]); + setValues(current => { + if (isNewEntry) { + return nextValues; + } + + return fieldMapping.reduce((acc, field) => ({ + ...acc, + [field.fieldName]: editingFieldsRef.current[field.fieldName] ? + current[field.fieldName] ?? '' : + nextValues[field.fieldName], + }), {}); + }); + + if (isNewEntry) { + editingFieldsRef.current = {}; + setEditingFields({}); + setFieldErrors({}); + } + + previousIdRef.current = id; + }, [fieldMapping, id, initialEntry]); + + const committedValue = fieldName => toEditorValue(entry?.lmsConfig?.[fieldName]); + + const setFieldEditing = (fieldName, isEditing) => { + const nextEditingFields = { + ...editingFieldsRef.current, + [fieldName]: isEditing, + }; + + editingFieldsRef.current = nextEditingFields; + setEditingFields(nextEditingFields); + }; const handleChange = fieldName => event => { setValues(current => ({ @@ -89,6 +128,30 @@ const LMSConfigEditor = ({ id, entry: initialEntry, fieldMapping = [] }) => { })); }; + const editField = fieldName => { + setValues(current => ({ + ...current, + [fieldName]: committedValue(fieldName), + })); + setFieldErrors(current => ({ + ...current, + [fieldName]: undefined, + })); + setFieldEditing(fieldName, true); + }; + + const cancelEditingField = fieldName => { + setValues(current => ({ + ...current, + [fieldName]: committedValue(fieldName), + })); + setFieldErrors(current => ({ + ...current, + [fieldName]: undefined, + })); + setFieldEditing(fieldName, false); + }; + const saveField = field => { const { fieldName, valueType, required } = field; const value = values[fieldName]; @@ -125,6 +188,11 @@ const LMSConfigEditor = ({ id, entry: initialEntry, fieldMapping = [] }) => { }; setEntry(nextEntry); + setValues(current => ({ + ...current, + [fieldName]: toEditorValue(nextEntry?.lmsConfig?.[fieldName]), + })); + setFieldEditing(fieldName, false); queryClient.setQueryData(entryPath(id), nextEntry); queryClient.invalidateQueries(entryPath(id)); callout.sendCallout({ @@ -147,12 +215,12 @@ const LMSConfigEditor = ({ id, entry: initialEntry, fieldMapping = [] }) => { const { fieldName, valueType, required, validChoices = [] } = field; const type = normalizedValueType(valueType); const commonProps = { + 'aria-label': intl.formatMessage({ id: fieldLabelId(fieldName), defaultMessage: fieldName }), id: `lms-config-${fieldName}`, error: fieldErrors[fieldName], - label: intl.formatMessage({ id: fieldLabelId(fieldName), defaultMessage: fieldName }), onChange: handleChange(fieldName), required, - value: values[fieldName] || '', + value: values[fieldName] ?? '', }; if (validChoices.length > 0) { @@ -183,23 +251,50 @@ const LMSConfigEditor = ({ id, entry: initialEntry, fieldMapping = [] }) => { return (
- {fieldMapping.map(field => ( - - - {renderFieldInput(field)} - - - - - - ))} + {fieldMapping.map(field => { + const { fieldName } = field; + const isEditing = editingFields[fieldName]; + const isSaving = savingFields[fieldName]; + + return ( + (isEditing ? saveField(field) : editField(fieldName))} + > + {isEditing ? + : + + } + + } + > + {isEditing ? +
+
+ {renderFieldInput(field)} +
+ cancelEditingField(fieldName)} + size="small" + /> +
: + committedValue(fieldName) + } +
+ ); + })} {!entry?.lmsConfig &&
Date: Thu, 30 Jul 2026 08:42:24 -0400 Subject: [PATCH 2/2] Copilot suggestion for clearing savingFileds when we switch entries Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- ui-rsdir/src/components/LMSConfigEditor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-rsdir/src/components/LMSConfigEditor.js b/ui-rsdir/src/components/LMSConfigEditor.js index bb98c85..25a0eaa 100644 --- a/ui-rsdir/src/components/LMSConfigEditor.js +++ b/ui-rsdir/src/components/LMSConfigEditor.js @@ -103,6 +103,7 @@ const LMSConfigEditor = ({ id, entry: initialEntry, fieldMapping = [] }) => { if (isNewEntry) { editingFieldsRef.current = {}; setEditingFields({}); + setSavingFields({}); setFieldErrors({}); }