diff --git a/src/components/Dashboard/EditBulkTerms/EditBulkTermsDialog.jsx b/src/components/Dashboard/EditBulkTerms/EditBulkTermsDialog.jsx
index 2e15717..513345b 100644
--- a/src/components/Dashboard/EditBulkTerms/EditBulkTermsDialog.jsx
+++ b/src/components/Dashboard/EditBulkTerms/EditBulkTermsDialog.jsx
@@ -15,7 +15,7 @@ import { patchTerm } from "../../../api/endpoints";
const initialSearchConditions = { attribute: '', value: '', condition: 'where', relation: SearchTermsData.objectOptions[0].value }
-const HeaderRightSideContent = ({ handleClose, activeStep, handleNext, handleBack, setActiveStep, isAllFieldsFilled, selectedOntology, isUpdating }) => {
+const HeaderRightSideContent = ({ handleClose, activeStep, handleNext, handleBack, setActiveStep, isAllFieldsFilled, selectedOntology, isUpdating, ontologyTerms }) => {
return (
{isUpdating ? 'Saving Changes...' : 'Continue'}
@@ -65,6 +65,8 @@ HeaderRightSideContent.propTypes = {
setActiveStep: PropTypes.func.isRequired,
isAllFieldsFilled: PropTypes.bool.isRequired,
selectedOntology: PropTypes.object,
+ isUpdating: PropTypes.bool.isRequired,
+ ontologyTerms: PropTypes.array,
};
const EditBulkTermsDialog = ({ open, handleClose, activeStep, setActiveStep }) => {
@@ -218,6 +220,7 @@ const EditBulkTermsDialog = ({ open, handleClose, activeStep, setActiveStep }) =
isAllFieldsFilled={isAllFieldsFilled(searchConditions)}
selectedOntology={selectedOntology}
isUpdating={isUpdating}
+ ontologyTerms={ontologyTerms}
/>
}
sx={{
diff --git a/src/components/Dashboard/EditBulkTerms/SearchTerms.jsx b/src/components/Dashboard/EditBulkTerms/SearchTerms.jsx
index d1ca3ec..59af63e 100644
--- a/src/components/Dashboard/EditBulkTerms/SearchTerms.jsx
+++ b/src/components/Dashboard/EditBulkTerms/SearchTerms.jsx
@@ -48,7 +48,7 @@ const styles = {
},
}
-const SearchTerms = ({ searchConditions, setSearchConditions, initialSearchConditions, setOntologyTerms, ontologyAttributes, setOntologyAttributes, selectedOntology, setSelectedOntology, setOriginalTerms }) => {
+const SearchTerms = ({ searchConditions, setSearchConditions, initialSearchConditions, ontologyTerms, setOntologyTerms, ontologyAttributes, setOntologyAttributes, selectedOntology, setSelectedOntology, setOriginalTerms }) => {
const [ontologyEditOption, setOntologyEditOption] = useState(Confirmation.Yes);
const [attributesLoading, setAttributesLoading] = useState(false);
const { user } = useContext(GlobalDataContext);
@@ -292,13 +292,20 @@ const SearchTerms = ({ searchConditions, setSearchConditions, initialSearchCondi
{ontologyEditOption === Confirmation.Yes && (
-
+ <>
+
+ {selectedOntology && ontologyTerms.length === 0 && !attributesLoading && (
+
+ ⚠️ The selected ontology "{selectedOntology.label}" contains no terms to edit.
+
+ )}
+ >
)}
diff --git a/src/components/Dashboard/EditBulkTerms/TermsTable.jsx b/src/components/Dashboard/EditBulkTerms/TermsTable.jsx
index 0a32a30..13d6977 100644
--- a/src/components/Dashboard/EditBulkTerms/TermsTable.jsx
+++ b/src/components/Dashboard/EditBulkTerms/TermsTable.jsx
@@ -112,7 +112,10 @@ const TermsTable = ({ setOpenEditAttributes, setAttributes, attributes, ontology
};
const sortedRows = React.useMemo(
- () => stableSort(terms || [], getComparator(order, orderBy)),
+ () => {
+ if (!terms || terms.length === 0) return [];
+ return stableSort(terms, getComparator(order, orderBy));
+ },
[order, orderBy, terms]
);
@@ -156,7 +159,7 @@ const TermsTable = ({ setOpenEditAttributes, setAttributes, attributes, ontology
}
return (
- terms.length > 0 ? (
+ terms && terms.length > 0 ? (
Edit your terms or select an header to bulk edit that property
@@ -243,11 +246,11 @@ const TermsTable = ({ setOpenEditAttributes, setAttributes, attributes, ontology
attributes={attributes}
/>
- {sortedRows.map((row, index) => (
+ {sortedRows && sortedRows.length > 0 ? sortedRows.map((row, index) => (
{filteredColumns.map((column) => {
const isEditing = editingCell?.rowIndex === index && editingCell?.columnId === column.id;
- const cellValue = row[column.id];
+ const cellValue = row && row[column.id];
return (
- ) : Array.isArray(cellValue) ? (
+ ) : Array.isArray(cellValue) && cellValue.length > 0 ? (
- {cellValue.map((chip, chipIndex) => (
- } onClick={() => handleChipClick(chip)} />
- ))}
+ {cellValue.map((chip, chipIndex) => {
+ const chipLabel = typeof chip === 'object' && chip !== null
+ ? chip['@value'] || chip.value || chip['@id'] || JSON.stringify(chip)
+ : chip || '';
+ const chipValue = typeof chip === 'object' && chip !== null
+ ? chip['@id'] || chip.value || chip['@value']
+ : chip;
+ return (
+ }
+ onClick={() => handleChipClick(chipValue)}
+ />
+ );
+ })}
) : column.id === '@id' ? (
// Format the Interlex ID to show just the ID part - read-only display
- {cellValue?.split('/').pop() || cellValue}
+ {(() => {
+ if (!cellValue) return '';
+ if (typeof cellValue === 'object') {
+ const idValue = cellValue['@id'] || cellValue.id || cellValue['@value'] || JSON.stringify(cellValue);
+ return typeof idValue === 'string' ? idValue.split('/').pop() || idValue : idValue;
+ }
+ return typeof cellValue === 'string' ? cellValue.split('/').pop() || cellValue : cellValue;
+ })()}
) : (
- {cellValue}
+ {typeof cellValue === 'object' && cellValue !== null
+ ? cellValue['@value'] || cellValue.value || JSON.stringify(cellValue)
+ : cellValue || ''
+ }
)}
);
})}
- ))}
+ )) : null}
diff --git a/src/components/SingleTermView/OntologySearch.jsx b/src/components/SingleTermView/OntologySearch.jsx
index e3372ef..ea1987f 100644
--- a/src/components/SingleTermView/OntologySearch.jsx
+++ b/src/components/SingleTermView/OntologySearch.jsx
@@ -227,11 +227,17 @@ const OntologySearch = ({ placeholder, fullWidth = false, disabled, extra, userG
setSearchTerm('');
setSelectedValue(value);
+ // If value is null (cleared), also clear from context
+ if (!value) {
+ setOntologyData(null);
+ console.log('Ontology cleared from context');
+ }
+
// Call the callback if provided
if (onOntologySelect) {
onOntologySelect(value);
}
- }, [onOntologySelect]);
+ }, [onOntologySelect, setOntologyData]);
const popperProps = useMemo(() => ({
sx: {
@@ -315,15 +321,18 @@ const OntologySearch = ({ placeholder, fullWidth = false, disabled, extra, userG
),
- endAdornment: selectedValue?.selected && (
-
-
-
+ endAdornment: (
+
+ {selectedValue?.selected && (
+
+ )}
+ {params.InputProps.endAdornment}
+
),
}}
sx={{
@@ -345,8 +354,9 @@ const OntologySearch = ({ placeholder, fullWidth = false, disabled, extra, userG
path, // keep full path
+ configure: (proxy) => {
+ proxy.on('error', (err, req) => {
+ console.log('Password change proxy error:', err);
+ console.log('Request URL:', req.url);
+ });
+ proxy.on('proxyReq', (proxyReq, req) => {
+ console.log('Proxying password change request:', req.method, req.url);
+ // pass through auth/cookies if present
+ if (req.headers.authorization) proxyReq.setHeader('Authorization', req.headers.authorization);
+ if (req.headers.cookie) proxyReq.setHeader('Cookie', req.headers.cookie);
+ // Set appropriate content type for password change (likely form data)
+ if (req.method === 'POST') {
+ proxyReq.setHeader('Content-Type', 'application/x-www-form-urlencoded');
+ }
+ });
+ proxy.on('proxyRes', (proxyRes, req, res) => {
+ console.log('Password change response:', proxyRes.statusCode, req.url);
+ // handle redirects
+ const location = proxyRes.headers['location'];
+ if (proxyRes.statusCode === 303 && location) {
+ delete proxyRes.headers['location'];
+ res.setHeader('X-Redirect-Location', location);
+ }
+
+ // CORS headers
+ const origin = req.headers.origin;
+ if (origin) res.setHeader('Access-Control-Allow-Origin', origin);
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
+ res.setHeader('Access-Control-Expose-Headers', 'X-Redirect-Location');
+ });
+ },
+ },
'^/([^/]+)/priv/entity(.*)': {
target: "https://uri.olympiangods.org",
secure: false,