Allow users to configure offset when viewing crawl queued URLs (#1581)
This commit is contained in:
parent
1a668fe82f
commit
0479489bd8
@ -14,6 +14,7 @@ import("./desc-list");
|
|||||||
import("./details");
|
import("./details");
|
||||||
import("./dialog");
|
import("./dialog");
|
||||||
import("./file-list");
|
import("./file-list");
|
||||||
|
import("./inline-input");
|
||||||
import("./input");
|
import("./input");
|
||||||
import("./language-select");
|
import("./language-select");
|
||||||
import("./locale-picker");
|
import("./locale-picker");
|
||||||
|
25
frontend/src/components/ui/inline-input.ts
Normal file
25
frontend/src/components/ui/inline-input.ts
Normal 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;
|
||||||
|
}
|
@ -33,17 +33,12 @@ export class Pagination extends LitElement {
|
|||||||
static styles = [
|
static styles = [
|
||||||
srOnly,
|
srOnly,
|
||||||
css`
|
css`
|
||||||
:host {
|
|
||||||
--sl-input-height-small: var(--sl-font-size-x-large);
|
|
||||||
--sl-input-color: var(--sl-color-neutral-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: var(--sl-input-color);
|
color: var(--sl-color-neutral-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.compact {
|
ul.compact {
|
||||||
@ -64,11 +59,6 @@ export class Pagination extends LitElement {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
sl-input::part(input) {
|
|
||||||
text-align: center;
|
|
||||||
padding: 0 0.5ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.currentPage {
|
.currentPage {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -211,7 +201,7 @@ export class Pagination extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="pageInput">
|
<div class="pageInput">
|
||||||
<div class="totalPages" role="none">${this.pages}</div>
|
<div class="totalPages" role="none">${this.pages}</div>
|
||||||
<sl-input
|
<btrix-inline-input
|
||||||
class="input"
|
class="input"
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
size="small"
|
size="small"
|
||||||
@ -256,7 +246,7 @@ export class Pagination extends LitElement {
|
|||||||
// Select text on focus for easy typing
|
// Select text on focus for easy typing
|
||||||
(e.target as SlInput).select();
|
(e.target as SlInput).select();
|
||||||
}}
|
}}
|
||||||
></sl-input>
|
></btrix-inline-input>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ export class Observable extends LitElement {
|
|||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
this.observer?.disconnect();
|
this.observer?.disconnect();
|
||||||
|
super.disconnectedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { localized, msg, str } from "@lit/localize";
|
import { localized, msg, str } from "@lit/localize";
|
||||||
|
import type {
|
||||||
|
SlChangeEvent,
|
||||||
|
SlInput,
|
||||||
|
SlInputEvent,
|
||||||
|
} from "@shoelace-style/shoelace";
|
||||||
import type { PropertyValues } from "lit";
|
import type { PropertyValues } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators.js";
|
import { customElement, property, state } from "lit/decorators.js";
|
||||||
import { when } from "lit/directives/when.js";
|
import { when } from "lit/directives/when.js";
|
||||||
@ -60,6 +65,9 @@ export class CrawlQueue extends LiteElement {
|
|||||||
@state()
|
@state()
|
||||||
private isLoading = false;
|
private isLoading = false;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private pageOffset = 0;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private pageSize = 50;
|
private pageSize = 50;
|
||||||
|
|
||||||
@ -82,7 +90,10 @@ export class CrawlQueue extends LiteElement {
|
|||||||
changedProperties.has("orgId") ||
|
changedProperties.has("orgId") ||
|
||||||
changedProperties.has("crawlId") ||
|
changedProperties.has("crawlId") ||
|
||||||
changedProperties.has("pageSize") ||
|
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();
|
void this.fetchOnUpdate();
|
||||||
}
|
}
|
||||||
@ -90,13 +101,66 @@ export class CrawlQueue extends LiteElement {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<btrix-section-heading style="--margin: var(--sl-spacing-small)"
|
<btrix-section-heading style="--margin: var(--sl-spacing-small)">
|
||||||
>${msg("Queued URLs")} ${this.renderBadge()}</btrix-section-heading
|
${this.renderOffsetControl()} ${this.renderBadge()}
|
||||||
>
|
</btrix-section-heading>
|
||||||
${this.renderContent()}
|
${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() {
|
private renderContent() {
|
||||||
if (!this.queue?.total) {
|
if (!this.queue?.total) {
|
||||||
if (this.isLoading) {
|
if (this.isLoading) {
|
||||||
@ -119,9 +183,9 @@ export class CrawlQueue extends LiteElement {
|
|||||||
const isExcluded = !isMatch && this.isExcluded(url);
|
const isExcluded = !isMatch && this.isExcluded(url);
|
||||||
return html`
|
return html`
|
||||||
<btrix-numbered-list-item>
|
<btrix-numbered-list-item>
|
||||||
<span class="${isMatch ? "text-red-600" : ""}" slot="marker"
|
<span class="${isMatch ? "text-red-600" : ""}" slot="marker">
|
||||||
>${idx + 1}.</span
|
${(idx + this.pageOffset + 1).toLocaleString()}.
|
||||||
>
|
</span>
|
||||||
<a
|
<a
|
||||||
class="${isMatch
|
class="${isMatch
|
||||||
? "text-red-500 hover:text-red-400"
|
? "text-red-500 hover:text-red-400"
|
||||||
@ -140,7 +204,7 @@ export class CrawlQueue extends LiteElement {
|
|||||||
|
|
||||||
<footer class="text-center">
|
<footer class="text-center">
|
||||||
${when(
|
${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">
|
html`<div class="py-3 text-xs text-neutral-400">
|
||||||
${msg("End of queue")}
|
${msg("End of queue")}
|
||||||
@ -165,14 +229,6 @@ export class CrawlQueue extends LiteElement {
|
|||||||
if (!this.queue) return "";
|
if (!this.queue) return "";
|
||||||
|
|
||||||
return html`
|
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
|
${this.matchedTotal
|
||||||
? html`
|
? html`
|
||||||
<btrix-badge variant="danger" class="ml-1">
|
<btrix-badge variant="danger" class="ml-1">
|
||||||
@ -230,10 +286,13 @@ export class CrawlQueue extends LiteElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getQueue(): Promise<ResponseData> {
|
private async getQueue(): Promise<ResponseData> {
|
||||||
const offset = "0";
|
|
||||||
const count = this.pageSize.toString();
|
const count = this.pageSize.toString();
|
||||||
const regex = this.regex;
|
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(
|
const data: ResponseData = await this.apiFetch(
|
||||||
`/orgs/${this.orgId}/crawls/${this.crawlId}/queue?${params.toString()}`,
|
`/orgs/${this.orgId}/crawls/${this.crawlId}/queue?${params.toString()}`,
|
||||||
this.authState!,
|
this.authState!,
|
||||||
|
@ -1220,7 +1220,7 @@ export class WorkflowDetail extends LiteElement {
|
|||||||
return html`
|
return html`
|
||||||
<header class="flex items-center justify-between">
|
<header class="flex items-center justify-between">
|
||||||
<h3 class="mb-2 text-base font-semibold leading-none">
|
<h3 class="mb-2 text-base font-semibold leading-none">
|
||||||
${msg("Crawl URLs")}
|
${msg("Upcoming Pages")}
|
||||||
</h3>
|
</h3>
|
||||||
<sl-button
|
<sl-button
|
||||||
size="small"
|
size="small"
|
||||||
|
Loading…
Reference in New Issue
Block a user