Skip to content

Commit 344dfd6

Browse files
authored
[OGUI-1834] Saving QC configuration (#3227)
* Add endpoint request to save configuration in consul
1 parent 4349588 commit 344dfd6

File tree

4 files changed

+124
-7
lines changed

4 files changed

+124
-7
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
import { useMutation, useQueryClient } from '@tanstack/react-query';
16+
import axiosInstance from '../axiosInstance';
17+
import { CONFIGURATION_QUERY_KEY } from '../query/useConfigurationQuery';
18+
import { CONFIGURATION_RESTRICTIONS_QUERY_KEY } from '../query/useConfigurationRestrictionsQuery';
19+
import type { FormValue } from '~/components/form/types';
20+
21+
/**
22+
* useConfigurationMutation hook
23+
* Provides a mutation to save configuration data.
24+
* @param {string} configurationName - The name of the configuration to save.
25+
* @returns {UseMutationResult} The mutation result.
26+
*/
27+
export const useConfigurationMutation = (configurationName: string) => {
28+
const queryClient = useQueryClient();
29+
30+
return useMutation({
31+
mutationFn: async (configuration: FormValue) => {
32+
const response = await axiosInstance.put<FormValue>(
33+
`configurations/${configurationName}`,
34+
JSON.stringify({ configuration }),
35+
);
36+
return response.data;
37+
},
38+
onSuccess: () => {
39+
void queryClient.invalidateQueries({
40+
queryKey: [CONFIGURATION_QUERY_KEY, configurationName],
41+
});
42+
void queryClient.invalidateQueries({
43+
queryKey: [CONFIGURATION_RESTRICTIONS_QUERY_KEY, configurationName],
44+
});
45+
},
46+
});
47+
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @license
3+
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
4+
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
5+
* All rights not expressly granted are reserved.
6+
*
7+
* This software is distributed under the terms of the GNU General Public
8+
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
9+
*
10+
* In applying this license CERN does not waive the privileges and immunities
11+
* granted to it by virtue of its status as an Intergovernmental Organization
12+
* or submit itself to any jurisdiction.
13+
*/
14+
15+
import { KEY_SEPARATOR } from '../constants';
16+
import type { InputsType } from '~/routes/configuration';
17+
import type { FormObjectValue, FormValue } from '../types';
18+
19+
/**
20+
* Convert flat form values back to nested configuration object format.
21+
* @param {InputsType} formValues - The flat form values with prefixed keys.
22+
* @param {string} prefix - The prefix to remove from keys (e.g., '/configuration').
23+
* @returns {FormValue} The nested configuration object.
24+
*/
25+
export const convertFormValuesToConfigObject = (
26+
formValues: InputsType,
27+
prefix: string,
28+
): FormValue => {
29+
const result: FormValue = {};
30+
31+
for (const [key, value] of Object.entries(formValues)) {
32+
if (!key.startsWith(prefix)) {
33+
continue;
34+
}
35+
36+
const keyWithoutPrefix = key.slice(prefix.length);
37+
const cleanKey = keyWithoutPrefix.startsWith(KEY_SEPARATOR)
38+
? keyWithoutPrefix.slice(KEY_SEPARATOR.length)
39+
: keyWithoutPrefix;
40+
41+
if (!cleanKey) {
42+
continue;
43+
}
44+
45+
const keys = cleanKey.split(KEY_SEPARATOR).filter((k) => k.length > 0);
46+
47+
if (keys.length === 0) {
48+
continue;
49+
}
50+
51+
let current = result;
52+
for (let i = 0; i < keys.length - 1; i++) {
53+
const currentKey = keys[i];
54+
if (!(currentKey in current) || typeof current[currentKey] !== 'object') {
55+
current[currentKey] = {};
56+
}
57+
current = current[currentKey] as FormObjectValue;
58+
}
59+
60+
const finalKey = keys[keys.length - 1];
61+
current[finalKey] = value.toString();
62+
}
63+
64+
return result;
65+
};

Configuration/webapp/app/hooks/useConfigurationForm.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,30 @@ import { useEffect, useMemo } from 'react';
1616
import type { InputsType } from '~/routes/configuration';
1717
import { useForm, type KeepStateOptions, type SubmitHandler } from 'react-hook-form';
1818
import { getDefaultValuesFromConfigObject } from '~/components/form/utils/getDefaultValuesFromConfigObject';
19+
import { convertFormValuesToConfigObject } from '~/components/form/utils/convertFormValuesToConfigObject';
1920
import { useLocation } from 'react-router';
2021
import type { FormValue } from '~/components/form/types';
22+
import { useConfigurationMutation } from '~/api/mutations/useConfigurationMutation';
2123

2224
const RESET_PROPS: KeepStateOptions = { keepDirty: false };
2325

2426
/**
2527
* useConfigurationForm hook
2628
* Provides form state management to child components.
27-
* @param {FormItem | undefined} configuration - The configuration object.
29+
* @param {object} options - The options for the form.
30+
* @param {FormItem | undefined} options.configuration - The configuration object.
31+
* @param {string} options.configurationName - The name of the configuration.
2832
* @returns {FormContextValue} Form context value
2933
*/
3034
export const useConfigurationForm = ({
3135
configuration,
36+
configurationName,
3237
}: {
3338
configuration: FormValue | undefined;
39+
configurationName: string;
3440
}) => {
3541
const { pathname } = useLocation();
42+
const mutation = useConfigurationMutation(configurationName);
3643

3744
const defaultValues = useMemo(
3845
() => getDefaultValuesFromConfigObject(configuration, pathname),
@@ -44,14 +51,11 @@ export const useConfigurationForm = ({
4451
});
4552

4653
const onSubmit: SubmitHandler<InputsType> = (data) => {
47-
// for now only logging the values
48-
// eslint-disable-next-line no-console
49-
console.log(data);
50-
// eslint-disable-next-line no-console
51-
console.log(getValues());
54+
const configurationData = convertFormValuesToConfigObject(data, pathname);
55+
mutation.mutate(configurationData);
5256
};
5357

54-
useEffect(() => reset(defaultValues, RESET_PROPS), [defaultValues]);
58+
useEffect(() => reset(defaultValues, RESET_PROPS), [defaultValues, reset]);
5559

5660
return {
5761
control,

Configuration/webapp/app/routes/configuration.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const ConfigurationPage = () => {
4343
onSubmit,
4444
} = useConfigurationForm({
4545
configuration,
46+
configurationName,
4647
});
4748

4849
const { showModal, handleProceed, handleSaveAndProceed, handleCancel } = useUnsavedChangesBlocker(

0 commit comments

Comments
 (0)