@opencloning/ui 1.9.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/package.json +5 -6
  3. package/src/components/CloningSpeedDial.jsx +3 -5
  4. package/src/components/EditSequenceNameDialog.jsx +3 -5
  5. package/src/components/ExternalServicesStatusCheck.jsx +3 -5
  6. package/src/components/LoadCloningHistoryWrapper.jsx +5 -7
  7. package/src/components/assembler/Assembler.jsx +4 -6
  8. package/src/components/assembler/ExistingSyntaxDialog.jsx +2 -2
  9. package/src/components/assembler/useAssembler.js +6 -8
  10. package/src/components/domesticate/DomesticateDialog.jsx +3 -5
  11. package/src/components/form/EnzymeMultiSelect.jsx +3 -5
  12. package/src/components/navigation/MainAppBar.jsx +4 -2
  13. package/src/components/navigation/SelectTemplateDialog.jsx +4 -2
  14. package/src/components/primers/primer_design/SequenceTabComponents/hooks/useDesignPrimers.js +4 -6
  15. package/src/components/primers/primer_details/usePrimerDetailsEndpoints.js +4 -6
  16. package/src/components/sources/CollectionSource.jsx +2 -2
  17. package/src/components/sources/Source.jsx +32 -32
  18. package/src/components/sources/SourceAnnotation.jsx +2 -2
  19. package/src/components/sources/SourceAssembly.jsx +7 -7
  20. package/src/components/sources/SourceDatabase.jsx +2 -2
  21. package/src/components/sources/SourceFile.jsx +2 -2
  22. package/src/components/sources/SourceGenomeRegion.cy.jsx +46 -0
  23. package/src/components/sources/SourceGenomeRegion.jsx +29 -15
  24. package/src/components/sources/SourceHomologousRecombination.jsx +3 -3
  25. package/src/components/sources/SourceKnownGenomeRegion.jsx +3 -3
  26. package/src/components/sources/SourceManuallyTyped.jsx +2 -2
  27. package/src/components/sources/SourcePCRorHybridization.jsx +3 -3
  28. package/src/components/sources/SourcePolymeraseExtension.jsx +2 -2
  29. package/src/components/sources/SourceRepositoryId.jsx +4 -4
  30. package/src/components/sources/SourceRestriction.jsx +2 -2
  31. package/src/components/sources/SourceReverseComplement.jsx +2 -2
  32. package/src/components/sources/SourceServerStaticFile.jsx +3 -3
  33. package/src/components/verification/VerificationFileDialog.cy.jsx +17 -21
  34. package/src/components/verification/VerificationFileDialog.jsx +12 -11
  35. package/src/hooks/index.js +1 -2
  36. package/src/hooks/useBackendHttpClient.js +17 -0
  37. package/src/hooks/useCloningHistoryLoader.js +5 -7
  38. package/src/hooks/useGatewaySites.js +3 -5
  39. package/src/hooks/useInitializeApp.js +3 -4
  40. package/src/hooks/useLoadDatabaseFile.js +2 -2
  41. package/src/hooks/useSequencingAlignment.js +4 -6
  42. package/src/hooks/useServerStaticFiles.js +2 -2
  43. package/src/hooks/{useBackendAPI.js → useSourceRequest.js} +6 -8
  44. package/src/hooks/useStoreEditor.js +2 -1
  45. package/src/hooks/useUrlParamsLoader.js +8 -5
  46. package/src/hooks/useValidateState.js +4 -6
  47. package/src/version.js +1 -1
  48. package/src/hooks/useBackendRoute.js +0 -23
  49. package/src/hooks/useHttpClient.js +0 -20
@@ -21,12 +21,15 @@ import { isEqual } from 'lodash-es';
21
21
  import { getTeselaJsonFromBase64, file2base64 } from '@opencloning/utils/readNwrite';
22
22
  import SequencingFileRow from './SequencingFileRow';
23
23
  import { cloningActions } from '@opencloning/store/cloning';
24
- import useBackendRoute from '../../hooks/useBackendRoute';
25
24
  import useStoreEditor from '../../hooks/useStoreEditor';
26
25
  import LoadFromDatabaseButton from './LoadFromDatabaseButton';
27
26
  import { sequencingFileExtensions } from '@opencloning/utils/sequencingFileExtensions';
28
- import useHttpClient from '../../hooks/useHttpClient';
27
+ import useBackendHttpClient from '../../hooks/useBackendHttpClient';
29
28
  import { getVerificationFileName } from '@opencloning/utils/readNwrite';
29
+ import {
30
+ getVerificationFileContent,
31
+ setVerificationFileContent,
32
+ } from '@opencloning/utils/verificationFileStore';
30
33
  import ImportSequencingFilesInput from './ImportSequencingFilesInput';
31
34
 
32
35
  const { addFile, removeFile: removeFileAction, removeFilesAssociatedToSequence, setMainSequenceId, setCurrentTab } = cloningActions;
@@ -43,9 +46,8 @@ export default function VerificationFileDialog({ id, dialogOpen, setDialogOpen }
43
46
  const dispatch = useDispatch();
44
47
  const fileInputRef = useRef(null);
45
48
  const { updateStoreEditor } = useStoreEditor();
46
- const backendRoute = useBackendRoute();
47
49
  const store = useStore();
48
- const httpClient = useHttpClient();
50
+ const httpClient = useBackendHttpClient();
49
51
 
50
52
  const toggleMain = React.useCallback(() => {
51
53
  dispatch(setMainSequenceId(id));
@@ -78,7 +80,7 @@ export default function VerificationFileDialog({ id, dialogOpen, setDialogOpen }
78
80
  const existingSequencingFilesInState = await Promise.all(store.getState().cloning.files
79
81
  .filter((f) => f.sequence_id === id && f.file_type === 'Sequencing file')
80
82
  .map(async (f) => {
81
- const base64str = sessionStorage.getItem(getVerificationFileName(f));
83
+ const base64str = getVerificationFileContent(getVerificationFileName(f));
82
84
  const trace = (await getTeselaJsonFromBase64(base64str, f.file_name)).sequence;
83
85
  return { ...f, base64str, trace };
84
86
  }));
@@ -94,7 +96,7 @@ export default function VerificationFileDialog({ id, dialogOpen, setDialogOpen }
94
96
  const allSequencingFiles = [...existingSequencingFilesInState, ...parsedSequencingFiles];
95
97
  const alignments = [];
96
98
  const traces = allSequencingFiles.map((f) => f.trace);
97
- const resp = await httpClient.post(backendRoute('align_sanger'), { sequence, traces });
99
+ const resp = await httpClient.post('align_sanger', { sequence, traces });
98
100
 
99
101
  for (let i = 0; i < allSequencingFiles.length; i++) {
100
102
  alignments.push({ ...allSequencingFiles[i], alignment: [resp.data[0], resp.data[i + 1]] });
@@ -107,10 +109,10 @@ export default function VerificationFileDialog({ id, dialogOpen, setDialogOpen }
107
109
  const { trace, base64str, ...rest } = alignment;
108
110
  dispatch(addFile(rest));
109
111
  });
110
- alignments.forEach(({ base64str, file_name }) => { sessionStorage.setItem(`verification-${id}-${file_name}`, base64str); });
112
+ alignments.forEach(({ base64str, file_name }) => { setVerificationFileContent(`verification-${id}-${file_name}`, base64str); });
111
113
  });
112
114
  setLoadingMessage('');
113
- }, [id, dispatch, httpClient, backendRoute, store, sequence]);
115
+ }, [id, dispatch, httpClient, store, sequence]);
114
116
 
115
117
  const onFileChange = useCallback(async (files) => {
116
118
  setLoadingMessage('Aligning...');
@@ -126,7 +128,6 @@ export default function VerificationFileDialog({ id, dialogOpen, setDialogOpen }
126
128
 
127
129
  const removeFile = useCallback((fileName) => {
128
130
  dispatch(removeFileAction({ fileName, sequenceId: id }));
129
- sessionStorage.removeItem(`verification-${id}-${fileName}`);
130
131
  }, [id, dispatch]);
131
132
 
132
133
  const handleClickUpload = useCallback(() => {
@@ -134,9 +135,9 @@ export default function VerificationFileDialog({ id, dialogOpen, setDialogOpen }
134
135
  }, [fileInputRef]);
135
136
 
136
137
  const downloadFile = useCallback((fileName) => {
137
- const base64Content = sessionStorage.getItem(`verification-${id}-${fileName}`);
138
+ const base64Content = getVerificationFileContent(`verification-${id}-${fileName}`);
138
139
  if (!base64Content) {
139
- setError(`File ${fileName} not found in session storage`);
140
+ setError(`File ${fileName} not found in the verification file store`);
140
141
  return;
141
142
  }
142
143
  const binaryString = atob(base64Content);
@@ -1,4 +1,3 @@
1
1
  export { useConfig } from './useConfig.js';
2
2
  export { default as useServerStaticFiles, localFilesHttpClient } from './useServerStaticFiles.js';
3
- export { default as useBackendRoute } from './useBackendRoute.js';
4
- export { default as useHttpClient } from './useHttpClient.js';
3
+ export { default as useBackendHttpClient } from './useBackendHttpClient.js';
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { getBackendHttpClient } from '@opencloning/utils/httpClients';
3
+ import { useConfig } from './useConfig';
4
+
5
+ /**
6
+ * Http client for the backend: urls are relative to config.backendUrl
7
+ * (e.g. httpClient.post('validate', body)), and requests can only reach the backend.
8
+ * For external urls use getExternalHttpClient() from @opencloning/utils/httpClients.
9
+ */
10
+ export default function useBackendHttpClient() {
11
+ const { backendUrl, requiresBackendAuth = false } = useConfig();
12
+
13
+ return React.useMemo(
14
+ () => getBackendHttpClient(backendUrl, { authenticated: requiresBackendAuth }),
15
+ [backendUrl, requiresBackendAuth],
16
+ );
17
+ }
@@ -4,13 +4,12 @@ import { cloningActions } from '@opencloning/store/cloning';
4
4
  import { getEmptyPlaceholderSource } from '@opencloning/store/cloning_utils';
5
5
  import { graftState, getGraftSequenceId, mergeStates } from '@opencloning/utils/network';
6
6
  import {
7
- loadFilesToSessionStorage,
7
+ loadFilesToVerificationStore,
8
8
  parseHistoryFile,
9
9
  updateVerificationFileNames,
10
10
  } from '@opencloning/utils/readNwrite';
11
- import useBackendRoute from './useBackendRoute';
12
11
  import useCloningAlerts from './useCloningAlerts';
13
- import useHttpClient from './useHttpClient';
12
+ import useBackendHttpClient from './useBackendHttpClient';
14
13
  import useValidateState from './useValidateState';
15
14
 
16
15
  const {
@@ -31,9 +30,8 @@ export default function useCloningHistoryLoader() {
31
30
  const store = useStore();
32
31
  const validateState = useValidateState();
33
32
  const { addAlert } = useCloningAlerts();
34
- const backendRoute = useBackendRoute();
35
- const httpClient = useHttpClient();
36
- const snapgeneUrl = backendRoute('read_snapgene_history');
33
+ const httpClient = useBackendHttpClient();
34
+ const snapgeneUrl = 'read_snapgene_history';
37
35
 
38
36
  const applyCloningStrategy = React.useCallback(async (cloningStrategy, options = {}) => {
39
37
  const {
@@ -72,7 +70,7 @@ export default function useCloningHistoryLoader() {
72
70
  dispatch(setCloningState(newState));
73
71
  });
74
72
 
75
- await loadFilesToSessionStorage(verificationFiles, idShift);
73
+ await loadFilesToVerificationStore(verificationFiles, idShift);
76
74
  } catch (e) {
77
75
  console.error(e);
78
76
  dispatch(setCloningState(prevState));
@@ -2,16 +2,14 @@ import React, { useCallback, useState } from 'react';
2
2
  import { useStore } from 'react-redux';
3
3
  import error2String from '@opencloning/utils/error2String';
4
4
  import { formatGatewaySites } from '@opencloning/store/cloning_utils';
5
- import useBackendRoute from './useBackendRoute';
6
- import useHttpClient from './useHttpClient';
5
+ import useBackendHttpClient from './useBackendHttpClient';
7
6
 
8
7
  export default function useGatewaySites({ target, greedy }) {
9
8
  const store = useStore();
10
9
  const [requestStatus, setRequestStatus] = useState({ status: null, message: '' });
11
10
  const [connectAttempt, setConnectAttempt] = useState(0);
12
11
  const [sites, setSites] = useState([]);
13
- const backendRoute = useBackendRoute();
14
- const httpClient = useHttpClient();
12
+ const httpClient = useBackendHttpClient();
15
13
 
16
14
  const attemptAgain = useCallback(() => {
17
15
  setConnectAttempt((p) => p + 1);
@@ -20,7 +18,7 @@ export default function useGatewaySites({ target, greedy }) {
20
18
  React.useEffect(() => {
21
19
  async function getSitesInTarget() {
22
20
  setRequestStatus({ status: 'loading', message: 'loading' });
23
- const url = backendRoute('annotation/get_gateway_sites');
21
+ const url = 'annotation/get_gateway_sites';
24
22
  const state = store.getState();
25
23
  const sequence = state.cloning.sequences.find((seq) => seq.id === target);
26
24
  try {
@@ -1,15 +1,14 @@
1
1
  import { useEffect } from 'react';
2
+ import { clearVerificationFileContents } from '@opencloning/utils/verificationFileStore';
2
3
 
3
4
  /**
4
5
  * Hook to initialize application-level concerns
5
- * - Clears session storage
6
+ * - Clears the in-memory verification file store
6
7
  */
7
8
  export default function useInitializeApp() {
8
9
 
9
10
  useEffect(() => {
10
- // Clear session storage
11
- // eslint-disable-next-line no-undef
12
- sessionStorage.clear();
11
+ clearVerificationFileContents();
13
12
  }, []);
14
13
  }
15
14
 
@@ -6,7 +6,7 @@ import useCloningHistoryLoader from './useCloningHistoryLoader';
6
6
  import useDatabase from './useDatabase';
7
7
  import { useStore } from 'react-redux';
8
8
 
9
- export default function useLoadDatabaseFile({ source, sendPostRequest, setHistoryFileError }) {
9
+ export default function useLoadDatabaseFile({ source, sendSourceRequest, setHistoryFileError }) {
10
10
  const validateState = useValidateState();
11
11
  const store = useStore();
12
12
  const database = useDatabase();
@@ -88,7 +88,7 @@ export default function useLoadDatabaseFile({ source, sendPostRequest, setHistor
88
88
  },
89
89
  };
90
90
  const modifySource = (s) => ({ ...s, database_id: databaseId });
91
- sendPostRequest({ endpoint: 'read_from_file', requestData, config, source, modifySource });
91
+ sendSourceRequest({ endpoint: 'read_from_file', requestData, config, source, modifySource });
92
92
  }
93
93
  };
94
94
  return { loadDatabaseFile };
@@ -1,17 +1,15 @@
1
1
  import { useCallback } from 'react';
2
2
  import { useMutation } from '@tanstack/react-query';
3
3
  import { buildAlignmentTrack, buildReferenceTrack, buildAlignmentConfig } from '@opencloning/utils/alignmentUtils';
4
- import useBackendRoute from './useBackendRoute';
5
- import useHttpClient from './useHttpClient';
4
+ import useBackendHttpClient from './useBackendHttpClient';
6
5
 
7
6
  export default function useSequencingAlignment({ onError } = {}) {
8
- const backendRoute = useBackendRoute();
9
- const httpClient = useHttpClient();
7
+ const httpClient = useBackendHttpClient();
10
8
 
11
9
  const fetchAlignments = useCallback(async ({ sequenceModel, sequenceData, parsedFiles }) => {
12
10
  // parsedFiles: [{ fileName, fileContent }] where fileContent is getTeselaJsonFromBase64 output
13
11
  const traces = parsedFiles.map((f) => f.fileContent.sequence);
14
- const resp = await httpClient.post(backendRoute('align_sanger'), { sequence: sequenceModel, traces });
12
+ const resp = await httpClient.post('align_sanger', { sequence: sequenceModel, traces });
15
13
 
16
14
  const referenceTrack = buildReferenceTrack(sequenceData, resp.data[0]);
17
15
  const otherTracks = parsedFiles.map((f, i) => {
@@ -20,7 +18,7 @@ export default function useSequencingAlignment({ onError } = {}) {
20
18
  });
21
19
 
22
20
  return buildAlignmentConfig(sequenceModel.id, sequenceData, [referenceTrack, ...otherTracks]);
23
- }, [httpClient, backendRoute]);
21
+ }, [httpClient]);
24
22
 
25
23
  return useMutation({ mutationFn: fetchAlignments, onError });
26
24
  }
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
- import getHttpClient from '@opencloning/utils/getHttpClient';
2
+ import { getExternalHttpClient } from '@opencloning/utils/httpClients';
3
3
  import { useConfig } from '../providers';
4
4
  import useRequestForEffect from './useRequestForEffect';
5
5
 
6
6
 
7
- export const localFilesHttpClient = getHttpClient([]);
7
+ export const localFilesHttpClient = getExternalHttpClient();
8
8
 
9
9
  function sequencesToCategories(sequences) {
10
10
  const allCategories = sequences
@@ -1,22 +1,20 @@
1
1
  import { useState, useCallback } from 'react';
2
2
  import error2String from '@opencloning/utils/error2String';
3
- import useBackendRoute from './useBackendRoute';
4
3
  import useCloningAlerts from './useCloningAlerts';
5
- import useHttpClient from './useHttpClient';
4
+ import useBackendHttpClient from './useBackendHttpClient';
6
5
 
7
- export default function useBackendAPI() {
6
+ export default function useSourceRequest() {
8
7
  const [requestStatus, setRequestStatus] = useState({ status: null, message: '' });
9
8
  const [sources, setSources] = useState([]);
10
9
  const [sequences, setSequences] = useState([]);
11
- const backendRoute = useBackendRoute();
12
- const httpClient = useHttpClient();
10
+ const httpClient = useBackendHttpClient();
13
11
  const { addAlert } = useCloningAlerts();
14
12
 
15
- const sendPostRequest = useCallback(async ({ endpoint, requestData, config = {}, source: { output }, modifySource = (s) => s }) => {
13
+ const sendSourceRequest = useCallback(async ({ endpoint, requestData, config = {}, source: { output }, modifySource = (s) => s }) => {
16
14
  setRequestStatus({ status: 'loading', message: 'loading' });
17
15
 
18
16
  // Url built like this in case trailing slash
19
- const url = backendRoute(endpoint);
17
+ const url = endpoint;
20
18
  // paramsSerializer: { indexes: null } is to correctly serialize arrays in the URL
21
19
  const fullConfig = { ...config, paramsSerializer: { indexes: null } };
22
20
  try {
@@ -50,5 +48,5 @@ export default function useBackendAPI() {
50
48
  }
51
49
  }, []);
52
50
 
53
- return { requestStatus, sources, sequences, sendPostRequest };
51
+ return { requestStatus, sources, sequences, sendSourceRequest };
54
52
  }
@@ -2,6 +2,7 @@ import { useStore } from 'react-redux';
2
2
  import { updateEditor, addAlignment } from '@teselagen/ove';
3
3
  import { getPCRPrimers } from '@opencloning/store/cloning_utils';
4
4
  import { getTeselaJsonFromBase64 } from '@opencloning/utils/readNwrite';
5
+ import { getVerificationFileContent } from '@opencloning/utils/verificationFileStore';
5
6
  import { buildAlignmentTrack, buildReferenceTrack, buildAlignmentConfig, removePanelFromShown, updatePanelsShownWithAlignment } from '@opencloning/utils/alignmentUtils';
6
7
 
7
8
  export default function useStoreEditor() {
@@ -31,7 +32,7 @@ export default function useStoreEditor() {
31
32
  if (alignmentFiles.length > 0) {
32
33
  const referenceTrack = buildReferenceTrack(sequenceData, alignmentFiles[0].alignment[0]);
33
34
  const otherTracks = await Promise.all(alignmentFiles.map(async (aln) => {
34
- const fileContent = await getTeselaJsonFromBase64(sessionStorage.getItem(`verification-${id}-${aln.file_name}`), aln.file_name);
35
+ const fileContent = await getTeselaJsonFromBase64(getVerificationFileContent(`verification-${id}-${aln.file_name}`), aln.file_name);
35
36
  return buildAlignmentTrack(fileContent, aln);
36
37
  }));
37
38
  const alignmentConfig = buildAlignmentConfig(id, sequenceData, [referenceTrack, ...otherTracks]);
@@ -4,11 +4,15 @@ import { cloningActions } from '@opencloning/store/cloning';
4
4
  import useDatabase from './useDatabase';
5
5
  import useLoadDatabaseFile from './useLoadDatabaseFile';
6
6
  import useCloningAlerts from './useCloningAlerts';
7
- import useHttpClient from './useHttpClient';
8
7
  import useValidateState from './useValidateState';
9
8
  import useCloningHistoryLoader from './useCloningHistoryLoader';
10
9
  import { formatSequenceLocationString, getUrlParameters } from '@opencloning/utils/other';
11
10
  import { formatTemplate } from '@opencloning/utils/readNwrite';
11
+ import { encodePathSegment } from '@opencloning/utils/urlUtils';
12
+ import { getExternalHttpClient } from '@opencloning/utils/httpClients';
13
+
14
+ // For public urls (not the backend)
15
+ const httpClient = getExternalHttpClient();
12
16
 
13
17
  const { updateSource } = cloningActions;
14
18
 
@@ -21,9 +25,8 @@ export default function useUrlParamsLoader() {
21
25
  const database = useDatabase();
22
26
  const { addAlert } = useCloningAlerts();
23
27
  const setHistoryFileError = (e) => addAlert({ message: e, severity: 'error' });
24
- const { loadDatabaseFile } = useLoadDatabaseFile({ source: { id: 1 }, sendPostRequest: null, setHistoryFileError });
28
+ const { loadDatabaseFile } = useLoadDatabaseFile({ source: { id: 1 }, sendSourceRequest: null, setHistoryFileError });
25
29
  const validateState = useValidateState();
26
- const httpClient = useHttpClient();
27
30
  const { applyCloningStrategy, loadHistoryFromFile } = useCloningHistoryLoader();
28
31
 
29
32
  useEffect(() => {
@@ -46,7 +49,7 @@ export default function useUrlParamsLoader() {
46
49
  }
47
50
  } else if (urlParams.source === 'example' && urlParams.example) {
48
51
  try {
49
- const url = `${import.meta.env.BASE_URL}examples/${urlParams.example}`;
52
+ const url = `${import.meta.env.BASE_URL}examples/${encodePathSegment(urlParams.example)}`;
50
53
  const fileName = urlParams.example;
51
54
  if (fileName.endsWith('.zip')) {
52
55
  const resp = await httpClient.get(url, { responseType: 'blob' });
@@ -75,7 +78,7 @@ export default function useUrlParamsLoader() {
75
78
  } else if (urlParams.source === 'template' && urlParams.template && urlParams.key) {
76
79
  try {
77
80
  const baseUrl = 'https://assets.opencloning.org/OpenCloning-submission';
78
- const url = `${baseUrl}/processed/${urlParams.key}/templates/${urlParams.template}`;
81
+ const url = `${baseUrl}/processed/${encodePathSegment(urlParams.key)}/templates/${encodePathSegment(urlParams.template)}`;
79
82
  const { data } = await httpClient.get(url);
80
83
  const validatedData = await validateState(data);
81
84
  const newState = formatTemplate(validatedData, url);
@@ -1,18 +1,16 @@
1
1
  import React from 'react';
2
2
  import useCloningAlerts from './useCloningAlerts';
3
- import useBackendRoute from './useBackendRoute';
4
- import useHttpClient from './useHttpClient';
3
+ import useBackendHttpClient from './useBackendHttpClient';
5
4
 
6
5
  export default function useValidateState() {
7
- const backendRoute = useBackendRoute();
8
6
  const { addAlert } = useCloningAlerts();
9
- const httpClient = useHttpClient();
7
+ const httpClient = useBackendHttpClient();
10
8
 
11
9
  const validateState = React.useCallback(async (newState) => {
12
10
  // Returns null if the state is valid, otherwise the new updated state
13
11
  // It also adds alerts
14
12
  try {
15
- const response = await httpClient.post(backendRoute('validate'), newState);
13
+ const response = await httpClient.post('validate', newState);
16
14
  if (response.data !== null) {
17
15
  response.headers['x-warning'].split(';').forEach((warning) => {
18
16
  addAlert({
@@ -37,7 +35,7 @@ export default function useValidateState() {
37
35
  }
38
36
  return newState;
39
37
  }
40
- }, [addAlert, backendRoute, httpClient]);
38
+ }, [addAlert, httpClient]);
41
39
 
42
40
  return validateState;
43
41
  }
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Version placeholder - replaced at publish time via prepack script
2
- export const version = "1.9.2";
2
+ export const version = "2.0.0";
@@ -1,23 +0,0 @@
1
- import { useConfig } from './useConfig';
2
-
3
- export default function useBackendRoute() {
4
- const { backendUrl: configBackendUrl } = useConfig();
5
-
6
- if (!configBackendUrl) {
7
- return () => {};
8
- }
9
- const backendUrl = configBackendUrl.endsWith('/') ? configBackendUrl : `${configBackendUrl}/`;
10
-
11
- return function backendRoute(path) {
12
- if (!backendUrl) {
13
- throw new Error('Backend URL not set');
14
- }
15
- // console.log(new URL('/api', window.location.origin).href);
16
- // console.log(new URL(import.meta.env.VITE_REACT_APP_BACKEND_URL, window.location.origin).href);
17
- // This handles both the case where the backend url is absolute and the case where it is relative
18
- const backendRoot = new URL(backendUrl, window.location.origin).href;
19
- // Remove trailing slash from path
20
- const sanitizedPath = path.endsWith('/') ? path.slice(0, -1) : path;
21
- return new URL(sanitizedPath, backendRoot).href;
22
- };
23
- }
@@ -1,20 +0,0 @@
1
- import React from 'react';
2
- import getHttpClient, { getAuthenticatedHttpClient } from '@opencloning/utils/getHttpClient';
3
- import { useConfig } from './useConfig';
4
-
5
- export default function useHttpClient() {
6
- const { backendUrl, requiresBackendAuth = false } = useConfig();
7
-
8
- // Memoize the client creation and interceptor setup
9
- const apiClient = React.useMemo(() => {
10
- const createHttpClient = requiresBackendAuth ? getAuthenticatedHttpClient : getHttpClient;
11
-
12
- if (!backendUrl) {
13
- // Return a client without backend URL if config not loaded yet
14
- return createHttpClient([]);
15
- }
16
- return createHttpClient([backendUrl]);
17
- }, [backendUrl, requiresBackendAuth]);
18
-
19
- return apiClient;
20
- }