Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 60 additions & 11 deletions mock/mutator/customClient.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,84 @@
import Axios, { AxiosRequestConfig } from 'axios';
import Axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { API_CONFIG } from '../../src/config';
export const AXIOS_INSTANCE = Axios.create({ baseURL: API_CONFIG.BASE_URL });

// add a second `options` argument here if you want to pass extra options to each generated query
const AXIOS_INSTANCE = Axios.create({
baseURL: API_CONFIG.BASE_URL,
validateStatus: function (status) {
return status !== undefined && status >= 200 && status < 400;
},
withCredentials: true,
});

AXIOS_INSTANCE.interceptors.response.use(
async (response: AxiosResponse) => {
const redirectUrl = response.headers['x-redirect-location'];

if (response.status === 303 && redirectUrl) {
let redirectedPath: string;

try {
// If it's a full URL, extract only the pathname
const parsed = new URL(redirectUrl);
redirectedPath = parsed.pathname;
} catch {
// If it's already a relative path
redirectedPath = redirectUrl;
}

console.debug('Redirect intercepted. Rewriting to:', redirectedPath);

try {
const redirectedResponse = await AXIOS_INSTANCE.get(redirectedPath, {
headers: {
Accept: 'text/html',
...response.config.headers,
},
withCredentials: true,
});

return redirectedResponse;
} catch (fetchError) {
console.error('Redirect follow failed:', fetchError);
return Promise.reject(fetchError);
}
}

return response;
},
(error) => {
console.error('Interceptor error:', error);
return Promise.reject(error);
}
);

export default AXIOS_INSTANCE;

export const customInstance = <T>(
config: AxiosRequestConfig,
options?: AxiosRequestConfig,
): Promise<T> => {
const source = Axios.CancelToken.source();

const promise = AXIOS_INSTANCE({
...config,
...options,
cancelToken: source.token,
}).then(({ data }) => data).catch(error => {
throw error;
});
})
.then(({ data }) => data)
.catch((error) => {
throw error;
});

// @ts-ignore
promise.cancel = () => {
console.log("query was cancelled")
console.log('Query was cancelled');
source.cancel('Query was cancelled');
};

return promise;
};

// In some case with react-query and swr you want to be able to override the return error type so you can also do it here like this
export type ErrorType<Error> = AxiosError<Error>;

export type BodyType<BodyData> = BodyData;

// Or, in case you want to wrap the body type (optional)
// (if the custom instance is processing data before sending it, like changing the case for example)
export type BodyType<BodyData> = CamelCase<BodyData>;
6 changes: 2 additions & 4 deletions src/api/endpoints/apiActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ import { useCookies } from 'react-cookie'

type SecondParameter<T extends (...args: any) => any> = Parameters<T>[1];

export const createPostRequest = <T = any, D = any>(endpoint: string, contentType = "application/json") => {
export const createPostRequest = <T = any, D = any>(endpoint: string, headers : object) => {
return (data?: D, options?: SecondParameter<typeof customInstance>) => {
return customInstance<T>(
{
url: endpoint,
method: "POST",
data: data,
headers: {
"Content-Type": contentType,
},
headers: headers,
withCredentials: true
},
options,
Expand Down
52 changes: 49 additions & 3 deletions src/api/endpoints/apiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ interface JsonLdResponse {
'@graph'?: GraphNode[];
}

export const login = createPostRequest<any, LoginRequest>(API_CONFIG.REAL_API.SIGNIN, "application/x-www-form-urlencoded")
export const login = createPostRequest<any, LoginRequest>(API_CONFIG.REAL_API.SIGNIN, {"Content-Type": "application/x-www-form-urlencoded"})

export const register = createPostRequest<any, RegisterRequest>(API_CONFIG.REAL_API.NEWUSER_ILX, "application/x-www-form-urlencoded")
export const register = createPostRequest<any, RegisterRequest>(API_CONFIG.REAL_API.NEWUSER_ILX, {"Content-Type": "application/x-www-form-urlencoded"})


export const getUserSettings = (group: string) => {
Expand All @@ -40,7 +40,7 @@ export const getUserSettings = (group: string) => {

export const createNewOrganization = ({ group, data }: { group: string, data: any }) => {
const endpoint = `/${group}${API_CONFIG.REAL_API.CREATE_NEW_ORGANIZATION}`;
return createPostRequest<any, any>(endpoint, "application/json")(data);
return createPostRequest<any, any>(endpoint, { "Content-Type" : "application/json" })(data);
};

export const getOrganizations = (group: string) => {
Expand Down Expand Up @@ -77,4 +77,50 @@ export const getSelectedTermLabel = async (searchTerm: string): Promise<string |
console.error(err.message);
return undefined;
}
};

export const createNewEntity = async ({group,data,session}: { group: string; data: any; session: string }) => {
try {
const endpoint = `/${group}${API_CONFIG.REAL_API.CREATE_NEW_ENTITY}`;
const response = await createPostRequest<any, any>(
endpoint,
{ "Content-Type" : "application/x-www-form-urlencoded" }
)(data);

// If the response is HTML (a string), extract TMP ID
if (typeof response === "string") {
const match = response.match(/TMP:\d{9}/);
if (match) {
return {
term: {
id: `${match[0]}`,
},
raw: response,
status: 200,
};
}
}

// Otherwise, return response as-is
return response;
} catch (error) {
if (error?.response.status === 409) {
const match = error?.response?.data?.existing?.[0];
if (match) {
return {
term: {
id: `${match}`,
},
raw: error?.response,
status: error?.response?.status,
};
}
}

return {
raw: error?.response,
status: error?.response?.status,
};
}

};
42 changes: 19 additions & 23 deletions src/api/endpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@ export const getCuries = async (term) => {
});
}

export const getMatchTerms = async (term, filters = {}) => {
export const getMatchTerms = async (group, term, filters = {}) => {
const { getEndpointsIlx } = useApi();

/** Call Endpoint */
return getEndpointsIlx(BASE_GROUP,term, BASE_EXTENSION).then((data) => {
return getEndpointsIlx(group,term, BASE_EXTENSION).then((data) => {
return termParser(data, term);
})
.catch((error) => {
Expand Down Expand Up @@ -270,23 +270,22 @@ export const getRawData = async (group, termID, format) => {
});
}

export const addTerm = async (group, term) => {
export const addTerm = async (user: string, token: string, session: string, term: { label: string; synonyms: string[] }) => {
const { postPrivEntityNew } = useApi();

/** Call Endpoint */
return postPrivEntityNew(group, term).then((data) => {
let termParsed = getTerm(data.data);
let response = {
status : data.status,
term : termParsed
}
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
};

const body = {
'rdf-type': 'owl:Class',
label: term.label,
exact: term.synonyms,
};

return await postPrivEntityNew(user, body, { headers });
};

return response;
})
.catch((error) => {
return error;
});
}

export const bulkEditTerms = async (group, payload) => {
const { bulkEditTerms } = useMockApi();
Expand Down Expand Up @@ -330,14 +329,11 @@ export const getUser = async (id) => {
});
}

export const getExistingIDs = async () => {
const { getMatchTerms } = useMockApi();

export const getExistingIDs = async (searchTerm) => {
/** Call Endpoint */
return getMatchTerms("base", "*").then((data) => {
const terms = termParser(data, undefined);
let existingIds = terms?.results?.map( term => term.id?.split("/").pop() );
return terms?.results?.[0]?.id != undefined ? existingIds : [];
return elasticSearch(searchTerm).then((data) => {
const terms = data?.results;
return terms != undefined ? terms : [];
})
.catch((error) => {
return error;
Expand Down
25 changes: 15 additions & 10 deletions src/api/endpoints/interLexURIStructureAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7565,16 +7565,21 @@ after the label and exact synonyms are done an no matches confirmed the user sho
* @summary The workflow we want for this is a bit more complex than a simple form
*/
export const postPrivEntityNew = (
group: string,
options?: SecondParameter<typeof customInstance>,) => {


return customInstance<void>(
{url: `https://uri.olympiangods.org/${group}/priv/entity-new`, method: 'POST'
group: string,
data: any,
options?: SecondParameter<typeof customInstance> & { headers?: Record<string, string> }
) => {
return customInstance<void>(
{
url: `https://uri.olympiangods.org/${group}/priv/entity-new`,
method: 'POST',
data,
headers: options?.headers,
},
options);
}

options
);
};



export const getPostPrivEntityNewMutationOptions = <TError = ErrorType<unknown>,
Expand Down Expand Up @@ -9727,7 +9732,7 @@ export const getEndpointsIlx = (


return customInstance<void>(
{url: `https://uri.olympiangods.org/${group}/${fragPrefId}.${extension}`, method: 'GET', signal
{url: `/${group}/${fragPrefId}.${extension}`, method: 'GET', signal
},
options);
}
Expand Down
1 change: 1 addition & 0 deletions src/components/Auth/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const Login = () => {
value: sessionCookie.value,
expires: expires
}));
localStorage.setItem("token", sessionCookie.value)
setUserData({
name: userData['groupname'],
id: userData['orcid'],
Expand Down
2 changes: 1 addition & 1 deletion src/components/Dashboard/EditBulkTerms/TermsTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const TermsTable = ({ setOpenEditAttributes, setAttributes, attributes, searchCo

React.useEffect(() => {
setLoading(true)
getMatchTerms("i", { filters }).then(data => {
getMatchTerms("base", "i", { filters }).then(data => {
setTerms(data.results);
setLoading(false);
}).catch(err => {
Expand Down
5 changes: 4 additions & 1 deletion src/components/SingleTermView/OverView/CustomizedTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
import AddOutlinedIcon from '@mui/icons-material/AddOutlined';
import { useCallback, useEffect, useRef, useState } from "react";
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
import { GlobalDataContext } from "../../../contexts/DataContext";
import { useContext } from "react";

import { vars } from "../../../theme/variables";
const { gray100, gray50, gray600, gray500, brand600, brand50, brand700, gray700 } = vars;
Expand Down Expand Up @@ -156,6 +158,7 @@ const CustomizedTable = ({ data, term, isAddButtonVisible }) => {
// eslint-disable-next-line no-unused-vars
const [deletedObj, setDeletedObj] = useState({});
const [editTermDialogOpen, setEditTermDialogOpen] = useState(false);
const { user } = useContext(GlobalDataContext);

const targetRow = useRef();
const sourceRow = useRef();
Expand Down Expand Up @@ -245,7 +248,7 @@ const CustomizedTable = ({ data, term, isAddButtonVisible }) => {

// eslint-disable-next-line react-hooks/exhaustive-deps
const fetchTerms = useCallback(debounce(async (searchTerm) => {
const data = await getMatchTerms(searchTerm);
const data = await getMatchTerms(user?.groupname, searchTerm);
setTerms(data?.results[0]);
}, 500), [getMatchTerms]);

Expand Down
6 changes: 3 additions & 3 deletions src/components/SingleTermView/OverView/OverView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ const OverView = ({ searchTerm, isCodeViewVisible, selectedDataFormat }) => {
const fetchTerms = useCallback(
debounce((searchTerm) => {
if (searchTerm) {
getMatchTerms(searchTerm).then(data => {
setData(data?.results[0]);
getMatchTerms("base", searchTerm).then(data => {
setData(data?.results?.[0]);
setLoading(false);
});
}
Expand All @@ -43,7 +43,7 @@ const OverView = ({ searchTerm, isCodeViewVisible, selectedDataFormat }) => {
<Box p="2.5rem 5rem" sx={{
overflow: 'auto',
}}>
{isCodeViewVisible ? <RawDataViewer dataId={"ilx_0101901"} dataFormat={selectedDataFormat} /> :
{isCodeViewVisible ? <RawDataViewer dataId={searchTerm} dataFormat={selectedDataFormat} /> :
<>
<Details data={memoData} loading={loading} />
<Box p='5rem 0'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const PredicateGroupInput = ({ predicate, onChange }) => {

// eslint-disable-next-line react-hooks/exhaustive-deps
const fetchTerms = useCallback(debounce(async (searchTerm) => {
const data = await getMatchTerms(searchTerm);
const data = await getMatchTerms("base", searchTerm);
setTerms(data?.results);
}, 500), [getMatchTerms]);

Expand Down
6 changes: 1 addition & 5 deletions src/components/SingleTermView/OverView/RawDataViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { useState, useEffect } from 'react';
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
import { a11yLight } from 'react-syntax-highlighter/dist/esm/styles/hljs';
import { getRawData } from "../../../api/endpoints";
import { GlobalDataContext } from "../../../contexts/DataContext";
import { useContext } from "react";

import { vars } from '../../../theme/variables';
const { gray25, gray200, gray500 } = vars;
Expand All @@ -30,14 +28,12 @@ const RawDataViewer = ({ dataId, dataFormat }) => {
const [formattedData, setFormattedData] = useState(null);
// eslint-disable-next-line no-unused-vars
const [loading, setLoading] = useState(true);
const { user } = useContext(GlobalDataContext);

useEffect(() => {
getRawData(user?.name || "base",dataId, formatExtensions[dataFormat]).then( rawResponse => {
getRawData("base",dataId, formatExtensions[dataFormat]).then( rawResponse => {
setFormattedData(JSON.stringify(rawResponse, null, 2));
setLoading(false)
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dataId, dataFormat]);

return (
Expand Down
Loading