From eee11fe3976cc8b41067b1adbd6cb0159a5a4d17 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 10 Oct 2024 13:11:09 -0500 Subject: [PATCH 001/180] OLS search for filtered ontologies --- src/Contexts/SearchContext.jsx | 3 ++ .../MappingsFunctions/DefaultSearch.jsx | 52 +++++++++++++++++++ .../MappingsFunctions/GetMappingsModal.jsx | 17 +++++- .../Projects/Tables/TableDetails.jsx | 6 +-- 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/components/Manager/MappingsFunctions/DefaultSearch.jsx diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index 909846e..e90d907 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -12,6 +12,7 @@ export function SearchContextRoot() { const [apiResultsCount, setApiResultsCount] = useState(); const [apiPage, setApiPage] = useState(0); const [apiTotalCount, setApiTotalCount] = useState(); + const [apiPreferences, setApiPreferences] = useState({}); const context = { prefTerminologies, @@ -30,6 +31,8 @@ export function SearchContextRoot() { setApiPage, apiTotalCount, setApiTotalCount, + apiPreferences, + setApiPreferences, }; return ( diff --git a/src/components/Manager/MappingsFunctions/DefaultSearch.jsx b/src/components/Manager/MappingsFunctions/DefaultSearch.jsx new file mode 100644 index 0000000..ef91ae6 --- /dev/null +++ b/src/components/Manager/MappingsFunctions/DefaultSearch.jsx @@ -0,0 +1,52 @@ +import { ontologyReducer } from '../Utilitiy'; + +export const fetchResults = ( + page, + query, + entriesPerPage, + // setLoading, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + searchUrl, + selectedBoxes +) => { + if (!query) { + return undefined; + } + // setLoading(true); + const pageStart = page * entriesPerPage; + + return fetch( + `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + .then(res => res.json()) + .then(data => { + let res = ontologyReducer(data?.response?.docs); + + // Filter based on selectedBoxes + if (selectedBoxes) { + res.results = res.results.filter( + d => !selectedBoxes.some(box => box.obo_id === d.obo_id) + ); + } + + if (page > 0 && res.results.length > 0) { + res.results = results.concat(res.results); + } else { + setTotalCount(data.response.numFound); + } + + setResults(res.results); + setFilteredResultsCount(res?.filteredResults?.length); + setResultsCount(res.results.length); + }); + // .finally(() => setLoading(false)); +}; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 3c56feb..f8219b3 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -4,6 +4,7 @@ import { myContext } from '../../../App'; import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; +import { SearchContext } from '../../../Contexts/SearchContext'; export const GetMappingsModal = ({ componentString, @@ -17,6 +18,7 @@ export const GetMappingsModal = ({ const { Search } = Input; const { searchUrl, vocabUrl, setSelectedKey, user } = useContext(myContext); + const { apiPreferences } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -155,8 +157,21 @@ export const GetMappingsModal = ({ number of results to return per page (entriesPerPage) and a calculation of the first index to start the results on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ const pageStart = page * entriesPerPage; + const apiPreferenceOntologies = () => { + if (apiPreferences?.self?.api_preference?.ols) { + // Get the ontologies from the 'ols' array and join them with commas + const filteredOntologies = + apiPreferences.self.api_preference.ols.join(','); + console.log(filteredOntologies); + // Construct the final URL with the filteredOntologies + return filteredOntologies; + } else { + const defaultOntologies = 'mondo,hp,maxo,ncit'; + return defaultOntologies; + } + }; return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, + `${searchUrl}q=${query}&ontology=${apiPreferenceOntologies()}&rows=${entriesPerPage}&start=${pageStart}`, { method: 'GET', headers: { diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 46b3597..9bd6e05 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -20,12 +20,14 @@ import { Submenu } from '../../Manager/Submenu'; import { SettingsDropdownTable } from '../../Manager/Dropdown/SettingsDropdownTable'; import { RequiredLogin } from '../../Auth/RequiredLogin'; import { FilterSelect } from '../../Manager/MappingsFunctions/FilterSelect'; +import { SearchContext } from '../../../Contexts/SearchContext'; export const TableDetails = () => { const [form] = Form.useForm(); const { vocabUrl, edit, setEdit, table, setTable, user } = useContext(myContext); + const { apiPreferences, setApiPreferences } = useContext(SearchContext); const { getMappings, setGetMappings, @@ -37,7 +39,6 @@ export const TableDetails = () => { const { studyId, DDId, tableId } = useParams(); const [loading, setLoading] = useState(true); const [load, setLoad] = useState(false); - const [apiPreferences, setApiPreferences] = useState({}); const navigate = useNavigate(); @@ -66,8 +67,7 @@ export const TableDetails = () => { if (error) { notification.error({ message: 'Error', - description: - 'An error occurred loading mappings. Please try again.', + description: 'An error occurred loading mappings.', }); } return error; From 903d94e919db1abb8b9e950bc8629d0d26cd5c60 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 10 Oct 2024 15:29:45 -0500 Subject: [PATCH 002/180] added fetch function for ols search --- .../MappingsFunctions/GetMappingsModal.jsx | 100 +++++++++++++----- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index f8219b3..010728f 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -146,32 +146,9 @@ export const GetMappingsModal = ({ }); }; - // The function that makes the API call to search for the passed code. - - const fetchResults = (page, query) => { - if (!!!query) { - return undefined; - } - setLoading(true); - /* The OLS API returns 10 results by default unless specified otherwise. The fetch call includes a specified - number of results to return per page (entriesPerPage) and a calculation of the first index to start the results - on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ - const pageStart = page * entriesPerPage; - const apiPreferenceOntologies = () => { - if (apiPreferences?.self?.api_preference?.ols) { - // Get the ontologies from the 'ols' array and join them with commas - const filteredOntologies = - apiPreferences.self.api_preference.ols.join(','); - console.log(filteredOntologies); - // Construct the final URL with the filteredOntologies - return filteredOntologies; - } else { - const defaultOntologies = 'mondo,hp,maxo,ncit'; - return defaultOntologies; - } - }; + const fetchFunction = (query, ontologiesToSearch, page, pageStart) => { return fetch( - `${searchUrl}q=${query}&ontology=${apiPreferenceOntologies()}&rows=${entriesPerPage}&start=${pageStart}`, + `${searchUrl}q=${query}&ontology=${ontologiesToSearch}&rows=${entriesPerPage}&start=${pageStart}`, { method: 'GET', headers: { @@ -211,6 +188,79 @@ export const GetMappingsModal = ({ .then(() => setLoading(false)); }; + // The function that makes the API call to search for the passed code. + + const fetchResults = (page, query) => { + if (!!!query) { + return undefined; + } + setLoading(true); + /* The OLS API returns 10 results by default unless specified otherwise. The fetch call includes a specified + number of results to return per page (entriesPerPage) and a calculation of the first index to start the results + on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ + const pageStart = page * entriesPerPage; + + if ( + apiPreferences?.self?.api_preference && + 'ols' in apiPreferences?.self?.api_preference + ) { + const apiPreferenceOntologies = () => { + if (apiPreferences?.self?.api_preference?.ols) { + // Get the ontologies from the 'ols' array and join them with commas + const filteredOntologies = + apiPreferences.self.api_preference.ols.join(','); + console.log(filteredOntologies); + // Construct the final URL with the filteredOntologies + return filteredOntologies; + } else { + const defaultOntologies = 'mondo,hp,maxo,ncit'; + return defaultOntologies; + } + }; + return fetchFunction(query, apiPreferenceOntologies(), page, pageStart); + } else { + return fetch( + `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + .then(res => res.json()) + .then(data => { + // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) + + let res = ontologyReducer(data?.response?.docs); + // if the page > 0 (i.e. if this is not the first batch of results), the new results + // are concatenated to the old + if (selectedBoxes) { + res.results = res.results.filter( + d => !selectedBoxes.some(box => box.obo_id === d.obo_id) + ); + } + + if (page > 0 && results.length > 0) { + res.results = results.concat(res.results); + + // Apply filtering to remove results with obo_id in selectedBoxes + } else { + // Set the total number of search results for pagination + setTotalCount(data.response.numFound); + } + + //the results are set to res (the filtered, concatenated results) + + setResults(res.results); + setFilteredResultsCount(res?.filteredResults?.length); + // resultsCount is set to the length of the filtered, concatenated results for pagination + setResultsCount(res.results.length); + }) + .then(() => setLoading(false)); + } + }; + // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. const handleViewMore = e => { e.preventDefault(); From 156100e097f9bb4c5d346c2673bd998ae91e6f8c Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 14 Oct 2024 20:42:00 -0500 Subject: [PATCH 003/180] OLS ontology filters for mapping search --- src/App.jsx | 2 + src/components/Manager/FetchManager.jsx | 58 ++++++++ .../MappingsFunctions/GetMappingsModal.jsx | 132 +++++------------- .../Projects/Terminologies/Terminology.scss | 1 + 4 files changed, 99 insertions(+), 94 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index e036201..f581e8d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -7,6 +7,7 @@ export const myContext = createContext(); function App() { const searchUrl = import.meta.env.VITE_SEARCH_ENDPOINT; + const monarchUrl = import.meta.env.VITE_MONARCH_SEARCH; const vocabUrl = import.meta.env.VITE_VOCAB_ENDPOINT; const clientId = import.meta.env.VITE_CLIENT_ID; @@ -47,6 +48,7 @@ function App() { results, setResults, searchUrl, + monarchUrl, vocabUrl, tablesDD, setTablesDD, diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index 1b5e44e..fc5f4a6 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -1,3 +1,5 @@ +import { ontologyReducer } from './Utilitiy'; + // Fetches all elements at an endpoint export const getAll = (vocabUrl, name, navigate) => { return fetch(`${vocabUrl}/${name}`, { @@ -165,3 +167,59 @@ export const getOntologies = vocabUrl => { } }); }; + +export const olsFilterOntologiesSearch = ( + searchUrl, + query, + ontologiesToSearch, + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading +) => { + setLoading(true); + return fetch( + `${searchUrl}q=${query}&ontology=${ontologiesToSearch}&rows=${entriesPerPage}&start=${pageStart}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + .then(res => res.json()) + .then(data => { + // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) + + let res = ontologyReducer(data?.response?.docs); + // if the page > 0 (i.e. if this is not the first batch of results), the new results + // are concatenated to the old + if (selectedBoxes) { + res.results = res.results.filter( + d => !selectedBoxes.some(box => box.obo_id === d.obo_id) + ); + } + + if (page > 0 && results.length > 0) { + res.results = results.concat(res.results); + + // Apply filtering to remove results with obo_id in selectedBoxes + } else { + // Set the total number of search results for pagination + setTotalCount(data.response.numFound); + } + + //the results are set to res (the filtered, concatenated results) + + setResults(res.results); + setFilteredResultsCount(res?.filteredResults?.length); + // resultsCount is set to the length of the filtered, concatenated results for pagination + setResultsCount(res.results.length); + }) + .then(() => setLoading(false)); +}; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 010728f..e54b6f5 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -5,6 +5,8 @@ import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; +import { olsFilterOntologiesSearch } from '../FetchManager'; +import { defaultIconPrefixCls } from 'antd/es/config-provider'; export const GetMappingsModal = ({ componentString, @@ -21,8 +23,9 @@ export const GetMappingsModal = ({ const { apiPreferences } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(false); const [results, setResults] = useState([]); + const [monarchResults, setMonarchResults] = useState([]); const [totalCount, setTotalCount] = useState(); const [resultsCount, setResultsCount] = useState(); const [lastCount, setLastCount] = useState(0); //save last count as count of the results before you fetch data again @@ -38,6 +41,7 @@ export const GetMappingsModal = ({ setSelectedBoxes, } = useContext(MappingContext); let ref = useRef(); + const defaultOntologies = 'mondo,hp,maxo,ncit'; // since the code is passed through searchProp, the '!!' forces it to be evaluated as a boolean. // if there is a searchProp being passed, it evaluates to true and runs the search function. @@ -146,121 +150,61 @@ export const GetMappingsModal = ({ }); }; - const fetchFunction = (query, ontologiesToSearch, page, pageStart) => { - return fetch( - `${searchUrl}q=${query}&ontology=${ontologiesToSearch}&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) - - let res = ontologyReducer(data?.response?.docs); - // if the page > 0 (i.e. if this is not the first batch of results), the new results - // are concatenated to the old - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - - if (page > 0 && results.length > 0) { - res.results = results.concat(res.results); - - // Apply filtering to remove results with obo_id in selectedBoxes - } else { - // Set the total number of search results for pagination - setTotalCount(data.response.numFound); - } - - //the results are set to res (the filtered, concatenated results) - - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - // resultsCount is set to the length of the filtered, concatenated results for pagination - setResultsCount(res.results.length); - }) - .then(() => setLoading(false)); - }; - // The function that makes the API call to search for the passed code. const fetchResults = (page, query) => { if (!!!query) { return undefined; } - setLoading(true); /* The OLS API returns 10 results by default unless specified otherwise. The fetch call includes a specified number of results to return per page (entriesPerPage) and a calculation of the first index to start the results on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ const pageStart = page * entriesPerPage; if ( + //If there are api preferences and one of them is OLS, it gets the preferred ontologies apiPreferences?.self?.api_preference && 'ols' in apiPreferences?.self?.api_preference ) { const apiPreferenceOntologies = () => { if (apiPreferences?.self?.api_preference?.ols) { - // Get the ontologies from the 'ols' array and join them with commas - const filteredOntologies = - apiPreferences.self.api_preference.ols.join(','); - console.log(filteredOntologies); - // Construct the final URL with the filteredOntologies - return filteredOntologies; + return apiPreferences.self.api_preference.ols.join(','); } else { - const defaultOntologies = 'mondo,hp,maxo,ncit'; + // else if there are no preferred ontologies, it uses the default ontologies return defaultOntologies; } }; - return fetchFunction(query, apiPreferenceOntologies(), page, pageStart); - } else { - return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) - - let res = ontologyReducer(data?.response?.docs); - // if the page > 0 (i.e. if this is not the first batch of results), the new results - // are concatenated to the old - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - - if (page > 0 && results.length > 0) { - res.results = results.concat(res.results); - - // Apply filtering to remove results with obo_id in selectedBoxes - } else { - // Set the total number of search results for pagination - setTotalCount(data.response.numFound); - } - - //the results are set to res (the filtered, concatenated results) - - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - // resultsCount is set to the length of the filtered, concatenated results for pagination - setResultsCount(res.results.length); - }) - .then(() => setLoading(false)); - } + //fetch call to search OLS with either preferred or default ontologies + return olsFilterOntologiesSearch( + searchUrl, + query, + apiPreferenceOntologies(), + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); + } else + return olsFilterOntologiesSearch( + searchUrl, + query, + defaultOntologies, + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); }; - // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. const handleViewMore = e => { e.preventDefault(); diff --git a/src/components/Projects/Terminologies/Terminology.scss b/src/components/Projects/Terminologies/Terminology.scss index b640fcb..09485e7 100644 --- a/src/components/Projects/Terminologies/Terminology.scss +++ b/src/components/Projects/Terminologies/Terminology.scss @@ -108,6 +108,7 @@ .modal_search_result { display: flex; + flex-direction: column; align-items: center; justify-content: space-between; margin: 0 10px 10px 6px; From 27ff5feb41c36b090c9e22987d7c9bf105556aec Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 15 Oct 2024 13:21:42 -0500 Subject: [PATCH 004/180] first pass at editing ontology filters --- .../Manager/MappingsFunctions/FilterAPI.jsx | 2 + .../MappingsFunctions/FilterOntology.jsx | 108 +++++++++++++++--- .../MappingsFunctions/FilterSelect.jsx | 40 +++++-- 3 files changed, 123 insertions(+), 27 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index b3a0941..70e5d4a 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -22,6 +22,7 @@ export const FilterAPI = ({ pageSize, setPageSize, paginatedOntologies, + apiPreferences, }) => { const { Search } = Input; @@ -126,6 +127,7 @@ export const FilterAPI = ({ pageSize={pageSize} setPageSize={setPageSize} paginatedOntologies={paginatedOntologies} + apiPreferences={apiPreferences} /> )} diff --git a/src/components/Manager/MappingsFunctions/FilterOntology.jsx b/src/components/Manager/MappingsFunctions/FilterOntology.jsx index 327f1cd..27cb521 100644 --- a/src/components/Manager/MappingsFunctions/FilterOntology.jsx +++ b/src/components/Manager/MappingsFunctions/FilterOntology.jsx @@ -12,6 +12,7 @@ export const FilterOntology = ({ setDisplaySelectedOntologies, searchText, paginatedOntologies, + apiPreferences, }) => { const [allCheckboxes, setAllCheckboxes] = useState([]); const { ontologyForPagination, setOntologyForPagination } = @@ -110,28 +111,100 @@ export const FilterOntology = ({ ); }; + const existingDisplay = (ont, i) => { + return ( + <> +
+
+
+
{ont.ontology.toUpperCase()}
+
+
+
+ + ); + }; + + const existingFilters = Object.values(apiPreferences?.self || {}).flat(); + + const flattenedFilters = existingFilters + .flatMap(item => + Object.keys(item).map(key => + item[key].map(value => ({ + api: key, + ontology: value, + })) + ) + ) + .flat(); + + const initialChecked = flattenedFilters?.map(ef => + JSON.stringify({ + ontology: ef, + }) + ); return ( <>
+ {Object.keys(apiPreferences?.self?.api_preference || {}).some( + key => apiPreferences?.self?.api_preference[key]?.length > 0 + ) && ( + <> +

Ontology Filters

+ + {flattenedFilters?.length > 0 ? ( + { + return { + value: JSON.stringify({ + ontology: po, + }), + label: existingDisplay(po, index), + }; + })} + /> + ) : ( + '' + )} + + + )} {displaySelectedOntologies.length > 0 && ( - -
- {displaySelectedOntologies?.map((selected, i) => ( - box?.ontology_code === selected?.ontology_code - )} - value={selected} - onChange={e => onCheckboxChange(e, selected)} - > - {selectedOntDisplay(selected, i)} - - ))} -
-
+ <> +

Selected

+ +
+ {displaySelectedOntologies?.map((selected, i) => ( + box?.ontology_code === selected?.ontology_code + )} + value={selected} + onChange={e => onCheckboxChange(e, selected)} + > + {selectedOntDisplay(selected, i)} + + ))} +
+
+ )} + {(Object.keys(apiPreferences?.self?.api_preference || {}).some( + key => apiPreferences?.self?.api_preference[key]?.length > 0 + ) || + displaySelectedOntologies.length > 0) &&

Ontologies

} !displaySelectedOntologies.some( dsm => checkbox.ontology_code === dsm.ontology_code + ) && + !flattenedFilters.some( + ef => checkbox.ontology_code === ef.ontology ) ) .map((ont, i) => ({ diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index 7063a65..f7364e9 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -63,7 +63,6 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { // If the api doesn't exist in api_preference, creates an empty array for it // If the api_preference array for the api does not include an ontology_code, pushes the code to the array for the api // If there is an api in api_preferences that is not included with the ontology_code, it's added to apiPreference with an empty array - const handleSubmit = values => { // setLoading(true); const apiPreference = { @@ -71,7 +70,8 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { }; if (values?.ontologies?.length > 0) { - values?.ontologies.forEach(({ ontology_code, api }) => { + // If there are ontologies, populate apiPreference with them + values.ontologies.forEach(({ ontology_code, api }) => { if (!apiPreference.api_preference[api]) { apiPreference.api_preference[api] = []; } @@ -80,28 +80,45 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { } }); } else { - values?.selected_apis.forEach(item => { + // If no ontologies are provided, initialize api preferences from selected_apis + values?.selected_apis?.forEach(item => { const apiObj = JSON.parse(item); const apiName = apiObj.api_preference; apiPreference.api_preference[apiName] = []; // Create an empty array for each api_preference }); } - values?.selected_apis?.forEach(item => { - const apiObj = JSON.parse(item); - const apiName = apiObj.api_preference; - if (!apiPreference.api_preference[apiName]) { - apiPreference.api_preference[apiName] = []; - } - }); + // Now handle the existing_filters + if (values?.existing_filters?.length > 0) { + values.existing_filters.forEach(item => { + const apiObj = JSON.parse(item); // Parse the JSON string + const apiName = apiObj.ontology.api; // Extract the API + const ontologyCode = apiObj.ontology.ontology; // Extract the ontology code + + // Ensure the apiName exists in apiPreference.api_preference + if (!apiPreference.api_preference[apiName]) { + apiPreference.api_preference[apiName] = []; // Initialize if not already present + } + + // Add the ontologyCode to the corresponding api, if it's not already included + if (!apiPreference.api_preference[apiName].includes(ontologyCode)) { + apiPreference.api_preference[apiName].push(ontologyCode); + } + }); + } const apiPreferenceDTO = { api_preference: apiPreference?.api_preference, editor: user.email, }; + const method = + Object.keys(apiPreferences?.self?.api_preference || {}).length === 0 + ? 'POST' + : 'PUT'; + fetch(`${vocabUrl}/${table?.terminology?.reference}/filter`, { - method: 'POST', + method: method, headers: { 'Content-Type': 'application/json', }, @@ -259,6 +276,7 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { pageSize={pageSize} setPageSize={setPageSize} paginatedOntologies={paginatedOntologies} + apiPreferences={apiPreferences} /> From 970dee2b88d34eb80c576b9791e7a57c2a655554 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 15 Oct 2024 14:31:06 -0500 Subject: [PATCH 005/180] Delete preferred ontologies --- .../Manager/MappingsFunctions/FilterAPI.jsx | 2 + .../MappingsFunctions/FilterOntology.jsx | 6 +- .../Manager/MappingsFunctions/FilterReset.jsx | 62 +++++++++++++ .../MappingsFunctions/FilterSelect.jsx | 1 + .../MappingsFunctions/GetMappingsModal.jsx | 3 +- .../MappingsFunctions/MappingReset.jsx | 88 +++++++++---------- .../MappingsFunctions/MappingSearch.jsx | 88 ++++++++++--------- .../MappingsFunctions/MappingsFunctions.scss | 7 ++ 8 files changed, 167 insertions(+), 90 deletions(-) create mode 100644 src/components/Manager/MappingsFunctions/FilterReset.jsx diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 70e5d4a..92c3f24 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -23,6 +23,7 @@ export const FilterAPI = ({ setPageSize, paginatedOntologies, apiPreferences, + table, }) => { const { Search } = Input; @@ -128,6 +129,7 @@ export const FilterAPI = ({ setPageSize={setPageSize} paginatedOntologies={paginatedOntologies} apiPreferences={apiPreferences} + table={table} /> )}
diff --git a/src/components/Manager/MappingsFunctions/FilterOntology.jsx b/src/components/Manager/MappingsFunctions/FilterOntology.jsx index 27cb521..9ed6e40 100644 --- a/src/components/Manager/MappingsFunctions/FilterOntology.jsx +++ b/src/components/Manager/MappingsFunctions/FilterOntology.jsx @@ -1,6 +1,7 @@ import { Checkbox, Form, Pagination } from 'antd'; import { useContext, useEffect, useState } from 'react'; import { myContext } from '../../../App'; +import { FilterReset } from './FilterReset'; export const FilterOntology = ({ ontology, @@ -13,6 +14,7 @@ export const FilterOntology = ({ searchText, paginatedOntologies, apiPreferences, + table, }) => { const [allCheckboxes, setAllCheckboxes] = useState([]); const { ontologyForPagination, setOntologyForPagination } = @@ -151,7 +153,9 @@ export const FilterOntology = ({ key => apiPreferences?.self?.api_preference[key]?.length > 0 ) && ( <> -

Ontology Filters

+
+

Ontology Filters

+
{ + const { confirm } = Modal; + + const { user, vocabUrl } = useContext(myContext); + const { setApiPreferences } = useContext(SearchContext); + const [remove, setRemove] = useState(false); + + const deleteOntologies = evt => { + return fetch(`${vocabUrl}/${table?.terminology?.reference}/filter`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ editor: user.email }), + }) + .then(res => { + if (res.ok) { + return res.json().then(data => { + message.success('Ontology filters deleted successfully.'); + }); + } else { + notification.error({ + message: 'Error', + description: 'An error occurred deleting the table.', + }); + } + }) + .then(data => setApiPreferences(data)); + }; + + const showConfirm = () => { + confirm({ + className: 'delete_table_confirm', + title: 'Alert', + icon: , + content: + ' Are you sure you want to remove the ontology filters?', + onOk() { + deleteOntologies(); + setRemove(false); + }, + onCancel() { + setRemove(false); + }, + }); + }; + + return ( + <> + + {remove && showConfirm()} + + ); +}; diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index f7364e9..ace5cc0 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -277,6 +277,7 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { setPageSize={setPageSize} paginatedOntologies={paginatedOntologies} apiPreferences={apiPreferences} + table={table} /> diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index e54b6f5..05087a3 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -1,12 +1,11 @@ import { Checkbox, Input, message, Modal, Form, Tooltip } from 'antd'; import { useContext, useEffect, useRef, useState } from 'react'; import { myContext } from '../../../App'; -import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; +import { ellipsisString, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; import { olsFilterOntologiesSearch } from '../FetchManager'; -import { defaultIconPrefixCls } from 'antd/es/config-provider'; export const GetMappingsModal = ({ componentString, diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index dc9c75b..68901e7 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -4,6 +4,8 @@ import { myContext } from '../../../App'; import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; +import { olsFilterOntologiesSearch } from '../FetchManager'; +import { SearchContext } from '../../../Contexts/SearchContext'; export const MappingReset = ({ searchProp, @@ -12,6 +14,7 @@ export const MappingReset = ({ onClose, }) => { const { searchUrl } = useContext(myContext); + const { apiPreferences } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -103,52 +106,49 @@ export const MappingReset = ({ number of results to return per page (entriesPerPage) and a calculation of the first index to start the results on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ const pageStart = page * entriesPerPage; - return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) - let res = ontologyReducer(data?.response?.docs); - - // Filters out results that have already been selected in previous search if there is a change to the search term - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - - // if the page > 0 (i.e. if this is not the first batch of results), the new results - // are concatenated to the old - if (page > 0 && results.length > 0) { - res.results = results.concat(res.results); + if ( + //If there are api preferences and one of them is OLS, it gets the preferred ontologies + apiPreferences?.self?.api_preference && + 'ols' in apiPreferences?.self?.api_preference + ) { + const apiPreferenceOntologies = () => { + if (apiPreferences?.self?.api_preference?.ols) { + return apiPreferences.self.api_preference.ols.join(','); } else { - // the total number of search results are set to totalCount for pagination - setTotalCount(data.response.numFound); - } - //the results are set to res (the filtered, concatenated results) - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - - // resultsCount is set to the length of the filtered, concatenated results for pagination - setResultsCount(res.results.length); - }) - .catch(error => { - if (error) { - notification.error({ - message: 'Error', - description: 'An error occurred. Please try again.', - }); + // else if there are no preferred ontologies, it uses the default ontologies + return defaultOntologies; } - return error; - }) - .finally(() => setLoading(false)); + }; + //fetch call to search OLS with either preferred or default ontologies + return olsFilterOntologiesSearch( + searchUrl, + query, + apiPreferenceOntologies(), + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); + } else + return olsFilterOntologiesSearch( + searchUrl, + query, + defaultOntologies, + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); }; // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 80585e8..332083c 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -4,6 +4,8 @@ import { myContext } from '../../../App'; import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; +import { SearchContext } from '../../../Contexts/SearchContext'; +import { olsFilterOntologiesSearch } from '../FetchManager'; export const MappingSearch = ({ setEditMappings, @@ -13,6 +15,8 @@ export const MappingSearch = ({ searchProp, }) => { const { searchUrl } = useContext(myContext); + const { apiPreferences } = useContext(SearchContext); + const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -105,51 +109,49 @@ export const MappingSearch = ({ number of results to return per page (entriesPerPage) and a calculation of the first index to start the results on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ const pageStart = page * entriesPerPage; - return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) - let res = ontologyReducer(data?.response?.docs); - - // Filters out results that have already been selected in previous search if there is a change to the search term - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - // if the page > 0 (i.e. if this is not the first batch of results), the new results - // are concatenated to the old - if (page > 0 && results.length > 0) { - res.results = results.concat(res.results); + if ( + //If there are api preferences and one of them is OLS, it gets the preferred ontologies + apiPreferences?.self?.api_preference && + 'ols' in apiPreferences?.self?.api_preference + ) { + const apiPreferenceOntologies = () => { + if (apiPreferences?.self?.api_preference?.ols) { + return apiPreferences.self.api_preference.ols.join(','); } else { - // the total number of search results are set to totalCount for pagination - setTotalCount(data.response.numFound); - } - //the results are set to res (the filtered, concatenated results) - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - - // resultsCount is set to the length of the filtered, concatenated results for pagination - setResultsCount(res.results.length); - }) - .catch(error => { - if (error) { - notification.error({ - message: 'Error', - description: 'An error occurred. Please try again.', - }); + // else if there are no preferred ontologies, it uses the default ontologies + return defaultOntologies; } - return error; - }) - .finally(() => setLoading(false)); + }; + //fetch call to search OLS with either preferred or default ontologies + return olsFilterOntologiesSearch( + searchUrl, + query, + apiPreferenceOntologies(), + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); + } else + return olsFilterOntologiesSearch( + searchUrl, + query, + defaultOntologies, + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); }; // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. diff --git a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss index fa074f2..a4a8d45 100644 --- a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss +++ b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss @@ -78,3 +78,10 @@ width: 50vw; justify-content: center; } + +.onto_reset { + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; +} From b0519ecadfe6adbef85b3f9307471fd20c81c0dc Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 15 Oct 2024 16:06:35 -0500 Subject: [PATCH 006/180] committing to switch branches --- src/components/Manager/MappingsFunctions/FilterReset.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Manager/MappingsFunctions/FilterReset.jsx b/src/components/Manager/MappingsFunctions/FilterReset.jsx index f5349a8..ac37e40 100644 --- a/src/components/Manager/MappingsFunctions/FilterReset.jsx +++ b/src/components/Manager/MappingsFunctions/FilterReset.jsx @@ -54,7 +54,7 @@ export const FilterReset = ({ table }) => { return ( <> {remove && showConfirm()} From 36970255b6560efcdf25d64b5e0fe75bddb44802 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 16 Oct 2024 11:23:45 -0500 Subject: [PATCH 007/180] Newly added ontologies checking by default on load --- .../Manager/MappingsFunctions/FilterAPI.jsx | 2 +- .../MappingsFunctions/FilterSelect.jsx | 128 +++++++++--------- 2 files changed, 66 insertions(+), 64 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 92c3f24..1a63182 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -91,7 +91,7 @@ export const FilterAPI = ({ ) : (
-
+
APIs
diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index ace5cc0..c194961 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -214,72 +214,74 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { > API Filters {apiPrefObject ? `(${apiPrefLength})` : ''} - { - form.validateFields().then(values => { - handleSubmit(values); + {addFilter && ( + { + form.validateFields().then(values => { + handleSubmit(values); + onClose(); + }); + }} + onCancel={() => { + form.resetFields(); + setAddFilter(false); onClose(); - }); - }} - onCancel={() => { - form.resetFields(); - setAddFilter(false); - onClose(); - }} - maskClosable={false} - closeIcon={false} - footer={(_, { OkBtn, CancelBtn }) => ( - <> -
+ }} + maskClosable={false} + closeIcon={false} + footer={(_, { OkBtn, CancelBtn }) => ( + <>
- -
-
- - +
+ +
+
+ + +
-
- - )} - > - -
+ + )} + > + +
+ )} ); }; From a3bdbe2a240355cc3e7de61a21339bcf5da59b87 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 16 Oct 2024 15:56:56 -0500 Subject: [PATCH 008/180] ontology filter for mappings search --- src/Contexts/SearchContext.jsx | 2 + src/components/Manager/FetchManager.jsx | 3 +- .../Manager/MappingsFunctions/FilterAPI.jsx | 42 +++++++++++++--- .../MappingsFunctions/FilterSelect.jsx | 49 ++++++++++--------- .../MappingsFunctions/GetMappingsModal.jsx | 12 +++-- .../MappingsFunctions/MappingReset.jsx | 8 +-- .../MappingsFunctions/MappingSearch.jsx | 8 +-- src/components/Nav/NavBar.jsx | 4 +- .../Projects/Tables/TableDetails.jsx | 13 +++++ 9 files changed, 100 insertions(+), 41 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index e90d907..a8d1d27 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -13,6 +13,7 @@ export function SearchContextRoot() { const [apiPage, setApiPage] = useState(0); const [apiTotalCount, setApiTotalCount] = useState(); const [apiPreferences, setApiPreferences] = useState({}); + const defaultOntologies = 'mondo,hp,maxo,ncit'; const context = { prefTerminologies, @@ -33,6 +34,7 @@ export function SearchContextRoot() { setApiTotalCount, apiPreferences, setApiPreferences, + defaultOntologies, }; return ( diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index fc5f4a6..6b436c9 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -180,7 +180,8 @@ export const olsFilterOntologiesSearch = ( setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ) => { setLoading(true); return fetch( diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 1a63182..946f435 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from 'react'; -import { Checkbox, Form, Input } from 'antd'; +import { Checkbox, Form } from 'antd'; import { ModalSpinner, OntologySpinner } from '../Spinner'; import { myContext } from '../../../App'; import { FilterOntology } from './FilterOntology'; @@ -16,7 +16,6 @@ export const FilterAPI = ({ active, setActive, searchText, - setSearchText, currentPage, setCurrentPage, pageSize, @@ -25,13 +24,32 @@ export const FilterAPI = ({ apiPreferences, table, }) => { - const { Search } = Input; - const { vocabUrl } = useContext(myContext); const [ontology, setOntology] = useState([]); const [loading, setLoading] = useState(false); const [tableLoading, setTableLoading] = useState(false); + // The selected ontology filters that have already been selected + const existingFilters = Object.values(apiPreferences?.self || {}).flat(); + + // Flattens the existingFilters into a single array + const flattenedFilters = existingFilters + .flatMap(item => + Object.keys(item).map(key => + item[key].map(value => ({ + api: key, + })) + ) + ) + .flat(); + + // The initial value for the form. The checkboxes for the filters that have already been selected will be checked by default + const initialChecked = flattenedFilters?.map(ef => + JSON.stringify({ + ontology: ef, + }) + ); + // Fetches the active ontologyAPI each time the active API changes useEffect(() => { active && getOntologyApiById(); @@ -56,7 +74,20 @@ export const FilterAPI = ({ } }) .then(data => { - setOntology(data); + //Alphabetizes the data + const sortedData = data.map(api => { + const sortedOntologies = Object.fromEntries( + Object.entries(api.ontologies).sort((a, b) => + a[1].ontology_code > b[1].ontology_code ? 1 : -1 + ) + ); + + return { + ...api, + ontologies: sortedOntologies, + }; + }); + setOntology(sortedData); }) .finally(() => setTableLoading(false)) ); @@ -85,7 +116,6 @@ export const FilterAPI = ({ ); }; - return loading ? ( ) : ( diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index c194961..538f380 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -4,6 +4,7 @@ import { useContext, useEffect, useState } from 'react'; import { myContext } from '../../../App'; import { FilterAPI } from './FilterAPI'; import { getOntologies } from '../FetchManager'; +import { ModalSpinner } from '../Spinner'; export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { const [form] = Form.useForm(); @@ -64,7 +65,7 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { // If the api_preference array for the api does not include an ontology_code, pushes the code to the array for the api // If there is an api in api_preferences that is not included with the ontology_code, it's added to apiPreference with an empty array const handleSubmit = values => { - // setLoading(true); + setLoading(true); const apiPreference = { api_preference: {}, }; @@ -259,27 +260,31 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { )} > - + {loading ? ( + + ) : ( + + )} )} diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 05087a3..d079feb 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -19,7 +19,7 @@ export const GetMappingsModal = ({ const { Search } = Input; const { searchUrl, vocabUrl, setSelectedKey, user } = useContext(myContext); - const { apiPreferences } = useContext(SearchContext); + const { apiPreferences, defaultOntologies } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(false); @@ -40,7 +40,6 @@ export const GetMappingsModal = ({ setSelectedBoxes, } = useContext(MappingContext); let ref = useRef(); - const defaultOntologies = 'mondo,hp,maxo,ncit'; // since the code is passed through searchProp, the '!!' forces it to be evaluated as a boolean. // if there is a searchProp being passed, it evaluates to true and runs the search function. @@ -186,7 +185,8 @@ export const GetMappingsModal = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); } else return olsFilterOntologiesSearch( @@ -201,7 +201,8 @@ export const GetMappingsModal = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); }; // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. @@ -423,6 +424,9 @@ export const GetMappingsModal = ({ Displaying {resultsCount}  of {totalCount} + {console.log('total', totalCount)} + {console.log('filtered', filteredResultsCount)} + {console.log('results', filteredResultsCount)} {totalCount - filteredResultsCount !== resultsCount && ( { const { searchUrl } = useContext(myContext); - const { apiPreferences } = useContext(SearchContext); + const { apiPreferences, defaultOntologies } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -132,7 +132,8 @@ export const MappingReset = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); } else return olsFilterOntologiesSearch( @@ -147,7 +148,8 @@ export const MappingReset = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); }; diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 332083c..14724f1 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -15,7 +15,7 @@ export const MappingSearch = ({ searchProp, }) => { const { searchUrl } = useContext(myContext); - const { apiPreferences } = useContext(SearchContext); + const { apiPreferences, defaultOntologies } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; @@ -135,7 +135,8 @@ export const MappingSearch = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); } else return olsFilterOntologiesSearch( @@ -150,7 +151,8 @@ export const MappingSearch = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); }; diff --git a/src/components/Nav/NavBar.jsx b/src/components/Nav/NavBar.jsx index 13a0c11..80e39ff 100644 --- a/src/components/Nav/NavBar.jsx +++ b/src/components/Nav/NavBar.jsx @@ -27,11 +27,11 @@ export const NavBar = () => { {/* Placeholder elements below. No functionality at this time.*/} -
  • Help
  • +
  • About
  • -
  • About
  • +
  • Ontologies
  • diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 9bd6e05..863cb79 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -51,6 +51,19 @@ export const TableDetails = () => { setDataSource(tableData(table)); }, [table, mapping]); + const alphabetizeOntologies = ontologies => { + // Sort the keys alphabetically + const sortedKeys = Object.keys(ontologies).sort(); + + // Rebuild object using the sorted keys + const sortedOntologies = {}; + sortedKeys.forEach(key => { + sortedOntologies[key] = ontologies[key]; + }); + + return sortedOntologies; + }; + // fetches the table and sets 'table' to the response useEffect(() => { setLoading(true); From 642e2b1534282658db89b7dcc0149ffffaf734ee Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 16 Oct 2024 15:57:35 -0500 Subject: [PATCH 009/180] Removed unnecesary console logs --- src/components/Manager/MappingsFunctions/GetMappingsModal.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index d079feb..1451c01 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -424,9 +424,6 @@ export const GetMappingsModal = ({ Displaying {resultsCount}  of {totalCount} - {console.log('total', totalCount)} - {console.log('filtered', filteredResultsCount)} - {console.log('results', filteredResultsCount)} {totalCount - filteredResultsCount !== resultsCount && ( Date: Thu, 10 Oct 2024 13:11:09 -0500 Subject: [PATCH 010/180] OLS search for filtered ontologies --- src/Contexts/SearchContext.jsx | 3 ++ .../MappingsFunctions/DefaultSearch.jsx | 52 +++++++++++++++++++ .../MappingsFunctions/GetMappingsModal.jsx | 17 +++++- .../Projects/Tables/TableDetails.jsx | 6 +-- 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/components/Manager/MappingsFunctions/DefaultSearch.jsx diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index 909846e..e90d907 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -12,6 +12,7 @@ export function SearchContextRoot() { const [apiResultsCount, setApiResultsCount] = useState(); const [apiPage, setApiPage] = useState(0); const [apiTotalCount, setApiTotalCount] = useState(); + const [apiPreferences, setApiPreferences] = useState({}); const context = { prefTerminologies, @@ -30,6 +31,8 @@ export function SearchContextRoot() { setApiPage, apiTotalCount, setApiTotalCount, + apiPreferences, + setApiPreferences, }; return ( diff --git a/src/components/Manager/MappingsFunctions/DefaultSearch.jsx b/src/components/Manager/MappingsFunctions/DefaultSearch.jsx new file mode 100644 index 0000000..ef91ae6 --- /dev/null +++ b/src/components/Manager/MappingsFunctions/DefaultSearch.jsx @@ -0,0 +1,52 @@ +import { ontologyReducer } from '../Utilitiy'; + +export const fetchResults = ( + page, + query, + entriesPerPage, + // setLoading, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + searchUrl, + selectedBoxes +) => { + if (!query) { + return undefined; + } + // setLoading(true); + const pageStart = page * entriesPerPage; + + return fetch( + `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + .then(res => res.json()) + .then(data => { + let res = ontologyReducer(data?.response?.docs); + + // Filter based on selectedBoxes + if (selectedBoxes) { + res.results = res.results.filter( + d => !selectedBoxes.some(box => box.obo_id === d.obo_id) + ); + } + + if (page > 0 && res.results.length > 0) { + res.results = results.concat(res.results); + } else { + setTotalCount(data.response.numFound); + } + + setResults(res.results); + setFilteredResultsCount(res?.filteredResults?.length); + setResultsCount(res.results.length); + }); + // .finally(() => setLoading(false)); +}; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 3c56feb..f8219b3 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -4,6 +4,7 @@ import { myContext } from '../../../App'; import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; +import { SearchContext } from '../../../Contexts/SearchContext'; export const GetMappingsModal = ({ componentString, @@ -17,6 +18,7 @@ export const GetMappingsModal = ({ const { Search } = Input; const { searchUrl, vocabUrl, setSelectedKey, user } = useContext(myContext); + const { apiPreferences } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -155,8 +157,21 @@ export const GetMappingsModal = ({ number of results to return per page (entriesPerPage) and a calculation of the first index to start the results on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ const pageStart = page * entriesPerPage; + const apiPreferenceOntologies = () => { + if (apiPreferences?.self?.api_preference?.ols) { + // Get the ontologies from the 'ols' array and join them with commas + const filteredOntologies = + apiPreferences.self.api_preference.ols.join(','); + console.log(filteredOntologies); + // Construct the final URL with the filteredOntologies + return filteredOntologies; + } else { + const defaultOntologies = 'mondo,hp,maxo,ncit'; + return defaultOntologies; + } + }; return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, + `${searchUrl}q=${query}&ontology=${apiPreferenceOntologies()}&rows=${entriesPerPage}&start=${pageStart}`, { method: 'GET', headers: { diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 46b3597..9bd6e05 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -20,12 +20,14 @@ import { Submenu } from '../../Manager/Submenu'; import { SettingsDropdownTable } from '../../Manager/Dropdown/SettingsDropdownTable'; import { RequiredLogin } from '../../Auth/RequiredLogin'; import { FilterSelect } from '../../Manager/MappingsFunctions/FilterSelect'; +import { SearchContext } from '../../../Contexts/SearchContext'; export const TableDetails = () => { const [form] = Form.useForm(); const { vocabUrl, edit, setEdit, table, setTable, user } = useContext(myContext); + const { apiPreferences, setApiPreferences } = useContext(SearchContext); const { getMappings, setGetMappings, @@ -37,7 +39,6 @@ export const TableDetails = () => { const { studyId, DDId, tableId } = useParams(); const [loading, setLoading] = useState(true); const [load, setLoad] = useState(false); - const [apiPreferences, setApiPreferences] = useState({}); const navigate = useNavigate(); @@ -66,8 +67,7 @@ export const TableDetails = () => { if (error) { notification.error({ message: 'Error', - description: - 'An error occurred loading mappings. Please try again.', + description: 'An error occurred loading mappings.', }); } return error; From ada5d61ec4febf40440b2d5844f8b2ba3767579a Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 10 Oct 2024 15:29:45 -0500 Subject: [PATCH 011/180] added fetch function for ols search --- .../MappingsFunctions/GetMappingsModal.jsx | 100 +++++++++++++----- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index f8219b3..010728f 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -146,32 +146,9 @@ export const GetMappingsModal = ({ }); }; - // The function that makes the API call to search for the passed code. - - const fetchResults = (page, query) => { - if (!!!query) { - return undefined; - } - setLoading(true); - /* The OLS API returns 10 results by default unless specified otherwise. The fetch call includes a specified - number of results to return per page (entriesPerPage) and a calculation of the first index to start the results - on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ - const pageStart = page * entriesPerPage; - const apiPreferenceOntologies = () => { - if (apiPreferences?.self?.api_preference?.ols) { - // Get the ontologies from the 'ols' array and join them with commas - const filteredOntologies = - apiPreferences.self.api_preference.ols.join(','); - console.log(filteredOntologies); - // Construct the final URL with the filteredOntologies - return filteredOntologies; - } else { - const defaultOntologies = 'mondo,hp,maxo,ncit'; - return defaultOntologies; - } - }; + const fetchFunction = (query, ontologiesToSearch, page, pageStart) => { return fetch( - `${searchUrl}q=${query}&ontology=${apiPreferenceOntologies()}&rows=${entriesPerPage}&start=${pageStart}`, + `${searchUrl}q=${query}&ontology=${ontologiesToSearch}&rows=${entriesPerPage}&start=${pageStart}`, { method: 'GET', headers: { @@ -211,6 +188,79 @@ export const GetMappingsModal = ({ .then(() => setLoading(false)); }; + // The function that makes the API call to search for the passed code. + + const fetchResults = (page, query) => { + if (!!!query) { + return undefined; + } + setLoading(true); + /* The OLS API returns 10 results by default unless specified otherwise. The fetch call includes a specified + number of results to return per page (entriesPerPage) and a calculation of the first index to start the results + on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ + const pageStart = page * entriesPerPage; + + if ( + apiPreferences?.self?.api_preference && + 'ols' in apiPreferences?.self?.api_preference + ) { + const apiPreferenceOntologies = () => { + if (apiPreferences?.self?.api_preference?.ols) { + // Get the ontologies from the 'ols' array and join them with commas + const filteredOntologies = + apiPreferences.self.api_preference.ols.join(','); + console.log(filteredOntologies); + // Construct the final URL with the filteredOntologies + return filteredOntologies; + } else { + const defaultOntologies = 'mondo,hp,maxo,ncit'; + return defaultOntologies; + } + }; + return fetchFunction(query, apiPreferenceOntologies(), page, pageStart); + } else { + return fetch( + `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + .then(res => res.json()) + .then(data => { + // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) + + let res = ontologyReducer(data?.response?.docs); + // if the page > 0 (i.e. if this is not the first batch of results), the new results + // are concatenated to the old + if (selectedBoxes) { + res.results = res.results.filter( + d => !selectedBoxes.some(box => box.obo_id === d.obo_id) + ); + } + + if (page > 0 && results.length > 0) { + res.results = results.concat(res.results); + + // Apply filtering to remove results with obo_id in selectedBoxes + } else { + // Set the total number of search results for pagination + setTotalCount(data.response.numFound); + } + + //the results are set to res (the filtered, concatenated results) + + setResults(res.results); + setFilteredResultsCount(res?.filteredResults?.length); + // resultsCount is set to the length of the filtered, concatenated results for pagination + setResultsCount(res.results.length); + }) + .then(() => setLoading(false)); + } + }; + // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. const handleViewMore = e => { e.preventDefault(); From ede8b8c121581cf55e3368c191945c7a656ff56f Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 14 Oct 2024 20:42:00 -0500 Subject: [PATCH 012/180] OLS ontology filters for mapping search --- src/App.jsx | 2 + src/components/Manager/FetchManager.jsx | 58 ++++++++ .../MappingsFunctions/GetMappingsModal.jsx | 132 +++++------------- .../Projects/Terminologies/Terminology.scss | 1 + 4 files changed, 99 insertions(+), 94 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 64d3e56..2096b18 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -7,6 +7,7 @@ export const myContext = createContext(); function App() { const searchUrl = import.meta.env.VITE_SEARCH_ENDPOINT; + const monarchUrl = import.meta.env.VITE_MONARCH_SEARCH; const vocabUrl = import.meta.env.VITE_VOCAB_ENDPOINT; const clientId = import.meta.env.VITE_CLIENT_ID; @@ -47,6 +48,7 @@ function App() { results, setResults, searchUrl, + monarchUrl, vocabUrl, tablesDD, setTablesDD, diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index 1b5e44e..fc5f4a6 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -1,3 +1,5 @@ +import { ontologyReducer } from './Utilitiy'; + // Fetches all elements at an endpoint export const getAll = (vocabUrl, name, navigate) => { return fetch(`${vocabUrl}/${name}`, { @@ -165,3 +167,59 @@ export const getOntologies = vocabUrl => { } }); }; + +export const olsFilterOntologiesSearch = ( + searchUrl, + query, + ontologiesToSearch, + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading +) => { + setLoading(true); + return fetch( + `${searchUrl}q=${query}&ontology=${ontologiesToSearch}&rows=${entriesPerPage}&start=${pageStart}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + .then(res => res.json()) + .then(data => { + // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) + + let res = ontologyReducer(data?.response?.docs); + // if the page > 0 (i.e. if this is not the first batch of results), the new results + // are concatenated to the old + if (selectedBoxes) { + res.results = res.results.filter( + d => !selectedBoxes.some(box => box.obo_id === d.obo_id) + ); + } + + if (page > 0 && results.length > 0) { + res.results = results.concat(res.results); + + // Apply filtering to remove results with obo_id in selectedBoxes + } else { + // Set the total number of search results for pagination + setTotalCount(data.response.numFound); + } + + //the results are set to res (the filtered, concatenated results) + + setResults(res.results); + setFilteredResultsCount(res?.filteredResults?.length); + // resultsCount is set to the length of the filtered, concatenated results for pagination + setResultsCount(res.results.length); + }) + .then(() => setLoading(false)); +}; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 010728f..e54b6f5 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -5,6 +5,8 @@ import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; +import { olsFilterOntologiesSearch } from '../FetchManager'; +import { defaultIconPrefixCls } from 'antd/es/config-provider'; export const GetMappingsModal = ({ componentString, @@ -21,8 +23,9 @@ export const GetMappingsModal = ({ const { apiPreferences } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(false); const [results, setResults] = useState([]); + const [monarchResults, setMonarchResults] = useState([]); const [totalCount, setTotalCount] = useState(); const [resultsCount, setResultsCount] = useState(); const [lastCount, setLastCount] = useState(0); //save last count as count of the results before you fetch data again @@ -38,6 +41,7 @@ export const GetMappingsModal = ({ setSelectedBoxes, } = useContext(MappingContext); let ref = useRef(); + const defaultOntologies = 'mondo,hp,maxo,ncit'; // since the code is passed through searchProp, the '!!' forces it to be evaluated as a boolean. // if there is a searchProp being passed, it evaluates to true and runs the search function. @@ -146,121 +150,61 @@ export const GetMappingsModal = ({ }); }; - const fetchFunction = (query, ontologiesToSearch, page, pageStart) => { - return fetch( - `${searchUrl}q=${query}&ontology=${ontologiesToSearch}&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) - - let res = ontologyReducer(data?.response?.docs); - // if the page > 0 (i.e. if this is not the first batch of results), the new results - // are concatenated to the old - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - - if (page > 0 && results.length > 0) { - res.results = results.concat(res.results); - - // Apply filtering to remove results with obo_id in selectedBoxes - } else { - // Set the total number of search results for pagination - setTotalCount(data.response.numFound); - } - - //the results are set to res (the filtered, concatenated results) - - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - // resultsCount is set to the length of the filtered, concatenated results for pagination - setResultsCount(res.results.length); - }) - .then(() => setLoading(false)); - }; - // The function that makes the API call to search for the passed code. const fetchResults = (page, query) => { if (!!!query) { return undefined; } - setLoading(true); /* The OLS API returns 10 results by default unless specified otherwise. The fetch call includes a specified number of results to return per page (entriesPerPage) and a calculation of the first index to start the results on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ const pageStart = page * entriesPerPage; if ( + //If there are api preferences and one of them is OLS, it gets the preferred ontologies apiPreferences?.self?.api_preference && 'ols' in apiPreferences?.self?.api_preference ) { const apiPreferenceOntologies = () => { if (apiPreferences?.self?.api_preference?.ols) { - // Get the ontologies from the 'ols' array and join them with commas - const filteredOntologies = - apiPreferences.self.api_preference.ols.join(','); - console.log(filteredOntologies); - // Construct the final URL with the filteredOntologies - return filteredOntologies; + return apiPreferences.self.api_preference.ols.join(','); } else { - const defaultOntologies = 'mondo,hp,maxo,ncit'; + // else if there are no preferred ontologies, it uses the default ontologies return defaultOntologies; } }; - return fetchFunction(query, apiPreferenceOntologies(), page, pageStart); - } else { - return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) - - let res = ontologyReducer(data?.response?.docs); - // if the page > 0 (i.e. if this is not the first batch of results), the new results - // are concatenated to the old - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - - if (page > 0 && results.length > 0) { - res.results = results.concat(res.results); - - // Apply filtering to remove results with obo_id in selectedBoxes - } else { - // Set the total number of search results for pagination - setTotalCount(data.response.numFound); - } - - //the results are set to res (the filtered, concatenated results) - - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - // resultsCount is set to the length of the filtered, concatenated results for pagination - setResultsCount(res.results.length); - }) - .then(() => setLoading(false)); - } + //fetch call to search OLS with either preferred or default ontologies + return olsFilterOntologiesSearch( + searchUrl, + query, + apiPreferenceOntologies(), + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); + } else + return olsFilterOntologiesSearch( + searchUrl, + query, + defaultOntologies, + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); }; - // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. const handleViewMore = e => { e.preventDefault(); diff --git a/src/components/Projects/Terminologies/Terminology.scss b/src/components/Projects/Terminologies/Terminology.scss index b640fcb..09485e7 100644 --- a/src/components/Projects/Terminologies/Terminology.scss +++ b/src/components/Projects/Terminologies/Terminology.scss @@ -108,6 +108,7 @@ .modal_search_result { display: flex; + flex-direction: column; align-items: center; justify-content: space-between; margin: 0 10px 10px 6px; From 02fa958d6a5cf213c29eb78b23d1bd6bde24d108 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 15 Oct 2024 13:21:42 -0500 Subject: [PATCH 013/180] first pass at editing ontology filters --- .../Manager/MappingsFunctions/FilterAPI.jsx | 2 + .../MappingsFunctions/FilterOntology.jsx | 108 +++++++++++++++--- .../MappingsFunctions/FilterSelect.jsx | 40 +++++-- 3 files changed, 123 insertions(+), 27 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index b3a0941..70e5d4a 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -22,6 +22,7 @@ export const FilterAPI = ({ pageSize, setPageSize, paginatedOntologies, + apiPreferences, }) => { const { Search } = Input; @@ -126,6 +127,7 @@ export const FilterAPI = ({ pageSize={pageSize} setPageSize={setPageSize} paginatedOntologies={paginatedOntologies} + apiPreferences={apiPreferences} /> )}
    diff --git a/src/components/Manager/MappingsFunctions/FilterOntology.jsx b/src/components/Manager/MappingsFunctions/FilterOntology.jsx index 327f1cd..27cb521 100644 --- a/src/components/Manager/MappingsFunctions/FilterOntology.jsx +++ b/src/components/Manager/MappingsFunctions/FilterOntology.jsx @@ -12,6 +12,7 @@ export const FilterOntology = ({ setDisplaySelectedOntologies, searchText, paginatedOntologies, + apiPreferences, }) => { const [allCheckboxes, setAllCheckboxes] = useState([]); const { ontologyForPagination, setOntologyForPagination } = @@ -110,28 +111,100 @@ export const FilterOntology = ({ ); }; + const existingDisplay = (ont, i) => { + return ( + <> +
    +
    +
    +
    {ont.ontology.toUpperCase()}
    +
    +
    +
    + + ); + }; + + const existingFilters = Object.values(apiPreferences?.self || {}).flat(); + + const flattenedFilters = existingFilters + .flatMap(item => + Object.keys(item).map(key => + item[key].map(value => ({ + api: key, + ontology: value, + })) + ) + ) + .flat(); + + const initialChecked = flattenedFilters?.map(ef => + JSON.stringify({ + ontology: ef, + }) + ); return ( <>
    + {Object.keys(apiPreferences?.self?.api_preference || {}).some( + key => apiPreferences?.self?.api_preference[key]?.length > 0 + ) && ( + <> +

    Ontology Filters

    + + {flattenedFilters?.length > 0 ? ( + { + return { + value: JSON.stringify({ + ontology: po, + }), + label: existingDisplay(po, index), + }; + })} + /> + ) : ( + '' + )} + + + )} {displaySelectedOntologies.length > 0 && ( - -
    - {displaySelectedOntologies?.map((selected, i) => ( - box?.ontology_code === selected?.ontology_code - )} - value={selected} - onChange={e => onCheckboxChange(e, selected)} - > - {selectedOntDisplay(selected, i)} - - ))} -
    -
    + <> +

    Selected

    + +
    + {displaySelectedOntologies?.map((selected, i) => ( + box?.ontology_code === selected?.ontology_code + )} + value={selected} + onChange={e => onCheckboxChange(e, selected)} + > + {selectedOntDisplay(selected, i)} + + ))} +
    +
    + )} + {(Object.keys(apiPreferences?.self?.api_preference || {}).some( + key => apiPreferences?.self?.api_preference[key]?.length > 0 + ) || + displaySelectedOntologies.length > 0) &&

    Ontologies

    } !displaySelectedOntologies.some( dsm => checkbox.ontology_code === dsm.ontology_code + ) && + !flattenedFilters.some( + ef => checkbox.ontology_code === ef.ontology ) ) .map((ont, i) => ({ diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index 7063a65..f7364e9 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -63,7 +63,6 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { // If the api doesn't exist in api_preference, creates an empty array for it // If the api_preference array for the api does not include an ontology_code, pushes the code to the array for the api // If there is an api in api_preferences that is not included with the ontology_code, it's added to apiPreference with an empty array - const handleSubmit = values => { // setLoading(true); const apiPreference = { @@ -71,7 +70,8 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { }; if (values?.ontologies?.length > 0) { - values?.ontologies.forEach(({ ontology_code, api }) => { + // If there are ontologies, populate apiPreference with them + values.ontologies.forEach(({ ontology_code, api }) => { if (!apiPreference.api_preference[api]) { apiPreference.api_preference[api] = []; } @@ -80,28 +80,45 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { } }); } else { - values?.selected_apis.forEach(item => { + // If no ontologies are provided, initialize api preferences from selected_apis + values?.selected_apis?.forEach(item => { const apiObj = JSON.parse(item); const apiName = apiObj.api_preference; apiPreference.api_preference[apiName] = []; // Create an empty array for each api_preference }); } - values?.selected_apis?.forEach(item => { - const apiObj = JSON.parse(item); - const apiName = apiObj.api_preference; - if (!apiPreference.api_preference[apiName]) { - apiPreference.api_preference[apiName] = []; - } - }); + // Now handle the existing_filters + if (values?.existing_filters?.length > 0) { + values.existing_filters.forEach(item => { + const apiObj = JSON.parse(item); // Parse the JSON string + const apiName = apiObj.ontology.api; // Extract the API + const ontologyCode = apiObj.ontology.ontology; // Extract the ontology code + + // Ensure the apiName exists in apiPreference.api_preference + if (!apiPreference.api_preference[apiName]) { + apiPreference.api_preference[apiName] = []; // Initialize if not already present + } + + // Add the ontologyCode to the corresponding api, if it's not already included + if (!apiPreference.api_preference[apiName].includes(ontologyCode)) { + apiPreference.api_preference[apiName].push(ontologyCode); + } + }); + } const apiPreferenceDTO = { api_preference: apiPreference?.api_preference, editor: user.email, }; + const method = + Object.keys(apiPreferences?.self?.api_preference || {}).length === 0 + ? 'POST' + : 'PUT'; + fetch(`${vocabUrl}/${table?.terminology?.reference}/filter`, { - method: 'POST', + method: method, headers: { 'Content-Type': 'application/json', }, @@ -259,6 +276,7 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { pageSize={pageSize} setPageSize={setPageSize} paginatedOntologies={paginatedOntologies} + apiPreferences={apiPreferences} /> From 77dbfe353282cdfa6a11fad56b50bb506b194b6b Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 15 Oct 2024 14:31:06 -0500 Subject: [PATCH 014/180] Delete preferred ontologies --- .../Manager/MappingsFunctions/FilterAPI.jsx | 2 + .../MappingsFunctions/FilterOntology.jsx | 6 +- .../Manager/MappingsFunctions/FilterReset.jsx | 62 +++++++++++++ .../MappingsFunctions/FilterSelect.jsx | 1 + .../MappingsFunctions/GetMappingsModal.jsx | 3 +- .../MappingsFunctions/MappingReset.jsx | 88 +++++++++---------- .../MappingsFunctions/MappingSearch.jsx | 88 ++++++++++--------- .../MappingsFunctions/MappingsFunctions.scss | 7 ++ 8 files changed, 167 insertions(+), 90 deletions(-) create mode 100644 src/components/Manager/MappingsFunctions/FilterReset.jsx diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 70e5d4a..92c3f24 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -23,6 +23,7 @@ export const FilterAPI = ({ setPageSize, paginatedOntologies, apiPreferences, + table, }) => { const { Search } = Input; @@ -128,6 +129,7 @@ export const FilterAPI = ({ setPageSize={setPageSize} paginatedOntologies={paginatedOntologies} apiPreferences={apiPreferences} + table={table} /> )}
    diff --git a/src/components/Manager/MappingsFunctions/FilterOntology.jsx b/src/components/Manager/MappingsFunctions/FilterOntology.jsx index 27cb521..9ed6e40 100644 --- a/src/components/Manager/MappingsFunctions/FilterOntology.jsx +++ b/src/components/Manager/MappingsFunctions/FilterOntology.jsx @@ -1,6 +1,7 @@ import { Checkbox, Form, Pagination } from 'antd'; import { useContext, useEffect, useState } from 'react'; import { myContext } from '../../../App'; +import { FilterReset } from './FilterReset'; export const FilterOntology = ({ ontology, @@ -13,6 +14,7 @@ export const FilterOntology = ({ searchText, paginatedOntologies, apiPreferences, + table, }) => { const [allCheckboxes, setAllCheckboxes] = useState([]); const { ontologyForPagination, setOntologyForPagination } = @@ -151,7 +153,9 @@ export const FilterOntology = ({ key => apiPreferences?.self?.api_preference[key]?.length > 0 ) && ( <> -

    Ontology Filters

    +
    +

    Ontology Filters

    +
    { + const { confirm } = Modal; + + const { user, vocabUrl } = useContext(myContext); + const { setApiPreferences } = useContext(SearchContext); + const [remove, setRemove] = useState(false); + + const deleteOntologies = evt => { + return fetch(`${vocabUrl}/${table?.terminology?.reference}/filter`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ editor: user.email }), + }) + .then(res => { + if (res.ok) { + return res.json().then(data => { + message.success('Ontology filters deleted successfully.'); + }); + } else { + notification.error({ + message: 'Error', + description: 'An error occurred deleting the table.', + }); + } + }) + .then(data => setApiPreferences(data)); + }; + + const showConfirm = () => { + confirm({ + className: 'delete_table_confirm', + title: 'Alert', + icon: , + content: + ' Are you sure you want to remove the ontology filters?', + onOk() { + deleteOntologies(); + setRemove(false); + }, + onCancel() { + setRemove(false); + }, + }); + }; + + return ( + <> + + {remove && showConfirm()} + + ); +}; diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index f7364e9..ace5cc0 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -277,6 +277,7 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { setPageSize={setPageSize} paginatedOntologies={paginatedOntologies} apiPreferences={apiPreferences} + table={table} /> diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index e54b6f5..05087a3 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -1,12 +1,11 @@ import { Checkbox, Input, message, Modal, Form, Tooltip } from 'antd'; import { useContext, useEffect, useRef, useState } from 'react'; import { myContext } from '../../../App'; -import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; +import { ellipsisString, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; import { olsFilterOntologiesSearch } from '../FetchManager'; -import { defaultIconPrefixCls } from 'antd/es/config-provider'; export const GetMappingsModal = ({ componentString, diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index dc9c75b..68901e7 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -4,6 +4,8 @@ import { myContext } from '../../../App'; import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; +import { olsFilterOntologiesSearch } from '../FetchManager'; +import { SearchContext } from '../../../Contexts/SearchContext'; export const MappingReset = ({ searchProp, @@ -12,6 +14,7 @@ export const MappingReset = ({ onClose, }) => { const { searchUrl } = useContext(myContext); + const { apiPreferences } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -103,52 +106,49 @@ export const MappingReset = ({ number of results to return per page (entriesPerPage) and a calculation of the first index to start the results on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ const pageStart = page * entriesPerPage; - return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) - let res = ontologyReducer(data?.response?.docs); - - // Filters out results that have already been selected in previous search if there is a change to the search term - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - - // if the page > 0 (i.e. if this is not the first batch of results), the new results - // are concatenated to the old - if (page > 0 && results.length > 0) { - res.results = results.concat(res.results); + if ( + //If there are api preferences and one of them is OLS, it gets the preferred ontologies + apiPreferences?.self?.api_preference && + 'ols' in apiPreferences?.self?.api_preference + ) { + const apiPreferenceOntologies = () => { + if (apiPreferences?.self?.api_preference?.ols) { + return apiPreferences.self.api_preference.ols.join(','); } else { - // the total number of search results are set to totalCount for pagination - setTotalCount(data.response.numFound); - } - //the results are set to res (the filtered, concatenated results) - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - - // resultsCount is set to the length of the filtered, concatenated results for pagination - setResultsCount(res.results.length); - }) - .catch(error => { - if (error) { - notification.error({ - message: 'Error', - description: 'An error occurred. Please try again.', - }); + // else if there are no preferred ontologies, it uses the default ontologies + return defaultOntologies; } - return error; - }) - .finally(() => setLoading(false)); + }; + //fetch call to search OLS with either preferred or default ontologies + return olsFilterOntologiesSearch( + searchUrl, + query, + apiPreferenceOntologies(), + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); + } else + return olsFilterOntologiesSearch( + searchUrl, + query, + defaultOntologies, + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); }; // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 80585e8..332083c 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -4,6 +4,8 @@ import { myContext } from '../../../App'; import { ellipsisString, ontologyReducer, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; +import { SearchContext } from '../../../Contexts/SearchContext'; +import { olsFilterOntologiesSearch } from '../FetchManager'; export const MappingSearch = ({ setEditMappings, @@ -13,6 +15,8 @@ export const MappingSearch = ({ searchProp, }) => { const { searchUrl } = useContext(myContext); + const { apiPreferences } = useContext(SearchContext); + const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -105,51 +109,49 @@ export const MappingSearch = ({ number of results to return per page (entriesPerPage) and a calculation of the first index to start the results on each new batch of results (pageStart, calculated as the number of the page * the number of entries per page */ const pageStart = page * entriesPerPage; - return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - // filters results through the ontologyReducer function (defined in Manager/Utility.jsx) - let res = ontologyReducer(data?.response?.docs); - - // Filters out results that have already been selected in previous search if there is a change to the search term - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - // if the page > 0 (i.e. if this is not the first batch of results), the new results - // are concatenated to the old - if (page > 0 && results.length > 0) { - res.results = results.concat(res.results); + if ( + //If there are api preferences and one of them is OLS, it gets the preferred ontologies + apiPreferences?.self?.api_preference && + 'ols' in apiPreferences?.self?.api_preference + ) { + const apiPreferenceOntologies = () => { + if (apiPreferences?.self?.api_preference?.ols) { + return apiPreferences.self.api_preference.ols.join(','); } else { - // the total number of search results are set to totalCount for pagination - setTotalCount(data.response.numFound); - } - //the results are set to res (the filtered, concatenated results) - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - - // resultsCount is set to the length of the filtered, concatenated results for pagination - setResultsCount(res.results.length); - }) - .catch(error => { - if (error) { - notification.error({ - message: 'Error', - description: 'An error occurred. Please try again.', - }); + // else if there are no preferred ontologies, it uses the default ontologies + return defaultOntologies; } - return error; - }) - .finally(() => setLoading(false)); + }; + //fetch call to search OLS with either preferred or default ontologies + return olsFilterOntologiesSearch( + searchUrl, + query, + apiPreferenceOntologies(), + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); + } else + return olsFilterOntologiesSearch( + searchUrl, + query, + defaultOntologies, + page, + entriesPerPage, + pageStart, + selectedBoxes, + setTotalCount, + setResults, + setFilteredResultsCount, + setResultsCount, + setLoading + ); }; // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. diff --git a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss index fa074f2..a4a8d45 100644 --- a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss +++ b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss @@ -78,3 +78,10 @@ width: 50vw; justify-content: center; } + +.onto_reset { + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; +} From 9b128e52ef9df8b0bd869241faba53ba7c29cf66 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 15 Oct 2024 16:06:35 -0500 Subject: [PATCH 015/180] committing to switch branches --- src/components/Manager/MappingsFunctions/FilterReset.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Manager/MappingsFunctions/FilterReset.jsx b/src/components/Manager/MappingsFunctions/FilterReset.jsx index f5349a8..ac37e40 100644 --- a/src/components/Manager/MappingsFunctions/FilterReset.jsx +++ b/src/components/Manager/MappingsFunctions/FilterReset.jsx @@ -54,7 +54,7 @@ export const FilterReset = ({ table }) => { return ( <> {remove && showConfirm()} From 79255a5ce0c3e598be273183eccb11d9d9a96d47 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 16 Oct 2024 11:23:45 -0500 Subject: [PATCH 016/180] Newly added ontologies checking by default on load --- .../Manager/MappingsFunctions/FilterAPI.jsx | 2 +- .../MappingsFunctions/FilterSelect.jsx | 128 +++++++++--------- 2 files changed, 66 insertions(+), 64 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 92c3f24..1a63182 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -91,7 +91,7 @@ export const FilterAPI = ({ ) : (
    - +
    APIs
    diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index ace5cc0..c194961 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -214,72 +214,74 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { > API Filters {apiPrefObject ? `(${apiPrefLength})` : ''} - { - form.validateFields().then(values => { - handleSubmit(values); + {addFilter && ( + { + form.validateFields().then(values => { + handleSubmit(values); + onClose(); + }); + }} + onCancel={() => { + form.resetFields(); + setAddFilter(false); onClose(); - }); - }} - onCancel={() => { - form.resetFields(); - setAddFilter(false); - onClose(); - }} - maskClosable={false} - closeIcon={false} - footer={(_, { OkBtn, CancelBtn }) => ( - <> -
    + }} + maskClosable={false} + closeIcon={false} + footer={(_, { OkBtn, CancelBtn }) => ( + <>
    - -
    -
    - - +
    + +
    +
    + + +
    -
    - - )} - > - -
    + + )} + > + +
    + )} ); }; From bd0e506efd69b5b60dc4e72ad759dd54af5b82a4 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 16 Oct 2024 15:56:56 -0500 Subject: [PATCH 017/180] ontology filter for mappings search --- src/Contexts/SearchContext.jsx | 2 + src/components/Manager/FetchManager.jsx | 3 +- .../Manager/MappingsFunctions/FilterAPI.jsx | 42 +++++++++++++--- .../MappingsFunctions/FilterSelect.jsx | 49 ++++++++++--------- .../MappingsFunctions/GetMappingsModal.jsx | 12 +++-- .../MappingsFunctions/MappingReset.jsx | 8 +-- .../MappingsFunctions/MappingSearch.jsx | 8 +-- src/components/Nav/NavBar.jsx | 4 +- .../Projects/Tables/TableDetails.jsx | 13 +++++ 9 files changed, 100 insertions(+), 41 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index e90d907..a8d1d27 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -13,6 +13,7 @@ export function SearchContextRoot() { const [apiPage, setApiPage] = useState(0); const [apiTotalCount, setApiTotalCount] = useState(); const [apiPreferences, setApiPreferences] = useState({}); + const defaultOntologies = 'mondo,hp,maxo,ncit'; const context = { prefTerminologies, @@ -33,6 +34,7 @@ export function SearchContextRoot() { setApiTotalCount, apiPreferences, setApiPreferences, + defaultOntologies, }; return ( diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index fc5f4a6..6b436c9 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -180,7 +180,8 @@ export const olsFilterOntologiesSearch = ( setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ) => { setLoading(true); return fetch( diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 1a63182..946f435 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from 'react'; -import { Checkbox, Form, Input } from 'antd'; +import { Checkbox, Form } from 'antd'; import { ModalSpinner, OntologySpinner } from '../Spinner'; import { myContext } from '../../../App'; import { FilterOntology } from './FilterOntology'; @@ -16,7 +16,6 @@ export const FilterAPI = ({ active, setActive, searchText, - setSearchText, currentPage, setCurrentPage, pageSize, @@ -25,13 +24,32 @@ export const FilterAPI = ({ apiPreferences, table, }) => { - const { Search } = Input; - const { vocabUrl } = useContext(myContext); const [ontology, setOntology] = useState([]); const [loading, setLoading] = useState(false); const [tableLoading, setTableLoading] = useState(false); + // The selected ontology filters that have already been selected + const existingFilters = Object.values(apiPreferences?.self || {}).flat(); + + // Flattens the existingFilters into a single array + const flattenedFilters = existingFilters + .flatMap(item => + Object.keys(item).map(key => + item[key].map(value => ({ + api: key, + })) + ) + ) + .flat(); + + // The initial value for the form. The checkboxes for the filters that have already been selected will be checked by default + const initialChecked = flattenedFilters?.map(ef => + JSON.stringify({ + ontology: ef, + }) + ); + // Fetches the active ontologyAPI each time the active API changes useEffect(() => { active && getOntologyApiById(); @@ -56,7 +74,20 @@ export const FilterAPI = ({ } }) .then(data => { - setOntology(data); + //Alphabetizes the data + const sortedData = data.map(api => { + const sortedOntologies = Object.fromEntries( + Object.entries(api.ontologies).sort((a, b) => + a[1].ontology_code > b[1].ontology_code ? 1 : -1 + ) + ); + + return { + ...api, + ontologies: sortedOntologies, + }; + }); + setOntology(sortedData); }) .finally(() => setTableLoading(false)) ); @@ -85,7 +116,6 @@ export const FilterAPI = ({ ); }; - return loading ? ( ) : ( diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index c194961..538f380 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -4,6 +4,7 @@ import { useContext, useEffect, useState } from 'react'; import { myContext } from '../../../App'; import { FilterAPI } from './FilterAPI'; import { getOntologies } from '../FetchManager'; +import { ModalSpinner } from '../Spinner'; export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { const [form] = Form.useForm(); @@ -64,7 +65,7 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { // If the api_preference array for the api does not include an ontology_code, pushes the code to the array for the api // If there is an api in api_preferences that is not included with the ontology_code, it's added to apiPreference with an empty array const handleSubmit = values => { - // setLoading(true); + setLoading(true); const apiPreference = { api_preference: {}, }; @@ -259,27 +260,31 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { )} > - + {loading ? ( + + ) : ( + + )} )} diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 05087a3..d079feb 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -19,7 +19,7 @@ export const GetMappingsModal = ({ const { Search } = Input; const { searchUrl, vocabUrl, setSelectedKey, user } = useContext(myContext); - const { apiPreferences } = useContext(SearchContext); + const { apiPreferences, defaultOntologies } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(false); @@ -40,7 +40,6 @@ export const GetMappingsModal = ({ setSelectedBoxes, } = useContext(MappingContext); let ref = useRef(); - const defaultOntologies = 'mondo,hp,maxo,ncit'; // since the code is passed through searchProp, the '!!' forces it to be evaluated as a boolean. // if there is a searchProp being passed, it evaluates to true and runs the search function. @@ -186,7 +185,8 @@ export const GetMappingsModal = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); } else return olsFilterOntologiesSearch( @@ -201,7 +201,8 @@ export const GetMappingsModal = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); }; // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. @@ -423,6 +424,9 @@ export const GetMappingsModal = ({ Displaying {resultsCount}  of {totalCount} + {console.log('total', totalCount)} + {console.log('filtered', filteredResultsCount)} + {console.log('results', filteredResultsCount)} {totalCount - filteredResultsCount !== resultsCount && ( { const { searchUrl } = useContext(myContext); - const { apiPreferences } = useContext(SearchContext); + const { apiPreferences, defaultOntologies } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -132,7 +132,8 @@ export const MappingReset = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); } else return olsFilterOntologiesSearch( @@ -147,7 +148,8 @@ export const MappingReset = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); }; diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 332083c..14724f1 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -15,7 +15,7 @@ export const MappingSearch = ({ searchProp, }) => { const { searchUrl } = useContext(myContext); - const { apiPreferences } = useContext(SearchContext); + const { apiPreferences, defaultOntologies } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; @@ -135,7 +135,8 @@ export const MappingSearch = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); } else return olsFilterOntologiesSearch( @@ -150,7 +151,8 @@ export const MappingSearch = ({ setResults, setFilteredResultsCount, setResultsCount, - setLoading + setLoading, + results ); }; diff --git a/src/components/Nav/NavBar.jsx b/src/components/Nav/NavBar.jsx index 13a0c11..80e39ff 100644 --- a/src/components/Nav/NavBar.jsx +++ b/src/components/Nav/NavBar.jsx @@ -27,11 +27,11 @@ export const NavBar = () => { {/* Placeholder elements below. No functionality at this time.*/} -
  • Help
  • +
  • About
  • -
  • About
  • +
  • Ontologies
  • diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 9bd6e05..863cb79 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -51,6 +51,19 @@ export const TableDetails = () => { setDataSource(tableData(table)); }, [table, mapping]); + const alphabetizeOntologies = ontologies => { + // Sort the keys alphabetically + const sortedKeys = Object.keys(ontologies).sort(); + + // Rebuild object using the sorted keys + const sortedOntologies = {}; + sortedKeys.forEach(key => { + sortedOntologies[key] = ontologies[key]; + }); + + return sortedOntologies; + }; + // fetches the table and sets 'table' to the response useEffect(() => { setLoading(true); From 48cefbb7c40409e60bc45d44321e477850c1322d Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 16 Oct 2024 15:57:35 -0500 Subject: [PATCH 018/180] Removed unnecesary console logs --- src/components/Manager/MappingsFunctions/GetMappingsModal.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index d079feb..1451c01 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -424,9 +424,6 @@ export const GetMappingsModal = ({ Displaying {resultsCount}  of {totalCount} - {console.log('total', totalCount)} - {console.log('filtered', filteredResultsCount)} - {console.log('results', filteredResultsCount)} {totalCount - filteredResultsCount !== resultsCount && ( Date: Wed, 16 Oct 2024 16:01:49 -0500 Subject: [PATCH 019/180] Rebased branch --- .env | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..7471b56 --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +VITE_SEARCH_ENDPOINT = https://www.ebi.ac.uk/ols4/api/search? +VITE_MONARCH_SEARCH = https://api-v3.monarchinitiative.org/v3/api/search? +# VITE_VOCAB_ENDPOINT = http://127.0.0.1:5000/api # local +VITE_VOCAB_ENDPOINT = https://locutus-110109177269.us-central1.run.app/api # dev +# VITE_VOCAB_ENDPOINT = https://locutus-1066621297011.us-central1.run.app/api # uat +VITE_CLIENT_ID = 907694787484-36jr4oaf04mmniik6482batc87ejemm8.apps.googleusercontent.com +VITE_CLIENT_SECRET = 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 \ No newline at end of file From a902065d49c63188b8e750febd24d679efca760f Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 17 Oct 2024 09:50:59 -0500 Subject: [PATCH 020/180] Updated .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dd5161b..13a3147 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ dist-ssr .env.local .env.qa .env.dev +.env From 3e80ca641762259d8255e3e0a220d3f5680c8558 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 17 Oct 2024 10:26:52 -0500 Subject: [PATCH 021/180] cleaned up .env --- .env | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.env b/.env index 7471b56..774b5d7 100644 --- a/.env +++ b/.env @@ -3,5 +3,4 @@ VITE_MONARCH_SEARCH = https://api-v3.monarchinitiative.org/v3/api/search? # VITE_VOCAB_ENDPOINT = http://127.0.0.1:5000/api # local VITE_VOCAB_ENDPOINT = https://locutus-110109177269.us-central1.run.app/api # dev # VITE_VOCAB_ENDPOINT = https://locutus-1066621297011.us-central1.run.app/api # uat -VITE_CLIENT_ID = 907694787484-36jr4oaf04mmniik6482batc87ejemm8.apps.googleusercontent.com -VITE_CLIENT_SECRET = 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 \ No newline at end of file +VITE_CLIENT_ID = 907694787484-36jr4oaf04mmniik6482batc87ejemm8.apps.googleusercontent.com \ No newline at end of file From 91bf1c52df2c4a9ac7444f4eac087ce1037fe742 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 17 Oct 2024 13:26:04 -0500 Subject: [PATCH 022/180] Committing to switch branch --- src/Contexts/SearchContext.jsx | 3 + src/components/Manager/FetchManager.jsx | 4 +- .../MappingsFunctions/GetMappingsModal.jsx | 129 ++++++++++-------- .../MappingsFunctions/MappingReset.jsx | 9 +- .../MappingsFunctions/MappingSearch.jsx | 9 +- .../MappingsFunctions/MappingsFunctions.scss | 23 +++- src/components/Manager/Utilitiy.jsx | 20 +++ 7 files changed, 131 insertions(+), 66 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index a8d1d27..dc0724c 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -13,6 +13,7 @@ export function SearchContextRoot() { const [apiPage, setApiPage] = useState(0); const [apiTotalCount, setApiTotalCount] = useState(); const [apiPreferences, setApiPreferences] = useState({}); + const [facetCounts, setFacetCounts] = useState([]); const defaultOntologies = 'mondo,hp,maxo,ncit'; const context = { @@ -35,6 +36,8 @@ export function SearchContextRoot() { apiPreferences, setApiPreferences, defaultOntologies, + facetCounts, + setFacetCounts, }; return ( diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index 6b436c9..ac6f712 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -181,7 +181,8 @@ export const olsFilterOntologiesSearch = ( setFilteredResultsCount, setResultsCount, setLoading, - results + results, + setFacetCounts ) => { setLoading(true); return fetch( @@ -221,6 +222,7 @@ export const olsFilterOntologiesSearch = ( setFilteredResultsCount(res?.filteredResults?.length); // resultsCount is set to the length of the filtered, concatenated results for pagination setResultsCount(res.results.length); + setFacetCounts(data?.facet_counts?.facet_fields?.ontologyPreferredPrefix); }) .then(() => setLoading(false)); }; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 1451c01..9856587 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -1,7 +1,7 @@ import { Checkbox, Input, message, Modal, Form, Tooltip } from 'antd'; import { useContext, useEffect, useRef, useState } from 'react'; import { myContext } from '../../../App'; -import { ellipsisString, systemsMatch } from '../Utilitiy'; +import { ellipsisString, ontologyCounts, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; @@ -19,7 +19,8 @@ export const GetMappingsModal = ({ const { Search } = Input; const { searchUrl, vocabUrl, setSelectedKey, user } = useContext(myContext); - const { apiPreferences, defaultOntologies } = useContext(SearchContext); + const { apiPreferences, defaultOntologies, setFacetCounts, facetCounts } = + useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(false); @@ -186,7 +187,8 @@ export const GetMappingsModal = ({ setFilteredResultsCount, setResultsCount, setLoading, - results + results, + setFacetCounts ); } else return olsFilterOntologiesSearch( @@ -202,9 +204,13 @@ export const GetMappingsModal = ({ setFilteredResultsCount, setResultsCount, setLoading, - results + results, + setFacetCounts ); }; + + console.log('formattedData:', ontologyCounts(facetCounts)); + // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. const handleViewMore = e => { e.preventDefault(); @@ -320,7 +326,7 @@ export const GetMappingsModal = ({ { @@ -358,61 +364,68 @@ export const GetMappingsModal = ({ {results?.length > 0 ? (
    - {displaySelectedMappings?.length > 0 && ( - -
    - {displaySelectedMappings?.map((sm, i) => ( - box.obo_id === sm.obo_id +
    +
    poop
    +
    + {displaySelectedMappings?.length > 0 && ( + +
    + {displaySelectedMappings?.map((sm, i) => ( + box.obo_id === sm.obo_id + )} + value={sm} + onChange={e => onCheckboxChange(e, sm, i)} + > + {selectedTermsDisplay(sm, i)} + + ))} +
    +
    + )} + + {filteredResultsArray?.length > 0 ? ( + { + return { + value: JSON.stringify({ + code: d.obo_id, + display: d.label, + description: d.description[0], + system: systemsMatch( + d?.obo_id.split(':')[0] + ), + }), + label: checkBoxDisplay(d, index), + }; + } )} - value={sm} - onChange={e => onCheckboxChange(e, sm, i)} - > - {selectedTermsDisplay(sm, i)} - - ))} -
    - - )} - - {filteredResultsArray?.length > 0 ? ( - { - return { - value: JSON.stringify({ - code: d.obo_id, - display: d.label, - description: d.description[0], - system: systemsMatch( - d?.obo_id.split(':')[0] - ), - }), - label: checkBoxDisplay(d, index), - }; - })} - onChange={onSelectedChange} - /> - ) : ( - '' - )} - + onChange={onSelectedChange} + /> + ) : ( + '' + )} + +
    +
    -
    +
    {/* 'View More' pagination displaying the number of results being displayed out of the total number of results. Because of the filter to filter out the duplicates, there is a tooltip informing the user that redundant entries have been removed to explain any diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index a026c91..2da7ae0 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -14,7 +14,8 @@ export const MappingReset = ({ onClose, }) => { const { searchUrl } = useContext(myContext); - const { apiPreferences, defaultOntologies } = useContext(SearchContext); + const { apiPreferences, defaultOntologies, facetCounts, setFacetCounts } = + useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; const [loading, setLoading] = useState(true); @@ -133,7 +134,8 @@ export const MappingReset = ({ setFilteredResultsCount, setResultsCount, setLoading, - results + results, + setFacetCounts ); } else return olsFilterOntologiesSearch( @@ -149,7 +151,8 @@ export const MappingReset = ({ setFilteredResultsCount, setResultsCount, setLoading, - results + results, + setFacetCounts ); }; diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 14724f1..a98cd90 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -15,7 +15,8 @@ export const MappingSearch = ({ searchProp, }) => { const { searchUrl } = useContext(myContext); - const { apiPreferences, defaultOntologies } = useContext(SearchContext); + const { apiPreferences, defaultOntologies, facetCounts, setFacetCounts } = + useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 15; @@ -136,7 +137,8 @@ export const MappingSearch = ({ setFilteredResultsCount, setResultsCount, setLoading, - results + results, + setFacetCounts ); } else return olsFilterOntologiesSearch( @@ -152,7 +154,8 @@ export const MappingSearch = ({ setFilteredResultsCount, setResultsCount, setLoading, - results + results, + setFacetCounts ); }; diff --git a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss index db00c2f..c6d781c 100644 --- a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss +++ b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss @@ -5,9 +5,23 @@ top: 25vh; } +.all_checkboxes_container { + display: flex; + flex-direction: row; +} +.ontology_form { + width: 10vw; + height: 50vh; + overflow: auto; + position: fixed; +} +.result_form { + margin-left: 10vw; +} + .modal_search_results_header { background-color: white; - top:0; + top: 0; position: sticky; margin: 0 0 15px 0; display: flex; @@ -89,3 +103,10 @@ align-items: center; gap: 8px; } + +.view_more_link { + display: flex; + flex-direction: column; + margin-left: 10vw; + gap: 10px; +} diff --git a/src/components/Manager/Utilitiy.jsx b/src/components/Manager/Utilitiy.jsx index 4052b6d..1515f19 100644 --- a/src/components/Manager/Utilitiy.jsx +++ b/src/components/Manager/Utilitiy.jsx @@ -40,3 +40,23 @@ export const ontologySystems = { export const systemsMatch = ont => { return ontologySystems[ont]; }; + +// Iterates over the facet counts in the result to make an object of search results per ontology +export const ontologyCounts = arr => { + let result = []; + let i = 0; + + while (i < arr.length) { + if (isNaN(arr[i])) { + // If element in array, it not a number (i.e. it's a string), it sets it as the key + const key = arr[i]; + const value = arr[i + 1]; // Gets the first number after the string + result.push({ [key]: value }); // Pushes the key (string) and value (number) pair to the result array + i += 2; // Moves to the next letter-number pair + } else { + i += 1; // If the element is a number, it keeps going until it starts over and finds a string + } + } + + return result; +}; From b71723ee03d1809b0a9a077fc9239bad8fe487e3 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 17 Oct 2024 13:35:46 -0500 Subject: [PATCH 023/180] Ran git rm -r --cached . --- .env | 7 ------- .gitignore | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 7471b56..0000000 --- a/.env +++ /dev/null @@ -1,7 +0,0 @@ -VITE_SEARCH_ENDPOINT = https://www.ebi.ac.uk/ols4/api/search? -VITE_MONARCH_SEARCH = https://api-v3.monarchinitiative.org/v3/api/search? -# VITE_VOCAB_ENDPOINT = http://127.0.0.1:5000/api # local -VITE_VOCAB_ENDPOINT = https://locutus-110109177269.us-central1.run.app/api # dev -# VITE_VOCAB_ENDPOINT = https://locutus-1066621297011.us-central1.run.app/api # uat -VITE_CLIENT_ID = 907694787484-36jr4oaf04mmniik6482batc87ejemm8.apps.googleusercontent.com -VITE_CLIENT_SECRET = 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 \ No newline at end of file diff --git a/.gitignore b/.gitignore index dd5161b..13a3147 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ dist-ssr .env.local .env.qa .env.dev +.env From 3771f7d9abedd9b6cac4046004c84f3cd695d8b4 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 17 Oct 2024 17:54:08 -0500 Subject: [PATCH 024/180] Ontologies with number of results on search page --- .../Manager/MappingsFunctions/FilterAPI.jsx | 9 +++- .../MappingsFunctions/GetMappingsModal.jsx | 10 ++-- .../MappingsFunctions/MappingsFunctions.scss | 9 ++-- .../MappingsFunctions/OntologyCheckboxes.jsx | 49 +++++++++++++++++++ 4 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 946f435..8998711 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from 'react'; -import { Checkbox, Form } from 'antd'; +import { Checkbox, Form, Tooltip } from 'antd'; import { ModalSpinner, OntologySpinner } from '../Spinner'; import { myContext } from '../../../App'; import { FilterOntology } from './FilterOntology'; @@ -123,7 +123,12 @@ export const FilterAPI = ({
    -
    APIs
    + +
    APIs
    +
    -
    poop
    +
    {displaySelectedMappings?.length > 0 && (
    -
    +
    {/* 'View More' pagination displaying the number of results being displayed out of the total number of results. Because of the filter to filter out the duplicates, there is a tooltip informing the user that redundant entries have been removed to explain any diff --git a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss index c6d781c..001d127 100644 --- a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss +++ b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss @@ -16,7 +16,7 @@ position: fixed; } .result_form { - margin-left: 10vw; + margin-left: 11vw; } .modal_search_results_header { @@ -104,9 +104,6 @@ gap: 8px; } -.view_more_link { - display: flex; - flex-direction: column; - margin-left: 10vw; - gap: 10px; +.view_more_wrapper { + margin-left: 11vw; } diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx new file mode 100644 index 0000000..bc7e044 --- /dev/null +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -0,0 +1,49 @@ +import { Checkbox, Form } from 'antd'; + +export const OntologyCheckboxes = ({ facetCounts, apiPreferences }) => { + const ontologyCheckboxDisplay = fc => { + // Extract the key (assuming it's only one key in the object) + const key = Object.keys(fc); + console.log(fc); + const value = fc[key]; // Get the value for that key + + return `${key} (${value})`; // Format it to "KEY (value)" + }; + + console.log(apiPreferences); + + return ( +
    + +
    + {facetCounts?.map((fc, i) => { + // Check if the index is even (assuming even index = key and odd index = value) + if (i % 2 === 0) { + const key = fc.toUpperCase(); // Use the current string as the key (uppercase) + const value = facetCounts[i + 1]; // The next element as the value + + return ( + box.obo_id === fc.obo_id)} // Uncomment if needed + value={fc} // You can keep this if you need the whole object + // onChange={(e) => onCheckboxChange(e, sm, i)} // Uncomment if needed + > + {`${key} ${value !== '0' ? `(${value})` : ''}`} + + {/* Display formatted key-value pair */} + + ); + } + return null; // Skip odd indexed elements + })} +
    +
    +
    + ); +}; From ba803a82df40346bf310380ae8ae58b2169f7c36 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 17 Oct 2024 18:20:17 -0500 Subject: [PATCH 025/180] changed formatting for ontology counts for checkbox display --- .../MappingsFunctions/GetMappingsModal.jsx | 2 - .../MappingsFunctions/OntologyCheckboxes.jsx | 40 +++++-------------- 2 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index a8add34..c4d9d68 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -210,8 +210,6 @@ export const GetMappingsModal = ({ ); }; - console.log('formattedData:', ontologyCounts(facetCounts)); - // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. const handleViewMore = e => { e.preventDefault(); diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index bc7e044..4fb6d06 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -1,16 +1,8 @@ import { Checkbox, Form } from 'antd'; +import { ontologyCounts } from '../Utilitiy'; export const OntologyCheckboxes = ({ facetCounts, apiPreferences }) => { - const ontologyCheckboxDisplay = fc => { - // Extract the key (assuming it's only one key in the object) - const key = Object.keys(fc); - console.log(fc); - const value = fc[key]; // Get the value for that key - - return `${key} (${value})`; // Format it to "KEY (value)" - }; - - console.log(apiPreferences); + const formattedFacetCounts = ontologyCounts(facetCounts); return (
    @@ -20,27 +12,15 @@ export const OntologyCheckboxes = ({ facetCounts, apiPreferences }) => { rules={[{ required: false }]} >
    - {facetCounts?.map((fc, i) => { - // Check if the index is even (assuming even index = key and odd index = value) - if (i % 2 === 0) { - const key = fc.toUpperCase(); // Use the current string as the key (uppercase) - const value = facetCounts[i + 1]; // The next element as the value - - return ( - box.obo_id === fc.obo_id)} // Uncomment if needed - value={fc} // You can keep this if you need the whole object - // onChange={(e) => onCheckboxChange(e, sm, i)} // Uncomment if needed - > - {`${key} ${value !== '0' ? `(${value})` : ''}`} + {formattedFacetCounts?.map((fc, i) => { + const key = Object.keys(fc)[0]; + const value = fc[key]; - {/* Display formatted key-value pair */} - - ); - } - return null; // Skip odd indexed elements + return ( + + {`${key.toUpperCase()} ${value !== '0' ? `(${value})` : ''}`} + + ); })}
    From 0c470b2c6b9e324aca8f9f024bc7d67db95a09fc Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Fri, 18 Oct 2024 14:21:43 -0500 Subject: [PATCH 026/180] [FD-1727]showing description in GetMappingsModal MappingRest and MappingSearch --- .../MappingsFunctions/GetMappingsModal.jsx | 2 + .../MappingsFunctions/MappingReset.jsx | 185 +++++++++--------- .../MappingsFunctions/MappingSearch.jsx | 2 + .../MappingsFunctions/MappingsFunctions.scss | 23 ++- .../Tables/EditMappingsTableModal.jsx | 2 + .../Projects/Tables/TableDetails.jsx | 1 + 6 files changed, 119 insertions(+), 96 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 1451c01..202f2ca 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -14,6 +14,7 @@ export const GetMappingsModal = ({ searchProp, component, mappingProp, + mappingDesc }) => { const [form] = Form.useForm(); const { Search } = Input; @@ -353,6 +354,7 @@ export const GetMappingsModal = ({ onChange={handleChange} />
    + {mappingDesc}
    {/* ant.design form displaying the checkboxes with the search results. */} {results?.length > 0 ? ( diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index a026c91..be0dc58 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -9,6 +9,7 @@ import { SearchContext } from '../../../Contexts/SearchContext'; export const MappingReset = ({ searchProp, + mappingDesc, setEditMappings, form, onClose, @@ -280,109 +281,111 @@ export const MappingReset = ({

    {searchProp}

    -
    - -
    +
    +
    - {/* ant.design form displaying the checkboxes with the search results. */} - {results?.length > 0 ? ( -
    -
    - {displaySelectedMappings?.length > 0 && ( - - {' '} -
    - {displaySelectedMappings?.map((sm, i) => ( - onCheckboxChange(e, sm)} - checked={selectedBoxes.some( - box => box.obo_id === sm.obo_id - )} - value={sm} - > - {selectedTermsDisplay(sm, i)} - - ))} -
    -
    - )} + {mappingDesc} +
    + + {/* ant.design form displaying the checkboxes with the search results. */} + {results?.length > 0 ? ( +
    + + {displaySelectedMappings?.length > 0 && ( - {filteredResultsArray?.length > 0 ? ( - { - return { - value: JSON.stringify({ - code: d.obo_id, - display: d.label, - // description: d.description[0], - system: systemsMatch(d?.obo_id.split(':')[0]), - }), - label: checkBoxDisplay(d, index), - }; - })} - onChange={onSelectedChange} - /> - ) : ( - '' - )} + {' '} +
    + {displaySelectedMappings?.map((sm, i) => ( + onCheckboxChange(e, sm)} + checked={selectedBoxes.some( + box => box.obo_id === sm.obo_id + )} + value={sm} + > + {selectedTermsDisplay(sm, i)} + + ))} +
    - -
    - {/* 'View More' pagination displaying the number of results being displayed + )} + + {filteredResultsArray?.length > 0 ? ( + { + return { + value: JSON.stringify({ + code: d.obo_id, + display: d.label, + // description: d.description[0], + system: systemsMatch(d?.obo_id.split(':')[0]), + }), + label: checkBoxDisplay(d, index), + }; + })} + onChange={onSelectedChange} + /> + ) : ( + '' + )} + + +
    + {/* 'View More' pagination displaying the number of results being displayed out of the total number of results. Because of the filter to filter out the duplicates, there is a tooltip informing the user that redundant entries have been removed to explain any inconsistencies in results numbers per page. */} - + Displaying {resultsCount} +  of {totalCount} + + {totalCount - filteredResultsCount !== resultsCount && ( + { + handleViewMore(e); + setLastCount(resultsCount); + }} > - Displaying {resultsCount} -  of {totalCount} - - {totalCount - filteredResultsCount !== resultsCount && ( - { - handleViewMore(e); - setLastCount(resultsCount); - }} - > - View More - - )} -
    + View More + + )}
    - ) : ( -

    No results found.

    - )} -
    - - ) : ( -
    - +
    + ) : ( +

    No results found.

    + )}
    - )} -
    + ) : ( +
    + +
    + )} + +
    ); }; diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 14724f1..1d21085 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -13,6 +13,7 @@ export const MappingSearch = ({ mappingsForSearch, onClose, searchProp, + mappingDesc }) => { const { searchUrl } = useContext(myContext); const { apiPreferences, defaultOntologies } = useContext(SearchContext); @@ -351,6 +352,7 @@ export const MappingSearch = ({ onChange={handleChange} />
    + {mappingDesc}
    {/* ant.design form displaying the checkboxes with the search results. */} {results?.length > 0 ? ( diff --git a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss index db00c2f..d74c69a 100644 --- a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss +++ b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss @@ -11,15 +11,28 @@ position: sticky; margin: 0 0 15px 0; display: flex; + flex-wrap: wrap; flex-direction: row; - align-items: center; - gap: 20px; + justify-content: flex-start; + align-items: end; z-index: 10; + flex: 1; + border-bottom: solid 1px #eeee; + h4 { + margin:0; + padding-right:1rem; + } + .mappings_search_bar { + width: 60%; + } + .search-desc { + flex: 0 0 100%; + margin-bottom:1rem; + } } -.mappings_search_bar { - width: 50%; -} + + .inactive_term, .active_term { diff --git a/src/components/Projects/Tables/EditMappingsTableModal.jsx b/src/components/Projects/Tables/EditMappingsTableModal.jsx index 3408f96..06c9a84 100644 --- a/src/components/Projects/Tables/EditMappingsTableModal.jsx +++ b/src/components/Projects/Tables/EditMappingsTableModal.jsx @@ -337,11 +337,13 @@ export const EditMappingsTableModal = ({ reset={reset} onClose={form.resetFields} searchProp={editMappings.name} + mappingDesc={editMappings.description ? editMappings.description : 'No Description'} /> ) : ( reset && ( From d1d073027522e500543c6868f6ded458838d1ac0 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Fri, 18 Oct 2024 16:04:01 -0500 Subject: [PATCH 027/180] Working on updating ontologies for search by checkbox check --- src/Contexts/SearchContext.jsx | 6 ++ src/components/Manager/FetchManager.jsx | 58 +++++++++++++++ .../MappingsFunctions/GetMappingsModal.jsx | 66 ++++++++++++++--- .../MappingsFunctions/OntologyCheckboxes.jsx | 72 +++++++++++++++++-- 4 files changed, 189 insertions(+), 13 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index dc0724c..b6b211a 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -13,6 +13,8 @@ export function SearchContextRoot() { const [apiPage, setApiPage] = useState(0); const [apiTotalCount, setApiTotalCount] = useState(); const [apiPreferences, setApiPreferences] = useState({}); + const [apiPreferencesCode, setApiPreferencesCode] = useState({}); + const [unformattedPref, setUnformattedPref] = useState([]); const [facetCounts, setFacetCounts] = useState([]); const defaultOntologies = 'mondo,hp,maxo,ncit'; @@ -35,9 +37,13 @@ export function SearchContextRoot() { setApiTotalCount, apiPreferences, setApiPreferences, + apiPreferencesCode, + setApiPreferencesCode, defaultOntologies, facetCounts, setFacetCounts, + unformattedPref, + setUnformattedPref, }; return ( diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index ac6f712..467fddd 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -226,3 +226,61 @@ export const olsFilterOntologiesSearch = ( }) .then(() => setLoading(false)); }; + +export const getFiltersByCode = ( + vocabUrl, + component, + mappingProp, + setApiPreferencesCode, + notification, + apiPreferencesCode, + setUnformattedPref +) => { + return fetch( + `${vocabUrl}/${component?.terminology?.reference}/filter/${mappingProp}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + .then(res => { + if (res.ok) { + return res.json(); + } else { + throw new Error('An unknown error occurred.'); + } + }) + .then(data => { + setUnformattedPref(data); + + // Dynamically derive the mappingProp based on a condition or the structure of the data + const codeToSearch = Object.keys(data)[0]; // Example: get the first key in the object + if (data?.[codeToSearch]?.api_preference?.ols) { + const joinedOntologies = + data[codeToSearch].api_preference.ols.join(','); + setApiPreferencesCode(joinedOntologies); // Set state to the comma-separated string + } else { + setApiPreferencesCode(''); // Fallback if no ols found + } + }) + .catch(error => { + if (error) { + notification.error({ + message: 'Error', + description: 'An error occurred loading the ontology preferences.', + }); + } + return error; + }); +}; + +// const preferredCodeOntologies = () => { +// if (apiPreferences?.mappingProp?.api_preference?.ols) { +// return apiPreferences.self.api_preference.ols.join(','); +// } else { +// // else if there are no preferred ontologies, it uses the default ontologies +// return defaultOntologies; +// } +// }; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index c4d9d68..c3f6dae 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -1,11 +1,19 @@ -import { Checkbox, Input, message, Modal, Form, Tooltip } from 'antd'; +import { + Checkbox, + Form, + Input, + message, + Modal, + notification, + Tooltip, +} from 'antd'; import { useContext, useEffect, useRef, useState } from 'react'; import { myContext } from '../../../App'; import { ellipsisString, ontologyCounts, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; -import { olsFilterOntologiesSearch } from '../FetchManager'; +import { getFiltersByCode, olsFilterOntologiesSearch } from '../FetchManager'; import { OntologyCheckboxes } from './OntologyCheckboxes'; export const GetMappingsModal = ({ @@ -20,10 +28,18 @@ export const GetMappingsModal = ({ const { Search } = Input; const { searchUrl, vocabUrl, setSelectedKey, user } = useContext(myContext); - const { apiPreferences, defaultOntologies, setFacetCounts, facetCounts } = - useContext(SearchContext); + const { + apiPreferences, + defaultOntologies, + setFacetCounts, + facetCounts, + setApiPreferencesCode, + apiPreferencesCode, + setUnformattedPref, + unformattedPref, + } = useContext(SearchContext); const [page, setPage] = useState(0); - const entriesPerPage = 5000; + const entriesPerPage = 2500; const [loading, setLoading] = useState(false); const [results, setResults] = useState([]); const [monarchResults, setMonarchResults] = useState([]); @@ -33,7 +49,7 @@ export const GetMappingsModal = ({ const [filteredResultsCount, setFilteredResultsCount] = useState(0); const [inputValue, setInputValue] = useState(searchProp); //Sets the value of the search bar const [currentSearchProp, setCurrentSearchProp] = useState(searchProp); - + console.log(unformattedPref); const { setSelectedMappings, displaySelectedMappings, @@ -52,10 +68,24 @@ export const GetMappingsModal = ({ setCurrentSearchProp(searchProp); setPage(0); if (!!searchProp) { - fetchResults(0, searchProp); + getFiltersByCode( + vocabUrl, + component, + mappingProp, + setApiPreferencesCode, + notification, + apiPreferencesCode, + setUnformattedPref + ); } }, [searchProp]); + useEffect(() => { + if (apiPreferencesCode) { + fetchResults(0, searchProp); + } + }, [apiPreferencesCode, searchProp]); + // The '!!' forces currentSearchProp to be evaluated as a boolean. // If there is a currentSearchProp in the search bar, it evaluates to true and runs the search function. // The function is run when the code and when the page changes. @@ -110,6 +140,7 @@ export const GetMappingsModal = ({ setCurrentSearchProp(query); setPage(0); }; + // Function to send a PUT call to update the mappings. // Each mapping in the mappings array being edited is JSON.parsed and pushed to the blank mappings array. // The mappings are turned into objects in the mappings array. @@ -178,7 +209,7 @@ export const GetMappingsModal = ({ return olsFilterOntologiesSearch( searchUrl, query, - apiPreferenceOntologies(), + apiPreferencesCode ? apiPreferencesCode : apiPreferenceOntologies(), page, entriesPerPage, pageStart, @@ -195,7 +226,9 @@ export const GetMappingsModal = ({ return olsFilterOntologiesSearch( searchUrl, query, - defaultOntologies, + apiPreferencesCode && Object.keys(apiPreferencesCode).length > 0 + ? apiPreferencesCode + : defaultOntologies, page, entriesPerPage, pageStart, @@ -367,6 +400,21 @@ export const GetMappingsModal = ({
    {displaySelectedMappings?.length > 0 && ( diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index 4fb6d06..a7e2a8d 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -1,9 +1,63 @@ -import { Checkbox, Form } from 'antd'; +import { Checkbox, Form, notification } from 'antd'; import { ontologyCounts } from '../Utilitiy'; +import { useContext, useEffect, useState } from 'react'; +import { myContext } from '../../../App'; +import { SearchContext } from '../../../Contexts/SearchContext'; +import { olsFilterOntologiesSearch } from '../FetchManager'; +import { MappingContext } from '../../../Contexts/MappingContext'; -export const OntologyCheckboxes = ({ facetCounts, apiPreferences }) => { +export const OntologyCheckboxes = ({ apiPreferences }) => { + const { vocabUrl, searchUrl } = useContext(myContext); + const { apiPreferencesCode, setApiPreferencesCode, facetCounts } = + useContext(SearchContext); + const [checkedOntologies, setCheckedOntologies] = useState([]); + + const existingOntologies = apiPreferencesCode + ? apiPreferencesCode + : Object.values(apiPreferences?.self?.api_preference).flat(); // Flatten arrays into a single array + useEffect(() => { + setCheckedOntologies(existingOntologies); // Set the initial checked keys + }, [apiPreferences]); + ``; + + const onCheckboxChange = e => { + const { value, checked } = e.target; + + setCheckedOntologies(existingOntologies => { + const newCheckedOntologies = checked + ? [...existingOntologies, value] // Add key if checked + : existingOntologies.filter(key => key !== value); // Remove key if unchecked + + // Update apiPreferencesCode + setApiPreferencesCode(existingCode => { + if (checked) { + // Add value if checked, and avoid duplications + return existingCode ? `${existingCode},${value}` : value; + } else { + // Remove the value if unchecked + const updatedCode = existingCode + .split(',') + .filter(code => code !== value) + .join(','); + + return updatedCode; + } + }); + + return newCheckedOntologies; + }); + }; const formattedFacetCounts = ontologyCounts(facetCounts); + console.log(apiPreferencesCode); + + // Sort the `formattedFacetCounts` before rendering, not inside the `map()` + const sortedFacetCounts = formattedFacetCounts?.sort( + (a, b) => + (existingOntologies.includes(Object.keys(a)[0]) ? -1 : 1) - + (existingOntologies.includes(Object.keys(b)[0]) ? -1 : 1) + ); + return (
    { rules={[{ required: false }]} >
    - {formattedFacetCounts?.map((fc, i) => { + {sortedFacetCounts?.map((fc, i) => { const key = Object.keys(fc)[0]; const value = fc[key]; + formattedFacetCounts.sort( + (a, b) => + (existingOntologies.includes(Object.keys(a)[0]) ? -1 : 1) - + (existingOntologies.includes(Object.keys(b)[0]) ? -1 : 1) + ); return ( - + {`${key.toUpperCase()} ${value !== '0' ? `(${value})` : ''}`} ); From afc0d9e829b00e4072a91565a5d4b9e0f54664ab Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Mon, 21 Oct 2024 09:01:48 -0500 Subject: [PATCH 028/180] added pagesize select + remembering pagesize to TerminologyList --- .../Projects/Terminologies/TerminologyList.jsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/Projects/Terminologies/TerminologyList.jsx b/src/components/Projects/Terminologies/TerminologyList.jsx index 5b3ca6f..99d0cbf 100644 --- a/src/components/Projects/Terminologies/TerminologyList.jsx +++ b/src/components/Projects/Terminologies/TerminologyList.jsx @@ -14,7 +14,8 @@ export const TerminologyList = () => { const [terms, setTerms] = useState([]); const [filter, setFilter] = useState(null); const [deleteId, setDeleteId] = useState(null); - + const [pageSize, setPageSize] = useState( + parseInt(localStorage.getItem('pageSize'), 10) || 10); const { vocabUrl } = useContext(myContext); const navigate = useNavigate(); @@ -28,7 +29,8 @@ export const TerminologyList = () => { setTerms(data); }) .finally(() => setLoading(false)); - }, []); + localStorage.setItem('pageSize', pageSize); + }, [pageSize]); const terminologyTitle = () => { return ( @@ -44,6 +46,9 @@ export const TerminologyList = () => { {item.name ? item.name : item.id} ); + const handleTableChange = (current, size) => { + setPageSize(size); + }; const columns = [ { @@ -140,9 +145,16 @@ export const TerminologyList = () => {

    Terminology Index

    trigger.parentNode} + pagination={{ + showSizeChanger: true, + pageSizeOptions: ['10', '20', '30'], + pageSize: pageSize, // Use the stored pageSize + onChange: handleTableChange, // Capture pagination changes + }} /> Date: Mon, 21 Oct 2024 10:12:38 -0500 Subject: [PATCH 029/180] unchecked checkboxes remove ontology from api call --- .../MappingsFunctions/GetMappingsModal.jsx | 1 - .../MappingsFunctions/OntologyCheckboxes.jsx | 21 ++++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index c3f6dae..09a90b6 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -49,7 +49,6 @@ export const GetMappingsModal = ({ const [filteredResultsCount, setFilteredResultsCount] = useState(0); const [inputValue, setInputValue] = useState(searchProp); //Sets the value of the search bar const [currentSearchProp, setCurrentSearchProp] = useState(searchProp); - console.log(unformattedPref); const { setSelectedMappings, displaySelectedMappings, diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index a7e2a8d..afd383d 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -20,13 +20,18 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { }, [apiPreferences]); ``; + console.log(existingOntologies); + const onCheckboxChange = e => { const { value, checked } = e.target; setCheckedOntologies(existingOntologies => { - const newCheckedOntologies = checked - ? [...existingOntologies, value] // Add key if checked - : existingOntologies.filter(key => key !== value); // Remove key if unchecked + // Ensure existingOntologies is always an array + const newCheckedOntologies = Array.isArray(existingOntologies) + ? checked + ? [...existingOntologies, value] // Add value if checked + : existingOntologies.filter(key => key !== value) // Remove value if unchecked + : []; // Fallback to an empty array if it's not an array // Update apiPreferencesCode setApiPreferencesCode(existingCode => { @@ -34,22 +39,22 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { // Add value if checked, and avoid duplications return existingCode ? `${existingCode},${value}` : value; } else { - // Remove the value if unchecked + // Remove value if unchecked, handling cases where the string might be empty const updatedCode = existingCode .split(',') - .filter(code => code !== value) + .filter(code => code !== value) // Remove the unchecked value .join(','); - return updatedCode; + // Ensure there's no trailing comma + return updatedCode.replace(/,$/, ''); } }); return newCheckedOntologies; }); }; - const formattedFacetCounts = ontologyCounts(facetCounts); - console.log(apiPreferencesCode); + const formattedFacetCounts = ontologyCounts(facetCounts); // Sort the `formattedFacetCounts` before rendering, not inside the `map()` const sortedFacetCounts = formattedFacetCounts?.sort( From e798b24de94022b3c60d6a8528b38a3dfcf8b1b2 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Mon, 21 Oct 2024 10:39:03 -0500 Subject: [PATCH 030/180] null check --- src/components/Projects/Tables/TableDetails.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 1a759db..80a00a4 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -365,7 +365,7 @@ There is then a tooltip that displays the variables on hover.*/ setMapping={setMapping} tableId={tableId} mappingProp={getMappings?.code} - mappingDesc={getMappings.description ? getMappings.description : 'No Description'} + mappingDesc={getMappings?.description ? getMappings?.description : 'No Description'} /> From a2e5e5f574348140bd53615e65991dff263b954c Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Mon, 21 Oct 2024 11:04:20 -0500 Subject: [PATCH 031/180] fixes --- src/components/Manager/MappingsFunctions/MappingReset.jsx | 2 +- src/components/Projects/Terminologies/EditMappingModal.jsx | 4 ++++ src/components/Projects/Terminologies/Terminology.jsx | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index be0dc58..332961e 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -12,7 +12,7 @@ export const MappingReset = ({ mappingDesc, setEditMappings, form, - onClose, + onClose }) => { const { searchUrl } = useContext(myContext); const { apiPreferences, defaultOntologies } = useContext(SearchContext); diff --git a/src/components/Projects/Terminologies/EditMappingModal.jsx b/src/components/Projects/Terminologies/EditMappingModal.jsx index ecc352c..0288f12 100644 --- a/src/components/Projects/Terminologies/EditMappingModal.jsx +++ b/src/components/Projects/Terminologies/EditMappingModal.jsx @@ -21,6 +21,7 @@ export const EditMappingsModal = ({ setEditMappings, terminologyId, setMapping, + mappingDesc }) => { const [form] = Form.useForm(); const [termMappings, setTermMappings] = useState([]); @@ -320,6 +321,7 @@ export const EditMappingsModal = ({ ? editMappings.display : editMappings?.code} + {mappingDesc}
    ) : ( reset && ( @@ -356,6 +359,7 @@ export const EditMappingsModal = ({ form={form} reset={reset} onClose={form.resetFields} + mappingDesc={editMappings?.description} /> ) )} diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index a7c49b3..65970cf 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -259,6 +259,7 @@ There is then a tooltip that displays the codes on hover.*/ mapping={mapping} terminologyId={terminologyId} setMapping={setMapping} + mappingDesc={editMappings?.description ? editMappings?.description : 'No Description'} /> {/* Displays the edit form */} From 19110298fc0bd1b6dc202a3b9eb9e568c445e038 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 21 Oct 2024 14:12:17 -0500 Subject: [PATCH 032/180] code searching by terminology's filter ontologies --- src/Contexts/SearchContext.jsx | 2 +- src/components/Manager/FetchManager.jsx | 9 - .../MappingsFunctions/GetMappingsModal.jsx | 249 ++++++++---------- .../MappingsFunctions/OntologyCheckboxes.jsx | 10 +- 4 files changed, 112 insertions(+), 158 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index b6b211a..ecfebde 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -13,7 +13,7 @@ export function SearchContextRoot() { const [apiPage, setApiPage] = useState(0); const [apiTotalCount, setApiTotalCount] = useState(); const [apiPreferences, setApiPreferences] = useState({}); - const [apiPreferencesCode, setApiPreferencesCode] = useState({}); + const [apiPreferencesCode, setApiPreferencesCode] = useState(''); const [unformattedPref, setUnformattedPref] = useState([]); const [facetCounts, setFacetCounts] = useState([]); const defaultOntologies = 'mondo,hp,maxo,ncit'; diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index 467fddd..756ccf0 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -275,12 +275,3 @@ export const getFiltersByCode = ( return error; }); }; - -// const preferredCodeOntologies = () => { -// if (apiPreferences?.mappingProp?.api_preference?.ols) { -// return apiPreferences.self.api_preference.ols.join(','); -// } else { -// // else if there are no preferred ontologies, it uses the default ontologies -// return defaultOntologies; -// } -// }; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 09a90b6..1e94ac1 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -32,17 +32,14 @@ export const GetMappingsModal = ({ apiPreferences, defaultOntologies, setFacetCounts, - facetCounts, setApiPreferencesCode, apiPreferencesCode, setUnformattedPref, - unformattedPref, } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 2500; const [loading, setLoading] = useState(false); const [results, setResults] = useState([]); - const [monarchResults, setMonarchResults] = useState([]); const [totalCount, setTotalCount] = useState(); const [resultsCount, setResultsCount] = useState(); const [lastCount, setLastCount] = useState(0); //save last count as count of the results before you fetch data again @@ -81,19 +78,12 @@ export const GetMappingsModal = ({ useEffect(() => { if (apiPreferencesCode) { + fetchResults(0, searchProp); // Pass apiPreferencesCode correctly + } else { fetchResults(0, searchProp); } }, [apiPreferencesCode, searchProp]); - // The '!!' forces currentSearchProp to be evaluated as a boolean. - // If there is a currentSearchProp in the search bar, it evaluates to true and runs the search function. - // The function is run when the code and when the page changes. - useEffect(() => { - if (!!currentSearchProp) { - fetchResults(page, currentSearchProp); - } - }, [page, currentSearchProp]); - /* Pagination is handled via a "View More" link at the bottom of the page. Each click on the "View More" link makes an API call to fetch the next 15 results. This useEffect moves the scroll bar on the modal to the first index of the new batch of results. @@ -127,7 +117,6 @@ export const GetMappingsModal = ({ const onClose = () => { setPage(0); setResults([]); - setLoading(true); setSelectedMappings([]); setDisplaySelectedMappings([]); setSelectedBoxes([]); @@ -180,8 +169,6 @@ export const GetMappingsModal = ({ }); }; - // The function that makes the API call to search for the passed code. - const fetchResults = (page, query) => { if (!!!query) { return undefined; @@ -208,7 +195,9 @@ export const GetMappingsModal = ({ return olsFilterOntologiesSearch( searchUrl, query, - apiPreferencesCode ? apiPreferencesCode : apiPreferenceOntologies(), + apiPreferencesCode !== '' + ? apiPreferencesCode + : apiPreferenceOntologies(), page, entriesPerPage, pageStart, @@ -225,9 +214,9 @@ export const GetMappingsModal = ({ return olsFilterOntologiesSearch( searchUrl, query, - apiPreferencesCode && Object.keys(apiPreferencesCode).length > 0 + apiPreferencesCode !== '' ? apiPreferencesCode - : defaultOntologies, + : apiPreferenceOntologies(), page, entriesPerPage, pageStart, @@ -376,141 +365,119 @@ export const GetMappingsModal = ({ cancelButtonProps={{ disabled: loading }} okButtonProps={{ disabled: loading }} > -
    - <> - {loading === false ? ( - <> -
    -
    -

    {searchProp}

    -
    - -
    + {loading ? ( + + ) : ( +
    + <> +
    +
    +

    {searchProp}

    +
    +
    - {/* ant.design form displaying the checkboxes with the search results. */} - {results?.length > 0 ? ( -
    - -
    - -
    - {displaySelectedMappings?.length > 0 && ( - -
    - {displaySelectedMappings?.map((sm, i) => ( - box.obo_id === sm.obo_id - )} - value={sm} - onChange={e => onCheckboxChange(e, sm, i)} - > - {selectedTermsDisplay(sm, i)} - - ))} -
    -
    - )} +
    + {/* ant.design form displaying the checkboxes with the search results. */} + {results?.length > 0 ? ( +
    + +
    + +
    + {displaySelectedMappings?.length > 0 && ( - {filteredResultsArray?.length > 0 ? ( - { - return { - value: JSON.stringify({ - code: d.obo_id, - display: d.label, - description: d.description[0], - system: systemsMatch( - d?.obo_id.split(':')[0] - ), - }), - label: checkBoxDisplay(d, index), - }; - } - )} - onChange={onSelectedChange} - /> - ) : ( - '' - )} +
    + {displaySelectedMappings?.map((sm, i) => ( + box.obo_id === sm.obo_id + )} + value={sm} + onChange={e => onCheckboxChange(e, sm, i)} + > + {selectedTermsDisplay(sm, i)} + + ))} +
    -
    + )} + + {filteredResultsArray?.length > 0 ? ( + { + return { + value: JSON.stringify({ + code: d.obo_id, + display: d.label, + description: d.description[0], + system: systemsMatch( + d?.obo_id.split(':')[0] + ), + }), + label: checkBoxDisplay(d, index), + }; + } + )} + onChange={onSelectedChange} + /> + ) : ( + '' + )} +
    - -
    - {/* 'View More' pagination displaying the number of results being displayed +
    + +
    + {/* 'View More' pagination displaying the number of results being displayed out of the total number of results. Because of the filter to filter out the duplicates, there is a tooltip informing the user that redundant entries have been removed to explain any inconsistencies in results numbers per page. */} - + Displaying {resultsCount} +  of {totalCount} + + {totalCount - filteredResultsCount !== resultsCount && ( + { + handleViewMore(e); + setLastCount(resultsCount); + }} > - Displaying {resultsCount} -  of {totalCount} - - {totalCount - filteredResultsCount !== resultsCount && ( - { - handleViewMore(e); - setLastCount(resultsCount); - }} - > - View More - - )} -
    + View More + + )}
    - ) : ( -

    No results found.

    - )} -
    - - ) : ( -
    - +
    + ) : ( +

    No results found.

    + )}
    - )} - -
    + +
    + )} ); diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index afd383d..7b62408 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -1,13 +1,9 @@ -import { Checkbox, Form, notification } from 'antd'; +import { Checkbox, Form } from 'antd'; import { ontologyCounts } from '../Utilitiy'; import { useContext, useEffect, useState } from 'react'; -import { myContext } from '../../../App'; import { SearchContext } from '../../../Contexts/SearchContext'; -import { olsFilterOntologiesSearch } from '../FetchManager'; -import { MappingContext } from '../../../Contexts/MappingContext'; export const OntologyCheckboxes = ({ apiPreferences }) => { - const { vocabUrl, searchUrl } = useContext(myContext); const { apiPreferencesCode, setApiPreferencesCode, facetCounts } = useContext(SearchContext); const [checkedOntologies, setCheckedOntologies] = useState([]); @@ -15,13 +11,13 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { const existingOntologies = apiPreferencesCode ? apiPreferencesCode : Object.values(apiPreferences?.self?.api_preference).flat(); // Flatten arrays into a single array + useEffect(() => { setCheckedOntologies(existingOntologies); // Set the initial checked keys }, [apiPreferences]); ``; - console.log(existingOntologies); - + console.log('existing', existingOntologies); const onCheckboxChange = e => { const { value, checked } = e.target; From 8824917a13efbd90ce41b1be2511a41141593162 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Mon, 21 Oct 2024 14:26:56 -0500 Subject: [PATCH 033/180] =?UTF-8?q?OntologyTable=20=E2=88=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/About/OntologyTable.jsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/About/OntologyTable.jsx b/src/components/About/OntologyTable.jsx index 905d099..a326572 100644 --- a/src/components/About/OntologyTable.jsx +++ b/src/components/About/OntologyTable.jsx @@ -1,10 +1,19 @@ import { Button, Input, Space, Table } from 'antd'; import { SearchOutlined } from '@ant-design/icons'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; export const OntologyTable = ({ ontology }) => { const [filter, setFilter] = useState(null); + const [pageSize, setPageSize] = useState( + parseInt(localStorage.getItem('pageSize'), 10) || 10); + const handleTableChange = (current, size) => { + setPageSize(size); + }; + useEffect(() => { + localStorage.setItem('pageSize', pageSize); + }, [pageSize]); + const ontologyTitle = () => { return (
    @@ -85,6 +94,8 @@ export const OntologyTable = ({ ontology }) => { })) ); + + return (
    { scroll={{ y: 470, }} + pagination={{ + showSizeChanger: true, + pageSizeOptions: ['10', '20', '30'], + pageSize: pageSize, // Use the stored pageSize + onChange: handleTableChange, // Capture pagination changes + }} /> ); }; From 3beb65b2f0c6fa3bbbff6f1ed8d297fa58c6d9ff Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Mon, 21 Oct 2024 14:27:11 -0500 Subject: [PATCH 034/180] =?UTF-8?q?tableDetails=20=E2=88=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Projects/Tables/TableDetails.jsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 80a00a4..69eddd6 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -40,6 +40,11 @@ export const TableDetails = () => { const [loading, setLoading] = useState(true); const [load, setLoad] = useState(false); + const [pageSize, setPageSize] = useState( + parseInt(localStorage.getItem('pageSize'), 10) || 10); + const handleTableChange = (current, size) => { + setPageSize(size); + }; const navigate = useNavigate(); const handleSuccess = () => { @@ -49,7 +54,8 @@ export const TableDetails = () => { useEffect(() => { setDataSource(tableData(table)); - }, [table, mapping]); + localStorage.setItem('pageSize', pageSize); + }, [table, mapping, pageSize]); const alphabetizeOntologies = ontologies => { // Sort the keys alphabetically @@ -309,6 +315,12 @@ There is then a tooltip that displays the variables on hover.*/ record.data_type === 'INTEGER' || record.data_type === 'QUANTITY', }} + pagination={{ + showSizeChanger: true, + pageSizeOptions: ['10', '20', '30'], + pageSize: pageSize, // Use the stored pageSize + onChange: handleTableChange, // Capture pagination changes + }} /> From 945a8008078bf89b3a8682ad924adc378b8ec6d0 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Mon, 21 Oct 2024 14:27:21 -0500 Subject: [PATCH 035/180] =?UTF-8?q?Terminology=20=E2=88=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Projects/Terminologies/Terminology.jsx | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index 65970cf..70d1f3a 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -33,6 +33,16 @@ export const Terminology = () => { setMapping, } = useContext(MappingContext); + const [pageSize, setPageSize] = useState( + parseInt(localStorage.getItem('pageSize'), 10) || 10); + const handleTableChange = (current, size) => { + setPageSize(size); + }; + useEffect(() => { + localStorage.setItem('pageSize', pageSize); + }, [pageSize]); + + const [loading, setLoading] = useState(true); const initialTerminology = { url: '', description: '', name: '', codes: [] }; //initial state of terminology const [terminology, setTerminology] = useState(initialTerminology); @@ -248,7 +258,15 @@ There is then a tooltip that displays the codes on hover.*/ ) : (
    -
    +
    )} From 234fe1e6039247cadc556ce734e6e339d4b7848e Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 21 Oct 2024 23:06:52 -0500 Subject: [PATCH 036/180] default ontologies checking by default --- src/App.jsx | 1 - src/Contexts/SearchContext.jsx | 2 +- src/components/Manager/FetchManager.jsx | 9 +- .../MappingsFunctions/GetMappingsModal.jsx | 193 +++++++++--------- .../MappingsFunctions/OntologyCheckboxes.jsx | 36 +++- .../Projects/Tables/TableDetails.jsx | 1 + 6 files changed, 133 insertions(+), 109 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 2096b18..4769f37 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -41,7 +41,6 @@ function App() { top: '25vh', }); return ( - { return fetch( - `${vocabUrl}/${component?.terminology?.reference}/filter/${mappingProp}`, + `${vocabUrl}/${ + component === table + ? component?.terminology?.reference + : `Terminology/${component.id}` + }/filter/${mappingProp}`, { method: 'GET', headers: { diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 1e94ac1..902328d 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -9,7 +9,7 @@ import { } from 'antd'; import { useContext, useEffect, useRef, useState } from 'react'; import { myContext } from '../../../App'; -import { ellipsisString, ontologyCounts, systemsMatch } from '../Utilitiy'; +import { ellipsisString, systemsMatch } from '../Utilitiy'; import { ModalSpinner } from '../Spinner'; import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; @@ -23,6 +23,7 @@ export const GetMappingsModal = ({ searchProp, component, mappingProp, + table, }) => { const [form] = Form.useForm(); const { Search } = Input; @@ -30,6 +31,7 @@ export const GetMappingsModal = ({ const { searchUrl, vocabUrl, setSelectedKey, user } = useContext(myContext); const { apiPreferences, + setApiPreferences, defaultOntologies, setFacetCounts, setApiPreferencesCode, @@ -71,17 +73,14 @@ export const GetMappingsModal = ({ setApiPreferencesCode, notification, apiPreferencesCode, - setUnformattedPref + setUnformattedPref, + table ); } }, [searchProp]); useEffect(() => { - if (apiPreferencesCode) { - fetchResults(0, searchProp); // Pass apiPreferencesCode correctly - } else { - fetchResults(0, searchProp); - } + if (apiPreferencesCode !== undefined) fetchResults(0, searchProp); }, [apiPreferencesCode, searchProp]); /* Pagination is handled via a "View More" link at the bottom of the page. @@ -89,7 +88,7 @@ export const GetMappingsModal = ({ This useEffect moves the scroll bar on the modal to the first index of the new batch of results. Because the content is in a modal and not the window, the closest class name to the modal is used for the location of the ref. */ useEffect(() => { - if (results && page > 0) { + if (results?.length > 0 && page > 0) { const container = ref.current.closest('.ant-modal-body'); const scrollTop = ref.current.offsetTop - container.offsetTop; container.scrollTop = scrollTop; @@ -119,6 +118,8 @@ export const GetMappingsModal = ({ setResults([]); setSelectedMappings([]); setDisplaySelectedMappings([]); + setApiPreferencesCode(undefined); + setApiPreferences([]); setSelectedBoxes([]); setSelectedKey(null); }; @@ -214,9 +215,7 @@ export const GetMappingsModal = ({ return olsFilterOntologiesSearch( searchUrl, query, - apiPreferencesCode !== '' - ? apiPreferencesCode - : apiPreferenceOntologies(), + apiPreferencesCode !== '' ? apiPreferencesCode : defaultOntologies, page, entriesPerPage, pageStart, @@ -341,6 +340,7 @@ export const GetMappingsModal = ({ }; const filteredResultsArray = getFilteredResults(); + return ( <> { form.validateFields().then(values => { - handleSubmit(values); + // handleSubmit(values); + console.log(values); onClose(); }); }} @@ -382,98 +383,100 @@ export const GetMappingsModal = ({ {/* ant.design form displaying the checkboxes with the search results. */} - {results?.length > 0 ? ( -
    -
    -
    - -
    - {displaySelectedMappings?.length > 0 && ( +
    + +
    + +
    + {results?.length > 0 ? ( + <> + {displaySelectedMappings?.length > 0 && ( + +
    + {displaySelectedMappings?.map((sm, i) => ( + box.obo_id === sm.obo_id + )} + value={sm} + onChange={e => onCheckboxChange(e, sm, i)} + > + {selectedTermsDisplay(sm, i)} + + ))} +
    +
    + )} -
    - {displaySelectedMappings?.map((sm, i) => ( - box.obo_id === sm.obo_id - )} - value={sm} - onChange={e => onCheckboxChange(e, sm, i)} - > - {selectedTermsDisplay(sm, i)} - - ))} -
    -
    - )} - - {filteredResultsArray?.length > 0 ? ( - { - return { - value: JSON.stringify({ - code: d.obo_id, - display: d.label, - description: d.description[0], - system: systemsMatch( - d?.obo_id.split(':')[0] - ), - }), - label: checkBoxDisplay(d, index), - }; - } - )} - onChange={onSelectedChange} - /> - ) : ( - '' - )} - -
    + {filteredResultsArray?.length > 0 ? ( + { + return { + value: JSON.stringify({ + code: d.obo_id, + display: d.label, + description: d.description[0], + system: systemsMatch( + d?.obo_id.split(':')[0] + ), + }), + label: checkBoxDisplay(d, index), + }; + } + )} + onChange={onSelectedChange} + /> + ) : ( + '' + )} + {' '} + + ) : ( +

    No results found

    + )}
    - -
    - {/* 'View More' pagination displaying the number of results being displayed +
    + +
    + {/* 'View More' pagination displaying the number of results being displayed out of the total number of results. Because of the filter to filter out the duplicates, there is a tooltip informing the user that redundant entries have been removed to explain any inconsistencies in results numbers per page. */} - + Displaying {resultsCount} +  of {totalCount} + + {totalCount - filteredResultsCount !== resultsCount && ( + { + handleViewMore(e); + setLastCount(resultsCount); + }} > - Displaying {resultsCount} -  of {totalCount} - - {totalCount - filteredResultsCount !== resultsCount && ( - { - handleViewMore(e); - setLastCount(resultsCount); - }} - > - View More - - )} -
    + View More + + )}
    - ) : ( -

    No results found.

    - )} +
    diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index 7b62408..e6085d9 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -8,16 +8,23 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { useContext(SearchContext); const [checkedOntologies, setCheckedOntologies] = useState([]); + const defaultOntologies = ['mondo', 'hp', 'maxo', 'ncit']; const existingOntologies = apiPreferencesCode ? apiPreferencesCode - : Object.values(apiPreferences?.self?.api_preference).flat(); // Flatten arrays into a single array + : apiPreferences && + apiPreferences?.self && + apiPreferences?.self?.api_preference + ? Object?.values(apiPreferences?.self?.api_preference).flat() + : defaultOntologies; useEffect(() => { - setCheckedOntologies(existingOntologies); // Set the initial checked keys + setCheckedOntologies(existingOntologies); }, [apiPreferences]); - ``; - console.log('existing', existingOntologies); + console.log('default', defaultOntologies); + console.log('exsiting', existingOntologies); + console.log('checked', checkedOntologies); + const onCheckboxChange = e => { const { value, checked } = e.target; @@ -52,11 +59,18 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { const formattedFacetCounts = ontologyCounts(facetCounts); + const existingOntologiesArray = Array.isArray(existingOntologies) + ? existingOntologies + : []; + + const checkedOntologiesArray = Array.isArray(checkedOntologies) + ? checkedOntologies + : []; // Sort the `formattedFacetCounts` before rendering, not inside the `map()` const sortedFacetCounts = formattedFacetCounts?.sort( (a, b) => - (existingOntologies.includes(Object.keys(a)[0]) ? -1 : 1) - - (existingOntologies.includes(Object.keys(b)[0]) ? -1 : 1) + (existingOntologiesArray?.includes(Object.keys(a)[0]) ? -1 : 1) - + (existingOntologiesArray?.includes(Object.keys(b)[0]) ? -1 : 1) ); return ( @@ -72,16 +86,18 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { const value = fc[key]; formattedFacetCounts.sort( (a, b) => - (existingOntologies.includes(Object.keys(a)[0]) ? -1 : 1) - - (existingOntologies.includes(Object.keys(b)[0]) ? -1 : 1) + (existingOntologiesArray?.includes(Object.keys(a)[0]) + ? -1 + : 1) - + (existingOntologiesArray?.includes(Object.keys(b)[0]) ? -1 : 1) ); return ( {`${key.toUpperCase()} ${value !== '0' ? `(${value})` : ''}`} diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 863cb79..f1edf07 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -365,6 +365,7 @@ There is then a tooltip that displays the variables on hover.*/ setMapping={setMapping} tableId={tableId} mappingProp={getMappings?.code} + table={table} /> From fe5ff4cd9180ba30ab45bdb4d11e9c7ab7400ef1 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Tue, 22 Oct 2024 14:38:28 -0500 Subject: [PATCH 037/180] c2c --- .../Projects/Tables/TableDetails.jsx | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 80a00a4..744e922 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -48,6 +48,7 @@ export const TableDetails = () => { const login = RequiredLogin({ handleSuccess: handleSuccess }); useEffect(() => { + setDataSource(tableData(table)); }, [table, mapping]); @@ -177,22 +178,24 @@ The function maps through the mapping array. For each variable, if the mapping v variable in the table, AND the mappings array length for the variable is > 0, the mappings array is mapped through and returns the length of the mapping array (i.e. returns the number of variables mapped to the table variable). There is then a tooltip that displays the variables on hover.*/ - const matchCode = variable => - mapping?.length > 0 && - mapping?.map( - (item, index) => - item?.code === variable?.code && - item?.mappings?.length > 0 && ( - { - return
    {code.code}
    ; - })} - key={index} - > - {item?.mappings?.length} -
    - ) - ); +const noMapping = "noMapping" +const matchCode = variable => { + if (!mapping?.length) { + return noMapping; // Return "noMapping" if there are no mappings + } + + const mappedTerms = mapping.map((item, index) => { + if (item?.code === variable?.code && item?.mappings?.length) { + return item.mappings.map(code =>
    {code.display}
    ); + } + return null; // Return null if no match is found for this variable + }); + + // Check if any mappings were found for this variable + return mappedTerms.some(term => term !== null) ? mappedTerms : noMapping; +}; + + // data for the table columns. Each table has an array of variables. Each variable has a name, description, and data type. // The integer and quantity data types include additional details. @@ -365,7 +368,6 @@ There is then a tooltip that displays the variables on hover.*/ setMapping={setMapping} tableId={tableId} mappingProp={getMappings?.code} - mappingDesc={getMappings?.description ? getMappings?.description : 'No Description'} /> From 11bb27a5ff7c3398ed299fbcc453e0e56dfd8d84 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Tue, 22 Oct 2024 15:06:34 -0500 Subject: [PATCH 038/180] user and access the setmapping window from table --- .../Projects/Tables/TableDetails.jsx | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 744e922..375d3fc 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -178,22 +178,25 @@ The function maps through the mapping array. For each variable, if the mapping v variable in the table, AND the mappings array length for the variable is > 0, the mappings array is mapped through and returns the length of the mapping array (i.e. returns the number of variables mapped to the table variable). There is then a tooltip that displays the variables on hover.*/ -const noMapping = "noMapping" -const matchCode = variable => { - if (!mapping?.length) { - return noMapping; // Return "noMapping" if there are no mappings +const noMapping = variable => { +return } - const mappedTerms = mapping.map((item, index) => { - if (item?.code === variable?.code && item?.mappings?.length) { - return item.mappings.map(code =>
    {code.display}
    ); - } - return null; // Return null if no match is found for this variable - }); - - // Check if any mappings were found for this variable - return mappedTerms.some(term => term !== null) ? mappedTerms : noMapping; -}; + const matchCode = variable => { + if (!mapping?.length) { + return noMapping(variable); + } + + const variableMappings = mapping.find(item => item?.code === variable?.code); + + if (variableMappings && variableMappings.mappings?.length) { + return variableMappings.mappings.map(code =>
    {code.display}
    ); + } else { + return noMapping(variable); + } + }; From d4096f53a0d1e8537a6f5497968cc6c18f970374 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Tue, 22 Oct 2024 15:08:11 -0500 Subject: [PATCH 039/180] user and access the setmapping window from table --- src/components/Projects/Tables/TableDetails.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 375d3fc..71de573 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -180,7 +180,7 @@ and returns the length of the mapping array (i.e. returns the number of variable There is then a tooltip that displays the variables on hover.*/ const noMapping = variable => { return } From eec9f38c5c14c68ccfe1684c5bcfcbe47709716a Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 22 Oct 2024 15:24:52 -0500 Subject: [PATCH 040/180] all ontologies listed with checkboxes --- src/Contexts/SearchContext.jsx | 4 + .../Manager/MappingsFunctions/FilterReset.jsx | 2 +- .../MappingsFunctions/FilterSelect.jsx | 3 +- .../MappingsFunctions/GetMappingsModal.jsx | 1 - .../MappingsFunctions/OntologyCheckboxes.jsx | 103 ++++++++++-------- 5 files changed, 63 insertions(+), 50 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index d7098af..1266910 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -16,6 +16,8 @@ export function SearchContextRoot() { const [apiPreferencesCode, setApiPreferencesCode] = useState(undefined); const [unformattedPref, setUnformattedPref] = useState([]); const [facetCounts, setFacetCounts] = useState([]); + const [ontologyApis, setOntologyApis] = useState([]); + const defaultOntologies = 'mondo,hp,maxo,ncit'; const context = { @@ -44,6 +46,8 @@ export function SearchContextRoot() { setFacetCounts, unformattedPref, setUnformattedPref, + ontologyApis, + setOntologyApis, }; return ( diff --git a/src/components/Manager/MappingsFunctions/FilterReset.jsx b/src/components/Manager/MappingsFunctions/FilterReset.jsx index ac37e40..d1229fe 100644 --- a/src/components/Manager/MappingsFunctions/FilterReset.jsx +++ b/src/components/Manager/MappingsFunctions/FilterReset.jsx @@ -12,7 +12,7 @@ export const FilterReset = ({ table }) => { const [remove, setRemove] = useState(false); const deleteOntologies = evt => { - return fetch(`${vocabUrl}/${table?.terminology?.reference}/filter`, { + return fetch(`${vocabUrl}/${table?.terminology?.reference}/filter/self`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index 538f380..d763a39 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -5,6 +5,7 @@ import { myContext } from '../../../App'; import { FilterAPI } from './FilterAPI'; import { getOntologies } from '../FetchManager'; import { ModalSpinner } from '../Spinner'; +import { SearchContext } from '../../../Contexts/SearchContext'; export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { const [form] = Form.useForm(); @@ -19,7 +20,7 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { const [active, setActive] = useState(null); const [loading, setLoading] = useState(false); const { user, vocabUrl, ontologyForPagination } = useContext(myContext); - const [ontologyApis, setOntologyApis] = useState([]); + const { ontologyApis, setOntologyApis } = useContext(SearchContext); const [searchText, setSearchText] = useState(''); // Gets the ontologyAPIs on first load, automatically sets active to the first of the list to display on the page diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 902328d..2f7dcb7 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -119,7 +119,6 @@ export const GetMappingsModal = ({ setSelectedMappings([]); setDisplaySelectedMappings([]); setApiPreferencesCode(undefined); - setApiPreferences([]); setSelectedBoxes([]); setSelectedKey(null); }; diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index e6085d9..61482ed 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -4,8 +4,12 @@ import { useContext, useEffect, useState } from 'react'; import { SearchContext } from '../../../Contexts/SearchContext'; export const OntologyCheckboxes = ({ apiPreferences }) => { - const { apiPreferencesCode, setApiPreferencesCode, facetCounts } = - useContext(SearchContext); + const { + apiPreferencesCode, + setApiPreferencesCode, + facetCounts, + ontologyApis, + } = useContext(SearchContext); const [checkedOntologies, setCheckedOntologies] = useState([]); const defaultOntologies = ['mondo', 'hp', 'maxo', 'ncit']; @@ -21,35 +25,26 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { setCheckedOntologies(existingOntologies); }, [apiPreferences]); - console.log('default', defaultOntologies); - console.log('exsiting', existingOntologies); - console.log('checked', checkedOntologies); - const onCheckboxChange = e => { const { value, checked } = e.target; setCheckedOntologies(existingOntologies => { - // Ensure existingOntologies is always an array const newCheckedOntologies = Array.isArray(existingOntologies) ? checked - ? [...existingOntologies, value] // Add value if checked - : existingOntologies.filter(key => key !== value) // Remove value if unchecked - : []; // Fallback to an empty array if it's not an array + ? [...existingOntologies, value] + : existingOntologies.filter(key => key !== value) + : []; - // Update apiPreferencesCode setApiPreferencesCode(existingCode => { if (checked) { - // Add value if checked, and avoid duplications return existingCode ? `${existingCode},${value}` : value; } else { - // Remove value if unchecked, handling cases where the string might be empty const updatedCode = existingCode .split(',') - .filter(code => code !== value) // Remove the unchecked value + .filter(code => code !== value) .join(','); - // Ensure there's no trailing comma - return updatedCode.replace(/,$/, ''); + return updatedCode; } }); @@ -59,19 +54,35 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { const formattedFacetCounts = ontologyCounts(facetCounts); - const existingOntologiesArray = Array.isArray(existingOntologies) - ? existingOntologies - : []; + const sortedData = ontologyApis.map(api => { + const sortedOntologies = Object.fromEntries( + Object.entries(api.ontologies).sort((a, b) => + a[1].ontology_code > b[1].ontology_code ? 1 : -1 + ) + ); + + return { + ...api, + ontologies: sortedOntologies, + }; + }); + + const countsMap = formattedFacetCounts.reduce((acc, item) => { + const key = Object.keys(item)[0]; + acc[key] = parseInt(item[key], 10); + return acc; + }, {}); + + // // Build the new data structure + const countsResult = Object.keys(sortedData[0].ontologies).map(key => { + return { [key]: countsMap[key] || 0 }; + }); const checkedOntologiesArray = Array.isArray(checkedOntologies) ? checkedOntologies : []; - // Sort the `formattedFacetCounts` before rendering, not inside the `map()` - const sortedFacetCounts = formattedFacetCounts?.sort( - (a, b) => - (existingOntologiesArray?.includes(Object.keys(a)[0]) ? -1 : 1) - - (existingOntologiesArray?.includes(Object.keys(b)[0]) ? -1 : 1) - ); + + console.log(checkedOntologiesArray); return (
    @@ -81,28 +92,26 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { rules={[{ required: false }]} >
    - {sortedFacetCounts?.map((fc, i) => { - const key = Object.keys(fc)[0]; - const value = fc[key]; - formattedFacetCounts.sort( - (a, b) => - (existingOntologiesArray?.includes(Object.keys(a)[0]) - ? -1 - : 1) - - (existingOntologiesArray?.includes(Object.keys(b)[0]) ? -1 : 1) - ); - - return ( - - {`${key.toUpperCase()} ${value !== '0' ? `(${value})` : ''}`} - - ); - })} + {countsResult + ?.sort((a, b) => { + const aValue = Object.values(a)[0]; + const bValue = Object.values(b)[0]; + return bValue - aValue; + }) + .map((fc, i) => { + const key = Object.keys(fc)[0]; + const value = fc[key]; + return ( + + {`${key.toUpperCase()} ${value !== 0 ? `(${value})` : ''}`} + + ); + })}
    From 674320612443a6c8f24e7841784d38c43eb71034 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 22 Oct 2024 16:04:25 -0500 Subject: [PATCH 041/180] checkboxes checking and updating apiPreferencesCode --- .../MappingsFunctions/OntologyCheckboxes.jsx | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index 61482ed..addba01 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -13,6 +13,7 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { const [checkedOntologies, setCheckedOntologies] = useState([]); const defaultOntologies = ['mondo', 'hp', 'maxo', 'ncit']; + const existingOntologies = apiPreferencesCode ? apiPreferencesCode : apiPreferences && @@ -35,18 +36,7 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { : existingOntologies.filter(key => key !== value) : []; - setApiPreferencesCode(existingCode => { - if (checked) { - return existingCode ? `${existingCode},${value}` : value; - } else { - const updatedCode = existingCode - .split(',') - .filter(code => code !== value) - .join(','); - - return updatedCode; - } - }); + setApiPreferencesCode(newCheckedOntologies); return newCheckedOntologies; }); From f0f3d9e7f7c2444fdd9458e011ae4d7de4fa0f22 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Wed, 23 Oct 2024 08:45:39 -0500 Subject: [PATCH 042/180] adding delete mapping from table --- .../Projects/Tables/TableDetails.jsx | 76 ++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 71de573..a8b353b 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -4,7 +4,7 @@ import './TableStyling.scss'; import { Link, useNavigate, useParams } from 'react-router-dom'; import { Spinner } from '../../Manager/Spinner'; import { getById } from '../../Manager/FetchManager'; -import { Card, Col, Form, notification, Row, Table, Tooltip } from 'antd'; +import { Card, Col, Form, notification, Row, Table, Button } from 'antd'; import { EditTableDetails } from './EditTableDetails'; import { DeleteTable } from './DeleteTable'; import { LoadVariables } from './LoadVariables'; @@ -52,6 +52,51 @@ export const TableDetails = () => { setDataSource(tableData(table)); }, [table, mapping]); + + const updateMappings = (mapArr,mappingCode ) => { + + // setLoading(true); + const mappingsDTO = { + mappings: mapArr, + editor: user.email, + }; + console.log(mappingsDTO,"mappingsDTO"); + + fetch(`${vocabUrl}/Table/${tableId}/mapping/${mappingCode}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(mappingsDTO), + }) + .then(res => { + if (res.ok) { + return res.json(); + } else { + throw new Error('An unknown error occurred.'); + } + }) + .then(data => { + setMapping(data.codes); + setEditMappings(null); + form.resetFields(); + notification.success({ description:'Mapping removed.'}); + }) + .catch(error => { + console.log(error,'error'); + + if (error) { + notification.error({ + message: 'Error', + description: 'An error occurred. Please try again.', + }); + } + return error; + }) + .finally(() => setLoading(false)); + }; + + const alphabetizeOntologies = ontologies => { // Sort the keys alphabetically const sortedKeys = Object.keys(ontologies).sort(); @@ -79,6 +124,8 @@ export const TableDetails = () => { .then(data => setMapping(data.codes)) .catch(error => { if (error) { + console.log(error,"error"); + notification.error({ message: 'Error', description: 'An error occurred loading mappings.', @@ -178,26 +225,37 @@ The function maps through the mapping array. For each variable, if the mapping v variable in the table, AND the mappings array length for the variable is > 0, the mappings array is mapped through and returns the length of the mapping array (i.e. returns the number of variables mapped to the table variable). There is then a tooltip that displays the variables on hover.*/ -const noMapping = variable => { -return + const noMapping = variable => { + return } const matchCode = variable => { + + if (!mapping?.length) { return noMapping(variable); } - - const variableMappings = mapping.find(item => item?.code === variable?.code); - + + const variableMappings = mapping.find(item => item?.code === variable?.code); + if (variableMappings && variableMappings.mappings?.length) { - return variableMappings.mappings.map(code =>
    {code.display}
    ); + return variableMappings.mappings.map(code =>
    handleRemoveMapping(variableMappings,code)}>X {code.display}
    ); } else { return noMapping(variable); } }; + const handleRemoveMapping = (variableMappings,code) => { + // console.log(variableMappings,"variableMappings"); + const mappingToRemove = variableMappings.mappings.indexOf(code); + //remove mapping from mappings + {mappingToRemove !== -1 && variableMappings.mappings.splice(mappingToRemove,1)} + updateMappings(variableMappings?.mappings,variableMappings?.code); + + } + // data for the table columns. Each table has an array of variables. Each variable has a name, description, and data type. From 16832f2a0507f0e29ee1fb5072cede2433c47215 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Wed, 23 Oct 2024 08:47:09 -0500 Subject: [PATCH 043/180] adding ant icons --- package-lock.json | 15 ++++++++------- package.json | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index e277d09..419d30d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "vocab-management-tool", "version": "0.0.0", "dependencies": { + "@ant-design/icons": "^5.5.1", "@react-oauth/google": "^0.12.1", "antd": "^5.15.2", "jwt-decode": "^4.0.0", @@ -77,13 +78,13 @@ } }, "node_modules/@ant-design/icons": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.3.7.tgz", - "integrity": "sha512-bCPXTAg66f5bdccM4TT21SQBDO1Ek2gho9h3nO9DAKXJP4sq+5VBjrQMSxMVXSB3HyEz+cUbHQ5+6ogxCOpaew==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.1.tgz", + "integrity": "sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==", "dependencies": { "@ant-design/colors": "^7.0.0", "@ant-design/icons-svg": "^4.4.0", - "@babel/runtime": "^7.11.2", + "@babel/runtime": "^7.24.8", "classnames": "^2.2.6", "rc-util": "^5.31.1" }, @@ -394,9 +395,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz", + "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==", "dependencies": { "regenerator-runtime": "^0.14.0" }, diff --git a/package.json b/package.json index 5855550..38334e7 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "preview": "vite preview" }, "dependencies": { + "@ant-design/icons": "^5.5.1", "@react-oauth/google": "^0.12.1", "antd": "^5.15.2", "jwt-decode": "^4.0.0", From d0be76d103d33a4320b68279d838d499640fba5b Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Wed, 23 Oct 2024 09:13:04 -0500 Subject: [PATCH 044/180] adding styling --- .../Projects/Tables/TableDetails.jsx | 3 ++- .../Projects/Tables/TableStyling.scss | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index a8b353b..d5f93e5 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -5,6 +5,7 @@ import { Link, useNavigate, useParams } from 'react-router-dom'; import { Spinner } from '../../Manager/Spinner'; import { getById } from '../../Manager/FetchManager'; import { Card, Col, Form, notification, Row, Table, Button } from 'antd'; +import { CloseCircleOutlined } from '@ant-design/icons'; import { EditTableDetails } from './EditTableDetails'; import { DeleteTable } from './DeleteTable'; import { LoadVariables } from './LoadVariables'; @@ -241,7 +242,7 @@ There is then a tooltip that displays the variables on hover.*/ const variableMappings = mapping.find(item => item?.code === variable?.code); if (variableMappings && variableMappings.mappings?.length) { - return variableMappings.mappings.map(code =>
    handleRemoveMapping(variableMappings,code)}>X {code.display}
    ); + return variableMappings.mappings.map(code =>
    {code.display} handleRemoveMapping(variableMappings,code)}>
    ); } else { return noMapping(variable); } diff --git a/src/components/Projects/Tables/TableStyling.scss b/src/components/Projects/Tables/TableStyling.scss index 4cf5288..4767acb 100644 --- a/src/components/Projects/Tables/TableStyling.scss +++ b/src/components/Projects/Tables/TableStyling.scss @@ -54,6 +54,7 @@ input::file-selector-button:hover { border: 1px solid darkgrey; color: gray; border-radius: 25px; + font: { size: 0.7rem; weight: 800; @@ -74,3 +75,20 @@ input::file-selector-button:hover { gap: 10px; margin-left: 50px; } + +.mapping { + &-display{ + white-space: nowrap; + } + display: flex; + .remove-mapping { + padding-left:.25rem; + cursor: pointer; + opacity: 0; + + &:hover { + transition: all .4s linear; + opacity: 1; + } + } +} \ No newline at end of file From 7e229972e793c996eb3d31ea29c047ad9d324745 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Wed, 23 Oct 2024 09:29:40 -0500 Subject: [PATCH 045/180] Get MappingS --- src/components/Projects/Tables/TableDetails.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index d5f93e5..f0f2afb 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -228,7 +228,7 @@ and returns the length of the mapping array (i.e. returns the number of variable There is then a tooltip that displays the variables on hover.*/ const noMapping = variable => { return } From 7fb589c289d7ba886b5ad336823209e6fa996d15 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Wed, 23 Oct 2024 09:31:07 -0500 Subject: [PATCH 046/180] updating comment --- src/components/Projects/Tables/TableDetails.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index f0f2afb..f570285 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -225,7 +225,7 @@ The variables in the mappings need to be matched up to each variable in the tabl The function maps through the mapping array. For each variable, if the mapping variable is equal to the variable in the table, AND the mappings array length for the variable is > 0, the mappings array is mapped through and returns the length of the mapping array (i.e. returns the number of variables mapped to the table variable). -There is then a tooltip that displays the variables on hover.*/ +It then shows the mappings as table data and alows the user to delete a mapping from the table.*/ const noMapping = variable => { return + } + + const matchCode = variable => { + + + if (!mapping?.length) { + return noMapping(variable); + } + + const variableMappings = mapping.find(item => item?.code === variable?.code); + + if (variableMappings && variableMappings.mappings?.length) { + return variableMappings.mappings.map(code =>
    {code.display} handleRemoveMapping(variableMappings,code)}>
    ); + } else { + return noMapping(variable); + } + }; + + const handleRemoveMapping = (variableMappings,code) => { + // console.log(variableMappings,"variableMappings"); + const mappingToRemove = variableMappings.mappings.indexOf(code); + //remove mapping from mappings + {mappingToRemove !== -1 && variableMappings.mappings.splice(mappingToRemove,1)} + updateMappings(variableMappings?.mappings,variableMappings?.code); + + } + // data for each column in the table. // Map through the codes in the terminology and display the code, display, number of mapped terms, From 954e2772c0afd28fbe5d390d24e6d756515cf3bf Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 24 Oct 2024 08:39:36 -0500 Subject: [PATCH 060/180] margins --- src/components/Nav/NavBar.scss | 3 ++- src/components/Projects/Terminologies/Terminology.scss | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/Nav/NavBar.scss b/src/components/Nav/NavBar.scss index 02b9884..95459e7 100644 --- a/src/components/Nav/NavBar.scss +++ b/src/components/Nav/NavBar.scss @@ -91,12 +91,13 @@ nav.navbar { display: flex; align-items: baseline; z-index: 1; - padding: 0 .5rem; + padding: 0 10vw; position: sticky; top: 115px; background:#eeeeee; li { + list-style: none; font-size: 14px; line-height: 1.5714285714285714; color: rgba(0, 0, 0, 0.45); diff --git a/src/components/Projects/Terminologies/Terminology.scss b/src/components/Projects/Terminologies/Terminology.scss index a73c8ef..7a7405b 100644 --- a/src/components/Projects/Terminologies/Terminology.scss +++ b/src/components/Projects/Terminologies/Terminology.scss @@ -1,6 +1,6 @@ @import '../../Styling/Variables'; .terminology_container { - margin: 5rem 10vw 10vh 5rem; + margin: 5rem 10vw 10vh 10vw; width: 66vw; } From d431cd00fa0010e17fd8d4759c0fc8886a2373e0 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 24 Oct 2024 08:44:33 -0500 Subject: [PATCH 061/180] rm fixed ontology table --- src/components/About/OntologyInfo.scss | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/About/OntologyInfo.scss b/src/components/About/OntologyInfo.scss index 226e395..db5a8b1 100644 --- a/src/components/About/OntologyInfo.scss +++ b/src/components/About/OntologyInfo.scss @@ -13,7 +13,6 @@ .api_list { width: 12vw; height: fit-content; - position: fixed; display: flex; flex-flow: column wrap; gap: 2px; @@ -40,7 +39,6 @@ } .ontology_list { margin: 0 0 0 15vw; - position: fixed; top: 20vh; height: 20%; width: 70vw; From a04663807380d32eafde7af6903ea7cee62aa8e6 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 24 Oct 2024 08:47:43 -0500 Subject: [PATCH 062/180] about_container margin --- src/components/About/OntologyInfo.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/About/OntologyInfo.scss b/src/components/About/OntologyInfo.scss index db5a8b1..249f4de 100644 --- a/src/components/About/OntologyInfo.scss +++ b/src/components/About/OntologyInfo.scss @@ -1,7 +1,7 @@ @import '../Styling/Variables'; .about_container { - margin: 17vh 10vw 10vh 10vw; + margin: 0 10vw; line-height: 1.5rem; } From 120e23721ed182833085157f5e2a2f78ecb9d4fd Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 24 Oct 2024 09:23:57 -0500 Subject: [PATCH 063/180] moved 'no results found' to still display any selected mappings --- .../MappingsFunctions/GetMappingsModal.jsx | 44 ++++---- .../MappingsFunctions/MappingReset.jsx | 44 ++++---- .../MappingsFunctions/MappingSearch.jsx | 105 +++++++++--------- 3 files changed, 95 insertions(+), 98 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index a6e3974..74dc182 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -402,30 +402,30 @@ export const GetMappingsModal = ({
    + {displaySelectedMappings?.length > 0 && ( + +
    + {displaySelectedMappings?.map((sm, i) => ( + box.obo_id === sm.obo_id + )} + value={sm} + onChange={e => onCheckboxChange(e, sm, i)} + > + {selectedTermsDisplay(sm, i)} + + ))} +
    +
    + )} {results?.length > 0 ? ( <> - {displaySelectedMappings?.length > 0 && ( - -
    - {displaySelectedMappings?.map((sm, i) => ( - box.obo_id === sm.obo_id - )} - value={sm} - onChange={e => onCheckboxChange(e, sm, i)} - > - {selectedTermsDisplay(sm, i)} - - ))} -
    -
    - )}
    + {displaySelectedMappings?.length > 0 && ( + +
    + {displaySelectedMappings?.map((sm, i) => ( + onCheckboxChange(e, sm)} + checked={selectedBoxes.some( + box => box.obo_id === sm.obo_id + )} + value={sm} + > + {selectedTermsDisplay(sm, i)} + + ))} +
    +
    + )}{' '} {results?.length > 0 ? ( <> - {displaySelectedMappings?.length > 0 && ( - -
    - {displaySelectedMappings?.map((sm, i) => ( - onCheckboxChange(e, sm)} - checked={selectedBoxes.some( - box => box.obo_id === sm.obo_id - )} - value={sm} - > - {selectedTermsDisplay(sm, i)} - - ))} -
    -
    - )}
    + + {mappingsForSearch?.length > 0 && ( + { + return { + value: JSON.stringify({ + code: d.code, + display: d.display, + description: d.description, + system: d.system, + }), + label: existingMappingDisplay(d, index), + }; + })} + onChange={onExistingChange} + /> + )} + + {displaySelectedMappings?.length > 0 && ( + + {' '} +
    + {displaySelectedMappings?.map((sm, i) => ( + onCheckboxChange(e, sm)} + checked={selectedBoxes.some( + box => box.obo_id === sm.obo_id + )} + value={sm} + > + {selectedTermsDisplay(sm, i)} + + ))} +
    +
    + )}{' '} {results?.length > 0 ? ( <> - - {mappingsForSearch?.length > 0 && ( - { - return { - value: JSON.stringify({ - code: d.code, - display: d.display, - description: d.description, - system: d.system, - }), - label: existingMappingDisplay(d, index), - }; - } - )} - onChange={onExistingChange} - /> - )} - - - {displaySelectedMappings?.length > 0 && ( - - {' '} -
    - {displaySelectedMappings?.map((sm, i) => ( - onCheckboxChange(e, sm)} - checked={selectedBoxes.some( - box => box.obo_id === sm.obo_id - )} - value={sm} - > - {selectedTermsDisplay(sm, i)} - - ))} -
    -
    - )} Date: Thu, 24 Oct 2024 09:42:49 -0500 Subject: [PATCH 064/180] Styling fix for FilterAPIs to stop results from appearing mid-page --- .../Manager/MappingsFunctions/FilterAPI.jsx | 92 ++++++++++--------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 183cd3b..faee0ea 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from 'react'; -import { Checkbox, Form, Tooltip } from 'antd'; +import { Checkbox, Form } from 'antd'; import { ModalSpinner, OntologySpinner } from '../Spinner'; import { myContext } from '../../../App'; import { FilterOntology } from './FilterOntology'; @@ -43,6 +43,13 @@ export const FilterAPI = ({ ) .flat(); + // The initial value for the form. The checkboxes for the filters that have already been selected will be checked by default + const initialChecked = flattenedFilters?.map(ef => + JSON.stringify({ + ontology: ef, + }) + ); + // Fetches the active ontologyAPI each time the active API changes useEffect(() => { active && getOntologyApiById(); @@ -115,51 +122,48 @@ export const FilterAPI = ({
    -
    - +
    +
    APIs
    - - - { - return { - value: JSON.stringify({ api_preference: api?.api_id }), - label: checkboxDisplay(api, index), - }; - })} - /> - -
    -
    - {tableLoading ? ( -
    - -
    - ) : ( - - )} + + { + return { + value: JSON.stringify({ api_preference: api?.api_id }), + label: checkboxDisplay(api, index), + }; + })} + /> + +
    +
    + {tableLoading ? ( +
    + +
    + ) : ( + + )} +
    From 3070bb026966eb00b02991add6f86976621f5c69 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 24 Oct 2024 09:48:32 -0500 Subject: [PATCH 065/180] changed labels in nav bar for accuracy --- src/components/Nav/NavBar.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Nav/NavBar.jsx b/src/components/Nav/NavBar.jsx index 13a0c11..80e39ff 100644 --- a/src/components/Nav/NavBar.jsx +++ b/src/components/Nav/NavBar.jsx @@ -27,11 +27,11 @@ export const NavBar = () => { {/* Placeholder elements below. No functionality at this time.*/} -
  • Help
  • +
  • About
  • -
  • About
  • +
  • Ontologies
  • From d7ee7c22af39397a8d83cabe8afa3bd13cfd5245 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 24 Oct 2024 10:24:53 -0500 Subject: [PATCH 066/180] modified endpoint in .env --- .env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 0815b66..0f6c051 100644 --- a/.env +++ b/.env @@ -1,6 +1,6 @@ VITE_SEARCH_ENDPOINT = https://www.ebi.ac.uk/ols4/api/search? VITE_MONARCH_SEARCH = https://api-v3.monarchinitiative.org/v3/api/search? # VITE_VOCAB_ENDPOINT = http://127.0.0.1:5000/api # local -VITE_VOCAB_ENDPOINT = https://locutus-110109177269.us-central1.run.app/api # dev -# VITE_VOCAB_ENDPOINT = https://locutus-1066621297011.us-central1.run.app/api # uat +# VITE_VOCAB_ENDPOINT = https://locutus-110109177269.us-central1.run.app/api # dev +VITE_VOCAB_ENDPOINT = https://locutus-1066621297011.us-central1.run.app/api # uat VITE_CLIENT_ID = 907694787484-36jr4oaf04mmniik6482batc87ejemm8.apps.googleusercontent.com From 292bc5d163f8eba7691e6a0bc152f524a3aaf327 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 24 Oct 2024 10:36:08 -0500 Subject: [PATCH 067/180] adding /Study/:studyId/DataDictionary/:DDId/Table/:tableId/Terminology/:terminologyId --- src/AppRouter.jsx | 5 +++++ src/components/Projects/Tables/TableDetails.jsx | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/AppRouter.jsx b/src/AppRouter.jsx index 5a5008e..1ca5075 100644 --- a/src/AppRouter.jsx +++ b/src/AppRouter.jsx @@ -62,6 +62,11 @@ export const AppRouter = () => { path="/Study/:studyId/DataDictionary/:DDId/Table/:tableId" element={} /> + } + /> + } /> diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 69eddd6..7d7a54a 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -217,7 +217,9 @@ There is then a tooltip that displays the variables on hover.*/ max: variable.max, units: variable.units, enumeration: variable.data_type === 'ENUMERATION' && ( - View/Edit + console.log(variable.enumerations.reference,"variable.enumerations.reference"), + + View/Edit ), mapped_terms: matchCode(variable), }; From f81dc803364a7574fa25e433c09f689fd59927fe Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 24 Oct 2024 11:17:00 -0500 Subject: [PATCH 068/180] Merged main with new main --- package-lock.json | 15 +- package.json | 1 + src/components/About/OntologyTable.jsx | 19 +- .../MappingsFunctions/GetMappingsModal.jsx | 2 + .../MappingsFunctions/MappingReset.jsx | 174 +++++++++--------- .../MappingsFunctions/MappingSearch.jsx | 2 + .../MappingsFunctions/MappingsFunctions.scss | 23 ++- .../Tables/EditMappingsTableModal.jsx | 10 + .../Projects/Tables/TableDetails.jsx | 115 ++++++++++-- .../Projects/Tables/TableStyling.scss | 18 ++ .../Terminologies/EditMappingModal.jsx | 4 + .../Projects/Terminologies/Terminology.jsx | 148 +++++++++++++-- .../Terminologies/TerminologyList.jsx | 16 +- 13 files changed, 407 insertions(+), 140 deletions(-) diff --git a/package-lock.json b/package-lock.json index e277d09..419d30d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "vocab-management-tool", "version": "0.0.0", "dependencies": { + "@ant-design/icons": "^5.5.1", "@react-oauth/google": "^0.12.1", "antd": "^5.15.2", "jwt-decode": "^4.0.0", @@ -77,13 +78,13 @@ } }, "node_modules/@ant-design/icons": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.3.7.tgz", - "integrity": "sha512-bCPXTAg66f5bdccM4TT21SQBDO1Ek2gho9h3nO9DAKXJP4sq+5VBjrQMSxMVXSB3HyEz+cUbHQ5+6ogxCOpaew==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.1.tgz", + "integrity": "sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==", "dependencies": { "@ant-design/colors": "^7.0.0", "@ant-design/icons-svg": "^4.4.0", - "@babel/runtime": "^7.11.2", + "@babel/runtime": "^7.24.8", "classnames": "^2.2.6", "rc-util": "^5.31.1" }, @@ -394,9 +395,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz", + "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==", "dependencies": { "regenerator-runtime": "^0.14.0" }, diff --git a/package.json b/package.json index 5855550..38334e7 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "preview": "vite preview" }, "dependencies": { + "@ant-design/icons": "^5.5.1", "@react-oauth/google": "^0.12.1", "antd": "^5.15.2", "jwt-decode": "^4.0.0", diff --git a/src/components/About/OntologyTable.jsx b/src/components/About/OntologyTable.jsx index 905d099..a326572 100644 --- a/src/components/About/OntologyTable.jsx +++ b/src/components/About/OntologyTable.jsx @@ -1,10 +1,19 @@ import { Button, Input, Space, Table } from 'antd'; import { SearchOutlined } from '@ant-design/icons'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; export const OntologyTable = ({ ontology }) => { const [filter, setFilter] = useState(null); + const [pageSize, setPageSize] = useState( + parseInt(localStorage.getItem('pageSize'), 10) || 10); + const handleTableChange = (current, size) => { + setPageSize(size); + }; + useEffect(() => { + localStorage.setItem('pageSize', pageSize); + }, [pageSize]); + const ontologyTitle = () => { return (
    @@ -85,6 +94,8 @@ export const OntologyTable = ({ ontology }) => { })) ); + + return (
    { scroll={{ y: 470, }} + pagination={{ + showSizeChanger: true, + pageSizeOptions: ['10', '20', '30'], + pageSize: pageSize, // Use the stored pageSize + onChange: handleTableChange, // Capture pagination changes + }} /> ); }; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 74dc182..474f5c8 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -24,6 +24,7 @@ export const GetMappingsModal = ({ searchProp, component, mappingProp, + mappingDesc, table, }) => { const [form] = Form.useForm(); @@ -395,6 +396,7 @@ export const GetMappingsModal = ({ onChange={handleChange} /> + {mappingDesc} {/* ant.design form displaying the checkboxes with the search results. */}
    diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index d789a27..552f9c3 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -10,6 +10,7 @@ import { OntologyCheckboxes } from './OntologyCheckboxes'; export const MappingReset = ({ searchProp, + mappingDesc, setEditMappings, form, onClose, @@ -315,102 +316,103 @@ export const MappingReset = ({ onChange={handleChange} />
    + {mappingDesc} - {/* ant.design form displaying the checkboxes with the search results. */} -
    -
    -
    - -
    - {displaySelectedMappings?.length > 0 && ( +
    + {/* ant.design form displaying the checkboxes with the search results. */} +
    + +
    + +
    + {displaySelectedMappings?.length > 0 && ( + +
    + {displaySelectedMappings?.map((sm, i) => ( + onCheckboxChange(e, sm)} + checked={selectedBoxes.some( + box => box.obo_id === sm.obo_id + )} + value={sm} + > + {selectedTermsDisplay(sm, i)} + + ))} +
    +
    + )}{' '} + {results?.length > 0 ? ( + <> -
    - {displaySelectedMappings?.map((sm, i) => ( - onCheckboxChange(e, sm)} - checked={selectedBoxes.some( - box => box.obo_id === sm.obo_id - )} - value={sm} - > - {selectedTermsDisplay(sm, i)} - - ))} -
    + {filteredResultsArray?.length > 0 ? ( + { + return { + value: JSON.stringify({ + code: d.obo_id, + display: d.label, + // description: d.description[0], + system: systemsMatch( + d?.obo_id.split(':')[0] + ), + }), + label: checkBoxDisplay(d, index), + }; + } + )} + onChange={onSelectedChange} + /> + ) : ( + '' + )}
    - )}{' '} - {results?.length > 0 ? ( - <> - - {filteredResultsArray?.length > 0 ? ( - { - return { - value: JSON.stringify({ - code: d.obo_id, - display: d.label, - // description: d.description[0], - system: systemsMatch( - d?.obo_id.split(':')[0] - ), - }), - label: checkBoxDisplay(d, index), - }; - } - )} - onChange={onSelectedChange} - /> - ) : ( - '' - )} - - - ) : ( -

    No results found

    - )} -
    + + ) : ( +

    No results found

    + )}
    - -
    - {/* 'View More' pagination displaying the number of results being displayed +
    + +
    + {/* 'View More' pagination displaying the number of results being displayed out of the total number of results. Because of the filter to filter out the duplicates, there is a tooltip informing the user that redundant entries have been removed to explain any inconsistencies in results numbers per page. */} - + Displaying {resultsCount} +  of {totalCount} + + {totalCount - filteredResultsCount !== resultsCount && ( + { + handleViewMore(e); + setLastCount(resultsCount); + }} > - Displaying {resultsCount} -  of {totalCount} - - {totalCount - filteredResultsCount !== resultsCount && ( - { - handleViewMore(e); - setLastCount(resultsCount); - }} - > - View More - - )} -
    + View More + + )}
    diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index b738931..88d8db4 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -14,6 +14,7 @@ export const MappingSearch = ({ mappingsForSearch, onClose, searchProp, + mappingDesc, component, mappingProp, table, @@ -378,6 +379,7 @@ export const MappingSearch = ({ onChange={handleChange} />
    + {mappingDesc} {/* ant.design form displaying the checkboxes with the search results. */}
    diff --git a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss index 001d127..170c28b 100644 --- a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss +++ b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss @@ -25,15 +25,28 @@ position: sticky; margin: 0 0 15px 0; display: flex; + flex-wrap: wrap; flex-direction: row; - align-items: center; - gap: 20px; + justify-content: flex-start; + align-items: end; z-index: 10; + flex: 1; + border-bottom: solid 1px #eeee; + h4 { + margin:0; + padding-right:1rem; + } + .mappings_search_bar { + width: 60%; + } + .search-desc { + flex: 0 0 100%; + margin-bottom:1rem; + } } -.mappings_search_bar { - width: 50%; -} + + .inactive_term, .active_term { diff --git a/src/components/Projects/Tables/EditMappingsTableModal.jsx b/src/components/Projects/Tables/EditMappingsTableModal.jsx index ce7a71c..15fdc98 100644 --- a/src/components/Projects/Tables/EditMappingsTableModal.jsx +++ b/src/components/Projects/Tables/EditMappingsTableModal.jsx @@ -341,6 +341,11 @@ export const EditMappingsTableModal = ({ reset={reset} onClose={form.resetFields} searchProp={editMappings.name} + mappingDesc={ + editMappings.description + ? editMappings.description + : 'No Description' + } component={table} mappingProp={editMappings.code} table={table} @@ -349,6 +354,11 @@ export const EditMappingsTableModal = ({ reset && ( { const [loading, setLoading] = useState(true); const [load, setLoad] = useState(false); + const [pageSize, setPageSize] = useState( + parseInt(localStorage.getItem('pageSize'), 10) || 10); + const handleTableChange = (current, size) => { + setPageSize(size); + }; const navigate = useNavigate(); const handleSuccess = () => { @@ -48,8 +54,55 @@ export const TableDetails = () => { const login = RequiredLogin({ handleSuccess: handleSuccess }); useEffect(() => { + setDataSource(tableData(table)); - }, [table, mapping]); + localStorage.setItem('pageSize', pageSize); + }, [table, mapping, pageSize]); + + + const updateMappings = (mapArr,mappingCode ) => { + + // setLoading(true); + const mappingsDTO = { + mappings: mapArr, + editor: user.email, + }; + console.log(mappingsDTO,"mappingsDTO"); + + fetch(`${vocabUrl}/Table/${tableId}/mapping/${mappingCode}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(mappingsDTO), + }) + .then(res => { + if (res.ok) { + return res.json(); + } else { + throw new Error('An unknown error occurred.'); + } + }) + .then(data => { + setMapping(data.codes); + setEditMappings(null); + form.resetFields(); + notification.success({ description:'Mapping removed.'}); + }) + .catch(error => { + console.log(error,'error'); + + if (error) { + notification.error({ + message: 'Error', + description: 'An error occurred. Please try again.', + }); + } + return error; + }) + .finally(() => setLoading(false)); + }; + const alphabetizeOntologies = ontologies => { // Sort the keys alphabetically @@ -78,6 +131,8 @@ export const TableDetails = () => { .then(data => setMapping(data.codes)) .catch(error => { if (error) { + console.log(error,"error"); + notification.error({ message: 'Error', description: 'An error occurred loading mappings.', @@ -179,23 +234,39 @@ The variables in the mappings need to be matched up to each variable in the tabl The function maps through the mapping array. For each variable, if the mapping variable is equal to the variable in the table, AND the mappings array length for the variable is > 0, the mappings array is mapped through and returns the length of the mapping array (i.e. returns the number of variables mapped to the table variable). -There is then a tooltip that displays the variables on hover.*/ - const matchCode = variable => - mapping?.length > 0 && - mapping?.map( - (item, index) => - item?.code === variable?.code && - item?.mappings?.length > 0 && ( - { - return
    {code.code}
    ; - })} - key={index} - > - {item?.mappings?.length} -
    - ) - ); +It then shows the mappings as table data and alows the user to delete a mapping from the table.*/ + const noMapping = variable => { + return + } + + const matchCode = variable => { + + + if (!mapping?.length) { + return noMapping(variable); + } + + const variableMappings = mapping.find(item => item?.code === variable?.code); + + if (variableMappings && variableMappings.mappings?.length) { + return variableMappings.mappings.map(code =>
    {code.display} handleRemoveMapping(variableMappings,code)}>
    ); + } else { + return noMapping(variable); + } + }; + + const handleRemoveMapping = (variableMappings,code) => { + // console.log(variableMappings,"variableMappings"); + const mappingToRemove = variableMappings.mappings.indexOf(code); + //remove mapping from mappings + {mappingToRemove !== -1 && variableMappings.mappings.splice(mappingToRemove,1)} + updateMappings(variableMappings?.mappings,variableMappings?.code); + + } + + // data for the table columns. Each table has an array of variables. Each variable has a name, description, and data type. // The integer and quantity data types include additional details. @@ -312,6 +383,12 @@ There is then a tooltip that displays the variables on hover.*/ record.data_type === 'INTEGER' || record.data_type === 'QUANTITY', }} + pagination={{ + showSizeChanger: true, + pageSizeOptions: ['10', '20', '30'], + pageSize: pageSize, // Use the stored pageSize + onChange: handleTableChange, // Capture pagination changes + }} /> diff --git a/src/components/Projects/Tables/TableStyling.scss b/src/components/Projects/Tables/TableStyling.scss index 4cf5288..4767acb 100644 --- a/src/components/Projects/Tables/TableStyling.scss +++ b/src/components/Projects/Tables/TableStyling.scss @@ -54,6 +54,7 @@ input::file-selector-button:hover { border: 1px solid darkgrey; color: gray; border-radius: 25px; + font: { size: 0.7rem; weight: 800; @@ -74,3 +75,20 @@ input::file-selector-button:hover { gap: 10px; margin-left: 50px; } + +.mapping { + &-display{ + white-space: nowrap; + } + display: flex; + .remove-mapping { + padding-left:.25rem; + cursor: pointer; + opacity: 0; + + &:hover { + transition: all .4s linear; + opacity: 1; + } + } +} \ No newline at end of file diff --git a/src/components/Projects/Terminologies/EditMappingModal.jsx b/src/components/Projects/Terminologies/EditMappingModal.jsx index 27bb93a..6eb19b5 100644 --- a/src/components/Projects/Terminologies/EditMappingModal.jsx +++ b/src/components/Projects/Terminologies/EditMappingModal.jsx @@ -22,6 +22,7 @@ export const EditMappingsModal = ({ setEditMappings, terminologyId, setMapping, + mappingDesc, terminology, }) => { const [form] = Form.useForm(); @@ -324,6 +325,7 @@ export const EditMappingsModal = ({ ? editMappings.display : editMappings?.code} + {mappingDesc}
    ) : ( reset && ( @@ -360,6 +363,7 @@ export const EditMappingsModal = ({ form={form} reset={reset} onClose={form.resetFields} + mappingDesc={editMappings?.description} /> ) )} diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index e6dcc85..5316c5f 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -4,7 +4,8 @@ import { myContext } from '../../../App'; import './Terminology.scss'; import { Spinner } from '../../Manager/Spinner'; import { getById } from '../../Manager/FetchManager'; -import { Col, Form, notification, Row, Table, Tooltip } from 'antd'; +import { Col, Form, notification, Row, Table, Button } from 'antd'; +import { CloseCircleOutlined } from '@ant-design/icons'; import { EditMappingsModal } from './EditMappingModal'; import { EditTerminologyDetails } from './EditTerminologyDetails'; import { SettingsDropdownTerminology } from '../../Manager/Dropdown/SettingsDropdownTerminology'; @@ -21,8 +22,8 @@ import { SearchContext } from '../../../Contexts/SearchContext'; export const Terminology = () => { const [form] = Form.useForm(); - const { terminologyId } = useParams(); - const { vocabUrl } = useContext(myContext); + const { terminologyId, tableId } = useParams(); + const { vocabUrl, user } = useContext(myContext); const { setPrefTerminologies, prefTerminologies } = useContext(SearchContext); const { editMappings, @@ -33,33 +34,121 @@ export const Terminology = () => { setMapping, } = useContext(MappingContext); + const [pageSize, setPageSize] = useState( + parseInt(localStorage.getItem('pageSize'), 10) || 10 + ); + const handleTableChange = (current, size) => { + setPageSize(size); + }; + useEffect(() => { + localStorage.setItem('pageSize', pageSize); + }, [pageSize]); + const [loading, setLoading] = useState(true); const initialTerminology = { url: '', description: '', name: '', codes: [] }; //initial state of terminology const [terminology, setTerminology] = useState(initialTerminology); const navigate = useNavigate(); + + const updateMappings = (mapArr, mappingCode) => { + // setLoading(true); + const mappingsDTO = { + mappings: mapArr, + editor: user.email, + }; + console.log(tableId, 'tableId'); + + fetch(`${vocabUrl}/Terminology/${terminologyId}/mapping/${mappingCode}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(mappingsDTO), + }) + .then(res => { + if (res.ok) { + return res.json(); + } else { + throw new Error('An unknown error occurred.'); + } + }) + .then(data => { + setMapping(data.codes); + setEditMappings(null); + form.resetFields(); + notification.success({ description: 'Mapping removed.' }); + }) + .catch(error => { + console.log(error, 'error'); + + if (error) { + console.log(error, 'error'); + + notification.error({ + message: 'Error', + description: 'An error occurred. Please try again.', + }); + } + return error; + }) + .finally(() => setLoading(false)); + }; + /* The terminology may have numerous codes. The API call to fetch the mappings returns all mappings for the terminology. The codes in the mappings need to be matched up to each code in the terminology. The function maps through the mapping array. For each code, if the mapping code is equal to the code in the terminology, AND the mappings array length for the code is > 0, the mappings array is mapped through and returns the length of the mapping array (i.e. returns the number of codes mapped to the terminology code). -There is then a tooltip that displays the codes on hover.*/ - const matchCode = code => - mapping?.length > 0 && - mapping?.map( - (item, index) => - item.code === code.code && - item?.mappings?.length > 0 && ( - { - return
    {code.code}
    ; - })} - key={index} - > - {item.mappings.length} -
    - ) +It then shows the mappings as table data and alows the user to delete a mapping from the table.*/ + + const noMapping = variable => { + return ( + + ); + }; + + const matchCode = variable => { + if (!mapping?.length) { + return noMapping(variable); + } + + const variableMappings = mapping.find( + item => item?.code === variable?.code ); + if (variableMappings && variableMappings.mappings?.length) { + return variableMappings.mappings.map(code => ( +
    + {code.display} + handleRemoveMapping(variableMappings, code)} + > + + +
    + )); + } else { + return noMapping(variable); + } + }; + + const handleRemoveMapping = (variableMappings, code) => { + // console.log(variableMappings,"variableMappings"); + const mappingToRemove = variableMappings.mappings.indexOf(code); + //remove mapping from mappings + { + mappingToRemove !== -1 && + variableMappings.mappings.splice(mappingToRemove, 1); + } + updateMappings(variableMappings?.mappings, variableMappings?.code); + }; + // data for each column in the table. // Map through the codes in the terminology and display the code, display, number of mapped terms, // and an edit or get mappings button depending on the condition. @@ -248,7 +337,16 @@ There is then a tooltip that displays the codes on hover.*/ ) : ( -
    +
    )} @@ -258,6 +356,11 @@ There is then a tooltip that displays the codes on hover.*/ setEditMappings={setEditMappings} terminologyId={terminologyId} setMapping={setMapping} + mappingDesc={ + editMappings?.description + ? editMappings?.description + : 'No Description' + } terminology={terminology} /> {/* Displays the edit form */} diff --git a/src/components/Projects/Terminologies/TerminologyList.jsx b/src/components/Projects/Terminologies/TerminologyList.jsx index 5b3ca6f..99d0cbf 100644 --- a/src/components/Projects/Terminologies/TerminologyList.jsx +++ b/src/components/Projects/Terminologies/TerminologyList.jsx @@ -14,7 +14,8 @@ export const TerminologyList = () => { const [terms, setTerms] = useState([]); const [filter, setFilter] = useState(null); const [deleteId, setDeleteId] = useState(null); - + const [pageSize, setPageSize] = useState( + parseInt(localStorage.getItem('pageSize'), 10) || 10); const { vocabUrl } = useContext(myContext); const navigate = useNavigate(); @@ -28,7 +29,8 @@ export const TerminologyList = () => { setTerms(data); }) .finally(() => setLoading(false)); - }, []); + localStorage.setItem('pageSize', pageSize); + }, [pageSize]); const terminologyTitle = () => { return ( @@ -44,6 +46,9 @@ export const TerminologyList = () => { {item.name ? item.name : item.id} ); + const handleTableChange = (current, size) => { + setPageSize(size); + }; const columns = [ { @@ -140,9 +145,16 @@ export const TerminologyList = () => {

    Terminology Index

    trigger.parentNode} + pagination={{ + showSizeChanger: true, + pageSizeOptions: ['10', '20', '30'], + pageSize: pageSize, // Use the stored pageSize + onChange: handleTableChange, // Capture pagination changes + }} /> Date: Thu, 24 Oct 2024 11:47:27 -0500 Subject: [PATCH 069/180] CSS styling for footer and main content --- .env | 4 +- src/App.scss | 3 + src/AppRouter.jsx | 26 +++- src/components/About/OntologyInfo.scss | 4 +- src/components/Nav/Breadcrumbs.jsx | 30 ++++ src/components/Nav/NavBar.scss | 143 +++++++++++------- .../Projects/Studies/StudyStyling.scss | 3 +- .../Projects/Tables/TableDetails.jsx | 4 +- .../Projects/Tables/TableStyling.scss | 10 +- .../Projects/Terminologies/Terminology.scss | 2 +- 10 files changed, 160 insertions(+), 69 deletions(-) create mode 100644 src/components/Nav/Breadcrumbs.jsx diff --git a/.env b/.env index 0f6c051..0815b66 100644 --- a/.env +++ b/.env @@ -1,6 +1,6 @@ VITE_SEARCH_ENDPOINT = https://www.ebi.ac.uk/ols4/api/search? VITE_MONARCH_SEARCH = https://api-v3.monarchinitiative.org/v3/api/search? # VITE_VOCAB_ENDPOINT = http://127.0.0.1:5000/api # local -# VITE_VOCAB_ENDPOINT = https://locutus-110109177269.us-central1.run.app/api # dev -VITE_VOCAB_ENDPOINT = https://locutus-1066621297011.us-central1.run.app/api # uat +VITE_VOCAB_ENDPOINT = https://locutus-110109177269.us-central1.run.app/api # dev +# VITE_VOCAB_ENDPOINT = https://locutus-1066621297011.us-central1.run.app/api # uat VITE_CLIENT_ID = 907694787484-36jr4oaf04mmniik6482batc87ejemm8.apps.googleusercontent.com diff --git a/src/App.scss b/src/App.scss index 5ea8142..6a5342c 100644 --- a/src/App.scss +++ b/src/App.scss @@ -1,9 +1,12 @@ .approuter_div { display: flex; flex-direction: column; + justify-content: space-between; } .outlet_div { height: 100%; min-height: 100vh; + position: relative; + // top:-2.5rem; } diff --git a/src/AppRouter.jsx b/src/AppRouter.jsx index 4892b4b..1ca5075 100644 --- a/src/AppRouter.jsx +++ b/src/AppRouter.jsx @@ -1,6 +1,7 @@ import { OntologySearch } from './components/Search/OntologySearch'; -import { BrowserRouter, Outlet, Route, Routes } from 'react-router-dom'; +import { BrowserRouter, Outlet, Route, Routes, Navigate } from 'react-router-dom'; import { NavBar } from './components/Nav/NavBar'; +import { Breadcrumbs } from './components/Nav/Breadcrumbs.jsx'; import { Footer } from './components/Nav/Footer'; import { SearchResults } from './components/Search/SearchResults'; import { Terminology } from './components/Projects/Terminologies/Terminology'; @@ -27,6 +28,7 @@ export const AppRouter = () => { <>
    +
    @@ -41,17 +43,31 @@ export const AppRouter = () => { } /> } /> } /> + } /> }> }> } /> + } /> } /> - - } /> + + } /> } + path="/Study/:studyId/DataDictionary/:DDId/Table/" + element={} /> + + } /> + } + /> + } + /> + } /> + { + const location = useLocation(); + const pathParts = location.pathname.split('/').filter(Boolean); + const pathArr = [] + pathParts.forEach(path => { + pathArr.push({ title: path, path: path }); + }); + + console.log(location,'location'); + + + return +
  • Home {location.pathname != '/' &&   /  }
  • + +
    +} +function itemRender(currentRoute, params, items, pathArr) { + const isLast = currentRoute?.path === items[items.length - 1]?.path; + + return <> + {isLast ? ( + {currentRoute.title} + ) : ( + {currentRoute.title} + )} + +} \ No newline at end of file diff --git a/src/components/Nav/NavBar.scss b/src/components/Nav/NavBar.scss index 25c21e9..95459e7 100644 --- a/src/components/Nav/NavBar.scss +++ b/src/components/Nav/NavBar.scss @@ -3,7 +3,7 @@ $navColor: #080705; $linkColor: #fffc31; -nav { +nav.navbar { z-index: 1; width: 100%; background-color: $navColor; @@ -11,81 +11,122 @@ nav { display: flex; flex-direction: row; justify-content: center; - position: fixed; + position: sticky; top: 0; + li { list-style-type: none; } + a:not(.nav_logo) { text-decoration: none; color: $navColor; + font: { size: 1em; weight: 800; } } -} -.nav_body { - width: 100%; - display: grid; - grid-template-columns: 1fr auto 1fr; -} -.logo_container { - left: 0; - padding-left: 100px; -} + .nav_body { + width: 100%; + display: grid; + grid-template-columns: 1fr auto 1fr; + } -.nav_logo { - width: 81px; - color: white; - font: { - weight: 800; - size: 1.3rem; + .logo_container { + left: 0; + padding-left: 100px; } - text-align: left; - text-decoration: none; -} -.nav_links { - margin: auto; - display: flex; - flex-direction: row; - gap: 2rem; - grid-column-start: 2; -} + .nav_logo { + width: 81px; + color: white; -.nav_link { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - background-color: $linkColor; - height: 75px; - padding: 0 4px; - width: $navHeight; - border-radius: 10px; -} + font: { + weight: 800; + size: 1.3rem; + } + + text-align: left; + text-decoration: none; + } + + .nav_links { + margin: auto; + display: flex; + flex-direction: row; + gap: 2rem; + grid-column-start: 2; + } + + .nav_link { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + background-color: $linkColor; + height: 75px; + padding: 0 4px; + width: $navHeight; + border-radius: 10px; + } + + .nav_link:hover { + color: rgb(45, 42, 34); + box-shadow: 0 5px 15px rgba(178, 182, 92, 0.8); + } -.nav_link:hover { - color: rgb(45, 42, 34); - box-shadow: 0 5px 15px rgba(178, 182, 92, 0.8); + .login { + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + margin: 0 100px 0 0; + } } -.login { +.breadcrumbs { display: flex; - flex-direction: row; - justify-content: flex-end; - align-items: center; - margin: 0 100px 0 0; + align-items: baseline; + z-index: 1; + padding: 0 10vw; + position: sticky; + top: 115px; + background:#eeeeee; + + li { + list-style: none; + font-size: 14px; + line-height: 1.5714285714285714; + color: rgba(0, 0, 0, 0.45); + + &>a { + color: rgba(0, 0, 0, 0.45); + text-decoration: none; + transition: color 0.2s; + padding: 0 4px; + border-radius: 4px; + height: 22px; + display: inline-block; + margin-inline: -4px; + + &:hover { + color: rgba(0, 0, 0, 0.88); + background-color: rgba(0, 0, 0, 0.06); + } + } + } + + & * { + text-transform: capitalize; + } + } footer { - margin-top: auto; - bottom: 0; width: 100%; height: 50px; - margin-top: -50px; background-color: $navColor; -} +} \ No newline at end of file diff --git a/src/components/Projects/Studies/StudyStyling.scss b/src/components/Projects/Studies/StudyStyling.scss index 62eca80..7a2cae2 100644 --- a/src/components/Projects/Studies/StudyStyling.scss +++ b/src/components/Projects/Studies/StudyStyling.scss @@ -1,6 +1,7 @@ .studies_container { - margin: 17vh 10vw 10vh 10vw; + margin: 5vh 10vw 10vh 10vw; line-height: 1.5rem; + height: 100vh; } .cards_container { diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 6da13b8..ca17c9d 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -285,7 +285,9 @@ It then shows the mappings as table data and alows the user to delete a mapping max: variable.max, units: variable.units, enumeration: variable.data_type === 'ENUMERATION' && ( - View/Edit + console.log(variable.enumerations.reference,"variable.enumerations.reference"), + + View/Edit ), mapped_terms: matchCode(variable), }; diff --git a/src/components/Projects/Tables/TableStyling.scss b/src/components/Projects/Tables/TableStyling.scss index 4767acb..22dd6f1 100644 --- a/src/components/Projects/Tables/TableStyling.scss +++ b/src/components/Projects/Tables/TableStyling.scss @@ -2,7 +2,7 @@ @import '../../Styling/Variables'; .table_id_container { - margin: 17vh 10vw 13vh 10vw; //Make 10vh bottom without export button + margin: 5vh 10vw 13vh 10vw; //Make 10vh bottom without export button width: 66vw; } @@ -77,18 +77,18 @@ input::file-selector-button:hover { } .mapping { - &-display{ + &-display { white-space: nowrap; } display: flex; .remove-mapping { - padding-left:.25rem; + padding-left: 0.25rem; cursor: pointer; opacity: 0; &:hover { - transition: all .4s linear; + transition: all 0.4s linear; opacity: 1; } } -} \ No newline at end of file +} diff --git a/src/components/Projects/Terminologies/Terminology.scss b/src/components/Projects/Terminologies/Terminology.scss index 09485e7..ca3ad43 100644 --- a/src/components/Projects/Terminologies/Terminology.scss +++ b/src/components/Projects/Terminologies/Terminology.scss @@ -1,6 +1,6 @@ @import '../../Styling/Variables'; .terminology_container { - margin: 17vh 10vw 10vh 10vw; + margin: 5vh 10vw 10vh 10vw; width: 66vw; } From cd0ae9b7762e6364d7f6d2c41c10bfc38d624bce Mon Sep 17 00:00:00 2001 From: Yelena Cox <107718499+yelenacox@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:59:38 -0500 Subject: [PATCH 070/180] Update Terminology.jsx --- .../Projects/Terminologies/Terminology.jsx | 55 ++++++------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index 9f1a245..5316c5f 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -23,7 +23,6 @@ export const Terminology = () => { const [form] = Form.useForm(); const { terminologyId, tableId } = useParams(); - const { vocabUrl, user } = useContext(myContext); const { setPrefTerminologies, prefTerminologies } = useContext(SearchContext); const { @@ -31,13 +30,13 @@ export const Terminology = () => { setEditMappings, getMappings, setGetMappings, - mapping, + mapping, setMapping, } = useContext(MappingContext); const [pageSize, setPageSize] = useState( - - parseInt(localStorage.getItem('pageSize'), 10) || 10); + parseInt(localStorage.getItem('pageSize'), 10) || 10 + ); const handleTableChange = (current, size) => { setPageSize(size); }; @@ -51,7 +50,6 @@ export const Terminology = () => { const navigate = useNavigate(); const updateMappings = (mapArr, mappingCode) => { - // setLoading(true); const mappingsDTO = { mappings: mapArr, @@ -59,7 +57,6 @@ export const Terminology = () => { }; console.log(tableId, 'tableId'); - fetch(`${vocabUrl}/Terminology/${terminologyId}/mapping/${mappingCode}`, { method: 'PUT', headers: { @@ -86,7 +83,6 @@ export const Terminology = () => { if (error) { console.log(error, 'error'); - notification.error({ message: 'Error', description: 'An error occurred. Please try again.', @@ -117,30 +113,13 @@ It then shows the mappings as table data and alows the user to delete a mapping }; const matchCode = variable => { - if (!mapping?.length) { return noMapping(variable); } - - const variableMappings = mapping.find(item => item?.code === variable?.code); - - if (variableMappings && variableMappings.mappings?.length) { - return variableMappings.mappings.map(code =>
    {code.display} handleRemoveMapping(variableMappings,code)}>
    ); - } else { - return noMapping(variable); - } - }; - - const handleRemoveMapping = (variableMappings,code) => { - // console.log(variableMappings,"variableMappings"); - const mappingToRemove = variableMappings.mappings.indexOf(code); - //remove mapping from mappings - {mappingToRemove !== -1 && variableMappings.mappings.splice(mappingToRemove,1)} - updateMappings(variableMappings?.mappings,variableMappings?.code); - - } - + const variableMappings = mapping.find( + item => item?.code === variable?.code + ); if (variableMappings && variableMappings.mappings?.length) { return variableMappings.mappings.map(code => ( @@ -358,16 +337,16 @@ It then shows the mappings as table data and alows the user to delete a mapping ) : (
    - -
    +
    )} @@ -383,7 +362,6 @@ It then shows the mappings as table data and alows the user to delete a mapping : 'No Description' } terminology={terminology} - /> {/* Displays the edit form */} From b667d18925eff672ec56bfaff93375aaa96ba2ba Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 24 Oct 2024 13:22:09 -0500 Subject: [PATCH 071/180] fixed it --- src/components/Manager/MappingsFunctions/MappingReset.jsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index f87c1b7..10d91fd 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -417,12 +417,6 @@ export const MappingReset = ({ ) : ( -
    - - -
    - - ) : (
    @@ -432,3 +426,4 @@ export const MappingReset = ({ ); }; + \ No newline at end of file From 88ff11851b1b736d154560064b9e4981b91ec626 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 24 Oct 2024 15:39:45 -0500 Subject: [PATCH 072/180] Search bar for ontologies in OntologyCheckboxes --- .../MappingsFunctions/MappingsFunctions.scss | 18 +++-- .../MappingsFunctions/OntologyCheckboxes.jsx | 25 +++++- src/components/Nav/Breadcrumbs.jsx | 50 ++++++------ .../Projects/Tables/TableDetails.jsx | 77 +++++++++++-------- .../Projects/Terminologies/Terminology.jsx | 2 - 5 files changed, 104 insertions(+), 68 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss index 170c28b..b24fc07 100644 --- a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss +++ b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss @@ -10,7 +10,7 @@ flex-direction: row; } .ontology_form { - width: 10vw; + width: 10.5vw; height: 50vh; overflow: auto; position: fixed; @@ -28,26 +28,24 @@ flex-wrap: wrap; flex-direction: row; justify-content: flex-start; - align-items: end; + align-items: center; z-index: 10; flex: 1; border-bottom: solid 1px #eeee; h4 { - margin:0; - padding-right:1rem; + margin: 0; + padding-right: 1rem; } .mappings_search_bar { + margin: 0 0 0 8px; width: 60%; } .search-desc { flex: 0 0 100%; - margin-bottom:1rem; + margin-bottom: 1rem; } } - - - .inactive_term, .active_term { padding: 10px; @@ -120,3 +118,7 @@ .view_more_wrapper { margin-left: 11vw; } + +.onto_search_bar { + margin-bottom: 8px; +} diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index 123f96c..14d33ad 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -1,4 +1,4 @@ -import { Checkbox, Form } from 'antd'; +import { Checkbox, Form, Input } from 'antd'; import { ontologyCounts } from '../Utilitiy'; import { useContext, useEffect, useState } from 'react'; import { SearchContext } from '../../../Contexts/SearchContext'; @@ -9,14 +9,19 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { setApiPreferencesCode, facetCounts, ontologyApis, - component, } = useContext(SearchContext); + const { Search } = Input; + const [checkedOntologies, setCheckedOntologies] = useState([]); + const [searchText, setSearchText] = useState(''); const defaultOntologies = ['mondo', 'hp', 'maxo', 'ncit']; let processedApiPreferencesCode; + // Ensures the data sent to the API is in the correct format. + // If apiPreferencesCode is an array, sets processedApiPreferencesCode equal to it. + // If it is a comma-separated string, it splits it by the commas and adds them to an array if (Array.isArray(apiPreferencesCode)) { processedApiPreferencesCode = apiPreferencesCode; } else if (typeof apiPreferencesCode === 'string') { @@ -81,15 +86,29 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { ? checkedOntologies : []; + const getFilteredItems = searchText => { + const filtered = countsResult?.filter(item => { + const key = Object.keys(item)[0]; + return key.startsWith(searchText); + }); + return filtered; + }; + return (
    + setSearchText(e.target.value)} + />
    - {countsResult + {getFilteredItems(searchText) ?.sort((a, b) => { const aValue = Object.values(a)[0]; const bValue = Object.values(b)[0]; diff --git a/src/components/Nav/Breadcrumbs.jsx b/src/components/Nav/Breadcrumbs.jsx index f6b29ee..245d2f0 100644 --- a/src/components/Nav/Breadcrumbs.jsx +++ b/src/components/Nav/Breadcrumbs.jsx @@ -1,30 +1,34 @@ -import { Breadcrumb } from "antd" +import { Breadcrumb } from 'antd'; import { useLocation, Link } from 'react-router-dom'; // import { Link } from 'react-router'; export const Breadcrumbs = () => { - const location = useLocation(); - const pathParts = location.pathname.split('/').filter(Boolean); - const pathArr = [] - pathParts.forEach(path => { - pathArr.push({ title: path, path: path }); - }); - - console.log(location,'location'); - + const location = useLocation(); + const pathParts = location.pathname.split('/').filter(Boolean); + const pathArr = []; + pathParts.forEach(path => { + pathArr.push({ title: path, path: path }); + }); - return -
  • Home {location.pathname != '/' &&   /  }
  • + return ( + +
  • + Home{' '} + {location.pathname != '/' &&   /  } +
  • -
    -} +
    + ); +}; function itemRender(currentRoute, params, items, pathArr) { - const isLast = currentRoute?.path === items[items.length - 1]?.path; + const isLast = currentRoute?.path === items[items.length - 1]?.path; - return <> - {isLast ? ( - {currentRoute.title} - ) : ( - {currentRoute.title} - )} - -} \ No newline at end of file + return ( + <> + {isLast ? ( + {currentRoute.title} + ) : ( + {currentRoute.title} + )} + + ); +} diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index ca17c9d..327a105 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -42,7 +42,8 @@ export const TableDetails = () => { const [load, setLoad] = useState(false); const [pageSize, setPageSize] = useState( - parseInt(localStorage.getItem('pageSize'), 10) || 10); + parseInt(localStorage.getItem('pageSize'), 10) || 10 + ); const handleTableChange = (current, size) => { setPageSize(size); }; @@ -54,21 +55,17 @@ export const TableDetails = () => { const login = RequiredLogin({ handleSuccess: handleSuccess }); useEffect(() => { - setDataSource(tableData(table)); localStorage.setItem('pageSize', pageSize); }, [table, mapping, pageSize]); - - const updateMappings = (mapArr,mappingCode ) => { - + const updateMappings = (mapArr, mappingCode) => { // setLoading(true); const mappingsDTO = { mappings: mapArr, editor: user.email, }; - console.log(mappingsDTO,"mappingsDTO"); - + fetch(`${vocabUrl}/Table/${tableId}/mapping/${mappingCode}`, { method: 'PUT', headers: { @@ -87,11 +84,11 @@ export const TableDetails = () => { setMapping(data.codes); setEditMappings(null); form.resetFields(); - notification.success({ description:'Mapping removed.'}); + notification.success({ description: 'Mapping removed.' }); }) .catch(error => { - console.log(error,'error'); - + console.log(error, 'error'); + if (error) { notification.error({ message: 'Error', @@ -103,7 +100,6 @@ export const TableDetails = () => { .finally(() => setLoading(false)); }; - const alphabetizeOntologies = ontologies => { // Sort the keys alphabetically const sortedKeys = Object.keys(ontologies).sort(); @@ -131,8 +127,8 @@ export const TableDetails = () => { .then(data => setMapping(data.codes)) .catch(error => { if (error) { - console.log(error,"error"); - + console.log(error, 'error'); + notification.error({ message: 'Error', description: 'An error occurred loading mappings.', @@ -236,37 +232,52 @@ variable in the table, AND the mappings array length for the variable is > 0, th and returns the length of the mapping array (i.e. returns the number of variables mapped to the table variable). It then shows the mappings as table data and alows the user to delete a mapping from the table.*/ const noMapping = variable => { - return - } + return ( + + ); + }; const matchCode = variable => { - - if (!mapping?.length) { return noMapping(variable); } - const variableMappings = mapping.find(item => item?.code === variable?.code); + const variableMappings = mapping.find( + item => item?.code === variable?.code + ); if (variableMappings && variableMappings.mappings?.length) { - return variableMappings.mappings.map(code =>
    {code.display} handleRemoveMapping(variableMappings,code)}>
    ); + return variableMappings.mappings.map(code => ( +
    + {code.display} + handleRemoveMapping(variableMappings, code)} + > + + +
    + )); } else { return noMapping(variable); } }; - const handleRemoveMapping = (variableMappings,code) => { - // console.log(variableMappings,"variableMappings"); + const handleRemoveMapping = (variableMappings, code) => { const mappingToRemove = variableMappings.mappings.indexOf(code); //remove mapping from mappings - {mappingToRemove !== -1 && variableMappings.mappings.splice(mappingToRemove,1)} - updateMappings(variableMappings?.mappings,variableMappings?.code); - - } - - + { + mappingToRemove !== -1 && + variableMappings.mappings.splice(mappingToRemove, 1); + } + updateMappings(variableMappings?.mappings, variableMappings?.code); + }; // data for the table columns. Each table has an array of variables. Each variable has a name, description, and data type. // The integer and quantity data types include additional details. @@ -285,9 +296,11 @@ It then shows the mappings as table data and alows the user to delete a mapping max: variable.max, units: variable.units, enumeration: variable.data_type === 'ENUMERATION' && ( - console.log(variable.enumerations.reference,"variable.enumerations.reference"), - - View/Edit + + View/Edit + ), mapped_terms: matchCode(variable), }; diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index 5316c5f..b3c4709 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -55,7 +55,6 @@ export const Terminology = () => { mappings: mapArr, editor: user.email, }; - console.log(tableId, 'tableId'); fetch(`${vocabUrl}/Terminology/${terminologyId}/mapping/${mappingCode}`, { method: 'PUT', @@ -139,7 +138,6 @@ It then shows the mappings as table data and alows the user to delete a mapping }; const handleRemoveMapping = (variableMappings, code) => { - // console.log(variableMappings,"variableMappings"); const mappingToRemove = variableMappings.mappings.indexOf(code); //remove mapping from mappings { From b40ab4ab825a8dd100499827066a5a1759705d57 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Fri, 25 Oct 2024 12:47:43 -0500 Subject: [PATCH 073/180] Changed 'url' to 'system' --- src/components/Nav/Breadcrumbs.jsx | 50 ++++++------ src/components/Projects/Studies/AddStudy.jsx | 4 +- .../Projects/Studies/EditStudyDetails.jsx | 6 +- .../Projects/Studies/StudyDetails.jsx | 2 +- .../Projects/Tables/EditTableDetails.jsx | 14 +++- .../Projects/Tables/TableDetails.jsx | 77 +++++++++++-------- .../Projects/Tables/UploadTable.jsx | 6 +- .../Projects/Terminologies/AddTerminology.jsx | 4 +- .../Terminologies/EditTerminologyDetails.jsx | 6 +- .../Projects/Terminologies/Terminology.jsx | 2 - 10 files changed, 99 insertions(+), 72 deletions(-) diff --git a/src/components/Nav/Breadcrumbs.jsx b/src/components/Nav/Breadcrumbs.jsx index f6b29ee..245d2f0 100644 --- a/src/components/Nav/Breadcrumbs.jsx +++ b/src/components/Nav/Breadcrumbs.jsx @@ -1,30 +1,34 @@ -import { Breadcrumb } from "antd" +import { Breadcrumb } from 'antd'; import { useLocation, Link } from 'react-router-dom'; // import { Link } from 'react-router'; export const Breadcrumbs = () => { - const location = useLocation(); - const pathParts = location.pathname.split('/').filter(Boolean); - const pathArr = [] - pathParts.forEach(path => { - pathArr.push({ title: path, path: path }); - }); - - console.log(location,'location'); - + const location = useLocation(); + const pathParts = location.pathname.split('/').filter(Boolean); + const pathArr = []; + pathParts.forEach(path => { + pathArr.push({ title: path, path: path }); + }); - return -
  • Home {location.pathname != '/' &&   /  }
  • + return ( + +
  • + Home{' '} + {location.pathname != '/' &&   /  } +
  • -
    -} +
    + ); +}; function itemRender(currentRoute, params, items, pathArr) { - const isLast = currentRoute?.path === items[items.length - 1]?.path; + const isLast = currentRoute?.path === items[items.length - 1]?.path; - return <> - {isLast ? ( - {currentRoute.title} - ) : ( - {currentRoute.title} - )} - -} \ No newline at end of file + return ( + <> + {isLast ? ( + {currentRoute.title} + ) : ( + {currentRoute.title} + )} + + ); +} diff --git a/src/components/Projects/Studies/AddStudy.jsx b/src/components/Projects/Studies/AddStudy.jsx index 8517ba0..23422c5 100644 --- a/src/components/Projects/Studies/AddStudy.jsx +++ b/src/components/Projects/Studies/AddStudy.jsx @@ -109,8 +109,8 @@ export const AddStudy = ({ addStudy, setAddStudy }) => { diff --git a/src/components/Projects/Studies/EditStudyDetails.jsx b/src/components/Projects/Studies/EditStudyDetails.jsx index bc10e8e..ba11754 100644 --- a/src/components/Projects/Studies/EditStudyDetails.jsx +++ b/src/components/Projects/Studies/EditStudyDetails.jsx @@ -87,8 +87,10 @@ export const EditStudyDetails = ({ form, study, setStudy, edit, setEdit }) => { diff --git a/src/components/Projects/Studies/StudyDetails.jsx b/src/components/Projects/Studies/StudyDetails.jsx index 3066ece..786c8c6 100644 --- a/src/components/Projects/Studies/StudyDetails.jsx +++ b/src/components/Projects/Studies/StudyDetails.jsx @@ -107,7 +107,7 @@ export const StudyDetails = () => {
    -
    URL: {study?.url}
    +
    System: {study?.url}
    diff --git a/src/components/Projects/Tables/EditTableDetails.jsx b/src/components/Projects/Tables/EditTableDetails.jsx index d31f344..cae5c4c 100644 --- a/src/components/Projects/Tables/EditTableDetails.jsx +++ b/src/components/Projects/Tables/EditTableDetails.jsx @@ -1,4 +1,4 @@ -import { Form, Input, message, Modal } from 'antd'; +import { Form, Input, message, Modal, notification } from 'antd'; import { useContext, useState } from 'react'; import { myContext } from '../../../App'; import { handleUpdate } from '../../Manager/FetchManager'; @@ -35,6 +35,12 @@ export const EditTableDetails = ({ table, setTable, edit, setEdit }) => { }) // Displays a self-closing message that the udpates have been successfully saved. .then(() => message.success('Changes saved successfully.')) + .catch(error => { + notification.error({ + message: 'Error', + description: 'An error occurred editing the Table.', + }); + }) .finally(() => setLoading(false)); }; return ( @@ -84,8 +90,10 @@ export const EditTableDetails = ({ table, setTable, edit, setEdit }) => { {' '} diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index ca17c9d..327a105 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -42,7 +42,8 @@ export const TableDetails = () => { const [load, setLoad] = useState(false); const [pageSize, setPageSize] = useState( - parseInt(localStorage.getItem('pageSize'), 10) || 10); + parseInt(localStorage.getItem('pageSize'), 10) || 10 + ); const handleTableChange = (current, size) => { setPageSize(size); }; @@ -54,21 +55,17 @@ export const TableDetails = () => { const login = RequiredLogin({ handleSuccess: handleSuccess }); useEffect(() => { - setDataSource(tableData(table)); localStorage.setItem('pageSize', pageSize); }, [table, mapping, pageSize]); - - const updateMappings = (mapArr,mappingCode ) => { - + const updateMappings = (mapArr, mappingCode) => { // setLoading(true); const mappingsDTO = { mappings: mapArr, editor: user.email, }; - console.log(mappingsDTO,"mappingsDTO"); - + fetch(`${vocabUrl}/Table/${tableId}/mapping/${mappingCode}`, { method: 'PUT', headers: { @@ -87,11 +84,11 @@ export const TableDetails = () => { setMapping(data.codes); setEditMappings(null); form.resetFields(); - notification.success({ description:'Mapping removed.'}); + notification.success({ description: 'Mapping removed.' }); }) .catch(error => { - console.log(error,'error'); - + console.log(error, 'error'); + if (error) { notification.error({ message: 'Error', @@ -103,7 +100,6 @@ export const TableDetails = () => { .finally(() => setLoading(false)); }; - const alphabetizeOntologies = ontologies => { // Sort the keys alphabetically const sortedKeys = Object.keys(ontologies).sort(); @@ -131,8 +127,8 @@ export const TableDetails = () => { .then(data => setMapping(data.codes)) .catch(error => { if (error) { - console.log(error,"error"); - + console.log(error, 'error'); + notification.error({ message: 'Error', description: 'An error occurred loading mappings.', @@ -236,37 +232,52 @@ variable in the table, AND the mappings array length for the variable is > 0, th and returns the length of the mapping array (i.e. returns the number of variables mapped to the table variable). It then shows the mappings as table data and alows the user to delete a mapping from the table.*/ const noMapping = variable => { - return - } + return ( + + ); + }; const matchCode = variable => { - - if (!mapping?.length) { return noMapping(variable); } - const variableMappings = mapping.find(item => item?.code === variable?.code); + const variableMappings = mapping.find( + item => item?.code === variable?.code + ); if (variableMappings && variableMappings.mappings?.length) { - return variableMappings.mappings.map(code =>
    {code.display} handleRemoveMapping(variableMappings,code)}>
    ); + return variableMappings.mappings.map(code => ( +
    + {code.display} + handleRemoveMapping(variableMappings, code)} + > + + +
    + )); } else { return noMapping(variable); } }; - const handleRemoveMapping = (variableMappings,code) => { - // console.log(variableMappings,"variableMappings"); + const handleRemoveMapping = (variableMappings, code) => { const mappingToRemove = variableMappings.mappings.indexOf(code); //remove mapping from mappings - {mappingToRemove !== -1 && variableMappings.mappings.splice(mappingToRemove,1)} - updateMappings(variableMappings?.mappings,variableMappings?.code); - - } - - + { + mappingToRemove !== -1 && + variableMappings.mappings.splice(mappingToRemove, 1); + } + updateMappings(variableMappings?.mappings, variableMappings?.code); + }; // data for the table columns. Each table has an array of variables. Each variable has a name, description, and data type. // The integer and quantity data types include additional details. @@ -285,9 +296,11 @@ It then shows the mappings as table data and alows the user to delete a mapping max: variable.max, units: variable.units, enumeration: variable.data_type === 'ENUMERATION' && ( - console.log(variable.enumerations.reference,"variable.enumerations.reference"), - - View/Edit + + View/Edit + ), mapped_terms: matchCode(variable), }; diff --git a/src/components/Projects/Tables/UploadTable.jsx b/src/components/Projects/Tables/UploadTable.jsx index cf2749c..850976e 100644 --- a/src/components/Projects/Tables/UploadTable.jsx +++ b/src/components/Projects/Tables/UploadTable.jsx @@ -152,8 +152,10 @@ export const UploadTable = ({ addTable, setAddTable }) => { diff --git a/src/components/Projects/Terminologies/AddTerminology.jsx b/src/components/Projects/Terminologies/AddTerminology.jsx index f85e77e..8e0c36a 100644 --- a/src/components/Projects/Terminologies/AddTerminology.jsx +++ b/src/components/Projects/Terminologies/AddTerminology.jsx @@ -149,9 +149,9 @@ export const AddTerminology = () => { diff --git a/src/components/Projects/Terminologies/EditTerminologyDetails.jsx b/src/components/Projects/Terminologies/EditTerminologyDetails.jsx index 7d9129f..18670cf 100644 --- a/src/components/Projects/Terminologies/EditTerminologyDetails.jsx +++ b/src/components/Projects/Terminologies/EditTerminologyDetails.jsx @@ -74,7 +74,7 @@ export const EditTerminologyDetails = ({ name="name" label="Name" rules={[ - { required: true, message: 'Please input terminology name.' }, + { required: true, message: 'Please input Terminology name.' }, ]} > @@ -88,9 +88,9 @@ export const EditTerminologyDetails = ({ diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index 5316c5f..b3c4709 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -55,7 +55,6 @@ export const Terminology = () => { mappings: mapArr, editor: user.email, }; - console.log(tableId, 'tableId'); fetch(`${vocabUrl}/Terminology/${terminologyId}/mapping/${mappingCode}`, { method: 'PUT', @@ -139,7 +138,6 @@ It then shows the mappings as table data and alows the user to delete a mapping }; const handleRemoveMapping = (variableMappings, code) => { - // console.log(variableMappings,"variableMappings"); const mappingToRemove = variableMappings.mappings.indexOf(code); //remove mapping from mappings { From 9f2b2016d82e72e71579878cb434210b96c6db63 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 28 Oct 2024 12:04:23 -0500 Subject: [PATCH 074/180] fetching inherited ontology filters from table into terminology --- src/Contexts/SearchContext.jsx | 3 ++ .../MappingsFunctions/FilterSelect.jsx | 9 ++++-- .../OntologyFilterCodeSubmit.jsx | 3 +- .../Projects/Tables/TableDetails.jsx | 1 + .../Projects/Terminologies/Terminology.jsx | 28 +++++++++++++++++-- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index 1266910..bb27b88 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -17,6 +17,7 @@ export function SearchContextRoot() { const [unformattedPref, setUnformattedPref] = useState([]); const [facetCounts, setFacetCounts] = useState([]); const [ontologyApis, setOntologyApis] = useState([]); + const [apiPreferencesTerm, setApiPreferencesTerm] = useState(undefined); const defaultOntologies = 'mondo,hp,maxo,ncit'; @@ -48,6 +49,8 @@ export function SearchContextRoot() { setUnformattedPref, ontologyApis, setOntologyApis, + setApiPreferencesTerm, + apiPreferencesTerm, }; return ( diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index 031396b..87b4771 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -7,7 +7,12 @@ import { getOntologies } from '../FetchManager'; import { ModalSpinner } from '../Spinner'; import { SearchContext } from '../../../Contexts/SearchContext'; -export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { +export const FilterSelect = ({ + component, + table, + apiPreferences, + setApiPreferences, +}) => { const [form] = Form.useForm(); const [addFilter, setAddFilter] = useState(false); const [currentPage, setCurrentPage] = useState(1); @@ -119,7 +124,7 @@ export const FilterSelect = ({ table, apiPreferences, setApiPreferences }) => { ? 'POST' : 'PUT'; - fetch(`${vocabUrl}/${table?.terminology?.reference}/filter`, { + fetch(`${vocabUrl}/${(component = table && terminology?.id)}/filter`, { method: method, headers: { 'Content-Type': 'application/json', diff --git a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx index 84050dc..807f780 100644 --- a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx @@ -2,7 +2,6 @@ import { notification } from 'antd'; export const OntologyFilterCodeSubmit = ( apiPreferencesCode, - setApiPreferencesCode, apiPreferences, mappingProp, table, @@ -23,7 +22,7 @@ export const OntologyFilterCodeSubmit = ( fetch( `${vocabUrl}/${(component = table - ? table?.terminology?.reference + ? `Table/${component?.id}` : `Terminology/${component?.id}`)}/filter/${mappingProp}`, { method: 'POST', diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 327a105..5507144 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -375,6 +375,7 @@ It then shows the mappings as table data and alows the user to delete a mapping {' '}
    { const { terminologyId, tableId } = useParams(); const { vocabUrl, user } = useContext(myContext); - const { setPrefTerminologies, prefTerminologies } = useContext(SearchContext); + const { + setPrefTerminologies, + prefTerminologies, + setApiPreferencesTerm, + apiPreferencesTerm, + } = useContext(SearchContext); const { editMappings, setEditMappings, @@ -180,6 +185,24 @@ It then shows the mappings as table data and alows the user to delete a mapping } else { setTerminology(data); if (data) { + const cleanedName = data?.name.toLowerCase().replaceAll(' ', '_'); + + fetch(`${vocabUrl}/Table/${tableId}/filter/${cleanedName}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + .then(res => { + if (res.ok) { + return res.json(); + } else { + throw new Error('An unknown error occurred.'); + } + }) + .then(data => { + setApiPreferencesTerm(data); + }); getById(vocabUrl, 'Terminology', `${terminologyId}/mapping`) .then(data => setMapping(data.codes)) .catch(error => { @@ -218,7 +241,8 @@ It then shows the mappings as table data and alows the user to delete a mapping if (error) { notification.error({ message: 'Error', - description: 'An error occurred loading the Terminology.', + description: + 'An error occurred loading the the ontology preferences.', }); } return error; From b68049024058d8ba9798271c44ec4f2aeb97b4d7 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 28 Oct 2024 14:30:14 -0500 Subject: [PATCH 075/180] Showing number of preferred ontologies in api filters button --- .../MappingsFunctions/FilterOntology.jsx | 16 +++++--- .../MappingsFunctions/FilterSelect.jsx | 41 ++++++++++++------- .../Projects/Tables/TableDetails.jsx | 7 +--- .../Projects/Terminologies/Terminology.jsx | 3 ++ 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/FilterOntology.jsx b/src/components/Manager/MappingsFunctions/FilterOntology.jsx index d62a5a3..1cef582 100644 --- a/src/components/Manager/MappingsFunctions/FilterOntology.jsx +++ b/src/components/Manager/MappingsFunctions/FilterOntology.jsx @@ -2,6 +2,7 @@ import { Checkbox, Form, Pagination } from 'antd'; import { useContext, useEffect, useState } from 'react'; import { myContext } from '../../../App'; import { FilterReset } from './FilterReset'; +import { SearchContext } from '../../../Contexts/SearchContext'; export const FilterOntology = ({ ontology, @@ -18,6 +19,7 @@ export const FilterOntology = ({ }) => { const [allCheckboxes, setAllCheckboxes] = useState([]); const { setOntologyForPagination } = useContext(myContext); + const { apiPreferencesTerm } = useContext(SearchContext); useEffect(() => { setOntologyForPagination(ontology); @@ -126,7 +128,11 @@ export const FilterOntology = ({ ); }; - const existingFilters = Object.values(apiPreferences?.self || {}).flat(); + const preferenceType = apiPreferencesTerm + ? apiPreferencesTerm + : apiPreferences; + + const existingFilters = Object.values(preferenceType?.self || {}).flat(); const flattenedFilters = existingFilters .flatMap(item => @@ -148,8 +154,8 @@ export const FilterOntology = ({ return ( <>
    - {Object.keys(apiPreferences?.self?.api_preference || {}).some( - key => apiPreferences?.self?.api_preference[key]?.length > 0 + {Object.keys(preferenceType?.self?.api_preference || {}).some( + key => preferenceType?.self?.api_preference[key]?.length > 0 ) && ( <>
    @@ -204,8 +210,8 @@ export const FilterOntology = ({ )} - {(Object.keys(apiPreferences?.self?.api_preference || {}).some( - key => apiPreferences?.self?.api_preference[key]?.length > 0 + {(Object.keys(preferenceType?.self?.api_preference || {}).some( + key => preferenceType?.self?.api_preference[key]?.length > 0 ) || displaySelectedOntologies.length > 0) &&

    Ontologies

    } diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index 87b4771..82a0a60 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -7,12 +7,7 @@ import { getOntologies } from '../FetchManager'; import { ModalSpinner } from '../Spinner'; import { SearchContext } from '../../../Contexts/SearchContext'; -export const FilterSelect = ({ - component, - table, - apiPreferences, - setApiPreferences, -}) => { +export const FilterSelect = ({ component, table, terminology }) => { const [form] = Form.useForm(); const [addFilter, setAddFilter] = useState(false); const [currentPage, setCurrentPage] = useState(1); @@ -25,7 +20,14 @@ export const FilterSelect = ({ const [active, setActive] = useState(null); const [loading, setLoading] = useState(false); const { user, vocabUrl, ontologyForPagination } = useContext(myContext); - const { ontologyApis, setOntologyApis } = useContext(SearchContext); + const { + ontologyApis, + setOntologyApis, + apiPreferences, + setApiPreferences, + apiPreferencesTerm, + setApiPreferencesTerm, + } = useContext(SearchContext); const [searchText, setSearchText] = useState(''); // Gets the ontologyAPIs on first load, automatically sets active to the first of the list to display on the page @@ -124,13 +126,18 @@ export const FilterSelect = ({ ? 'POST' : 'PUT'; - fetch(`${vocabUrl}/${(component = table && terminology?.id)}/filter`, { - method: method, - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(apiPreferenceDTO), - }) + fetch( + `${vocabUrl}/${(component = table + ? `Table/${table.id}` + : `Terminology/${terminology.id}`)}/filter`, + { + method: method, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(apiPreferenceDTO), + } + ) .then(res => { if (res.ok) { return res.json(); @@ -171,7 +178,11 @@ export const FilterSelect = ({ .finally(() => setLoading(false)); }; - const apiPrefObject = apiPreferences?.self?.api_preference; + const preferenceType = apiPreferencesTerm + ? apiPreferencesTerm + : apiPreferences; + + const apiPrefObject = preferenceType?.self?.api_preference; // // Calculate the total length of all arrays const apiPrefLength = diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 5507144..69a2a16 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -374,12 +374,7 @@ It then shows the mappings as table data and alows the user to delete a mapping <> {' '}
    - + { const [form] = Form.useForm(); @@ -345,6 +346,8 @@ It then shows the mappings as table data and alows the user to delete a mapping
    + + Date: Tue, 29 Oct 2024 13:27:52 -0500 Subject: [PATCH 076/180] Existing terminology ontology filters checking by default --- .../Manager/MappingsFunctions/FilterAPI.jsx | 2 + .../MappingsFunctions/FilterOntology.jsx | 38 +++++++++++++----- .../Manager/MappingsFunctions/FilterReset.jsx | 24 ++++++++---- .../MappingsFunctions/FilterSelect.jsx | 39 +++++++++++++------ .../MappingsFunctions/GetMappingsModal.jsx | 3 +- src/components/Manager/Utilitiy.jsx | 2 + .../Projects/Terminologies/Terminology.jsx | 26 +++++++++---- 7 files changed, 96 insertions(+), 38 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index faee0ea..e761834 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -23,6 +23,7 @@ export const FilterAPI = ({ paginatedOntologies, apiPreferences, table, + terminology, }) => { const { vocabUrl } = useContext(myContext); const [ontology, setOntology] = useState([]); @@ -161,6 +162,7 @@ export const FilterAPI = ({ paginatedOntologies={paginatedOntologies} apiPreferences={apiPreferences} table={table} + terminology={terminology} /> )}
    diff --git a/src/components/Manager/MappingsFunctions/FilterOntology.jsx b/src/components/Manager/MappingsFunctions/FilterOntology.jsx index 1cef582..6b07ca7 100644 --- a/src/components/Manager/MappingsFunctions/FilterOntology.jsx +++ b/src/components/Manager/MappingsFunctions/FilterOntology.jsx @@ -16,6 +16,7 @@ export const FilterOntology = ({ paginatedOntologies, apiPreferences, table, + terminology, }) => { const [allCheckboxes, setAllCheckboxes] = useState([]); const { setOntologyForPagination } = useContext(myContext); @@ -132,7 +133,11 @@ export const FilterOntology = ({ ? apiPreferencesTerm : apiPreferences; - const existingFilters = Object.values(preferenceType?.self || {}).flat(); + const prefTypeKey = Object.keys(preferenceType)[0]; + + const existingFilters = Object.values( + preferenceType[prefTypeKey] || {} + )?.flat(); const flattenedFilters = existingFilters .flatMap(item => @@ -151,15 +156,30 @@ export const FilterOntology = ({ }) ); + useEffect(() => { + form.setFieldsValue({ + existing_filters: flattenedFilters?.map((ff, index) => + JSON.stringify({ + ontology: ff, + }) + ), + }); + }, [apiPreferencesTerm, existingFilters, initialChecked, form]); + return ( <>
    - {Object.keys(preferenceType?.self?.api_preference || {}).some( - key => preferenceType?.self?.api_preference[key]?.length > 0 + {Object.keys(preferenceType[prefTypeKey]?.api_preference || {}).some( + key => preferenceType[prefTypeKey]?.api_preference[key]?.length > 0 ) && ( <>
    -

    Ontology Filters

    +

    Ontology Filters

    {' '} +
    - {flattenedFilters?.length > 0 ? ( + {flattenedFilters?.length > 0 && ( { + options={flattenedFilters?.map((ff, index) => { return { value: JSON.stringify({ - ontology: po, + ontology: ff, }), - label: existingDisplay(po, index), + label: existingDisplay(ff, index), }; })} /> - ) : ( - '' )} diff --git a/src/components/Manager/MappingsFunctions/FilterReset.jsx b/src/components/Manager/MappingsFunctions/FilterReset.jsx index d1229fe..83f3ed0 100644 --- a/src/components/Manager/MappingsFunctions/FilterReset.jsx +++ b/src/components/Manager/MappingsFunctions/FilterReset.jsx @@ -3,22 +3,30 @@ import { ExclamationCircleFilled } from '@ant-design/icons'; import { useContext, useState } from 'react'; import { myContext } from '../../../App'; import { SearchContext } from '../../../Contexts/SearchContext'; +import { useParams } from 'react-router-dom'; +import { cleanedName } from '../Utilitiy'; -export const FilterReset = ({ table }) => { +export const FilterReset = ({ table, component, terminology }) => { const { confirm } = Modal; + const { tableId } = useParams(); const { user, vocabUrl } = useContext(myContext); const { setApiPreferences } = useContext(SearchContext); const [remove, setRemove] = useState(false); const deleteOntologies = evt => { - return fetch(`${vocabUrl}/${table?.terminology?.reference}/filter/self`, { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ editor: user.email }), - }) + return fetch( + `${vocabUrl}/Table/${tableId}/filter/${ + component === table ? 'self' : cleanedName(terminology?.name) + }`, + { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ editor: user.email }), + } + ) .then(res => { if (res.ok) { return res.json().then(data => { diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index 82a0a60..acd26e7 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -6,9 +6,13 @@ import { FilterAPI } from './FilterAPI'; import { getOntologies } from '../FetchManager'; import { ModalSpinner } from '../Spinner'; import { SearchContext } from '../../../Contexts/SearchContext'; +import { cleanedName } from '../Utilitiy'; +import { useParams } from 'react-router-dom'; export const FilterSelect = ({ component, table, terminology }) => { const [form] = Form.useForm(); + const { tableId } = useParams(); + const [addFilter, setAddFilter] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); @@ -69,6 +73,9 @@ export const FilterSelect = ({ component, table, terminology }) => { setDisplaySelectedOntologies([]); }; + const preferenceTypeSet = data => + apiPreferencesTerm ? setApiPreferencesTerm(data) : setApiPreferences(data); + // If the api doesn't exist in api_preference, creates an empty array for it // If the api_preference array for the api does not include an ontology_code, pushes the code to the array for the api // If there is an api in api_preferences that is not included with the ontology_code, it's added to apiPreference with an empty array @@ -127,9 +134,11 @@ export const FilterSelect = ({ component, table, terminology }) => { : 'PUT'; fetch( - `${vocabUrl}/${(component = table - ? `Table/${table.id}` - : `Terminology/${terminology.id}`)}/filter`, + `${vocabUrl}/Table/${(component = table + ? table?.id + : tableId)}/${(component = table + ? `filter` + : `filter/${cleanedName(terminology?.name)}`)}`, { method: method, headers: { @@ -146,12 +155,17 @@ export const FilterSelect = ({ component, table, terminology }) => { } }) .then(() => - fetch(`${vocabUrl}/${table?.terminology?.reference}/filter/self`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }) + fetch( + `${vocabUrl}/Table/${tableId}/filter/${(component = table + ? `self` + : `${cleanedName(terminology?.name)}`)}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) ) .then(res => { if (res.ok) { @@ -161,7 +175,7 @@ export const FilterSelect = ({ component, table, terminology }) => { } }) .then(data => { - setApiPreferences(data); + preferenceTypeSet(data); form.resetFields(); setAddFilter(false); message.success('Preferred ontologies saved successfully.'); @@ -182,7 +196,9 @@ export const FilterSelect = ({ component, table, terminology }) => { ? apiPreferencesTerm : apiPreferences; - const apiPrefObject = preferenceType?.self?.api_preference; + const prefTypeKey = Object.keys(preferenceType)[0]; + + const apiPrefObject = preferenceType[prefTypeKey]?.api_preference; // // Calculate the total length of all arrays const apiPrefLength = @@ -300,6 +316,7 @@ export const FilterSelect = ({ component, table, terminology }) => { paginatedOntologies={paginatedOntologies} apiPreferences={apiPreferences} table={table} + terminology={terminology} /> )} diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 32fc530..8c26df3 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -25,7 +25,7 @@ export const GetMappingsModal = ({ component, mappingProp, mappingDesc, - table + table, }) => { const [form] = Form.useForm(); const { Search } = Input; @@ -37,6 +37,7 @@ export const GetMappingsModal = ({ setApiPreferencesCode, apiPreferencesCode, setUnformattedPref, + setApiPreferencesTerm, } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 2500; diff --git a/src/components/Manager/Utilitiy.jsx b/src/components/Manager/Utilitiy.jsx index 1515f19..787a5d3 100644 --- a/src/components/Manager/Utilitiy.jsx +++ b/src/components/Manager/Utilitiy.jsx @@ -60,3 +60,5 @@ export const ontologyCounts = arr => { return result; }; + +export const cleanedName = data => data?.toLowerCase().replaceAll(' ', '_'); diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index 6f471ca..a97556d 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -19,6 +19,7 @@ import { LoadCodes } from './LoadCodes'; import { PreferredTerminology } from './PreferredTerminology'; import { SearchContext } from '../../../Contexts/SearchContext'; import { FilterSelect } from '../../Manager/MappingsFunctions/FilterSelect'; +import { cleanedName } from '../../Manager/Utilitiy'; export const Terminology = () => { const [form] = Form.useForm(); @@ -50,6 +51,13 @@ export const Terminology = () => { localStorage.setItem('pageSize', pageSize); }, [pageSize]); + useEffect( + () => () => { + setApiPreferencesTerm(undefined); + }, + [] + ); + const [loading, setLoading] = useState(true); const initialTerminology = { url: '', description: '', name: '', codes: [] }; //initial state of terminology const [terminology, setTerminology] = useState(initialTerminology); @@ -186,14 +194,16 @@ It then shows the mappings as table data and alows the user to delete a mapping } else { setTerminology(data); if (data) { - const cleanedName = data?.name.toLowerCase().replaceAll(' ', '_'); - - fetch(`${vocabUrl}/Table/${tableId}/filter/${cleanedName}`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }) + cleanedName(data?.name); + fetch( + `${vocabUrl}/Table/${tableId}/filter/${cleanedName(data?.name)}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) .then(res => { if (res.ok) { return res.json(); From dc427dc19de524d541e1bde2ca693c694692662a Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 29 Oct 2024 15:11:12 -0500 Subject: [PATCH 077/180] Ability to select ontology filters for a terminology --- src/Contexts/SearchContext.jsx | 3 ++ .../Manager/MappingsFunctions/FilterAPI.jsx | 8 +++- .../MappingsFunctions/FilterOntology.jsx | 22 +++-------- .../Manager/MappingsFunctions/FilterReset.jsx | 38 +++++++++++++++++-- .../MappingsFunctions/FilterSelect.jsx | 17 +++++---- 5 files changed, 58 insertions(+), 30 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index bb27b88..e784fd6 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -20,6 +20,8 @@ export function SearchContextRoot() { const [apiPreferencesTerm, setApiPreferencesTerm] = useState(undefined); const defaultOntologies = 'mondo,hp,maxo,ncit'; + const preferenceTypeSet = data => + apiPreferencesTerm ? setApiPreferencesTerm(data) : setApiPreferences(data); const context = { prefTerminologies, @@ -51,6 +53,7 @@ export function SearchContextRoot() { setOntologyApis, setApiPreferencesTerm, apiPreferencesTerm, + preferenceTypeSet, }; return ( diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index e761834..538f2ea 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from 'react'; -import { Checkbox, Form } from 'antd'; +import { Checkbox, Form, Tooltip } from 'antd'; import { ModalSpinner, OntologySpinner } from '../Spinner'; import { myContext } from '../../../App'; import { FilterOntology } from './FilterOntology'; @@ -125,7 +125,11 @@ export const FilterAPI = ({
    -
    APIs
    +
    + + APIs + +
    ); }; + const checkBoxDisplay = (ont, i) => { return ( <> @@ -115,6 +116,7 @@ export const FilterOntology = ({ ); }; + const existingDisplay = (ont, i) => { return ( <> @@ -129,10 +131,12 @@ export const FilterOntology = ({ ); }; + // Checks if there are apiPreferences (table) or apiPreferencesTerm (terminology) and returns the appropriate one const preferenceType = apiPreferencesTerm ? apiPreferencesTerm : apiPreferences; + // The first key is different depending if it's coming from a table or terminology. This dynamically gets the first key const prefTypeKey = Object.keys(preferenceType)[0]; const existingFilters = Object.values( @@ -156,16 +160,6 @@ export const FilterOntology = ({ }) ); - useEffect(() => { - form.setFieldsValue({ - existing_filters: flattenedFilters?.map((ff, index) => - JSON.stringify({ - ontology: ff, - }) - ), - }); - }, [apiPreferencesTerm, existingFilters, initialChecked, form]); - return ( <>
    @@ -175,11 +169,7 @@ export const FilterOntology = ({ <>

    Ontology Filters

    {' '} - +
    { +export const FilterReset = ({ table, terminology }) => { const { confirm } = Modal; const { tableId } = useParams(); const { user, vocabUrl } = useContext(myContext); - const { setApiPreferences } = useContext(SearchContext); + const { preferenceTypeSet } = useContext(SearchContext); const [remove, setRemove] = useState(false); const deleteOntologies = evt => { + // If deleting from a table, 'self' in endpoint + // If deleting from a terminology, the terminology code in endpoint return fetch( `${vocabUrl}/Table/${tableId}/filter/${ - component === table ? 'self' : cleanedName(terminology?.name) + table ? 'self' : cleanedName(terminology?.name) }`, { method: 'DELETE', @@ -39,7 +41,35 @@ export const FilterReset = ({ table, component, terminology }) => { }); } }) - .then(data => setApiPreferences(data)); + .then(() => + // Fetch the updated api preferences + fetch( + `${vocabUrl}/Table/${tableId}/filter/${ + table ? `self` : `${cleanedName(terminology?.name)}` + }`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + ) + .then(res => { + if (res.ok) { + return res.json(); + } else { + notification.error({ + message: 'Error', + description: `An error occurred loading the ${ + table ? 'table' : 'terminology' + }.`, + }); + } + }) + .then(data => { + preferenceTypeSet(data); + }); }; const showConfirm = () => { diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index acd26e7..31ff783 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -28,9 +28,8 @@ export const FilterSelect = ({ component, table, terminology }) => { ontologyApis, setOntologyApis, apiPreferences, - setApiPreferences, apiPreferencesTerm, - setApiPreferencesTerm, + preferenceTypeSet, } = useContext(SearchContext); const [searchText, setSearchText] = useState(''); @@ -47,6 +46,7 @@ export const FilterSelect = ({ component, table, terminology }) => { .finally(() => setLoading(false)); }, []); + // Sets the first API in the list as active useEffect(() => { setActive(ontologyApis[0]?.api_id); }, [addFilter]); @@ -73,9 +73,6 @@ export const FilterSelect = ({ component, table, terminology }) => { setDisplaySelectedOntologies([]); }; - const preferenceTypeSet = data => - apiPreferencesTerm ? setApiPreferencesTerm(data) : setApiPreferences(data); - // If the api doesn't exist in api_preference, creates an empty array for it // If the api_preference array for the api does not include an ontology_code, pushes the code to the array for the api // If there is an api in api_preferences that is not included with the ontology_code, it's added to apiPreference with an empty array @@ -129,7 +126,8 @@ export const FilterSelect = ({ component, table, terminology }) => { }; const method = - Object.keys(apiPreferences?.self?.api_preference || {}).length === 0 + Object.keys(preferenceType[prefTypeKey]?.api_preference || {}).length === + 0 ? 'POST' : 'PUT'; @@ -192,15 +190,18 @@ export const FilterSelect = ({ component, table, terminology }) => { .finally(() => setLoading(false)); }; + // Checks if there are apiPreferences (table) or apiPreferencesTerm (terminology) and returns the appropriate one const preferenceType = apiPreferencesTerm ? apiPreferencesTerm : apiPreferences; - const prefTypeKey = Object.keys(preferenceType)[0]; + // The first key is different depending if it's coming from a table or terminology. This dynamically gets the first key + const prefTypeKey = Object?.keys(preferenceType)[0]; + // Creates a dynamic api preference object const apiPrefObject = preferenceType[prefTypeKey]?.api_preference; - // // Calculate the total length of all arrays + // Calculates the total length of all arrays to display number of ontology filters const apiPrefLength = apiPrefObject && Object.values(apiPrefObject)?.reduce((acc, arr) => acc + arr.length, 0); From 43b2ae76abfa1d4dab5c32ea069bbf9f15e472cb Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Tue, 29 Oct 2024 15:25:40 -0500 Subject: [PATCH 078/180] Added 'self' after table for ontology filters POST/PUT --- src/components/Manager/MappingsFunctions/FilterSelect.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index 31ff783..b5e1911 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -135,7 +135,7 @@ export const FilterSelect = ({ component, table, terminology }) => { `${vocabUrl}/Table/${(component = table ? table?.id : tableId)}/${(component = table - ? `filter` + ? `filter/self` : `filter/${cleanedName(terminology?.name)}`)}`, { method: method, From 70239d2deb001e50e9f19c2309000dab0a48cf0a Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 30 Oct 2024 10:08:45 -0500 Subject: [PATCH 079/180] committing to change branches --- src/Contexts/SearchContext.jsx | 9 +++++++ src/components/Manager/FetchManager.jsx | 21 ++++++---------- .../MappingsFunctions/FilterOntology.jsx | 10 +------- .../MappingsFunctions/FilterSelect.jsx | 11 ++------- .../MappingsFunctions/GetMappingsModal.jsx | 24 ++++++++++++------- .../MappingsFunctions/OntologyCheckboxes.jsx | 15 ++++++------ .../OntologyFilterCodeSubmit.jsx | 5 ++-- 7 files changed, 45 insertions(+), 50 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index e784fd6..ab17bb6 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -23,6 +23,13 @@ export function SearchContextRoot() { const preferenceTypeSet = data => apiPreferencesTerm ? setApiPreferencesTerm(data) : setApiPreferences(data); + // Checks if there are apiPreferences (table) or apiPreferencesTerm (terminology) and returns the appropriate one + const preferenceType = apiPreferencesTerm + ? apiPreferencesTerm + : apiPreferences; + + const prefTypeKey = Object.keys(preferenceType)[0]; + const context = { prefTerminologies, setPrefTerminologies, @@ -54,6 +61,8 @@ export function SearchContextRoot() { setApiPreferencesTerm, apiPreferencesTerm, preferenceTypeSet, + preferenceType, + prefTypeKey, }; return ( diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index 57c5b86..1f989ec 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -235,21 +235,14 @@ export const getFiltersByCode = ( notification, apiPreferencesCode, setUnformattedPref, - table + tableId ) => { - return fetch( - `${vocabUrl}/${ - component === table - ? component?.terminology?.reference - : `Terminology/${component?.id}` - }/filter/${mappingProp}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) + return fetch(`${vocabUrl}/Table/${tableId}/filter/${mappingProp}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) .then(res => { if (res.ok) { return res.json(); diff --git a/src/components/Manager/MappingsFunctions/FilterOntology.jsx b/src/components/Manager/MappingsFunctions/FilterOntology.jsx index 958b10b..10e67c2 100644 --- a/src/components/Manager/MappingsFunctions/FilterOntology.jsx +++ b/src/components/Manager/MappingsFunctions/FilterOntology.jsx @@ -12,15 +12,13 @@ export const FilterOntology = ({ setSelectedBoxes, displaySelectedOntologies, setDisplaySelectedOntologies, - searchText, paginatedOntologies, - apiPreferences, table, terminology, }) => { const [allCheckboxes, setAllCheckboxes] = useState([]); const { setOntologyForPagination } = useContext(myContext); - const { apiPreferencesTerm } = useContext(SearchContext); + const { preferenceType, prefTypeKey } = useContext(SearchContext); useEffect(() => { setOntologyForPagination(ontology); @@ -131,13 +129,7 @@ export const FilterOntology = ({ ); }; - // Checks if there are apiPreferences (table) or apiPreferencesTerm (terminology) and returns the appropriate one - const preferenceType = apiPreferencesTerm - ? apiPreferencesTerm - : apiPreferences; - // The first key is different depending if it's coming from a table or terminology. This dynamically gets the first key - const prefTypeKey = Object.keys(preferenceType)[0]; const existingFilters = Object.values( preferenceType[prefTypeKey] || {} diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index b5e1911..f6b47eb 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -28,8 +28,9 @@ export const FilterSelect = ({ component, table, terminology }) => { ontologyApis, setOntologyApis, apiPreferences, - apiPreferencesTerm, preferenceTypeSet, + preferenceType, + prefTypeKey, } = useContext(SearchContext); const [searchText, setSearchText] = useState(''); @@ -190,14 +191,6 @@ export const FilterSelect = ({ component, table, terminology }) => { .finally(() => setLoading(false)); }; - // Checks if there are apiPreferences (table) or apiPreferencesTerm (terminology) and returns the appropriate one - const preferenceType = apiPreferencesTerm - ? apiPreferencesTerm - : apiPreferences; - - // The first key is different depending if it's coming from a table or terminology. This dynamically gets the first key - const prefTypeKey = Object?.keys(preferenceType)[0]; - // Creates a dynamic api preference object const apiPrefObject = preferenceType[prefTypeKey]?.api_preference; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 8c26df3..b245975 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -16,6 +16,7 @@ import { SearchContext } from '../../../Contexts/SearchContext'; import { getFiltersByCode, olsFilterOntologiesSearch } from '../FetchManager'; import { OntologyCheckboxes } from './OntologyCheckboxes'; import { OntologyFilterCodeSubmit } from './OntologyFilterCodeSubmit'; +import { useParams } from 'react-router-dom'; export const GetMappingsModal = ({ componentString, @@ -27,17 +28,19 @@ export const GetMappingsModal = ({ mappingDesc, table, }) => { + const { tableId } = useParams(); const [form] = Form.useForm(); const { Search } = Input; const { searchUrl, vocabUrl, setSelectedKey, user } = useContext(myContext); const { - apiPreferences, + preferenceType, defaultOntologies, setFacetCounts, setApiPreferencesCode, apiPreferencesCode, setUnformattedPref, - setApiPreferencesTerm, + preferenceTypeSet, + prefTypeKey, } = useContext(SearchContext); const [page, setPage] = useState(0); const entriesPerPage = 2500; @@ -75,11 +78,13 @@ export const GetMappingsModal = ({ notification, apiPreferencesCode, setUnformattedPref, - table + tableId ); } }, [searchProp]); + console.log('component', component); + useEffect(() => { if (apiPreferencesCode !== undefined) fetchResults(0, searchProp); }, [apiPreferencesCode, searchProp]); @@ -178,7 +183,8 @@ export const GetMappingsModal = ({ OntologyFilterCodeSubmit( apiPreferencesCode, setApiPreferencesCode, - apiPreferences, + preferenceType, + prefTypeKey, mappingProp, table, vocabUrl, @@ -199,12 +205,12 @@ export const GetMappingsModal = ({ if ( //If there are api preferences and one of them is OLS, it gets the preferred ontologies - apiPreferences?.self?.api_preference && - 'ols' in apiPreferences?.self?.api_preference + preferenceType[prefTypeKey]?.api_preference && + 'ols' in preferenceType[prefTypeKey]?.api_preference ) { const apiPreferenceOntologies = () => { - if (apiPreferences?.self?.api_preference?.ols) { - return apiPreferences.self.api_preference.ols.join(','); + if (preferenceType[prefTypeKey]?.api_preference?.ols) { + return preferenceType[prefTypeKey].api_preference.ols.join(','); } else { // else if there are no preferred ontologies, it uses the default ontologies return defaultOntologies; @@ -403,7 +409,7 @@ export const GetMappingsModal = ({
    - +
    {displaySelectedMappings?.length > 0 && ( { +export const OntologyCheckboxes = ({ preferenceType }) => { const { apiPreferencesCode, setApiPreferencesCode, facetCounts, ontologyApis, + prefTypeKey, } = useContext(SearchContext); const { Search } = Input; - + console.log('api pref code', apiPreferencesCode); const [checkedOntologies, setCheckedOntologies] = useState([]); const [searchText, setSearchText] = useState(''); @@ -30,15 +31,15 @@ export const OntologyCheckboxes = ({ apiPreferences }) => { const existingOntologies = apiPreferencesCode ? processedApiPreferencesCode - : apiPreferences && - apiPreferences?.self && - apiPreferences?.self?.api_preference - ? Object?.values(apiPreferences?.self?.api_preference).flat() + : preferenceType && + preferenceType?.self && + preferenceType[prefTypeKey]?.api_preference + ? Object?.values(preferenceType[prefTypeKey]?.api_preference).flat() : defaultOntologies; useEffect(() => { setCheckedOntologies(existingOntologies); - }, [apiPreferences]); + }, [preferenceType]); const onCheckboxChange = e => { const { value, checked } = e.target; diff --git a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx index 807f780..c1cbe16 100644 --- a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx @@ -2,7 +2,8 @@ import { notification } from 'antd'; export const OntologyFilterCodeSubmit = ( apiPreferencesCode, - apiPreferences, + preferenceType, + prefTypeKey, mappingProp, table, vocabUrl, @@ -15,7 +16,7 @@ export const OntologyFilterCodeSubmit = ( if ( apiPreferencesCode && JSON.stringify( - Object.values(apiPreferences?.self?.api_preference)[0].sort() + Object.values(preferenceType[prefTypeKey]?.api_preference)[0].sort() ) !== JSON.stringify(apiPreferencesCode?.sort()) ) { apiPreference.api_preference.ols = apiPreferencesCode; From bbfe5a00a50f96a55de3101ecbf357e8a6daf01f Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 30 Oct 2024 12:44:06 -0500 Subject: [PATCH 080/180] Bean work on using terminology ontology filters for mapping search --- src/components/Manager/FetchManager.jsx | 27 +++++++++++------- .../MappingsFunctions/GetMappingsModal.jsx | 19 ++++++------- .../MappingsFunctions/MappingReset.jsx | 18 ++++++------ .../MappingsFunctions/MappingSearch.jsx | 8 ++++-- .../MappingsFunctions/OntologyCheckboxes.jsx | 2 +- .../OntologyFilterCodeSubmit.jsx | 28 +++++++++---------- .../Terminologies/EditMappingModal.jsx | 4 +-- .../Projects/Terminologies/Terminology.jsx | 1 + 8 files changed, 57 insertions(+), 50 deletions(-) diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index 1f989ec..f0e8b6d 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -1,4 +1,4 @@ -import { ontologyReducer } from './Utilitiy'; +import { cleanedName, ontologyReducer } from './Utilitiy'; // Fetches all elements at an endpoint export const getAll = (vocabUrl, name, navigate) => { @@ -219,7 +219,9 @@ export const olsFilterOntologiesSearch = ( //the results are set to res (the filtered, concatenated results) setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); + setFilteredResultsCount( + prevState => prevState + res?.filteredResults?.length + ); // resultsCount is set to the length of the filtered, concatenated results for pagination setResultsCount(res.results.length); setFacetCounts(data?.facet_counts?.facet_fields?.ontologyPreferredPrefix); @@ -233,16 +235,21 @@ export const getFiltersByCode = ( mappingProp, setApiPreferencesCode, notification, - apiPreferencesCode, setUnformattedPref, - tableId + tableId, + terminology ) => { - return fetch(`${vocabUrl}/Table/${tableId}/filter/${mappingProp}`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }) + return fetch( + `${vocabUrl}/Table/${tableId}/filter/${(component = terminology + ? cleanedName(terminology?.name) + : mappingProp)}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) .then(res => { if (res.ok) { return res.json(); diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index b245975..37e4c74 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -27,6 +27,7 @@ export const GetMappingsModal = ({ mappingProp, mappingDesc, table, + terminology, }) => { const { tableId } = useParams(); const [form] = Form.useForm(); @@ -43,7 +44,7 @@ export const GetMappingsModal = ({ prefTypeKey, } = useContext(SearchContext); const [page, setPage] = useState(0); - const entriesPerPage = 2500; + const entriesPerPage = 15; const [loading, setLoading] = useState(false); const [results, setResults] = useState([]); const [totalCount, setTotalCount] = useState(); @@ -76,15 +77,13 @@ export const GetMappingsModal = ({ mappingProp, setApiPreferencesCode, notification, - apiPreferencesCode, setUnformattedPref, - tableId + tableId, + terminology ); } }, [searchProp]); - console.log('component', component); - useEffect(() => { if (apiPreferencesCode !== undefined) fetchResults(0, searchProp); }, [apiPreferencesCode, searchProp]); @@ -100,7 +99,7 @@ export const GetMappingsModal = ({ This useEffect moves the scroll bar on the modal to the first index of the new batch of results. Because the content is in a modal and not the window, the closest class name to the modal is used for the location of the ref. */ useEffect(() => { - if (results?.length > 0 && page > 0) { + if (results?.length > 0 && page > 0 && ref.current) { const container = ref.current.closest('.ant-modal-body'); const scrollTop = ref.current.offsetTop - container.offsetTop; container.scrollTop = scrollTop; @@ -182,13 +181,11 @@ export const GetMappingsModal = ({ .then(() => OntologyFilterCodeSubmit( apiPreferencesCode, - setApiPreferencesCode, preferenceType, prefTypeKey, mappingProp, - table, vocabUrl, - component + tableId ) ) .finally(() => setLoading(false)); @@ -482,12 +479,12 @@ export const GetMappingsModal = ({ inconsistencies in results numbers per page. */} Displaying {resultsCount}  of {totalCount} - {totalCount - filteredResultsCount !== resultsCount && ( + {resultsCount < totalCount - filteredResultsCount && ( { diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index 10d91fd..3210ab7 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -7,6 +7,7 @@ import { MappingContext } from '../../../Contexts/MappingContext'; import { getFiltersByCode, olsFilterOntologiesSearch } from '../FetchManager'; import { SearchContext } from '../../../Contexts/SearchContext'; import { OntologyCheckboxes } from './OntologyCheckboxes'; +import { useParams } from 'react-router-dom'; export const MappingReset = ({ searchProp, @@ -17,8 +18,10 @@ export const MappingReset = ({ component, mappingProp, table, + terminology, }) => { const { searchUrl, vocabUrl } = useContext(myContext); + const { tableId } = useParams(); const { apiPreferences, defaultOntologies, @@ -63,9 +66,9 @@ export const MappingReset = ({ mappingProp, setApiPreferencesCode, notification, - apiPreferencesCode, setUnformattedPref, - table + tableId, + terminology ); } }, [searchProp]); @@ -417,13 +420,12 @@ export const MappingReset = ({
    ) : ( -
    - -
    +
    + +
    )} - -
    + +
    ); }; - \ No newline at end of file diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 88d8db4..1d56fa5 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -7,6 +7,7 @@ import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; import { getFiltersByCode, olsFilterOntologiesSearch } from '../FetchManager'; import { OntologyCheckboxes } from './OntologyCheckboxes'; +import { useParams } from 'react-router-dom'; export const MappingSearch = ({ setEditMappings, @@ -17,7 +18,7 @@ export const MappingSearch = ({ mappingDesc, component, mappingProp, - table, + terminology, }) => { const { searchUrl, vocabUrl } = useContext(myContext); const { @@ -28,6 +29,7 @@ export const MappingSearch = ({ apiPreferencesCode, setUnformattedPref, } = useContext(SearchContext); + const { tableId } = useParams(); const [page, setPage] = useState(0); const entriesPerPage = 2500; @@ -67,9 +69,9 @@ export const MappingSearch = ({ mappingProp, setApiPreferencesCode, notification, - apiPreferencesCode, setUnformattedPref, - table + tableId, + terminology ); } }, [searchProp]); diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index fcb4c3d..3477edf 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -12,7 +12,7 @@ export const OntologyCheckboxes = ({ preferenceType }) => { prefTypeKey, } = useContext(SearchContext); const { Search } = Input; - console.log('api pref code', apiPreferencesCode); + const [checkedOntologies, setCheckedOntologies] = useState([]); const [searchText, setSearchText] = useState(''); diff --git a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx index c1cbe16..15a6ad5 100644 --- a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx @@ -5,10 +5,13 @@ export const OntologyFilterCodeSubmit = ( preferenceType, prefTypeKey, mappingProp, - table, vocabUrl, - component + tableId ) => { + console.log('key', prefTypeKey); + console.log('code preferences', JSON.stringify(apiPreferencesCode?.sort())); + console.log('preferences', preferenceType[prefTypeKey]?.api_preference[0]); + const apiPreference = { api_preference: { 'ols': [] }, }; @@ -16,23 +19,18 @@ export const OntologyFilterCodeSubmit = ( if ( apiPreferencesCode && JSON.stringify( - Object.values(preferenceType[prefTypeKey]?.api_preference)[0].sort() + Object.values(preferenceType[prefTypeKey]?.api_preference)[0]?.sort() ) !== JSON.stringify(apiPreferencesCode?.sort()) ) { apiPreference.api_preference.ols = apiPreferencesCode; - fetch( - `${vocabUrl}/${(component = table - ? `Table/${component?.id}` - : `Terminology/${component?.id}`)}/filter/${mappingProp}`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(apiPreference), - } - ) + fetch(`${vocabUrl}/Table/${tableId}/filter/${mappingProp}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(apiPreference), + }) .then(res => { if (res.ok) { return res.json(); diff --git a/src/components/Projects/Terminologies/EditMappingModal.jsx b/src/components/Projects/Terminologies/EditMappingModal.jsx index 4845716..0fa0fe5 100644 --- a/src/components/Projects/Terminologies/EditMappingModal.jsx +++ b/src/components/Projects/Terminologies/EditMappingModal.jsx @@ -24,7 +24,6 @@ export const EditMappingsModal = ({ setMapping, mappingDesc, terminology, - }) => { const [form] = Form.useForm(); const [termMappings, setTermMappings] = useState([]); @@ -327,7 +326,6 @@ export const EditMappingsModal = ({ : editMappings?.code} {mappingDesc} -
    ) : ( reset && ( @@ -366,6 +365,7 @@ export const EditMappingsModal = ({ reset={reset} onClose={form.resetFields} mappingDesc={editMappings?.description} + terminology={terminology} /> ) )} diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index a97556d..e74e505 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -401,6 +401,7 @@ It then shows the mappings as table data and alows the user to delete a mapping Date: Wed, 30 Oct 2024 13:47:10 -0500 Subject: [PATCH 081/180] [FD-1779] Add deploy_alpha workflow --- .github/workflows/deploy_alpha.yml | 64 ++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/deploy_alpha.yml diff --git a/.github/workflows/deploy_alpha.yml b/.github/workflows/deploy_alpha.yml new file mode 100644 index 0000000..d7ce3cb --- /dev/null +++ b/.github/workflows/deploy_alpha.yml @@ -0,0 +1,64 @@ +# This workflow build and push a Docker container to Google Artifact Registry +# and deploy it on Cloud Run when manually triggered. + +name: 'Build and Deploy Alpha to Cloud Run' + +on: + workflow_dispatch + +env: + + PROJECT_ID: ${{ secrets.PROJECT_ID }} + REGION: ${{ secrets.REGION_LOC_1 }} + SERVICE: 'map-dragon' + IMAGE_NAME: 'map-dragon_img' + GCP_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS }} + + +jobs: + + deploy: + runs-on: 'ubuntu-latest' + + + environment: + name: alpha + + permissions: + contents: 'read' + id-token: 'write' + + steps: + - name: 'Checkout' + uses: 'actions/checkout@v4' + - id: 'auth' + name: 'Authenticate to Google Cloud' + uses: 'google-github-actions/auth@v2' + with: + credentials_json: '${{ env.GCP_CREDENTIALS }}' + + - name: Generate .env.alpha file + run: | + echo "VITE_CLIENT_ID = ${{ secrets.VITE_CLIENT_ID }}" > .env.alpha + echo "VITE_SEARCH_ENDPOINT = ${{ secrets.VITE_SEARCH_ENDPOINT }}" >> .env.alpha + echo "VITE_VOCAB_ENDPOINT= ${{ secrets.VITE_VOCAB_ENDPOINT }}" >> .env.alpha + - name: 'Docker Auth' + run: |- + gcloud auth configure-docker '${{ env.REGION }}-docker.pkg.dev' + + - name: 'Build Docker Image' # New step to build the image + run: |- + DOCKER_TAG="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + docker build -t "${DOCKER_TAG}" . + + - name: 'Push Docker Image' + run: |- + DOCKER_TAG="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + docker push "${DOCKER_TAG}" + + - name: 'Deploy to Cloud Run' + uses: 'google-github-actions/deploy-cloudrun@v2' + with: + service: '${{ env.SERVICE }}' + region: '${{ env.REGION }}' + image: "${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" \ No newline at end of file From bb93780ebc09eb5e723fa1055c7de107bc455f8c Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 30 Oct 2024 14:05:48 -0500 Subject: [PATCH 082/180] Rolling back backend bug workaround --- src/components/Manager/FetchManager.jsx | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index f0e8b6d..fa0290d 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -239,17 +239,12 @@ export const getFiltersByCode = ( tableId, terminology ) => { - return fetch( - `${vocabUrl}/Table/${tableId}/filter/${(component = terminology - ? cleanedName(terminology?.name) - : mappingProp)}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) + return fetch(`${vocabUrl}/Table/${tableId}/filter/${mappingProp}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) .then(res => { if (res.ok) { return res.json(); From c3ee2cb2df65d24391fcebe8090a4434f9e2387e Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Wed, 30 Oct 2024 21:39:19 -0500 Subject: [PATCH 083/180] committing to change branches --- .../Manager/MappingsFunctions/FilterReset.jsx | 16 ++++++++++++---- .../Manager/MappingsFunctions/FilterSelect.jsx | 18 ++++++++++-------- .../Projects/Tables/TableDetails.jsx | 15 ++++++--------- .../Projects/Terminologies/Terminology.jsx | 4 +++- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/FilterReset.jsx b/src/components/Manager/MappingsFunctions/FilterReset.jsx index 122fe2e..536baff 100644 --- a/src/components/Manager/MappingsFunctions/FilterReset.jsx +++ b/src/components/Manager/MappingsFunctions/FilterReset.jsx @@ -18,8 +18,12 @@ export const FilterReset = ({ table, terminology }) => { // If deleting from a table, 'self' in endpoint // If deleting from a terminology, the terminology code in endpoint return fetch( - `${vocabUrl}/Table/${tableId}/filter/${ - table ? 'self' : cleanedName(terminology?.name) + `${vocabUrl}/${ + table + ? `Table/${table.id}/filter/self` + : `Terminology/${terminology.id}/filter/${cleanedName( + terminology.name + )}` }`, { method: 'DELETE', @@ -44,8 +48,12 @@ export const FilterReset = ({ table, terminology }) => { .then(() => // Fetch the updated api preferences fetch( - `${vocabUrl}/Table/${tableId}/filter/${ - table ? `self` : `${cleanedName(terminology?.name)}` + `${vocabUrl}/${ + table + ? `Table/${table.id}/filter/self` + : `Terminology/${terminology.id}/filter/${cleanedName( + terminology.name + )}` }`, { method: 'GET', diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index f6b47eb..cab3d55 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -133,11 +133,11 @@ export const FilterSelect = ({ component, table, terminology }) => { : 'PUT'; fetch( - `${vocabUrl}/Table/${(component = table - ? table?.id - : tableId)}/${(component = table - ? `filter/self` - : `filter/${cleanedName(terminology?.name)}`)}`, + `${vocabUrl}/${(component = table + ? `Table/${table.id}/filter/self` + : `Terminology/${terminology.id}/filter/${cleanedName( + terminology.name + )}`)}`, { method: method, headers: { @@ -155,9 +155,11 @@ export const FilterSelect = ({ component, table, terminology }) => { }) .then(() => fetch( - `${vocabUrl}/Table/${tableId}/filter/${(component = table - ? `self` - : `${cleanedName(terminology?.name)}`)}`, + `${vocabUrl}/${(component = table + ? `Table/${table.id}/filter/self` + : `Terminology/${terminology.id}/filter/${cleanedName( + terminology.name + )}`)}`, { method: 'GET', headers: { diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 69a2a16..1bd0320 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -137,15 +137,12 @@ export const TableDetails = () => { return error; }) .then(() => - fetch( - `${vocabUrl}/${data?.terminology?.reference}/filter/self`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) + fetch(`${vocabUrl}/Table/${tableId}/filter/self`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) ) .then(res => { if (res.ok) { diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index e74e505..ca6e966 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -196,7 +196,9 @@ It then shows the mappings as table data and alows the user to delete a mapping if (data) { cleanedName(data?.name); fetch( - `${vocabUrl}/Table/${tableId}/filter/${cleanedName(data?.name)}`, + `${vocabUrl}/Terminology/${data?.id}/filter/${cleanedName( + data?.name + )}`, { method: 'GET', headers: { From 413db9e6aa5e6005c5fed804785206a1cc33837d Mon Sep 17 00:00:00 2001 From: brendagutman Date: Thu, 31 Oct 2024 10:41:10 -0500 Subject: [PATCH 084/180] [FD-1779] Specify branch to deploy prod and alpha --- .github/workflows/deploy_alpha.yml | 4 +++- .github/workflows/deploy_prod.yml | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy_alpha.yml b/.github/workflows/deploy_alpha.yml index d7ce3cb..7f9f7fe 100644 --- a/.github/workflows/deploy_alpha.yml +++ b/.github/workflows/deploy_alpha.yml @@ -20,7 +20,6 @@ jobs: deploy: runs-on: 'ubuntu-latest' - environment: name: alpha @@ -31,6 +30,9 @@ jobs: steps: - name: 'Checkout' uses: 'actions/checkout@v4' + with: + ref: release # release is deployed, not the default or working branch + - id: 'auth' name: 'Authenticate to Google Cloud' uses: 'google-github-actions/auth@v2' diff --git a/.github/workflows/deploy_prod.yml b/.github/workflows/deploy_prod.yml index d5fb093..7293668 100644 --- a/.github/workflows/deploy_prod.yml +++ b/.github/workflows/deploy_prod.yml @@ -35,6 +35,9 @@ jobs: steps: - name: 'Checkout' uses: 'actions/checkout@v4' + with: + ref: release # release is deployed, not the default or working branch. + - id: 'auth' name: 'Authenticate to Google Cloud' uses: 'google-github-actions/auth@v2' From 7a78f7ad9b027e3659985543b44f29d53e54af6b Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Thu, 31 Oct 2024 13:41:20 -0500 Subject: [PATCH 085/180] Ontology filters for terminology codes --- src/components/Manager/FetchManager.jsx | 21 +++++--- .../MappingsFunctions/DefaultSearch.jsx | 52 ------------------ .../MappingsFunctions/GetMappingsModal.jsx | 34 ++++++++---- .../MappingsFunctions/MappingReset.jsx | 11 ++-- .../MappingsFunctions/MappingSearch.jsx | 11 ++-- .../MappingsFunctions/OntologyCheckboxes.jsx | 2 +- .../OntologyFilterCodeSubmit.jsx | 53 ++++++++++++++++--- .../Tables/EditMappingsTableModal.jsx | 20 ++++++- .../Projects/Terminologies/APIResults.jsx | 4 +- .../Projects/Terminologies/APISearchBar.jsx | 2 +- .../Terminologies/EditMappingModal.jsx | 28 +++++++++- 11 files changed, 145 insertions(+), 93 deletions(-) delete mode 100644 src/components/Manager/MappingsFunctions/DefaultSearch.jsx diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index fa0290d..f358a31 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -236,15 +236,22 @@ export const getFiltersByCode = ( setApiPreferencesCode, notification, setUnformattedPref, - tableId, + table, terminology ) => { - return fetch(`${vocabUrl}/Table/${tableId}/filter/${mappingProp}`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }) + return fetch( + `${vocabUrl}/${ + table + ? `Table/${table.id}/filter/${mappingProp}` + : `Terminology/${terminology.id}/filter/${mappingProp}` + }`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + } + ) .then(res => { if (res.ok) { return res.json(); diff --git a/src/components/Manager/MappingsFunctions/DefaultSearch.jsx b/src/components/Manager/MappingsFunctions/DefaultSearch.jsx deleted file mode 100644 index ef91ae6..0000000 --- a/src/components/Manager/MappingsFunctions/DefaultSearch.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import { ontologyReducer } from '../Utilitiy'; - -export const fetchResults = ( - page, - query, - entriesPerPage, - // setLoading, - setTotalCount, - setResults, - setFilteredResultsCount, - setResultsCount, - searchUrl, - selectedBoxes -) => { - if (!query) { - return undefined; - } - // setLoading(true); - const pageStart = page * entriesPerPage; - - return fetch( - `${searchUrl}q=${query}&ontology=mondo,hp,maxo,ncit&rows=${entriesPerPage}&start=${pageStart}`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ) - .then(res => res.json()) - .then(data => { - let res = ontologyReducer(data?.response?.docs); - - // Filter based on selectedBoxes - if (selectedBoxes) { - res.results = res.results.filter( - d => !selectedBoxes.some(box => box.obo_id === d.obo_id) - ); - } - - if (page > 0 && res.results.length > 0) { - res.results = results.concat(res.results); - } else { - setTotalCount(data.response.numFound); - } - - setResults(res.results); - setFilteredResultsCount(res?.filteredResults?.length); - setResultsCount(res.results.length); - }); - // .finally(() => setLoading(false)); -}; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 37e4c74..511d6d6 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -15,7 +15,10 @@ import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; import { getFiltersByCode, olsFilterOntologiesSearch } from '../FetchManager'; import { OntologyCheckboxes } from './OntologyCheckboxes'; -import { OntologyFilterCodeSubmit } from './OntologyFilterCodeSubmit'; +import { + OntologyFilterCodeSubmit, + OntologyFilterCodeSubmitTerm, +} from './OntologyFilterCodeSubmit'; import { useParams } from 'react-router-dom'; export const GetMappingsModal = ({ @@ -44,7 +47,7 @@ export const GetMappingsModal = ({ prefTypeKey, } = useContext(SearchContext); const [page, setPage] = useState(0); - const entriesPerPage = 15; + const entriesPerPage = 2000; const [loading, setLoading] = useState(false); const [results, setResults] = useState([]); const [totalCount, setTotalCount] = useState(); @@ -78,7 +81,7 @@ export const GetMappingsModal = ({ setApiPreferencesCode, notification, setUnformattedPref, - tableId, + table, terminology ); } @@ -179,14 +182,23 @@ export const GetMappingsModal = ({ message.success('Changes saved successfully.'); }) .then(() => - OntologyFilterCodeSubmit( - apiPreferencesCode, - preferenceType, - prefTypeKey, - mappingProp, - vocabUrl, - tableId - ) + table + ? OntologyFilterCodeSubmit( + apiPreferencesCode, + preferenceType, + prefTypeKey, + mappingProp, + vocabUrl, + table + ) + : OntologyFilterCodeSubmitTerm( + apiPreferencesCode, + preferenceType, + prefTypeKey, + searchProp, + vocabUrl, + terminology + ) ) .finally(() => setLoading(false)); }; diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index 3210ab7..15ca486 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -21,7 +21,6 @@ export const MappingReset = ({ terminology, }) => { const { searchUrl, vocabUrl } = useContext(myContext); - const { tableId } = useParams(); const { apiPreferences, defaultOntologies, @@ -31,7 +30,7 @@ export const MappingReset = ({ setUnformattedPref, } = useContext(SearchContext); const [page, setPage] = useState(0); - const entriesPerPage = 15; + const entriesPerPage = 2000; const [loading, setLoading] = useState(true); const [results, setResults] = useState([]); const [totalCount, setTotalCount] = useState(); @@ -67,7 +66,7 @@ export const MappingReset = ({ setApiPreferencesCode, notification, setUnformattedPref, - tableId, + table, terminology ); } @@ -91,7 +90,7 @@ export const MappingReset = ({ This useEffect moves the scroll bar on the modal to the first index of the new batch of results. Because the content is in a modal and not the window, the closest class name to the modal is used for the location of the ref. */ useEffect(() => { - if (results?.length > 0 && page > 0) { + if (results?.length > 0 && page > 0 && ref.current) { const container = ref.current.closest('.ant-modal-body'); const scrollTop = ref.current.offsetTop - container.offsetTop; container.scrollTop = scrollTop; @@ -373,7 +372,7 @@ export const MappingReset = ({ display: d.label, // description: d.description[0], system: systemsMatch( - d?.obo_id.split(':')[0] + d?.obo_id?.split(':')[0] ), }), label: checkBoxDisplay(d, index), @@ -405,7 +404,7 @@ export const MappingReset = ({ Displaying {resultsCount}  of {totalCount} - {totalCount - filteredResultsCount !== resultsCount && ( + {resultsCount < totalCount - filteredResultsCount && ( { diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 1d56fa5..26b4589 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -15,10 +15,11 @@ export const MappingSearch = ({ mappingsForSearch, onClose, searchProp, + mappingProp, mappingDesc, component, - mappingProp, terminology, + table, }) => { const { searchUrl, vocabUrl } = useContext(myContext); const { @@ -32,7 +33,7 @@ export const MappingSearch = ({ const { tableId } = useParams(); const [page, setPage] = useState(0); - const entriesPerPage = 2500; + const entriesPerPage = 2000; const [loading, setLoading] = useState(true); const [results, setResults] = useState([]); const [totalCount, setTotalCount] = useState(); @@ -70,7 +71,7 @@ export const MappingSearch = ({ setApiPreferencesCode, notification, setUnformattedPref, - tableId, + table, terminology ); } @@ -94,7 +95,7 @@ export const MappingSearch = ({ This useEffect moves the scroll bar on the modal to the first index of the new batch of results. Because the content is in a modal and not the window, the closest class name to the modal is used for the location of the ref. */ useEffect(() => { - if (results?.length > 0 && page > 0) { + if (results?.length > 0 && page > 0 && ref.current) { const container = ref.current.closest('.ant-modal-body'); const scrollTop = ref.current.offsetTop - container.offsetTop; container.scrollTop = scrollTop; @@ -492,7 +493,7 @@ export const MappingSearch = ({ Displaying {resultsCount}  of {totalCount} - {totalCount - filteredResultsCount !== resultsCount && ( + {resultsCount < totalCount - filteredResultsCount && ( { diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index 3477edf..89e8662 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -32,7 +32,7 @@ export const OntologyCheckboxes = ({ preferenceType }) => { const existingOntologies = apiPreferencesCode ? processedApiPreferencesCode : preferenceType && - preferenceType?.self && + preferenceType[prefTypeKey] && preferenceType[prefTypeKey]?.api_preference ? Object?.values(preferenceType[prefTypeKey]?.api_preference).flat() : defaultOntologies; diff --git a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx index 15a6ad5..8e1b4d9 100644 --- a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx @@ -1,4 +1,5 @@ import { notification } from 'antd'; +import { cleanedName } from '../Utilitiy'; export const OntologyFilterCodeSubmit = ( apiPreferencesCode, @@ -6,16 +7,56 @@ export const OntologyFilterCodeSubmit = ( prefTypeKey, mappingProp, vocabUrl, - tableId + table ) => { - console.log('key', prefTypeKey); - console.log('code preferences', JSON.stringify(apiPreferencesCode?.sort())); - console.log('preferences', preferenceType[prefTypeKey]?.api_preference[0]); - const apiPreference = { api_preference: { 'ols': [] }, }; + if ( + apiPreferencesCode && + JSON.stringify( + Object.values(preferenceType[prefTypeKey]?.api_preference)[0]?.sort() + ) !== JSON.stringify(apiPreferencesCode?.sort()) + ) { + apiPreference.api_preference.ols = apiPreferencesCode; + fetch(`${vocabUrl}/Table/${table.id}/filter/${mappingProp}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(apiPreference), + }) + .then(res => { + if (res.ok) { + return res.json(); + } else { + throw new Error('An unknown error occurred.'); + } + }) + .catch(error => { + if (error) { + notification.error({ + message: 'Error', + description: 'An error occurred saving the ontology preferences.', + }); + } + return error; + }); + } +}; + +export const OntologyFilterCodeSubmitTerm = ( + apiPreferencesCode, + preferenceType, + prefTypeKey, + searchProp, + vocabUrl, + terminology +) => { + const apiPreference = { + api_preference: { 'ols': [] }, + }; if ( apiPreferencesCode && JSON.stringify( @@ -24,7 +65,7 @@ export const OntologyFilterCodeSubmit = ( ) { apiPreference.api_preference.ols = apiPreferencesCode; - fetch(`${vocabUrl}/Table/${tableId}/filter/${mappingProp}`, { + fetch(`${vocabUrl}/Terminology/${terminology.id}/filter/${searchProp}`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/src/components/Projects/Tables/EditMappingsTableModal.jsx b/src/components/Projects/Tables/EditMappingsTableModal.jsx index 15fdc98..ca8b0d5 100644 --- a/src/components/Projects/Tables/EditMappingsTableModal.jsx +++ b/src/components/Projects/Tables/EditMappingsTableModal.jsx @@ -17,6 +17,7 @@ import { ResetTableMappings } from './ResetTableMappings'; import { ellipsisString, systemsMatch } from '../../Manager/Utilitiy'; import { getById } from '../../Manager/FetchManager'; import { SearchContext } from '../../../Contexts/SearchContext'; +import { OntologyFilterCodeSubmit } from '../../Manager/MappingsFunctions/OntologyFilterCodeSubmit'; export const EditMappingsTableModal = ({ editMappings, @@ -35,7 +36,12 @@ export const EditMappingsTableModal = ({ const [editSearch, setEditSearch] = useState(false); const { setSelectedMappings, setDisplaySelectedMappings } = useContext(MappingContext); - const { setApiPreferencesCode } = useContext(SearchContext); + const { + apiPreferencesCode, + setApiPreferencesCode, + preferenceType, + prefTypeKey, + } = useContext(SearchContext); useEffect(() => { fetchMappings(); @@ -193,6 +199,7 @@ export const EditMappingsTableModal = ({ .finally(() => setLoading(false)); }; + const mappingProp = editMappings?.code; // Function to send a PUT call to update the mappings after code name change. // The existing and new mappings are JSON.parsed and combined into one mappings array to be passed into the body of the PUT call. const editUpdatedMappings = values => { @@ -240,6 +247,17 @@ export const EditMappingsTableModal = ({ } return error; }) + .then(() => + OntologyFilterCodeSubmit( + apiPreferencesCode, + preferenceType, + prefTypeKey, + mappingProp, + vocabUrl, + table + ) + ) + .finally(() => setLoading(false)); }; diff --git a/src/components/Projects/Terminologies/APIResults.jsx b/src/components/Projects/Terminologies/APIResults.jsx index b881ce1..cf125c1 100644 --- a/src/components/Projects/Terminologies/APIResults.jsx +++ b/src/components/Projects/Terminologies/APIResults.jsx @@ -21,7 +21,7 @@ export const APIResults = ({ This useEffect moves the scroll bar on the modal to the first index of the new batch of results. Because the content is in a modal and not the window, the closest class name to the modal is used for the location of the ref. */ useEffect(() => { - if (apiResults && apiPage > 0) { + if (apiResults && apiPage > 0 && ref.current) { const container = ref.current.closest('.ant-modal-body'); const scrollTop = ref.current.offsetTop - container.offsetTop; container.scrollTop = scrollTop; @@ -131,7 +131,7 @@ export const APIResults = ({ Displaying {apiResultsCount}  of {apiTotalCount} - {apiTotalCount - filteredResultsCount !== apiResultsCount && ( + {apiResultsCount < apiTotalCount - filteredResultsCount && ( { diff --git a/src/components/Projects/Terminologies/APISearchBar.jsx b/src/components/Projects/Terminologies/APISearchBar.jsx index 51f672e..3e25c9c 100644 --- a/src/components/Projects/Terminologies/APISearchBar.jsx +++ b/src/components/Projects/Terminologies/APISearchBar.jsx @@ -22,7 +22,7 @@ export const APISearchBar = ({ setApiTotalCount, } = useContext(SearchContext); const [inputValue, setInputValue] = useState(searchProp); - const entriesPerPage = 15; + const entriesPerPage = 2000; const [currentSearchProp, setCurrentSearchProp] = useState(searchProp); const [filteredResultsCount, setFilteredResultsCount] = useState(0); diff --git a/src/components/Projects/Terminologies/EditMappingModal.jsx b/src/components/Projects/Terminologies/EditMappingModal.jsx index 0fa0fe5..73b635d 100644 --- a/src/components/Projects/Terminologies/EditMappingModal.jsx +++ b/src/components/Projects/Terminologies/EditMappingModal.jsx @@ -16,6 +16,10 @@ import { MappingReset } from '../../Manager/MappingsFunctions/MappingReset'; import { ellipsisString, systemsMatch } from '../../Manager/Utilitiy'; import { getById } from '../../Manager/FetchManager'; import { SearchContext } from '../../../Contexts/SearchContext'; +import { + OntologyFilterCodeSubmit, + OntologyFilterCodeSubmitTerm, +} from '../../Manager/MappingsFunctions/OntologyFilterCodeSubmit'; export const EditMappingsModal = ({ editMappings, @@ -29,7 +33,12 @@ export const EditMappingsModal = ({ const [termMappings, setTermMappings] = useState([]); const [options, setOptions] = useState([]); const { vocabUrl, setSelectedKey, user } = useContext(myContext); - const { setApiPreferencesCode } = useContext(SearchContext); + const { + apiPreferencesCode, + setApiPreferencesCode, + preferenceType, + prefTypeKey, + } = useContext(SearchContext); const [loading, setLoading] = useState(false); const [reset, setReset] = useState(false); const [mappingsForSearch, setMappingsForSearch] = useState([]); @@ -148,6 +157,10 @@ export const EditMappingsModal = ({ ); }; + const searchProp = editMappings?.display + ? editMappings.display + : editMappings?.code; + // Function to send a PUT call to update the mappings. // Each mapping in the mappings array being edited is JSON.parsed and mappings are turned into objects in the mappings array. const updateMappings = values => { @@ -242,8 +255,19 @@ export const EditMappingsModal = ({ } return error; }) + .then(() => + OntologyFilterCodeSubmitTerm( + apiPreferencesCode, + preferenceType, + prefTypeKey, + searchProp, + vocabUrl, + terminology + ) + ) .finally(() => setLoading(false)); }; + return ( @@ -365,6 +390,7 @@ export const EditMappingsModal = ({ reset={reset} onClose={form.resetFields} mappingDesc={editMappings?.description} + mappingProp={editMappings?.code} terminology={terminology} /> ) From d389437ce7d707bc7253a5440ca74005ecdd2492 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 31 Oct 2024 14:07:02 -0500 Subject: [PATCH 086/180] Update deploy_alpha.yml --build-arg ENV=qa --- .github/workflows/deploy_alpha.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy_alpha.yml b/.github/workflows/deploy_alpha.yml index 7f9f7fe..fba3b58 100644 --- a/.github/workflows/deploy_alpha.yml +++ b/.github/workflows/deploy_alpha.yml @@ -51,7 +51,7 @@ jobs: - name: 'Build Docker Image' # New step to build the image run: |- DOCKER_TAG="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" - docker build -t "${DOCKER_TAG}" . + docker build -t "${DOCKER_TAG}" --build-arg ENV=alpha . - name: 'Push Docker Image' run: |- @@ -63,4 +63,4 @@ jobs: with: service: '${{ env.SERVICE }}' region: '${{ env.REGION }}' - image: "${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" \ No newline at end of file + image: "${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" From 5e50c946e95f0e14e779f2362a62758ebe321569 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 31 Oct 2024 14:09:17 -0500 Subject: [PATCH 087/180] Update package.json "build-alpha": "vite build --mode alpha", --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 38334e7..efb9880 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "build": "vite build", "build-dev": "vite build --mode dev", "build-qa": "vite build --mode qa", + "build-alpha": "vite build --mode alpha", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" }, From 2a9d58e7ffb1345b73c90f0cca98c793d129264f Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 31 Oct 2024 14:34:40 -0500 Subject: [PATCH 088/180] removed pack-lock --- package-lock.json | 5334 --------------------------------------------- 1 file changed, 5334 deletions(-) delete mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 419d30d..0000000 --- a/package-lock.json +++ /dev/null @@ -1,5334 +0,0 @@ -{ - "name": "vocab-management-tool", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "vocab-management-tool", - "version": "0.0.0", - "dependencies": { - "@ant-design/icons": "^5.5.1", - "@react-oauth/google": "^0.12.1", - "antd": "^5.15.2", - "jwt-decode": "^4.0.0", - "papaparse": "^5.4.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router-dom": "^6.22.3", - "sass": "^1.72.0" - }, - "devDependencies": { - "@types/react": "^18.2.64", - "@types/react-dom": "^18.2.21", - "@vitejs/plugin-react": "^4.2.1", - "eslint": "^8.57.0", - "eslint-plugin-react": "^7.34.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.5", - "vite": "^5.1.6" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@ant-design/colors": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.1.0.tgz", - "integrity": "sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==", - "dependencies": { - "@ctrl/tinycolor": "^3.6.1" - } - }, - "node_modules/@ant-design/cssinjs": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.21.0.tgz", - "integrity": "sha512-gIilraPl+9EoKdYxnupxjHB/Q6IHNRjEXszKbDxZdsgv4sAZ9pjkCq8yanDWNvyfjp4leir2OVAJm0vxwKK8YA==", - "dependencies": { - "@babel/runtime": "^7.11.1", - "@emotion/hash": "^0.8.0", - "@emotion/unitless": "^0.7.5", - "classnames": "^2.3.1", - "csstype": "^3.1.3", - "rc-util": "^5.35.0", - "stylis": "^4.0.13" - }, - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" - } - }, - "node_modules/@ant-design/icons": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.1.tgz", - "integrity": "sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==", - "dependencies": { - "@ant-design/colors": "^7.0.0", - "@ant-design/icons-svg": "^4.4.0", - "@babel/runtime": "^7.24.8", - "classnames": "^2.2.6", - "rc-util": "^5.31.1" - }, - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" - } - }, - "node_modules/@ant-design/icons-svg": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", - "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==" - }, - "node_modules/@ant-design/react-slick": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz", - "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==", - "dependencies": { - "@babel/runtime": "^7.10.4", - "classnames": "^2.2.5", - "json2mq": "^0.2.0", - "resize-observer-polyfill": "^1.5.1", - "throttle-debounce": "^5.0.0" - }, - "peerDependencies": { - "react": ">=16.9.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", - "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.0", - "@babel/parser": "^7.24.0", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", - "@babel/types": "^7.24.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz", - "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", - "@babel/types": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", - "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", - "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", - "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz", - "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", - "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" - }, - "node_modules/@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", - "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", - "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", - "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", - "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", - "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", - "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", - "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", - "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", - "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", - "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", - "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", - "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", - "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", - "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", - "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", - "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", - "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", - "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", - "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", - "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", - "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", - "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rc-component/async-validator": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", - "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", - "dependencies": { - "@babel/runtime": "^7.24.4" - }, - "engines": { - "node": ">=14.x" - } - }, - "node_modules/@rc-component/color-picker": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-1.5.3.tgz", - "integrity": "sha512-+tGGH3nLmYXTalVe0L8hSZNs73VTP5ueSHwUlDC77KKRaN7G4DS4wcpG5DTDzdcV/Yas+rzA6UGgIyzd8fS4cw==", - "dependencies": { - "@babel/runtime": "^7.23.6", - "@ctrl/tinycolor": "^3.6.1", - "classnames": "^2.2.6", - "rc-util": "^5.38.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/context": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", - "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "rc-util": "^5.27.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/mini-decimal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", - "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", - "dependencies": { - "@babel/runtime": "^7.18.0" - }, - "engines": { - "node": ">=8.x" - } - }, - "node_modules/@rc-component/mutate-observer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", - "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", - "dependencies": { - "@babel/runtime": "^7.18.0", - "classnames": "^2.3.2", - "rc-util": "^5.24.4" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/portal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", - "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", - "dependencies": { - "@babel/runtime": "^7.18.0", - "classnames": "^2.3.2", - "rc-util": "^5.24.4" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/qrcode": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz", - "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==", - "dependencies": { - "@babel/runtime": "^7.24.7", - "classnames": "^2.3.2", - "rc-util": "^5.38.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/tour": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.0.tgz", - "integrity": "sha512-h6hyILDwL+In9GAgRobwRWihLqqsD7Uft3fZGrJ7L4EiyCoxbnNYwzPXDfz7vNDhWeVyvAWQJj9fJCzpI4+b4g==", - "dependencies": { - "@babel/runtime": "^7.18.0", - "@rc-component/portal": "^1.0.0-9", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.3.2", - "rc-util": "^5.24.4" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rc-component/trigger": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.0.tgz", - "integrity": "sha512-QarBCji02YE9aRFhZgRZmOpXBj0IZutRippsVBv85sxvG4FGk/vRxwAlkn3MS9zK5mwbETd86mAVg2tKqTkdJA==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@rc-component/portal": "^1.1.0", - "classnames": "^2.3.2", - "rc-motion": "^2.0.0", - "rc-resize-observer": "^1.3.1", - "rc-util": "^5.38.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@react-oauth/google": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.12.1.tgz", - "integrity": "sha512-qagsy22t+7UdkYAiT5ZhfM4StXi9PPNvw0zuwNmabrWyMKddczMtBIOARflbaIj+wHiQjnMAsZmzsUYuXeyoSg==", - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@remix-run/router": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", - "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", - "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", - "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", - "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", - "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", - "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", - "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", - "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", - "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", - "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", - "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", - "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", - "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", - "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.2.66", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.66.tgz", - "integrity": "sha512-OYTmMI4UigXeFMF/j4uv0lBBEbongSgptPrHBxqME44h9+yNov+oL6Z3ocJKo0WyXR84sQUNeyIp9MRfckvZpg==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.2.22", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", - "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "dev": true - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", - "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.23.5", - "@babel/plugin-transform-react-jsx-self": "^7.23.3", - "@babel/plugin-transform-react-jsx-source": "^7.23.3", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" - } - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/antd": { - "version": "5.19.1", - "resolved": "https://registry.npmjs.org/antd/-/antd-5.19.1.tgz", - "integrity": "sha512-ogGEUPaamSZ2HFGvlyLBNfxZ0c4uX5aqEIwMtmqRTPNjcLY/k+qdMmdWrMMiY1CDJ3j1in5wjzQTvREG+do65g==", - "dependencies": { - "@ant-design/colors": "^7.1.0", - "@ant-design/cssinjs": "^1.21.0", - "@ant-design/icons": "^5.3.7", - "@ant-design/react-slick": "~1.1.2", - "@babel/runtime": "^7.24.7", - "@ctrl/tinycolor": "^3.6.1", - "@rc-component/color-picker": "~1.5.3", - "@rc-component/mutate-observer": "^1.1.0", - "@rc-component/qrcode": "~1.0.0", - "@rc-component/tour": "~1.15.0", - "@rc-component/trigger": "^2.2.0", - "classnames": "^2.5.1", - "copy-to-clipboard": "^3.3.3", - "dayjs": "^1.11.11", - "rc-cascader": "~3.27.0", - "rc-checkbox": "~3.3.0", - "rc-collapse": "~3.7.3", - "rc-dialog": "~9.5.2", - "rc-drawer": "~7.2.0", - "rc-dropdown": "~4.2.0", - "rc-field-form": "~2.2.1", - "rc-image": "~7.9.0", - "rc-input": "~1.5.1", - "rc-input-number": "~9.1.0", - "rc-mentions": "~2.14.0", - "rc-menu": "~9.14.1", - "rc-motion": "^2.9.2", - "rc-notification": "~5.6.0", - "rc-pagination": "~4.2.0", - "rc-picker": "~4.6.7", - "rc-progress": "~4.0.0", - "rc-rate": "~2.13.0", - "rc-resize-observer": "^1.4.0", - "rc-segmented": "~2.3.0", - "rc-select": "~14.15.0", - "rc-slider": "~10.6.2", - "rc-steps": "~6.0.1", - "rc-switch": "~4.1.0", - "rc-table": "~7.45.7", - "rc-tabs": "~15.1.1", - "rc-textarea": "~1.7.0", - "rc-tooltip": "~6.2.0", - "rc-tree": "~5.8.8", - "rc-tree-select": "~5.22.1", - "rc-upload": "~4.5.2", - "rc-util": "^5.43.0", - "scroll-into-view-if-needed": "^3.1.0", - "throttle-debounce": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ant-design" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-tree-filter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", - "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.4.tgz", - "integrity": "sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", - "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", - "es-shim-unscopables": "^1.0.2" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/asynciterator.prototype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001597", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", - "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/compute-scroll-into-view": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", - "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/copy-to-clipboard": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", - "dependencies": { - "toggle-selection": "^1.0.6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "node_modules/dayjs": { - "version": "1.11.11", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", - "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.705", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.705.tgz", - "integrity": "sha512-LKqhpwJCLhYId2VVwEzFXWrqQI5n5zBppz1W9ehhTlfYU8CUUW6kClbN8LHF/v7flMgRdETS772nqywJ+ckVAw==", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.22.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz", - "integrity": "sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.1", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.5", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.17.tgz", - "integrity": "sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==", - "dev": true, - "dependencies": { - "asynciterator.prototype": "^1.0.0", - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.4", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" - } - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.34.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.0.tgz", - "integrity": "sha512-MeVXdReleBTdkz/bvcQMSnCXGi+c9kvy51IpinjnJgutl3YTHWsDdke7Z1ufZpGfDG8xduBDKyjtB9JH1eBKIQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlast": "^1.2.4", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", - "array.prototype.tosorted": "^1.1.3", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.17", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7", - "object.hasown": "^1.1.3", - "object.values": "^1.1.7", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.10" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.6.tgz", - "integrity": "sha512-NjGXdm7zgcKRkKMua34qVO9doI7VOxZ6ancSvBELJSSoX97jyndXcSoa8XBh69JoB31dNz3EEzlMcizZl7LaMA==", - "dev": true, - "peerDependencies": { - "eslint": ">=7" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/immutable": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json2mq": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", - "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", - "dependencies": { - "string-convert": "^0.2.0" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/jwt-decode": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", - "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", - "engines": { - "node": ">=18" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/papaparse": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", - "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/rc-cascader": { - "version": "3.27.0", - "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.27.0.tgz", - "integrity": "sha512-z5uq8VvQadFUBiuZJ7YF5UAUGNkZtdEtcEYiIA94N/Kc2MIKr6lEbN5HyVddvYSgwWlKqnL6pH5bFXFuIK3MNg==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "array-tree-filter": "^2.1.0", - "classnames": "^2.3.1", - "rc-select": "~14.15.0", - "rc-tree": "~5.8.1", - "rc-util": "^5.37.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-checkbox": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz", - "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.3.2", - "rc-util": "^5.25.2" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-collapse": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.7.3.tgz", - "integrity": "sha512-60FJcdTRn0X5sELF18TANwtVi7FtModq649H11mYF1jh83DniMoM4MqY627sEKRCTm4+WXfGDcB7hY5oW6xhyw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.3.4", - "rc-util": "^5.27.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-dialog": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.5.2.tgz", - "integrity": "sha512-qVUjc8JukG+j/pNaHVSRa2GO2/KbV2thm7yO4hepQ902eGdYK913sGkwg/fh9yhKYV1ql3BKIN2xnud3rEXAPw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/portal": "^1.0.0-8", - "classnames": "^2.2.6", - "rc-motion": "^2.3.0", - "rc-util": "^5.21.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-drawer": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz", - "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@rc-component/portal": "^1.1.1", - "classnames": "^2.2.6", - "rc-motion": "^2.6.1", - "rc-util": "^5.38.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-dropdown": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.0.tgz", - "integrity": "sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.2.6", - "rc-util": "^5.17.0" - }, - "peerDependencies": { - "react": ">=16.11.0", - "react-dom": ">=16.11.0" - } - }, - "node_modules/rc-field-form": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.2.1.tgz", - "integrity": "sha512-uoNqDoR7A4tn4QTSqoWPAzrR7ZwOK5I+vuZ/qdcHtbKx+ZjEsTg7QXm2wk/jalDiSksAQmATxL0T5LJkRREdIA==", - "dependencies": { - "@babel/runtime": "^7.18.0", - "@rc-component/async-validator": "^5.0.3", - "rc-util": "^5.32.2" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-image": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.9.0.tgz", - "integrity": "sha512-l4zqO5E0quuLMCtdKfBgj4Suv8tIS011F5k1zBBlK25iMjjiNHxA0VeTzGFtUZERSA45gvpXDg8/P6qNLjR25g==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "@rc-component/portal": "^1.0.2", - "classnames": "^2.2.6", - "rc-dialog": "~9.5.2", - "rc-motion": "^2.6.2", - "rc-util": "^5.34.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-input": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.5.1.tgz", - "integrity": "sha512-+nOzQJDeIfIpNP/SgY45LXSKbuMlp4Yap2y8c+ZpU7XbLmNzUd6+d5/S75sA/52jsVE6S/AkhkkDEAOjIu7i6g==", - "dependencies": { - "@babel/runtime": "^7.11.1", - "classnames": "^2.2.1", - "rc-util": "^5.18.1" - }, - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" - } - }, - "node_modules/rc-input-number": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.1.0.tgz", - "integrity": "sha512-NqJ6i25Xn/AgYfVxynlevIhX3FuKlMwIFpucGG1h98SlK32wQwDK0zhN9VY32McOmuaqzftduNYWWooWz8pXQA==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/mini-decimal": "^1.0.1", - "classnames": "^2.2.5", - "rc-input": "~1.5.0", - "rc-util": "^5.40.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-mentions": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.14.0.tgz", - "integrity": "sha512-qKR59FMuF8PK4ZqsbWX3UuA5P1M/snzyqV6Yt3y1DCFbCEdqUGIBgQp6vEfLCO6Z0RoRFlzXtCeSlBTcDDpg1A==", - "dependencies": { - "@babel/runtime": "^7.22.5", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.2.6", - "rc-input": "~1.5.0", - "rc-menu": "~9.14.0", - "rc-textarea": "~1.7.0", - "rc-util": "^5.34.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-menu": { - "version": "9.14.1", - "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.14.1.tgz", - "integrity": "sha512-5wlRb3M8S4yGlWhSoEYJ7ZVRElyScdcpUHxgiLxkeig1tEdyKrnED3B2fhpN0Rrpdp9jyhnmZR/Lwq2fH5VvDQ==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/trigger": "^2.0.0", - "classnames": "2.x", - "rc-motion": "^2.4.3", - "rc-overflow": "^1.3.1", - "rc-util": "^5.27.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-motion": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.2.tgz", - "integrity": "sha512-fUAhHKLDdkAXIDLH0GYwof3raS58dtNUmzLF2MeiR8o6n4thNpSDQhOqQzWE4WfFZDCi9VEN8n7tiB7czREcyw==", - "dependencies": { - "@babel/runtime": "^7.11.1", - "classnames": "^2.2.1", - "rc-util": "^5.43.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-notification": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.0.tgz", - "integrity": "sha512-TGQW5T7waOxLwgJG7fXcw8l7AQiFOjaZ7ISF5PrU526nunHRNcTMuzKihQHaF4E/h/KfOCDk3Mv8eqzbu2e28w==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.9.0", - "rc-util": "^5.20.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-overflow": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", - "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", - "dependencies": { - "@babel/runtime": "^7.11.1", - "classnames": "^2.2.1", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.37.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-pagination": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.2.0.tgz", - "integrity": "sha512-V6qeANJsT6tmOcZ4XiUmj8JXjRLbkusuufpuoBw2GiAn94fIixYjFLmbruD1Sbhn8fPLDnWawPp4CN37zQorvw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.3.2", - "rc-util": "^5.38.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-picker": { - "version": "4.6.8", - "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.6.8.tgz", - "integrity": "sha512-Lq2m68YGcmWXhzAmxTcL3vOjik7NQjcZ6fmZqBlgdrMCg3VnuKHmtk5CHGWd3wCiy2qNxSYIqWAidB1EQViPpQ==", - "dependencies": { - "@babel/runtime": "^7.24.7", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.2.1", - "rc-overflow": "^1.3.2", - "rc-resize-observer": "^1.4.0", - "rc-util": "^5.43.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "date-fns": ">= 2.x", - "dayjs": ">= 1.x", - "luxon": ">= 3.x", - "moment": ">= 2.x", - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - }, - "peerDependenciesMeta": { - "date-fns": { - "optional": true - }, - "dayjs": { - "optional": true - }, - "luxon": { - "optional": true - }, - "moment": { - "optional": true - } - } - }, - "node_modules/rc-progress": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz", - "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.6", - "rc-util": "^5.16.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-rate": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", - "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.5", - "rc-util": "^5.0.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-resize-observer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", - "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", - "dependencies": { - "@babel/runtime": "^7.20.7", - "classnames": "^2.2.1", - "rc-util": "^5.38.0", - "resize-observer-polyfill": "^1.5.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-segmented": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.3.0.tgz", - "integrity": "sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg==", - "dependencies": { - "@babel/runtime": "^7.11.1", - "classnames": "^2.2.1", - "rc-motion": "^2.4.4", - "rc-util": "^5.17.0" - }, - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" - } - }, - "node_modules/rc-select": { - "version": "14.15.0", - "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.15.0.tgz", - "integrity": "sha512-BDqnDLhhm/8VyyyDlX7ju06S75k6ObJvbsN86zqZ4SY1Fu2ANQxeSWPo7pnwx5nwA5JgG+HcQevtddAgsdeBVQ==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/trigger": "^2.1.1", - "classnames": "2.x", - "rc-motion": "^2.0.1", - "rc-overflow": "^1.3.1", - "rc-util": "^5.16.1", - "rc-virtual-list": "^3.5.2" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-slider": { - "version": "10.6.2", - "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.6.2.tgz", - "integrity": "sha512-FjkoFjyvUQWcBo1F3RgSglky3ar0+qHLM41PlFVYB4Bj3RD8E/Mv7kqMouLFBU+3aFglMzzctAIWRwajEuueSw==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.5", - "rc-util": "^5.36.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-steps": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", - "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", - "dependencies": { - "@babel/runtime": "^7.16.7", - "classnames": "^2.2.3", - "rc-util": "^5.16.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-switch": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", - "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", - "dependencies": { - "@babel/runtime": "^7.21.0", - "classnames": "^2.2.1", - "rc-util": "^5.30.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-table": { - "version": "7.45.7", - "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.45.7.tgz", - "integrity": "sha512-wi9LetBL1t1csxyGkMB2p3mCiMt+NDexMlPbXHvQFmBBAsMxrgNSAPwUci2zDLUq9m8QdWc1Nh8suvrpy9mXrg==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "@rc-component/context": "^1.4.0", - "classnames": "^2.2.5", - "rc-resize-observer": "^1.1.0", - "rc-util": "^5.37.0", - "rc-virtual-list": "^3.14.2" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-tabs": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.1.1.tgz", - "integrity": "sha512-Tc7bJvpEdkWIVCUL7yQrMNBJY3j44NcyWS48jF/UKMXuUlzaXK+Z/pEL5LjGcTadtPvVmNqA40yv7hmr+tCOAw==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "classnames": "2.x", - "rc-dropdown": "~4.2.0", - "rc-menu": "~9.14.0", - "rc-motion": "^2.6.2", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.34.1" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-textarea": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.7.0.tgz", - "integrity": "sha512-UxizYJkWkmxP3zofXgc487QiGyDmhhheDLLjIWbFtDmiru1ls30KpO8odDaPyqNUIy9ugj5djxTEuezIn6t3Jg==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.1", - "rc-input": "~1.5.0", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.27.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-tooltip": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.0.tgz", - "integrity": "sha512-iS/3iOAvtDh9GIx1ulY7EFUXUtktFccNLsARo3NPgLf0QW9oT0w3dA9cYWlhqAKmD+uriEwdWz1kH0Qs4zk2Aw==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "@rc-component/trigger": "^2.0.0", - "classnames": "^2.3.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-tree": { - "version": "5.8.8", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.8.8.tgz", - "integrity": "sha512-S+mCMWo91m5AJqjz3PdzKilGgbFm7fFJRFiTDOcoRbD7UfMOPnerXwMworiga0O2XIo383UoWuEfeHs1WOltag==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-motion": "^2.0.1", - "rc-util": "^5.16.1", - "rc-virtual-list": "^3.5.1" - }, - "engines": { - "node": ">=10.x" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-tree-select": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.22.1.tgz", - "integrity": "sha512-b8mAK52xEpRgS+b2PTapCt29GoIrO5cO8jB7AfHttFsIJfcnynY9FCtnYzURsKXJkGHbFY6UzSEB2I3TETtdWg==", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "rc-select": "~14.15.0", - "rc-tree": "~5.8.1", - "rc-util": "^5.16.1" - }, - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/rc-upload": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.5.2.tgz", - "integrity": "sha512-QO3ne77DwnAPKFn0bA5qJM81QBjQi0e0NHdkvpFyY73Bea2NfITiotqJqVjHgeYPOJu5lLVR32TNGP084aSoXA==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "classnames": "^2.2.5", - "rc-util": "^5.2.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-util": { - "version": "5.43.0", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.43.0.tgz", - "integrity": "sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "react-is": "^18.2.0" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/rc-util/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/rc-virtual-list": { - "version": "3.14.5", - "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.14.5.tgz", - "integrity": "sha512-ZMOnkCLv2wUN8Jz7yI4XiSLa9THlYvf00LuMhb1JlsQCewuU7ydPuHw1rGVPhe9VZYl/5UqODtNd7QKJ2DMGfg==", - "dependencies": { - "@babel/runtime": "^7.20.0", - "classnames": "^2.2.6", - "rc-resize-observer": "^1.0.0", - "rc-util": "^5.36.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-router": { - "version": "6.22.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", - "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==", - "dependencies": { - "@remix-run/router": "1.15.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.22.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz", - "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==", - "dependencies": { - "@remix-run/router": "1.15.3", - "react-router": "6.22.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", - "integrity": "sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0", - "get-intrinsic": "^1.2.3", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" - }, - "node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", - "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.13.0", - "@rollup/rollup-android-arm64": "4.13.0", - "@rollup/rollup-darwin-arm64": "4.13.0", - "@rollup/rollup-darwin-x64": "4.13.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", - "@rollup/rollup-linux-arm64-gnu": "4.13.0", - "@rollup/rollup-linux-arm64-musl": "4.13.0", - "@rollup/rollup-linux-riscv64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-musl": "4.13.0", - "@rollup/rollup-win32-arm64-msvc": "4.13.0", - "@rollup/rollup-win32-ia32-msvc": "4.13.0", - "@rollup/rollup-win32-x64-msvc": "4.13.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sass": { - "version": "1.72.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.72.0.tgz", - "integrity": "sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==", - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/scroll-into-view-if-needed": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", - "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", - "dependencies": { - "compute-scroll-into-view": "^3.0.2" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-convert": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", - "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/stylis": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", - "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==" - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/throttle-debounce": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", - "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", - "engines": { - "node": ">=12.22" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vite": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz", - "integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==", - "dev": true, - "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.35", - "rollup": "^4.2.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} From 5371d3d7ebfee1cc59bc1c59d6ba062cb322547c Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 31 Oct 2024 14:41:41 -0500 Subject: [PATCH 089/180] Update package.json QUACK test --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index efb9880..d1c195e 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dev": "vite", "build": "vite build", "build-dev": "vite build --mode dev", - "build-qa": "vite build --mode qa", + "build-qaack": "vite build --mode qa", "build-alpha": "vite build --mode alpha", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" From 99af65d982f741461e6748e0e994eb89c7de33b1 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 31 Oct 2024 14:43:47 -0500 Subject: [PATCH 090/180] Update package.json revert qauack --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d1c195e..efb9880 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dev": "vite", "build": "vite build", "build-dev": "vite build --mode dev", - "build-qaack": "vite build --mode qa", + "build-qa": "vite build --mode qa", "build-alpha": "vite build --mode alpha", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" From a59ddc74c462d1bb6d493514a669de2384e84f64 Mon Sep 17 00:00:00 2001 From: Morgan Higby-Flowers Date: Thu, 31 Oct 2024 14:47:31 -0500 Subject: [PATCH 091/180] Update deploy_alpha.yml removed ref release --- .github/workflows/deploy_alpha.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy_alpha.yml b/.github/workflows/deploy_alpha.yml index fba3b58..a0f7b96 100644 --- a/.github/workflows/deploy_alpha.yml +++ b/.github/workflows/deploy_alpha.yml @@ -30,8 +30,8 @@ jobs: steps: - name: 'Checkout' uses: 'actions/checkout@v4' - with: - ref: release # release is deployed, not the default or working branch + # with: + # ref: release # release is deployed, not the default or working branch - id: 'auth' name: 'Authenticate to Google Cloud' From f84a35fe99ce5bb5ea8d62392f7d4cfb9676441d Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Fri, 1 Nov 2024 09:36:29 -0500 Subject: [PATCH 092/180] Saving ontologies in MappingSearch --- src/components/Manager/FetchManager.jsx | 14 +--- .../MappingsFunctions/GetMappingsModal.jsx | 42 +++++------ .../MappingsFunctions/MappingSearch.jsx | 1 - .../OntologyFilterCodeSubmit.jsx | 54 ++------------ .../OntologyFilterCodeSubmitTerm.jsx | 73 +++++++++++++++++++ .../Tables/EditMappingsTableModal.jsx | 27 +++---- .../Terminologies/EditMappingModal.jsx | 25 +++---- 7 files changed, 123 insertions(+), 113 deletions(-) create mode 100644 src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmitTerm.jsx diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index f358a31..bf9c11a 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -256,7 +256,10 @@ export const getFiltersByCode = ( if (res.ok) { return res.json(); } else { - throw new Error('An unknown error occurred.'); + notification.error({ + message: 'Error', + description: 'An error occurred loading the ontology preferences.', + }); } }) .then(data => { @@ -271,14 +274,5 @@ export const getFiltersByCode = ( } else { setApiPreferencesCode(''); // Fallback if no ols found } - }) - .catch(error => { - if (error) { - notification.error({ - message: 'Error', - description: 'An error occurred loading the ontology preferences.', - }); - } - return error; }); }; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 511d6d6..961b100 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -15,10 +15,8 @@ import { MappingContext } from '../../../Contexts/MappingContext'; import { SearchContext } from '../../../Contexts/SearchContext'; import { getFiltersByCode, olsFilterOntologiesSearch } from '../FetchManager'; import { OntologyCheckboxes } from './OntologyCheckboxes'; -import { - OntologyFilterCodeSubmit, - OntologyFilterCodeSubmitTerm, -} from './OntologyFilterCodeSubmit'; +import { OntologyFilterCodeSubmit } from './OntologyFilterCodeSubmit'; +import { OntologyFilterCodeSubmitTerm } from './OntologyFilterCodeSubmitTerm'; import { useParams } from 'react-router-dom'; export const GetMappingsModal = ({ @@ -181,26 +179,24 @@ export const GetMappingsModal = ({ setGetMappings(null); message.success('Changes saved successfully.'); }) - .then(() => - table - ? OntologyFilterCodeSubmit( - apiPreferencesCode, - preferenceType, - prefTypeKey, - mappingProp, - vocabUrl, - table - ) - : OntologyFilterCodeSubmitTerm( - apiPreferencesCode, - preferenceType, - prefTypeKey, - searchProp, - vocabUrl, - terminology - ) - ) .finally(() => setLoading(false)); + table + ? OntologyFilterCodeSubmit( + apiPreferencesCode, + preferenceType, + prefTypeKey, + mappingProp, + vocabUrl, + table + ) + : OntologyFilterCodeSubmitTerm( + apiPreferencesCode, + preferenceType, + prefTypeKey, + searchProp, + vocabUrl, + terminology + ); }; const fetchResults = (page, query) => { diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index 26b4589..fb58be7 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -186,7 +186,6 @@ export const MappingSearch = ({ setFacetCounts ); }; - // the 'View More' pagination onClick increments the page. The search function is triggered to run on page change in the useEffect. const handleViewMore = e => { e.preventDefault(); diff --git a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx index 8e1b4d9..e1c0fc5 100644 --- a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmit.jsx @@ -1,5 +1,4 @@ import { notification } from 'antd'; -import { cleanedName } from '../Utilitiy'; export const OntologyFilterCodeSubmit = ( apiPreferencesCode, @@ -12,60 +11,17 @@ export const OntologyFilterCodeSubmit = ( const apiPreference = { api_preference: { 'ols': [] }, }; - if ( - apiPreferencesCode && - JSON.stringify( - Object.values(preferenceType[prefTypeKey]?.api_preference)[0]?.sort() - ) !== JSON.stringify(apiPreferencesCode?.sort()) - ) { - apiPreference.api_preference.ols = apiPreferencesCode; - fetch(`${vocabUrl}/Table/${table.id}/filter/${mappingProp}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(apiPreference), - }) - .then(res => { - if (res.ok) { - return res.json(); - } else { - throw new Error('An unknown error occurred.'); - } - }) - .catch(error => { - if (error) { - notification.error({ - message: 'Error', - description: 'An error occurred saving the ontology preferences.', - }); - } - return error; - }); - } -}; - -export const OntologyFilterCodeSubmitTerm = ( - apiPreferencesCode, - preferenceType, - prefTypeKey, - searchProp, - vocabUrl, - terminology -) => { - const apiPreference = { - api_preference: { 'ols': [] }, - }; if ( apiPreferencesCode && - JSON.stringify( - Object.values(preferenceType[prefTypeKey]?.api_preference)[0]?.sort() - ) !== JSON.stringify(apiPreferencesCode?.sort()) + (!preferenceType[prefTypeKey]?.api_preference?.[0] || + JSON.stringify( + Object.values(preferenceType[prefTypeKey]?.api_preference)[0]?.sort() + ) !== JSON.stringify(apiPreferencesCode?.sort())) ) { apiPreference.api_preference.ols = apiPreferencesCode; - fetch(`${vocabUrl}/Terminology/${terminology.id}/filter/${searchProp}`, { + fetch(`${vocabUrl}/Table/${table.id}/filter/${mappingProp}`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmitTerm.jsx b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmitTerm.jsx new file mode 100644 index 0000000..748b97b --- /dev/null +++ b/src/components/Manager/MappingsFunctions/OntologyFilterCodeSubmitTerm.jsx @@ -0,0 +1,73 @@ +import { notification } from 'antd'; + +export const OntologyFilterCodeSubmitTerm = ( + apiPreferencesCode, + preferenceType, + prefTypeKey, + searchProp, + vocabUrl, + terminology +) => { + const apiPreference = { + api_preference: { 'ols': [] }, + }; + + if ( + apiPreferencesCode && + (!preferenceType[prefTypeKey]?.api_preference || + JSON.stringify( + Object.values(preferenceType[prefTypeKey]?.api_preference)[0]?.sort() + ) !== JSON.stringify(apiPreferencesCode?.sort())) + ) { + apiPreference.api_preference.ols = apiPreferencesCode; + + fetch(`${vocabUrl}/Terminology/${terminology.id}/filter/${searchProp}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(apiPreference), + }) + .then(res => { + if (res.ok) { + return res.json(); + } else { + throw new Error('An unknown error occurred.'); + } + }) + .catch(error => { + if (error) { + notification.error({ + message: 'Error', + description: 'An error occurred saving the ontology preferences.', + }); + } + }); + } +}; + +// apiPreference.api_preference.ols = apiPreferencesCode; + +// fetch(`${vocabUrl}/Terminology/${terminology.id}/filter/${searchProp}`, { +// method: 'POST', +// headers: { +// 'Content-Type': 'application/json', +// }, +// body: JSON.stringify(apiPreference), +// }) +// .then(res => { +// if (res.ok) { +// return res.json(); +// } else { +// throw new Error('An unknown error occurred.'); +// } +// }) +// .catch(error => { +// if (error) { +// notification.error({ +// message: 'Error', +// description: 'An error occurred saving the ontology preferences.', +// }); +// } +// return error; +// }); diff --git a/src/components/Projects/Tables/EditMappingsTableModal.jsx b/src/components/Projects/Tables/EditMappingsTableModal.jsx index ca8b0d5..474d4f0 100644 --- a/src/components/Projects/Tables/EditMappingsTableModal.jsx +++ b/src/components/Projects/Tables/EditMappingsTableModal.jsx @@ -247,18 +247,15 @@ export const EditMappingsTableModal = ({ } return error; }) - .then(() => - OntologyFilterCodeSubmit( - apiPreferencesCode, - preferenceType, - prefTypeKey, - mappingProp, - vocabUrl, - table - ) - ) - .finally(() => setLoading(false)); + OntologyFilterCodeSubmit( + apiPreferencesCode, + preferenceType, + prefTypeKey, + mappingProp, + vocabUrl, + table + ); }; return ( @@ -358,14 +355,14 @@ export const EditMappingsTableModal = ({ form={form} reset={reset} onClose={form.resetFields} - searchProp={editMappings.name} + searchProp={editMappings?.name} mappingDesc={ - editMappings.description - ? editMappings.description + editMappings?.description + ? editMappings?.description : 'No Description' } component={table} - mappingProp={editMappings.code} + mappingProp={editMappings?.code} table={table} /> ) : ( diff --git a/src/components/Projects/Terminologies/EditMappingModal.jsx b/src/components/Projects/Terminologies/EditMappingModal.jsx index 73b635d..6fc4916 100644 --- a/src/components/Projects/Terminologies/EditMappingModal.jsx +++ b/src/components/Projects/Terminologies/EditMappingModal.jsx @@ -16,10 +16,7 @@ import { MappingReset } from '../../Manager/MappingsFunctions/MappingReset'; import { ellipsisString, systemsMatch } from '../../Manager/Utilitiy'; import { getById } from '../../Manager/FetchManager'; import { SearchContext } from '../../../Contexts/SearchContext'; -import { - OntologyFilterCodeSubmit, - OntologyFilterCodeSubmitTerm, -} from '../../Manager/MappingsFunctions/OntologyFilterCodeSubmit'; +import { OntologyFilterCodeSubmitTerm } from '../../Manager/MappingsFunctions/OntologyFilterCodeSubmitTerm'; export const EditMappingsModal = ({ editMappings, @@ -255,17 +252,15 @@ export const EditMappingsModal = ({ } return error; }) - .then(() => - OntologyFilterCodeSubmitTerm( - apiPreferencesCode, - preferenceType, - prefTypeKey, - searchProp, - vocabUrl, - terminology - ) - ) .finally(() => setLoading(false)); + OntologyFilterCodeSubmitTerm( + apiPreferencesCode, + preferenceType, + prefTypeKey, + searchProp, + vocabUrl, + terminology + ); }; return ( @@ -372,7 +367,7 @@ export const EditMappingsModal = ({ reset={reset} onClose={form.resetFields} searchProp={ - editMappings?.display ? editMappings.display : editMappings?.code + editMappings?.display ? editMappings?.display : editMappings?.code } mappingProp={editMappings?.code} mappingDesc={editMappings?.description} From 09679f5b69c8926beff55f67c4ecc60d9188b769 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Fri, 1 Nov 2024 10:17:14 -0500 Subject: [PATCH 093/180] Changed entries per page for faster loading time --- src/components/Manager/MappingsFunctions/GetMappingsModal.jsx | 4 ++-- src/components/Manager/MappingsFunctions/MappingReset.jsx | 2 +- src/components/Manager/MappingsFunctions/MappingSearch.jsx | 2 +- .../Manager/MappingsFunctions/OntologyCheckboxes.jsx | 2 +- src/components/Projects/Terminologies/APISearchBar.jsx | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 961b100..75c7849 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -45,7 +45,7 @@ export const GetMappingsModal = ({ prefTypeKey, } = useContext(SearchContext); const [page, setPage] = useState(0); - const entriesPerPage = 2000; + const entriesPerPage = 1000; const [loading, setLoading] = useState(false); const [results, setResults] = useState([]); const [totalCount, setTotalCount] = useState(); @@ -460,7 +460,7 @@ export const GetMappingsModal = ({ display: d.label, description: d.description[0], system: systemsMatch( - d?.obo_id.split(':')[0] + d?.obo_id?.split(':')[0] ), }), label: checkBoxDisplay(d, index), diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index 15ca486..b8274ef 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -30,7 +30,7 @@ export const MappingReset = ({ setUnformattedPref, } = useContext(SearchContext); const [page, setPage] = useState(0); - const entriesPerPage = 2000; + const entriesPerPage = 1000; const [loading, setLoading] = useState(true); const [results, setResults] = useState([]); const [totalCount, setTotalCount] = useState(); diff --git a/src/components/Manager/MappingsFunctions/MappingSearch.jsx b/src/components/Manager/MappingsFunctions/MappingSearch.jsx index fb58be7..154f770 100644 --- a/src/components/Manager/MappingsFunctions/MappingSearch.jsx +++ b/src/components/Manager/MappingsFunctions/MappingSearch.jsx @@ -33,7 +33,7 @@ export const MappingSearch = ({ const { tableId } = useParams(); const [page, setPage] = useState(0); - const entriesPerPage = 2000; + const entriesPerPage = 1000; const [loading, setLoading] = useState(true); const [results, setResults] = useState([]); const [totalCount, setTotalCount] = useState(); diff --git a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx index 89e8662..0ad3168 100644 --- a/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx +++ b/src/components/Manager/MappingsFunctions/OntologyCheckboxes.jsx @@ -78,7 +78,7 @@ export const OntologyCheckboxes = ({ preferenceType }) => { return acc; }, {}); - // // Build the new data structure + // Build the new data structure const countsResult = Object.keys(sortedData[0]?.ontologies).map(key => { return { [key]: countsMap[key] || 0, api: sortedData[0]?.api_id }; }); diff --git a/src/components/Projects/Terminologies/APISearchBar.jsx b/src/components/Projects/Terminologies/APISearchBar.jsx index 3e25c9c..05441dc 100644 --- a/src/components/Projects/Terminologies/APISearchBar.jsx +++ b/src/components/Projects/Terminologies/APISearchBar.jsx @@ -22,7 +22,7 @@ export const APISearchBar = ({ setApiTotalCount, } = useContext(SearchContext); const [inputValue, setInputValue] = useState(searchProp); - const entriesPerPage = 2000; + const entriesPerPage = 1000; const [currentSearchProp, setCurrentSearchProp] = useState(searchProp); const [filteredResultsCount, setFilteredResultsCount] = useState(0); From 44ce18e51ae9c9a09d6739a6c52ee97b187b0ca9 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Fri, 1 Nov 2024 10:54:12 -0500 Subject: [PATCH 094/180] removed console logs --- src/components/Manager/FetchManager.jsx | 18 +++++++++++------- .../MappingsFunctions/GetMappingsModal.jsx | 1 - 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/Manager/FetchManager.jsx b/src/components/Manager/FetchManager.jsx index bf9c11a..307abe3 100644 --- a/src/components/Manager/FetchManager.jsx +++ b/src/components/Manager/FetchManager.jsx @@ -264,15 +264,19 @@ export const getFiltersByCode = ( }) .then(data => { setUnformattedPref(data); + const codeToSearch = Object.keys(data)?.[0]; - // Dynamically derive the mappingProp based on a condition or the structure of the data - const codeToSearch = Object.keys(data)[0]; // Example: get the first key in the object - if (data?.[codeToSearch]?.api_preference?.ols) { - const joinedOntologies = - data[codeToSearch].api_preference.ols.join(','); - setApiPreferencesCode(joinedOntologies); // Set state to the comma-separated string + const ols = data?.[codeToSearch]?.api_preference?.ols; + + if (Array.isArray(ols)) { + // If ols in api_preference is an array, use it as is + setApiPreferencesCode(ols); // Set state to the array + } else if (typeof ols === 'string') { + // If ols in api_preference is a string, split it into an array + const splitOntologies = ols.split(','); + setApiPreferencesCode(splitOntologies); // Set state to the array } else { - setApiPreferencesCode(''); // Fallback if no ols found + setApiPreferencesCode([]); // Fallback if no ols found } }); }; diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index 75c7849..c7b5ffa 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -368,7 +368,6 @@ export const GetMappingsModal = ({ }; const filteredResultsArray = getFilteredResults(); - return ( <> Date: Fri, 1 Nov 2024 15:54:47 -0500 Subject: [PATCH 095/180] Search bar for selecting ontology filters for a Table/Terminology --- src/Contexts/SearchContext.jsx | 3 +++ .../Manager/MappingsFunctions/FilterAPI.jsx | 2 -- .../Manager/MappingsFunctions/FilterOntology.jsx | 12 ++++++++++-- .../Manager/MappingsFunctions/FilterSelect.jsx | 16 +++++++++++----- .../MappingsFunctions/MappingsFunctions.scss | 5 +++++ 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/Contexts/SearchContext.jsx b/src/Contexts/SearchContext.jsx index ab17bb6..2de70e4 100644 --- a/src/Contexts/SearchContext.jsx +++ b/src/Contexts/SearchContext.jsx @@ -18,6 +18,7 @@ export function SearchContextRoot() { const [facetCounts, setFacetCounts] = useState([]); const [ontologyApis, setOntologyApis] = useState([]); const [apiPreferencesTerm, setApiPreferencesTerm] = useState(undefined); + const [searchText, setSearchText] = useState(''); const defaultOntologies = 'mondo,hp,maxo,ncit'; const preferenceTypeSet = data => @@ -63,6 +64,8 @@ export function SearchContextRoot() { preferenceTypeSet, preferenceType, prefTypeKey, + searchText, + setSearchText, }; return ( diff --git a/src/components/Manager/MappingsFunctions/FilterAPI.jsx b/src/components/Manager/MappingsFunctions/FilterAPI.jsx index 538f2ea..281151a 100644 --- a/src/components/Manager/MappingsFunctions/FilterAPI.jsx +++ b/src/components/Manager/MappingsFunctions/FilterAPI.jsx @@ -15,7 +15,6 @@ export const FilterAPI = ({ ontologyApis, active, setActive, - searchText, currentPage, setCurrentPage, pageSize, @@ -158,7 +157,6 @@ export const FilterAPI = ({ setSelectedBoxes={setSelectedBoxes} displaySelectedOntologies={displaySelectedOntologies} setDisplaySelectedOntologies={setDisplaySelectedOntologies} - searchText={searchText} currentPage={currentPage} setCurrentPage={setCurrentPage} pageSize={pageSize} diff --git a/src/components/Manager/MappingsFunctions/FilterOntology.jsx b/src/components/Manager/MappingsFunctions/FilterOntology.jsx index 10e67c2..0b1da87 100644 --- a/src/components/Manager/MappingsFunctions/FilterOntology.jsx +++ b/src/components/Manager/MappingsFunctions/FilterOntology.jsx @@ -1,4 +1,4 @@ -import { Checkbox, Form } from 'antd'; +import { Checkbox, Form, Input } from 'antd'; import { useContext, useEffect, useState } from 'react'; import { myContext } from '../../../App'; import { FilterReset } from './FilterReset'; @@ -16,9 +16,11 @@ export const FilterOntology = ({ table, terminology, }) => { + const { Search } = Input; const [allCheckboxes, setAllCheckboxes] = useState([]); const { setOntologyForPagination } = useContext(myContext); - const { preferenceType, prefTypeKey } = useContext(SearchContext); + const { preferenceType, prefTypeKey, searchText, setSearchText } = + useContext(SearchContext); useEffect(() => { setOntologyForPagination(ontology); @@ -155,6 +157,12 @@ export const FilterOntology = ({ return ( <>
    + setSearchText(e.target.value)} + /> {Object.keys(preferenceType[prefTypeKey]?.api_preference || {}).some( key => preferenceType[prefTypeKey]?.api_preference[key]?.length > 0 ) && ( diff --git a/src/components/Manager/MappingsFunctions/FilterSelect.jsx b/src/components/Manager/MappingsFunctions/FilterSelect.jsx index cab3d55..8addb6d 100644 --- a/src/components/Manager/MappingsFunctions/FilterSelect.jsx +++ b/src/components/Manager/MappingsFunctions/FilterSelect.jsx @@ -31,8 +31,9 @@ export const FilterSelect = ({ component, table, terminology }) => { preferenceTypeSet, preferenceType, prefTypeKey, + searchText, + setSearchText, } = useContext(SearchContext); - const [searchText, setSearchText] = useState(''); // Gets the ontologyAPIs on first load, automatically sets active to the first of the list to display on the page useEffect(() => { @@ -72,6 +73,7 @@ export const FilterSelect = ({ component, table, terminology }) => { setSelectedOntologies([]); setSelectedBoxes([]); setDisplaySelectedOntologies([]); + setSearchText(''); }; // If the api doesn't exist in api_preference, creates an empty array for it @@ -201,8 +203,9 @@ export const FilterSelect = ({ component, table, terminology }) => { apiPrefObject && Object.values(apiPrefObject)?.reduce((acc, arr) => acc + arr.length, 0); - // Makes a set of ontologies to exclude from the list of available ones to select(excludes those that have already been selected) - // Converts the ontologies object into an array and filter based on the ontologiesToExclude + // Makes a set of ontologies to exclude from the list of available (excludes those that have already been selected) + // Converts the ontologies object into an array and filters based on the ontologiesToExclude + // Then filters that object based on the searchText in the search bar const filterOntologies = () => { if (ontologyForPagination) { const firstOntology = ontologyForPagination[0]; @@ -218,7 +221,10 @@ export const FilterSelect = ({ component, table, terminology }) => { })) .filter(obj => { return !ontologiesToExclude.has(obj.ontology_code); - }); + }) + .filter(item => + item?.curie.toLowerCase().includes(searchText.toLowerCase()) + ); return filteredOntologies; } @@ -227,7 +233,7 @@ export const FilterSelect = ({ component, table, terminology }) => { const filteredOntologiesArray = filterOntologies(); - // // Pagination + // Pagination const paginatedOntologies = filteredOntologiesArray?.slice( (currentPage - 1) * pageSize, currentPage * pageSize diff --git a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss index b24fc07..c573bfa 100644 --- a/src/components/Manager/MappingsFunctions/MappingsFunctions.scss +++ b/src/components/Manager/MappingsFunctions/MappingsFunctions.scss @@ -119,6 +119,11 @@ margin-left: 11vw; } +.api_onto_search_bar, .onto_search_bar { margin-bottom: 8px; } + +.api_onto_search_bar { + width: 400px; +} From 83d4f1085f472c7493075e03d8dde28c8f87bed9 Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 4 Nov 2024 11:10:27 -0600 Subject: [PATCH 096/180] Hover to display code for mapped terms --- src/components/Projects/Tables/TableDetails.jsx | 16 ++++++++++++++-- .../Projects/Terminologies/Terminology.jsx | 6 ++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/components/Projects/Tables/TableDetails.jsx b/src/components/Projects/Tables/TableDetails.jsx index 1bd0320..cdf90b7 100644 --- a/src/components/Projects/Tables/TableDetails.jsx +++ b/src/components/Projects/Tables/TableDetails.jsx @@ -4,7 +4,16 @@ import './TableStyling.scss'; import { Link, useNavigate, useParams } from 'react-router-dom'; import { Spinner } from '../../Manager/Spinner'; import { getById } from '../../Manager/FetchManager'; -import { Card, Col, Form, notification, Row, Table, Button } from 'antd'; +import { + Button, + Card, + Col, + Form, + notification, + Row, + Table, + Tooltip, +} from 'antd'; import { CloseCircleOutlined } from '@ant-design/icons'; import { EditTableDetails } from './EditTableDetails'; import { DeleteTable } from './DeleteTable'; @@ -252,7 +261,10 @@ It then shows the mappings as table data and alows the user to delete a mapping if (variableMappings && variableMappings.mappings?.length) { return variableMappings.mappings.map(code => (
    - {code.display} + + {' '} + {code.display} + handleRemoveMapping(variableMappings, code)} diff --git a/src/components/Projects/Terminologies/Terminology.jsx b/src/components/Projects/Terminologies/Terminology.jsx index ca6e966..33824ba 100644 --- a/src/components/Projects/Terminologies/Terminology.jsx +++ b/src/components/Projects/Terminologies/Terminology.jsx @@ -4,7 +4,7 @@ import { myContext } from '../../../App'; import './Terminology.scss'; import { Spinner } from '../../Manager/Spinner'; import { getById } from '../../Manager/FetchManager'; -import { Col, Form, notification, Row, Table, Button } from 'antd'; +import { Button, Col, Form, notification, Row, Table, Tooltip } from 'antd'; import { CloseCircleOutlined } from '@ant-design/icons'; import { EditMappingsModal } from './EditMappingModal'; import { EditTerminologyDetails } from './EditTerminologyDetails'; @@ -137,7 +137,9 @@ It then shows the mappings as table data and alows the user to delete a mapping if (variableMappings && variableMappings.mappings?.length) { return variableMappings.mappings.map(code => (
    - {code.display} + + {code.display} + handleRemoveMapping(variableMappings, code)} From 9f5d552d2d89198d8fa5e99108f7173e6ac124fa Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 4 Nov 2024 11:31:47 -0600 Subject: [PATCH 097/180] Loading spinner stays on screen while results set in modal --- .../Manager/MappingsFunctions/GetMappingsModal.jsx | 2 +- .../Manager/MappingsFunctions/MappingReset.jsx | 9 ++------- .../Manager/MappingsFunctions/MappingSearch.jsx | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx index c7b5ffa..f6e00dc 100644 --- a/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx +++ b/src/components/Manager/MappingsFunctions/GetMappingsModal.jsx @@ -90,7 +90,7 @@ export const GetMappingsModal = ({ }, [apiPreferencesCode, searchProp]); useEffect(() => { - if (!!currentSearchProp) { + if (!!currentSearchProp && apiPreferencesCode !== undefined) { fetchResults(page, currentSearchProp); } }, [page, currentSearchProp]); diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index b8274ef..de99925 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -80,7 +80,7 @@ export const MappingReset = ({ // If there is a currentSearchProp in the search bar, it evaluates to true and runs the search function. // The function is run when the code and when the page changes. useEffect(() => { - if (!!currentSearchProp) { + if (!!currentSearchProp && apiPreferencesCode !== undefined) { fetchResults(page, currentSearchProp); } }, [page, currentSearchProp]); @@ -354,12 +354,7 @@ export const MappingReset = ({ {filteredResultsArray?.length > 0 ? ( { - if (!!currentSearchProp) { + if (!!currentSearchProp && apiPreferencesCode !== undefined) { fetchResults(page, currentSearchProp); } }, [page, currentSearchProp]); From ce4061c8e70e4ffa7f86e7017caadefd138da6da Mon Sep 17 00:00:00 2001 From: Yelena Cox Date: Mon, 4 Nov 2024 13:57:34 -0600 Subject: [PATCH 098/180] Changed 'name' to 'short code' for studies --- .../Manager/MappingsFunctions/MappingReset.jsx | 2 +- src/components/Projects/Studies/AddStudy.jsx | 17 +++++++++-------- .../Projects/Studies/EditStudyDetails.jsx | 6 ++++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/components/Manager/MappingsFunctions/MappingReset.jsx b/src/components/Manager/MappingsFunctions/MappingReset.jsx index de99925..5d2d3ad 100644 --- a/src/components/Manager/MappingsFunctions/MappingReset.jsx +++ b/src/components/Manager/MappingsFunctions/MappingReset.jsx @@ -348,7 +348,7 @@ export const MappingReset = ({ ))}
    - )}{' '} + )} {results?.length > 0 ? ( <> { const [loading, setLoading] = useState(false); const [form] = Form.useForm(); const { vocabUrl, setStudy } = useContext(myContext); + const { TextArea } = Input; const navigate = useNavigate(); // Submit function for adding a new study. @@ -75,19 +76,12 @@ export const AddStudy = ({ addStudy, setAddStudy }) => {

    Create Study

    - - - { > + +