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("./dialog"); | ||||
| import("./file-list"); | ||||
| import("./inline-input"); | ||||
| import("./input"); | ||||
| import("./language-select"); | ||||
| 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 = [ | ||||
|     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> | ||||
|     `;
 | ||||
|   } | ||||
|  | ||||
| @ -32,6 +32,7 @@ export class Observable extends LitElement { | ||||
| 
 | ||||
|   disconnectedCallback(): void { | ||||
|     this.observer?.disconnect(); | ||||
|     super.disconnectedCallback(); | ||||
|   } | ||||
| 
 | ||||
|   firstUpdated() { | ||||
|  | ||||
| @ -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!, | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user