diff --git a/frontend/src/component/application/ApplicationUpdate/ApplicationUpdate.tsx b/frontend/src/component/application/ApplicationUpdate/ApplicationUpdate.tsx
index a899851400..2b2b46cf25 100644
--- a/frontend/src/component/application/ApplicationUpdate/ApplicationUpdate.tsx
+++ b/frontend/src/component/application/ApplicationUpdate/ApplicationUpdate.tsx
@@ -7,7 +7,6 @@ import useApplicationsApi from '../../../hooks/api/actions/useApplicationsApi/us
import useToast from '../../../hooks/useToast';
import { IApplication } from '../../../interfaces/application';
-
interface IApplicationUpdateProps {
application: IApplication;
}
@@ -17,19 +16,22 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
const { appName, icon, url, description } = application;
const [localUrl, setLocalUrl] = useState(url || '');
const [localDescription, setLocalDescription] = useState(description || '');
- const { setToastApiError } = useToast();
+ const { setToastData, setToastApiError } = useToast();
const commonStyles = useCommonStyles();
const handleChange = (
- evt: ChangeEvent<{ name?: string | undefined; value: unknown }>
+ evt: ChangeEvent<{ name?: string | undefined; value: unknown }>,
+ field: string,
+ value: string
) => {
evt.preventDefault();
try {
- storeApplicationMetaData(
- appName,
- 'icon',
- evt.target.value as string
- );
+ storeApplicationMetaData(appName, field, value);
+ setToastData({
+ type: 'success',
+ title: 'Updated Successfully',
+ text: `${field} successfully updated`,
+ });
} catch (e: any) {
setToastApiError(e.toString());
}
@@ -45,7 +47,9 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
label="Icon"
options={icons.map(v => ({ key: v, label: v }))}
value={icon || 'apps'}
- onChange={e => handleChange(e)}
+ onChange={e =>
+ handleChange(e, 'icon', e.target.value as string)
+ }
/>
@@ -57,9 +61,7 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
type="url"
variant="outlined"
size="small"
- onBlur={() =>
- storeApplicationMetaData(appName, 'url', localUrl)
- }
+ onBlur={e => handleChange(e, 'url', localUrl)}
/>
@@ -70,12 +72,8 @@ export const ApplicationUpdate = ({ application }: IApplicationUpdateProps) => {
size="small"
rows={2}
onChange={e => setLocalDescription(e.target.value)}
- onBlur={() =>
- storeApplicationMetaData(
- appName,
- 'description',
- localDescription
- )
+ onBlur={e =>
+ handleChange(e, 'description', localDescription)
}
/>
diff --git a/frontend/src/store/application/actions.js b/frontend/src/store/application/actions.js
new file mode 100644
index 0000000000..0a2b62423b
--- /dev/null
+++ b/frontend/src/store/application/actions.js
@@ -0,0 +1,58 @@
+import api from './api';
+import { dispatchError } from '../util';
+import { MUTE_ERROR } from '../error/actions';
+
+export const RECEIVE_ALL_APPLICATIONS = 'RECEIVE_ALL_APPLICATIONS';
+export const ERROR_RECEIVE_ALL_APPLICATIONS = 'ERROR_RECEIVE_ALL_APPLICATIONS';
+export const ERROR_UPDATING_APPLICATION_DATA = 'ERROR_UPDATING_APPLICATION_DATA';
+
+export const RECEIVE_APPLICATION = 'RECEIVE_APPLICATION';
+export const UPDATE_APPLICATION_FIELD = 'UPDATE_APPLICATION_FIELD';
+export const DELETE_APPLICATION = 'DELETE_APPLICATION';
+export const ERROR_DELETE_APPLICATION = 'ERROR_DELETE_APPLICATION';
+
+const recieveAllApplications = json => ({
+ type: RECEIVE_ALL_APPLICATIONS,
+ value: json,
+});
+
+const recieveApplication = json => ({
+ type: RECEIVE_APPLICATION,
+ value: json,
+});
+
+export function fetchAll() {
+ return dispatch =>
+ api
+ .fetchAll()
+ .then(json => dispatch(recieveAllApplications(json)))
+ .catch(dispatchError(dispatch, ERROR_RECEIVE_ALL_APPLICATIONS));
+}
+
+export function storeApplicationMetaData(appName, key, value) {
+ return dispatch =>
+ api
+ .storeApplicationMetaData(appName, key, value)
+ .then(() => {
+ const info = `${appName} successfully updated!`;
+ setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000);
+ dispatch({ type: UPDATE_APPLICATION_FIELD, appName, key, value, info });
+ })
+ .catch(dispatchError(dispatch, ERROR_UPDATING_APPLICATION_DATA));
+}
+
+export function fetchApplication(appName) {
+ return dispatch =>
+ api
+ .fetchApplication(appName)
+ .then(json => dispatch(recieveApplication(json)))
+ .catch(dispatchError(dispatch, ERROR_RECEIVE_ALL_APPLICATIONS));
+}
+
+export function deleteApplication(appName) {
+ return dispatch =>
+ api
+ .deleteApplication(appName)
+ .then(() => dispatch({ type: DELETE_APPLICATION, appName }))
+ .catch(dispatchError(dispatch, ERROR_DELETE_APPLICATION));
+}
diff --git a/frontend/src/store/application/api.js b/frontend/src/store/application/api.js
new file mode 100644
index 0000000000..5a941d27f4
--- /dev/null
+++ b/frontend/src/store/application/api.js
@@ -0,0 +1,52 @@
+import { formatApiPath } from '../../utils/format-path';
+import { throwIfNotSuccess, headers } from '../api-helper';
+
+const URI = formatApiPath('api/admin/metrics/applications');
+
+function fetchAll() {
+ return fetch(URI, { headers, credentials: 'include' })
+ .then(throwIfNotSuccess)
+ .then(response => response.json());
+}
+
+function fetchApplication(appName) {
+ return fetch(`${URI}/${appName}`, { headers, credentials: 'include' })
+ .then(throwIfNotSuccess)
+ .then(response => response.json());
+}
+
+function fetchApplicationsWithStrategyName(strategyName) {
+ return fetch(`${URI}?strategyName=${strategyName}`, {
+ headers,
+ credentials: 'include',
+ })
+ .then(throwIfNotSuccess)
+ .then(response => response.json());
+}
+
+function storeApplicationMetaData(appName, key, value) {
+ const data = {};
+ data[key] = value;
+ return fetch(`${URI}/${appName}`, {
+ method: 'POST',
+ headers,
+ body: JSON.stringify(data),
+ credentials: 'include',
+ }).then(throwIfNotSuccess);
+}
+
+function deleteApplication(appName) {
+ return fetch(`${URI}/${appName}`, {
+ method: 'DELETE',
+ headers,
+ credentials: 'include',
+ }).then(throwIfNotSuccess);
+}
+
+export default {
+ fetchApplication,
+ fetchAll,
+ fetchApplicationsWithStrategyName,
+ storeApplicationMetaData,
+ deleteApplication,
+};
diff --git a/frontend/src/store/application/index.js b/frontend/src/store/application/index.js
new file mode 100644
index 0000000000..06da890586
--- /dev/null
+++ b/frontend/src/store/application/index.js
@@ -0,0 +1,30 @@
+import { fromJS, List, Map } from 'immutable';
+import { RECEIVE_ALL_APPLICATIONS, RECEIVE_APPLICATION, UPDATE_APPLICATION_FIELD, DELETE_APPLICATION } from './actions';
+import { USER_LOGOUT, USER_LOGIN } from '../user/actions';
+
+function getInitState() {
+ return fromJS({ list: [], apps: {} });
+}
+
+const store = (state = getInitState(), action) => {
+ switch (action.type) {
+ case RECEIVE_APPLICATION:
+ return state.setIn(['apps', action.value.appName], new Map(action.value));
+ case RECEIVE_ALL_APPLICATIONS:
+ return state.set('list', new List(action.value.applications));
+ case UPDATE_APPLICATION_FIELD:
+ return state.setIn(['apps', action.appName, action.key], action.value);
+ case DELETE_APPLICATION: {
+ const index = state.get('list').findIndex(item => item.appName === action.appName);
+ const result = state.removeIn(['list', index]);
+ return result.removeIn(['apps', action.appName]);
+ }
+ case USER_LOGOUT:
+ case USER_LOGIN:
+ return getInitState();
+ default:
+ return state;
+ }
+};
+
+export default store;