Allow users to configure offset when viewing crawl queued URLs (#1581)

This commit is contained in:
sua yoo 2024-05-15 14:42:00 -07:00 committed by GitHub
parent 1a668fe82f
commit 0479489bd8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 108 additions and 32 deletions

View File

@ -14,6 +14,7 @@ import("./desc-list");
import("./details");
import("./dialog");
import("./file-list");
import("./inline-input");
import("./input");
import("./language-select");
import("./locale-picker");

View File

@ -0,0 +1,25 @@
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js";
import inputStyles from "@shoelace-style/shoelace/dist/components/input/input.styles.js";
import { css } from "lit";
import { customElement } from "lit/decorators.js";
/**
* Input to use inline with text.
*/
@customElement("btrix-inline-input")
export class InlineInput extends SlInput {
static styles = [
inputStyles,
css`
:host {
--sl-input-height-small: var(--sl-font-size-x-large);
--sl-input-color: var(--sl-color-neutral-500);
}
.input--small .input__control {
text-align: center;
padding: 0 0.5ch;
}
`,
] as typeof SlInput.styles;
}

View File

@ -33,17 +33,12 @@ export class Pagination extends LitElement {
static styles = [
srOnly,
css`
:host {
--sl-input-height-small: var(--sl-font-size-x-large);
--sl-input-color: var(--sl-color-neutral-500);
}
ul {
align-items: center;
list-style: none;
margin: 0;
padding: 0;
color: var(--sl-input-color);
color: var(--sl-color-neutral-500);
}
ul.compact {
@ -64,11 +59,6 @@ export class Pagination extends LitElement {
cursor: pointer;
}
sl-input::part(input) {
text-align: center;
padding: 0 0.5ch;
}
.currentPage {
display: flex;
align-items: center;
@ -211,7 +201,7 @@ export class Pagination extends LitElement {
return html`
<div class="pageInput">
<div class="totalPages" role="none">${this.pages}</div>
<sl-input
<btrix-inline-input
class="input"
inputmode="numeric"
size="small"
@ -256,7 +246,7 @@ export class Pagination extends LitElement {
// Select text on focus for easy typing
(e.target as SlInput).select();
}}
></sl-input>
></btrix-inline-input>
</div>
`;
}

View File

@ -32,6 +32,7 @@ export class Observable extends LitElement {
disconnectedCallback(): void {
this.observer?.disconnect();
super.disconnectedCallback();
}
firstUpdated() {

View File

@ -1,4 +1,9 @@
import { localized, msg, str } from "@lit/localize";
import type {
SlChangeEvent,
SlInput,
SlInputEvent,
} from "@shoelace-style/shoelace";
import type { PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { when } from "lit/directives/when.js";
@ -60,6 +65,9 @@ export class CrawlQueue extends LiteElement {
@state()
private isLoading = false;
@state()
private pageOffset = 0;
@state()
private pageSize = 50;
@ -82,7 +90,10 @@ export class CrawlQueue extends LiteElement {
changedProperties.has("orgId") ||
changedProperties.has("crawlId") ||
changedProperties.has("pageSize") ||
changedProperties.has("regex")
changedProperties.has("regex") ||
(changedProperties.has("pageOffset") &&
// Prevents double-fetch when offset is programmatically changed according to queue total
!changedProperties.has("queue"))
) {
void this.fetchOnUpdate();
}
@ -90,13 +101,66 @@ export class CrawlQueue extends LiteElement {
render() {
return html`
<btrix-section-heading style="--margin: var(--sl-spacing-small)"
>${msg("Queued URLs")} ${this.renderBadge()}</btrix-section-heading
>
<btrix-section-heading style="--margin: var(--sl-spacing-small)">
${this.renderOffsetControl()} ${this.renderBadge()}
</btrix-section-heading>
${this.renderContent()}
`;
}
private renderOffsetControl() {
if (!this.queue) {
return msg("Queued URLs");
}
if (this.pageOffset === 0 && this.queue.total <= this.pageSize) {
return msg(
str`Queued URLs from 1 to ${this.queue.total.toLocaleString()}`,
);
}
const offsetValue = this.pageOffset + 1;
const countMax = Math.min(
this.pageOffset + this.pageSize,
this.queue.total,
);
const getInputWidth = (v: number | string) =>
`${Math.max(v.toString().length, 3) + 2}ch`;
return html`
<div class="flex items-center text-neutral-500">
${msg(html`
Queued URLs from
<btrix-inline-input
class="mx-1 inline-block"
style="width: ${Math.max(offsetValue.toString().length, 2) + 2}ch"
value="1"
inputmode="numeric"
size="small"
autocomplete="off"
@sl-input=${(e: SlInputEvent) => {
const input = e.target as SlInput;
input.style.width = getInputWidth(input.value);
}}
@sl-change=${async (e: SlChangeEvent) => {
const input = e.target as SlInput;
const int = +input.value.replace(/\D/g, "");
await this.updateComplete;
const value = Math.max(1, Math.min(int, this.queue!.total - 1));
input.value = value.toString();
this.pageOffset = value - 1;
}}
></btrix-inline-input>
to ${countMax.toLocaleString()} of
${this.queue.total.toLocaleString()}
`)}
</div>
`;
}
private renderContent() {
if (!this.queue?.total) {
if (this.isLoading) {
@ -119,9 +183,9 @@ export class CrawlQueue extends LiteElement {
const isExcluded = !isMatch && this.isExcluded(url);
return html`
<btrix-numbered-list-item>
<span class="${isMatch ? "text-red-600" : ""}" slot="marker"
>${idx + 1}.</span
>
<span class="${isMatch ? "text-red-600" : ""}" slot="marker">
${(idx + this.pageOffset + 1).toLocaleString()}.
</span>
<a
class="${isMatch
? "text-red-500 hover:text-red-400"
@ -140,7 +204,7 @@ export class CrawlQueue extends LiteElement {
<footer class="text-center">
${when(
this.queue.total === this.queue.results.length,
this.queue.total <= this.pageOffset + this.pageSize,
() =>
html`<div class="py-3 text-xs text-neutral-400">
${msg("End of queue")}
@ -165,14 +229,6 @@ export class CrawlQueue extends LiteElement {
if (!this.queue) return "";
return html`
<btrix-badge class="ml-1">
${this.queue.total
? this.queue.total > 1
? msg(str`${this.queue.total.toLocaleString()} URLs`)
: msg(str`1 URL`)
: msg("No queue")}
</btrix-badge>
${this.matchedTotal
? html`
<btrix-badge variant="danger" class="ml-1">
@ -230,10 +286,13 @@ export class CrawlQueue extends LiteElement {
}
private async getQueue(): Promise<ResponseData> {
const offset = "0";
const count = this.pageSize.toString();
const regex = this.regex;
const params = new URLSearchParams({ offset, count, regex });
const params = new URLSearchParams({
offset: this.pageOffset.toString(),
count,
regex,
});
const data: ResponseData = await this.apiFetch(
`/orgs/${this.orgId}/crawls/${this.crawlId}/queue?${params.toString()}`,
this.authState!,

View File

@ -1220,7 +1220,7 @@ export class WorkflowDetail extends LiteElement {
return html`
<header class="flex items-center justify-between">
<h3 class="mb-2 text-base font-semibold leading-none">
${msg("Crawl URLs")}
${msg("Upcoming Pages")}
</h3>
<sl-button
size="small"