|
@@ -1,4 +1,5 @@
|
|
-import create from 'zustand';
|
|
|
|
|
|
+import produce from 'immer';
|
|
|
|
+import create, { GetState, SetState } from 'zustand';
|
|
import api from '../core/api';
|
|
import api from '../core/api';
|
|
import { AppConfig, AppStatus, RequestStatus } from '../core/types';
|
|
import { AppConfig, AppStatus, RequestStatus } from '../core/types';
|
|
|
|
|
|
@@ -10,19 +11,58 @@ type AppsStore = {
|
|
fetch: () => void;
|
|
fetch: () => void;
|
|
getApp: (id: string) => AppConfig | undefined;
|
|
getApp: (id: string) => AppConfig | undefined;
|
|
fetchApp: (id: string) => void;
|
|
fetchApp: (id: string) => void;
|
|
- statues: {};
|
|
|
|
|
|
+ install: (id: string, form: Record<string, string>) => Promise<void>;
|
|
|
|
+ uninstall: (id: string) => Promise<void>;
|
|
|
|
+ stop: (id: string) => Promise<void>;
|
|
|
|
+ start: (id: string) => Promise<void>;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+type Set = SetState<AppsStore>;
|
|
|
|
+type Get = GetState<AppsStore>;
|
|
|
|
+
|
|
|
|
+const sortApps = (apps: AppConfig[]) => apps.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
+
|
|
|
|
+const setAppStatus = (appId: string, status: AppStatus, set: Set) => {
|
|
|
|
+ set((state) => {
|
|
|
|
+ return produce(state, (draft) => {
|
|
|
|
+ const app = draft.apps.find((a) => a.id === appId);
|
|
|
|
+ if (app) app.status = status;
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const installed = (get: Get) => {
|
|
|
|
+ const i = get().apps.filter((app) => app.installed);
|
|
|
|
+ return i;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Fetch one app and add it to the list of apps.
|
|
|
|
+ * @param appId
|
|
|
|
+ * @param set
|
|
|
|
+ */
|
|
|
|
+const fetchApp = async (appId: string, set: Set) => {
|
|
|
|
+ const response = await api.fetch<AppConfig>({
|
|
|
|
+ endpoint: `/apps/info/${appId}`,
|
|
|
|
+ method: 'get',
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ set((state) => {
|
|
|
|
+ const apps = state.apps.filter((app) => app.id !== appId);
|
|
|
|
+ apps.push(response);
|
|
|
|
+
|
|
|
|
+ return { ...state, apps: sortApps(apps) };
|
|
|
|
+ });
|
|
};
|
|
};
|
|
|
|
|
|
export const useAppsStore = create<AppsStore>((set, get) => ({
|
|
export const useAppsStore = create<AppsStore>((set, get) => ({
|
|
apps: [],
|
|
apps: [],
|
|
status: RequestStatus.LOADING,
|
|
status: RequestStatus.LOADING,
|
|
- installed: () => {
|
|
|
|
- const i = get().apps.filter((app) => app.installed);
|
|
|
|
- return i;
|
|
|
|
- },
|
|
|
|
|
|
+ installed: () => installed(get),
|
|
available: () => {
|
|
available: () => {
|
|
return get().apps.filter((app) => !app.installed);
|
|
return get().apps.filter((app) => !app.installed);
|
|
},
|
|
},
|
|
|
|
+ fetchApp: async (appId: string) => fetchApp(appId, set),
|
|
fetch: async () => {
|
|
fetch: async () => {
|
|
set({ status: RequestStatus.LOADING });
|
|
set({ status: RequestStatus.LOADING });
|
|
|
|
|
|
@@ -31,40 +71,63 @@ export const useAppsStore = create<AppsStore>((set, get) => ({
|
|
method: 'get',
|
|
method: 'get',
|
|
});
|
|
});
|
|
|
|
|
|
- set({ apps: response, status: RequestStatus.SUCCESS });
|
|
|
|
|
|
+ set({ apps: sortApps(response), status: RequestStatus.SUCCESS });
|
|
},
|
|
},
|
|
- install: async (appId: string) => {
|
|
|
|
- set((state) => ({ ...state, statues: { [appId]: AppStatus.INSTALLING } }));
|
|
|
|
-
|
|
|
|
- await api.fetch({
|
|
|
|
- endpoint: `/apps/install/${appId}`,
|
|
|
|
- method: 'post',
|
|
|
|
- });
|
|
|
|
|
|
+ getApp: (appId: string) => {
|
|
|
|
+ return get().apps.find((app) => app.id === appId);
|
|
|
|
+ },
|
|
|
|
+ install: async (appId: string, form?: Record<string, string>) => {
|
|
|
|
+ setAppStatus(appId, AppStatus.INSTALLING, set);
|
|
|
|
|
|
- set((state) => ({ ...state, statues: { [appId]: AppStatus.RUNNING } }));
|
|
|
|
|
|
+ try {
|
|
|
|
+ await api.fetch({
|
|
|
|
+ endpoint: `/apps/install/${appId}`,
|
|
|
|
+ method: 'POST',
|
|
|
|
+ data: { form },
|
|
|
|
+ });
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.error(e);
|
|
|
|
+ }
|
|
|
|
|
|
- await get().fetch();
|
|
|
|
|
|
+ await get().fetchApp(appId);
|
|
},
|
|
},
|
|
- fetchApp: async (appId: string) => {
|
|
|
|
- const response = await api.fetch<AppConfig>({
|
|
|
|
- endpoint: `/apps/info/${appId}`,
|
|
|
|
- method: 'get',
|
|
|
|
- });
|
|
|
|
|
|
+ uninstall: async (appId: string) => {
|
|
|
|
+ setAppStatus(appId, AppStatus.UNINSTALLING, set);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ await api.fetch({
|
|
|
|
+ endpoint: `/apps/uninstall/${appId}`,
|
|
|
|
+ });
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.error(e);
|
|
|
|
+ }
|
|
|
|
|
|
- set((state) => {
|
|
|
|
- const apps = state.apps.map((app) => {
|
|
|
|
- if (app.id === response.id) {
|
|
|
|
- return response;
|
|
|
|
- }
|
|
|
|
|
|
+ await get().fetchApp(appId);
|
|
|
|
+ },
|
|
|
|
+ stop: async (appId: string) => {
|
|
|
|
+ setAppStatus(appId, AppStatus.STOPPING, set);
|
|
|
|
|
|
- return app;
|
|
|
|
|
|
+ try {
|
|
|
|
+ await api.fetch({
|
|
|
|
+ endpoint: `/apps/stop/${appId}`,
|
|
});
|
|
});
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.error(e);
|
|
|
|
+ }
|
|
|
|
|
|
- return { ...state, apps };
|
|
|
|
- });
|
|
|
|
|
|
+ await get().fetchApp(appId);
|
|
},
|
|
},
|
|
- getApp: (appId: string) => {
|
|
|
|
- return get().apps.find((app) => app.id === appId);
|
|
|
|
|
|
+ start: async (appId: string) => {
|
|
|
|
+ setAppStatus(appId, AppStatus.STARTING, set);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ await api.fetch({
|
|
|
|
+ endpoint: `/apps/start/${appId}`,
|
|
|
|
+ });
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.error(e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ await get().fetchApp(appId);
|
|
},
|
|
},
|
|
- statues: {},
|
|
|
|
}));
|
|
}));
|