Skip to content

Commit c8b9f26

Browse files
committed
fix(ui): improve toast and plugin error handling
1 parent 93a8e4d commit c8b9f26

12 files changed

Lines changed: 101 additions & 82 deletions

File tree

src/api/query-hooks/useFeatureFlags.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function useAddFeatureFlag(onSuccess: () => void) {
7575
onSuccess();
7676
},
7777
onError: (error) => {
78-
toastError((error as Error).message);
78+
toastError(error);
7979
}
8080
});
8181
}
@@ -98,7 +98,7 @@ export function useUpdateFeatureFlag(onSuccess: () => void) {
9898
onSuccess();
9999
},
100100
onError: (error) => {
101-
toastError((error as Error).message);
101+
toastError(error);
102102
}
103103
});
104104
}
@@ -116,7 +116,7 @@ export function useDeleteFeatureFlag(onSuccess: () => void) {
116116
onSuccess();
117117
},
118118
onError: (error) => {
119-
toastError((error as Error).message);
119+
toastError(error);
120120
}
121121
});
122122
}

src/api/services/scrapePlugins.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ export const getAllScrapePlugins = (
4545
);
4646
};
4747

48-
export const createScrapePlugin = async (plugin: Partial<ScrapePlugin>) => {
48+
export const createScrapePlugin = async (
49+
plugin: Omit<Partial<ScrapePlugin>, "created_by"> & { created_by?: string }
50+
) => {
4951
return ConfigDB.post("/scrape_plugins", plugin);
5052
};
5153

src/components/Configs/Sidebar/ConfigsPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export function ConfigsPanelList({
6262
}
6363
toastError(response.error?.message);
6464
} catch (ex) {
65-
toastError((ex as Error).message);
65+
toastError(ex);
6666
}
6767
};
6868

src/components/Forms/Formik/FormikConnectionField.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default function FormikConnectionField({
3838
});
3939
},
4040
onError: (err: Error) => {
41-
toastError((err as Error).message);
41+
toastError(err);
4242
}
4343
});
4444

src/components/Plugins/PluginsForm.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type PluginsFormProps = {
1616
handleBack?: () => void;
1717
isSubmitting?: boolean;
1818
isDeleting?: boolean;
19+
errorMessage?: string;
1920
className?: string;
2021
};
2122

@@ -26,9 +27,11 @@ export default function PluginsForm({
2627
handleBack = () => {},
2728
isSubmitting = false,
2829
isDeleting = false,
30+
errorMessage,
2931
className
3032
}: PluginsFormProps) {
3133
const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(false);
34+
const [isErrorExpanded, setIsErrorExpanded] = useState(false);
3235
const isReadOnly = formValue?.source === "KubernetesCRD";
3336

3437
return (
@@ -77,6 +80,22 @@ export default function PluginsForm({
7780
/>
7881
</div>
7982
</div>
83+
{errorMessage && (
84+
<div className="mx-4 rounded-md border border-red-300 bg-red-50 p-3 text-sm text-red-800">
85+
<div className={isErrorExpanded ? "" : "line-clamp-2"}>
86+
{errorMessage}
87+
</div>
88+
{errorMessage.length > 120 && (
89+
<button
90+
type="button"
91+
className="mt-1 text-xs font-medium text-red-600 hover:text-red-800"
92+
onClick={() => setIsErrorExpanded(!isErrorExpanded)}
93+
>
94+
{isErrorExpanded ? "Show less" : "Show more"}
95+
</button>
96+
)}
97+
</div>
98+
)}
8099
<div className="flex items-center gap-2 rounded-lg bg-gray-100 px-5 py-4">
81100
{!formValue?.id && (
82101
<Button

src/components/Plugins/PluginsFormModal.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type PluginsFormModalProps = Omit<
1515
formValue?: ScrapePlugin;
1616
isSubmitting?: boolean;
1717
isDeleting?: boolean;
18+
errorMessage?: string;
1819
};
1920

2021
export default function PluginsFormModal({
@@ -25,7 +26,8 @@ export default function PluginsFormModal({
2526
onDelete,
2627
formValue,
2728
isSubmitting = false,
28-
isDeleting = false
29+
isDeleting = false,
30+
errorMessage
2931
}: PluginsFormModalProps) {
3032
const [, setHelpModal] = useAtom(modalHelpLinkAtom);
3133
useEffect(() => {
@@ -56,6 +58,7 @@ export default function PluginsFormModal({
5658
className={className}
5759
isSubmitting={isSubmitting}
5860
isDeleting={isDeleting}
61+
errorMessage={errorMessage}
5962
handleBack={() => setIsOpen(false)}
6063
/>
6164
</Modal>

src/components/Toast/toast.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,11 @@
1+
import { getErrorMessage } from "@flanksource-ui/api/types/error";
12
import toast, { ToastOptions } from "react-hot-toast";
23

3-
type ErrorMessage =
4-
| {
5-
response?: {
6-
data?: {
7-
error: string;
8-
message: string;
9-
};
10-
};
11-
}
12-
| string
13-
| undefined;
14-
15-
export function toastError(message: ErrorMessage) {
16-
if (typeof message === "string" || !message) {
4+
export function toastError(message: unknown) {
5+
if (typeof message === "string") {
176
toast.error(message || "An error occurred");
187
} else {
19-
toast.error(
20-
message.response?.data?.error ||
21-
message.response?.data?.message ||
22-
"An error occurred"
23-
);
8+
toast.error(getErrorMessage(message) || "An error occurred");
249
}
2510
}
2611

src/pages/Settings/ConnectionsPage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ export function ConnectionsPage() {
119119
toastSuccess("Connection added successfully");
120120
},
121121
onError: (ex) => {
122-
toastError((ex as Error).message);
122+
toastError(ex);
123123
}
124124
});
125125

@@ -138,7 +138,7 @@ export function ConnectionsPage() {
138138
toastSuccess("Connection updated successfully");
139139
},
140140
onError: (ex) => {
141-
toastError((ex as Error).message);
141+
toastError(ex);
142142
}
143143
});
144144

@@ -156,7 +156,7 @@ export function ConnectionsPage() {
156156
toastSuccess("Connection deleted successfully");
157157
},
158158
onError: (ex) => {
159-
toastError((ex as Error).message);
159+
toastError(ex);
160160
}
161161
});
162162

src/pages/applications/ApplicationsPage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export function ApplicationsPage() {
8686
toastSuccess("Application added successfully");
8787
},
8888
onError: (ex) => {
89-
toastError((ex as Error).message);
89+
toastError(ex);
9090
}
9191
});
9292

@@ -105,7 +105,7 @@ export function ApplicationsPage() {
105105
toastSuccess("Application updated successfully");
106106
},
107107
onError: (ex) => {
108-
toastError((ex as Error).message);
108+
toastError(ex);
109109
}
110110
});
111111

@@ -123,7 +123,7 @@ export function ApplicationsPage() {
123123
toastSuccess("Application deleted successfully");
124124
},
125125
onError: (ex) => {
126-
toastError((ex as Error).message);
126+
toastError(ex);
127127
}
128128
});
129129

src/pages/config/settings/ConfigPluginsPage.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ import {
88
import ConfigPageTabs from "@flanksource-ui/components/Configs/ConfigPageTabs";
99
import { AuthorizationAccessCheck } from "@flanksource-ui/components/Permissions/AuthorizationAccessCheck";
1010
import PluginsFormModal from "@flanksource-ui/components/Plugins/PluginsFormModal";
11-
import {
12-
toastError,
13-
toastSuccess
14-
} from "@flanksource-ui/components/Toast/toast";
11+
import { toastSuccess } from "@flanksource-ui/components/Toast/toast";
12+
import { getErrorMessage } from "@flanksource-ui/api/types/error";
1513
import { useUser } from "@flanksource-ui/context";
1614
import { tables } from "@flanksource-ui/context/UserAccessContext/permissions";
1715
import {
@@ -28,7 +26,7 @@ import { Head } from "@flanksource-ui/ui/Head";
2826
import { SearchLayout } from "@flanksource-ui/ui/Layout/SearchLayout";
2927
import { useMutation, useQuery } from "@tanstack/react-query";
3028
import { MRT_ColumnDef } from "mantine-react-table";
31-
import { useEffect, useMemo, useState } from "react";
29+
import { useCallback, useEffect, useMemo, useState } from "react";
3230
import { AiFillPlusCircle } from "react-icons/ai";
3331
import CRDSource from "@flanksource-ui/components/Settings/CRDSource";
3432

@@ -141,6 +139,9 @@ export default function ConfigPluginsPage() {
141139
const user = useUser();
142140
const [isOpen, setIsOpen] = useState(false);
143141
const [editedRow, setEditedRow] = useState<ScrapePlugin>();
142+
const [formError, setFormError] = useState<string>();
143+
144+
const clearFormError = useCallback(() => setFormError(undefined), []);
144145
const [sortState] = useReactTableSortState();
145146
const { pageIndex, pageSize } = useReactTablePaginationState();
146147

@@ -161,7 +162,7 @@ export default function ConfigPluginsPage() {
161162
const payload = buildPluginPayload(values.name, values.spec);
162163
const response = await createScrapePlugin({
163164
...payload,
164-
created_by: user.user,
165+
created_by: user.user?.id,
165166
source: payload.source || "UI"
166167
});
167168
return response?.data;
@@ -172,7 +173,7 @@ export default function ConfigPluginsPage() {
172173
toastSuccess("Plugin added successfully");
173174
},
174175
onError: (ex) => {
175-
toastError((ex as Error).message);
176+
setFormError(getErrorMessage(ex));
176177
}
177178
});
178179

@@ -194,7 +195,7 @@ export default function ConfigPluginsPage() {
194195
toastSuccess("Plugin updated successfully");
195196
},
196197
onError: (ex) => {
197-
toastError((ex as Error).message);
198+
setFormError(getErrorMessage(ex));
198199
}
199200
});
200201

@@ -209,7 +210,7 @@ export default function ConfigPluginsPage() {
209210
toastSuccess("Plugin deleted successfully");
210211
},
211212
onError: (ex) => {
212-
toastError((ex as Error).message);
213+
setFormError(getErrorMessage(ex));
213214
}
214215
});
215216

@@ -283,6 +284,7 @@ export default function ConfigPluginsPage() {
283284
isOpen={isOpen}
284285
setIsOpen={setIsOpen}
285286
onSubmit={(values: { name: string; spec: Record<string, any> }) => {
287+
clearFormError();
286288
if (editedRow?.id) {
287289
updatePlugin(values);
288290
} else {
@@ -293,6 +295,7 @@ export default function ConfigPluginsPage() {
293295
isSubmitting={isSubmitting}
294296
isDeleting={isDeleting}
295297
formValue={editedRow}
298+
errorMessage={formError}
296299
key={editedRow?.id || "plugin-form"}
297300
/>
298301
</SearchLayout>

0 commit comments

Comments
 (0)