Improve format of crawl template config error from server (#281)
* better display of api errors, such as fields missing or invalid urls, addresses #280
This commit is contained in:
parent
301b05ff4e
commit
9606d59c3d
@ -8,6 +8,7 @@ import LiteElement, { html } from "../../utils/LiteElement";
|
|||||||
import { ScheduleInterval, humanizeNextDate } from "../../utils/cron";
|
import { ScheduleInterval, humanizeNextDate } from "../../utils/cron";
|
||||||
import type { CrawlConfig, Profile } from "./types";
|
import type { CrawlConfig, Profile } from "./types";
|
||||||
import { getUTCSchedule } from "../../utils/cron";
|
import { getUTCSchedule } from "../../utils/cron";
|
||||||
|
import { TemplateResult } from "lit";
|
||||||
|
|
||||||
type NewCrawlTemplate = {
|
type NewCrawlTemplate = {
|
||||||
id?: string;
|
id?: string;
|
||||||
@ -89,7 +90,7 @@ export class CrawlTemplatesNew extends LiteElement {
|
|||||||
private browserProfileId?: string | null;
|
private browserProfileId?: string | null;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private serverError?: string;
|
private serverError?: TemplateResult | string;
|
||||||
|
|
||||||
private get formattededNextCrawlDate() {
|
private get formattededNextCrawlDate() {
|
||||||
const utcSchedule = this.getUTCSchedule();
|
const utcSchedule = this.getUTCSchedule();
|
||||||
@ -536,7 +537,13 @@ export class CrawlTemplatesNew extends LiteElement {
|
|||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.isApiError) {
|
if (e?.isApiError) {
|
||||||
this.serverError = e?.message;
|
const isConfigError = ({ loc }: any) =>
|
||||||
|
loc.some((v: string) => v === "config");
|
||||||
|
if (e.details && e.details.some(isConfigError)) {
|
||||||
|
this.serverError = this.formatConfigServerError(e.details);
|
||||||
|
} else {
|
||||||
|
this.serverError = e.message;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.serverError = msg("Something unexpected went wrong");
|
this.serverError = msg("Something unexpected went wrong");
|
||||||
}
|
}
|
||||||
@ -545,6 +552,34 @@ export class CrawlTemplatesNew extends LiteElement {
|
|||||||
this.isSubmitting = false;
|
this.isSubmitting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format `config` related API error returned from server
|
||||||
|
*/
|
||||||
|
private formatConfigServerError(details: any): TemplateResult {
|
||||||
|
const detailsWithoutDictError = details.filter(
|
||||||
|
({ type }: any) => type !== "type_error.dict"
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderDetail = ({ loc, msg: detailMsg }: any) => html`
|
||||||
|
<li>
|
||||||
|
${loc.some((v: string) => v === "seeds") &&
|
||||||
|
typeof loc[loc.length - 1] === "number"
|
||||||
|
? msg(str`Seed URL ${loc[loc.length - 1] + 1}: `)
|
||||||
|
: `${loc[loc.length - 1]}: `}
|
||||||
|
${detailMsg}
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
${msg(
|
||||||
|
"Couldn't save crawl template. Please fix the following crawl configuration issues:"
|
||||||
|
)}
|
||||||
|
<ul class="list-disc w-fit mx-auto">
|
||||||
|
${detailsWithoutDictError.map(renderDetail)}
|
||||||
|
</ul>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
private getUTCSchedule(): string {
|
private getUTCSchedule(): string {
|
||||||
if (!this.scheduleInterval) {
|
if (!this.scheduleInterval) {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { LitElement, html } from "lit";
|
import { LitElement, html } from "lit";
|
||||||
import type { TemplateResult } from "lit";
|
import type { TemplateResult } from "lit";
|
||||||
|
import { msg } from "@lit/localize";
|
||||||
|
|
||||||
import type { Auth } from "../utils/AuthService";
|
import type { Auth } from "../utils/AuthService";
|
||||||
import { APIError } from "./api";
|
import { APIError } from "./api";
|
||||||
@ -121,28 +122,29 @@ export default class LiteElement extends LitElement {
|
|||||||
this.dispatchEvent(new CustomEvent("need-login"));
|
this.dispatchEvent(new CustomEvent("need-login"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let errorMessage: string;
|
let detail;
|
||||||
|
let errorMessage: string = msg("Unknown API error");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const detail = (await resp.json()).detail;
|
detail = (await resp.json()).detail;
|
||||||
|
|
||||||
if (typeof detail === "string") {
|
if (typeof detail === "string") {
|
||||||
errorMessage = detail;
|
errorMessage = detail;
|
||||||
} else {
|
} else if (Array.isArray(detail) && detail.length) {
|
||||||
// TODO return client error details
|
const fieldDetail = detail[0];
|
||||||
const fieldDetail = detail[detail.length - 1];
|
|
||||||
const { loc, msg } = fieldDetail;
|
const { loc, msg } = fieldDetail;
|
||||||
|
|
||||||
errorMessage = `${loc[loc.length - 1]} ${msg}`;
|
const fieldName = loc
|
||||||
|
.filter((v: any) => v !== "body" && typeof v === "string")
|
||||||
|
.join(" ");
|
||||||
|
errorMessage = `${fieldName} ${msg}`;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {}
|
||||||
errorMessage = "Unknown API error";
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO client error details
|
|
||||||
throw new APIError({
|
throw new APIError({
|
||||||
message: errorMessage,
|
message: errorMessage,
|
||||||
status: resp.status,
|
status: resp.status,
|
||||||
|
details: detail,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,30 @@
|
|||||||
|
type StatusCode = number;
|
||||||
|
type Detail = {
|
||||||
|
loc: any[];
|
||||||
|
msg: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
export class APIError extends Error {
|
export class APIError extends Error {
|
||||||
statusCode: number;
|
statusCode: StatusCode;
|
||||||
|
details: Detail[] | null;
|
||||||
|
|
||||||
get isApiError() {
|
get isApiError() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor({ message, status }: { message: string; status: number }) {
|
constructor({
|
||||||
|
message,
|
||||||
|
status,
|
||||||
|
details,
|
||||||
|
}: {
|
||||||
|
message: string;
|
||||||
|
status: StatusCode;
|
||||||
|
details?: Detail[];
|
||||||
|
}) {
|
||||||
super(message);
|
super(message);
|
||||||
|
|
||||||
this.statusCode = status;
|
this.statusCode = status;
|
||||||
|
this.details = details || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user