Create crawl config UX enhancements (#90)

closes #87
This commit is contained in:
sua yoo 2022-01-19 11:01:17 -08:00 committed by GitHub
parent c3edb4bba4
commit 3645e3b096
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 73 deletions

View File

@ -372,6 +372,7 @@ export class App extends LiteElement {
class="w-full" class="w-full"
@navigate=${this.onNavigateTo} @navigate=${this.onNavigateTo}
@need-login=${this.onNeedLogin} @need-login=${this.onNeedLogin}
@notify="${this.onNotify}"
.authState=${this.authService.authState} .authState=${this.authService.authState}
.userInfo=${this.userInfo} .userInfo=${this.userInfo}
archiveId=${this.viewState.params.id} archiveId=${this.viewState.params.id}
@ -480,12 +481,15 @@ export class App extends LiteElement {
onNotify( onNotify(
event: CustomEvent<{ event: CustomEvent<{
title?: string; title?: string;
/** Can contain HTML */
message?: string; message?: string;
type?: "success" | "warning" | "danger" | "primary"; type?: "success" | "warning" | "danger" | "primary";
icon?: string; icon?: string;
duration?: number; duration?: number;
}> }>
) { ) {
event.stopPropagation();
const { const {
title, title,
message, message,
@ -494,12 +498,6 @@ export class App extends LiteElement {
duration = 5000, duration = 5000,
} = event.detail; } = event.detail;
const escapeHtml = (html: any) => {
const div = document.createElement("div");
div.textContent = html;
return div.innerHTML;
};
const alert = Object.assign(document.createElement("sl-alert"), { const alert = Object.assign(document.createElement("sl-alert"), {
type: type, type: type,
closable: true, closable: true,
@ -513,8 +511,8 @@ export class App extends LiteElement {
innerHTML: ` innerHTML: `
<sl-icon name="${icon}" slot="icon"></sl-icon> <sl-icon name="${icon}" slot="icon"></sl-icon>
<span> <span>
${title ? `<strong>${escapeHtml(title)}</strong>` : ""} ${title ? `<strong>${title}</strong>` : ""}
${message ? `<div>${escapeHtml(message)}</div>` : ""} ${message ? `<div>${message}</div>` : ""}
</span> </span>
`, `,

View File

@ -63,9 +63,9 @@ export class CrawlTemplates extends LiteElement {
@state() @state()
private scheduleTime: { hour: number; minute: number; period: "AM" | "PM" } = private scheduleTime: { hour: number; minute: number; period: "AM" | "PM" } =
{ {
hour: 12, hour: new Date().getHours() % 12 || 12,
minute: 0, minute: 0,
period: "AM", period: new Date().getHours() > 11 ? "PM" : "AM",
}; };
@state() @state()
@ -91,27 +91,26 @@ export class CrawlTemplates extends LiteElement {
return getLocaleTimeZone(); return getLocaleTimeZone();
} }
private get nextScheduledCrawlMessage() { private get formattededNextCrawlDate() {
const utcSchedule = this.getUTCSchedule(); const utcSchedule = this.getUTCSchedule();
return this.scheduleInterval return this.scheduleInterval
? msg(html`Next scheduled crawl: ? html`<sl-format-date
<sl-format-date date="${cronParser
date="${cronParser .parseExpression(utcSchedule, {
.parseExpression(utcSchedule, { utc: true,
utc: true, })
}) .next()
.next() .toString()}"
.toString()}" weekday="long"
weekday="long" month="long"
month="long" day="numeric"
day="numeric" year="numeric"
year="numeric" hour="numeric"
hour="numeric" minute="numeric"
minute="numeric" time-zone-name="short"
time-zone-name="short" time-zone=${this.timeZone}
time-zone=${this.timeZone} ></sl-format-date>`
></sl-format-date>`)
: undefined; : undefined;
} }
@ -136,7 +135,8 @@ export class CrawlTemplates extends LiteElement {
<div class="border rounded-lg"> <div class="border rounded-lg">
<sl-form @sl-submit=${this.onSubmit} aria-describedby="formError"> <sl-form @sl-submit=${this.onSubmit} aria-describedby="formError">
<div class="md:grid grid-cols-4"> <div class="md:grid grid-cols-4">
${this.renderBasicSettings()} ${this.renderPagesSettings()} ${this.renderBasicSettings()} ${this.renderCrawlConfigSettings()}
${this.renderScheduleSettings()}
</div> </div>
<div class="p-4 md:p-8 text-center grid gap-5"> <div class="p-4 md:p-8 text-center grid gap-5">
@ -165,7 +165,16 @@ export class CrawlTemplates extends LiteElement {
</p> </p>
` `
: ""} : ""}
${this.nextScheduledCrawlMessage} ${this.scheduleInterval
? html`
<p class="mb-2">
${msg(
html`Scheduled crawl will run
${this.formattededNextCrawlDate}.`
)}
</p>
`
: ""}
</div>` </div>`
: ""} : ""}
</div> </div>
@ -198,27 +207,38 @@ export class CrawlTemplates extends LiteElement {
private renderBasicSettings() { private renderBasicSettings() {
return html` return html`
<div class="col-span-1 p-4 md:p-8 md:border-b"> <div class="col-span-1 p-4 md:p-8 md:border-b">
<h3 class="text-lg font-medium">${msg("Basic settings")}</h3> <h3 class="font-medium">${msg("Basic settings")}</h3>
</div>
<section class="col-span-3 p-4 md:p-8 border-b grid gap-5">
<sl-input
name="name"
label=${msg("Name")}
help-text=${msg(
"Required. Name your template to easily identify it later."
)}
placeholder=${msg("Example (example.com) Weekly Crawl", {
desc: "Example crawl template name",
})}
autocomplete="off"
value=${initialValues.name}
required
></sl-input>
</section>
`;
}
private renderScheduleSettings() {
return html`
<div class="col-span-1 p-4 md:p-8 md:border-b">
<h3 class="font-medium">${msg("Crawl schedule")}</h3>
</div> </div>
<section class="col-span-3 p-4 md:p-8 border-b grid gap-5"> <section class="col-span-3 p-4 md:p-8 border-b grid gap-5">
<div>
<sl-input
name="name"
label=${msg("Name")}
placeholder=${msg("Example (example.com) Weekly Crawl", {
desc: "Example crawl template name",
})}
autocomplete="off"
value=${initialValues.name}
required
></sl-input>
</div>
<div> <div>
<div class="flex items-end"> <div class="flex items-end">
<div class="pr-2 flex-1"> <div class="pr-2 flex-1">
<sl-select <sl-select
name="schedule" name="schedule"
label=${msg("Schedule")} label=${msg("Recurring crawls")}
value=${this.scheduleInterval} value=${this.scheduleInterval}
@sl-select=${(e: any) => @sl-select=${(e: any) =>
(this.scheduleInterval = e.target.value)} (this.scheduleInterval = e.target.value)}
@ -265,7 +285,7 @@ export class CrawlTemplates extends LiteElement {
)} )}
</sl-select> </sl-select>
<sl-select <sl-select
value="AM" value=${this.scheduleTime.period}
class="w-24" class="w-24"
?disabled=${!this.scheduleInterval} ?disabled=${!this.scheduleInterval}
@sl-select=${(e: any) => @sl-select=${(e: any) =>
@ -285,37 +305,37 @@ export class CrawlTemplates extends LiteElement {
</div> </div>
</div> </div>
<div class="text-sm text-gray-500 mt-1"> <div class="text-sm text-gray-500 mt-1">
${this.nextScheduledCrawlMessage || msg("No crawls scheduled")} ${this.formattededNextCrawlDate
? msg(
html`Next scheduled crawl: ${this.formattededNextCrawlDate}`
)
: msg("No crawls scheduled")}
</div> </div>
</div> </div>
<div> <sl-switch
<sl-switch name="runNow"
name="runNow" ?checked=${initialValues.runNow}
?checked=${initialValues.runNow} @sl-change=${(e: any) => (this.isRunNow = e.target.checked)}
@sl-change=${(e: any) => (this.isRunNow = e.target.checked)} >${msg("Run immediately on save")}</sl-switch
>${msg("Run immediately on save")}</sl-switch >
>
</div>
<div> <sl-input
<sl-input name="crawlTimeoutMinutes"
name="crawlTimeoutMinutes" label=${msg("Time limit")}
label=${msg("Time limit")} placeholder=${msg("unlimited")}
placeholder=${msg("unlimited")} type="number"
type="number" >
> <span slot="suffix">${msg("minutes")}</span>
<span slot="suffix">${msg("minutes")}</span> </sl-input>
</sl-input>
</div>
</section> </section>
`; `;
} }
private renderPagesSettings() { private renderCrawlConfigSettings() {
return html` return html`
<div class="col-span-1 p-4 md:p-8 md:border-b"> <div class="col-span-1 p-4 md:p-8 md:border-b">
<h3 class="text-lg font-medium">${msg("Crawl configuration")}</h3> <h3 class="font-medium">${msg("Crawl configuration")}</h3>
</div> </div>
<section class="col-span-3 p-4 md:p-8 border-b grid gap-5"> <section class="col-span-3 p-4 md:p-8 border-b grid gap-5">
<div class="flex justify-between"> <div class="flex justify-between">
@ -344,11 +364,12 @@ export class CrawlTemplates extends LiteElement {
<sl-textarea <sl-textarea
name="seedUrls" name="seedUrls"
label=${msg("Seed URLs")} label=${msg("Seed URLs")}
helpText=${msg("Separated by a new line, space or comma")}
placeholder=${msg(`https://webrecorder.net\nhttps://example.com`, { placeholder=${msg(`https://webrecorder.net\nhttps://example.com`, {
desc: "Example seed URLs", desc: "Example seed URLs",
})} })}
help-text=${msg("Separate URLs with a new line, space or comma.")} help-text=${msg(
"Required. Separate URLs with a new line, space or comma."
)}
rows="3" rows="3"
required required
></sl-textarea> ></sl-textarea>
@ -511,7 +532,7 @@ export class CrawlTemplates extends LiteElement {
this.isSubmitting = true; this.isSubmitting = true;
try { try {
await this.apiFetch( const data = await this.apiFetch(
`/archives/${this.archiveId}/crawlconfigs/`, `/archives/${this.archiveId}/crawlconfigs/`,
this.authState, this.authState,
{ {
@ -520,6 +541,22 @@ export class CrawlTemplates extends LiteElement {
} }
); );
this.dispatchEvent(
new CustomEvent("notify", {
bubbles: true,
detail: {
message: data.run_now_job
? msg(
str`Crawl running with new template. <br /><a class="underline hover:no-underline" href="/archives/${this.archiveId}/crawls/${data.run_now_job}">View crawl</a>`
)
: msg("Crawl template created."),
type: "success",
icon: "check2-circle",
duration: 10000,
},
})
);
this.navTo(`/archives/${this.archiveId}/crawl-templates`); this.navTo(`/archives/${this.archiveId}/crawl-templates`);
} catch (e: any) { } catch (e: any) {
if (e?.isApiError) { if (e?.isApiError) {
@ -551,10 +588,8 @@ export class CrawlTemplates extends LiteElement {
if (period === "AM") { if (period === "AM") {
periodOffset = -12; periodOffset = -12;
} }
} else if (hour === 1) { } else if (period === "PM") {
if (period === "PM") { periodOffset = 12;
periodOffset = 12;
}
} }
localDate.setHours(+hour + periodOffset); localDate.setHours(+hour + periodOffset);