Edit crawl notes from crawl detail view (#595)

This commit is contained in:
sua yoo 2023-02-21 12:26:38 -06:00 committed by GitHub
parent 0fd18ed3dd
commit c309b809da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 94 additions and 17 deletions

View File

@ -51,7 +51,7 @@ export class DescList extends LitElement {
static styles = css` static styles = css`
dl { dl {
display: grid; display: grid;
grid-template-columns: auto; grid-template-columns: 100%;
grid-gap: 1rem; grid-gap: 1rem;
margin: 0; margin: 0;
} }

View File

@ -14,6 +14,10 @@ export class Tag extends SLTag {
static styles = css` static styles = css`
${tagStyles} ${tagStyles}
:host {
max-width: 100%;
}
.tag { .tag {
height: var(--tag-height, 1.5rem); height: var(--tag-height, 1.5rem);
background-color: var(--sl-color-blue-100); background-color: var(--sl-color-blue-100);

View File

@ -4,6 +4,7 @@ import { when } from "lit/directives/when.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
import { msg, localized, str } from "@lit/localize"; import { msg, localized, str } from "@lit/localize";
import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js"; import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js";
import type { SlTextarea } from "@shoelace-style/shoelace";
import Fuse from "fuse.js"; import Fuse from "fuse.js";
import type { import type {
@ -29,6 +30,7 @@ const SECTIONS = [
type SectionName = typeof SECTIONS[number]; type SectionName = typeof SECTIONS[number];
const POLL_INTERVAL_SECONDS = 10; const POLL_INTERVAL_SECONDS = 10;
const CRAWL_NOTES_MAXLENGTH = 500;
/** /**
* Usage: * Usage:
@ -209,15 +211,16 @@ export class CrawlDetail extends LiteElement {
${this.renderPanel( ${this.renderPanel(
html` html`
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
${msg("Tags")} ${msg("Metadata")}
<sl-icon-button <sl-icon-button
class="text-base" class="text-base"
name="pencil" name="pencil"
@click=${this.openDetailEditor} @click=${this.openMetadataEditor}
aria-label=${msg("Edit Metadata")}
></sl-icon-button> ></sl-icon-button>
</div> </div>
`, `,
this.renderDetails() this.renderMetadata()
)} )}
</div> </div>
</div> </div>
@ -266,13 +269,13 @@ export class CrawlDetail extends LiteElement {
</btrix-dialog> </btrix-dialog>
<btrix-dialog <btrix-dialog
label=${msg("Edit Tags")} label=${msg("Edit Metadata")}
?open=${this.openDialogName === "details"} ?open=${this.openDialogName === "details"}
@sl-request-close=${() => (this.openDialogName = undefined)} @sl-request-close=${() => (this.openDialogName = undefined)}
@sl-show=${() => (this.isDialogVisible = true)} @sl-show=${() => (this.isDialogVisible = true)}
@sl-after-hide=${() => (this.isDialogVisible = false)} @sl-after-hide=${() => (this.isDialogVisible = false)}
> >
${this.isDialogVisible ? this.renderEditDetails() : ""} ${this.isDialogVisible ? this.renderEditMetadata() : ""}
</btrix-dialog> </btrix-dialog>
`; `;
} }
@ -432,7 +435,7 @@ export class CrawlDetail extends LiteElement {
class="p-2 hover:bg-zinc-100 cursor-pointer" class="p-2 hover:bg-zinc-100 cursor-pointer"
role="menuitem" role="menuitem"
@click=${(e: any) => { @click=${(e: any) => {
this.openDetailEditor(); this.openMetadataEditor();
e.target.closest("sl-dropdown").hide(); e.target.closest("sl-dropdown").hide();
}} }}
> >
@ -441,7 +444,7 @@ export class CrawlDetail extends LiteElement {
name="pencil" name="pencil"
></sl-icon> ></sl-icon>
<span class="inline-block align-middle"> <span class="inline-block align-middle">
${msg("Edit Tags")} ${msg("Edit Metadata")}
</span> </span>
</li> </li>
<hr /> <hr />
@ -774,21 +777,37 @@ export class CrawlDetail extends LiteElement {
`; `;
} }
private renderDetails() { private renderMetadata() {
const noneText = html`<span class="text-neutral-300">${msg("None")}</span>`;
return html` return html`
<btrix-desc-list> <btrix-desc-list>
<btrix-desc-list-item label=${msg("Notes")}>
${when(
this.crawl,
() =>
when(
this.crawl!.notes?.length,
() => html`<pre class="whitespace-pre-line font-sans">
${this.crawl?.notes}
</pre
>`,
() => noneText
),
() => html`<sl-skeleton></sl-skeleton>`
)}
</btrix-desc-list-item>
<btrix-desc-list-item label=${msg("Tags")}> <btrix-desc-list-item label=${msg("Tags")}>
${when( ${when(
this.crawl, this.crawl,
() => () =>
when( when(
this.crawl?.tags?.length, this.crawl!.tags.length,
() => () =>
this.crawl!.tags!.map( this.crawl!.tags.map(
(tag) => (tag) =>
html`<btrix-tag class="mt-1 mr-2">${tag}</btrix-tag>` html`<btrix-tag class="mt-1 mr-2">${tag}</btrix-tag>`
), ),
() => html`${msg("None")}` () => noneText
), ),
() => html`<sl-skeleton></sl-skeleton>` () => html`<sl-skeleton></sl-skeleton>`
)} )}
@ -898,15 +917,47 @@ export class CrawlDetail extends LiteElement {
`; `;
} }
private renderEditDetails() { private renderEditMetadata() {
if (!this.crawl) return; if (!this.crawl) return;
const crawlNotesHelpText = msg(
str`Maximum ${CRAWL_NOTES_MAXLENGTH} characters`
);
return html` return html`
<form <form
id="crawlDetailsForm" id="crawlDetailsForm"
@submit=${this.onSubmitDetails} @submit=${this.onSubmitMetadata}
@reset=${() => (this.openDialogName = undefined)} @reset=${() => (this.openDialogName = undefined)}
> >
<sl-textarea
class="mb-3"
name="crawlNotes"
label=${msg("Notes")}
value=${this.crawl.notes || ""}
rows="3"
autocomplete="off"
resize="auto"
help-text=${crawlNotesHelpText}
style="--help-text-align: right"
@sl-input=${(e: CustomEvent) => {
const textarea = e.target as SlTextarea;
if (textarea.value.length > CRAWL_NOTES_MAXLENGTH) {
const overMax = textarea.value.length - CRAWL_NOTES_MAXLENGTH;
textarea.setCustomValidity(
msg(
str`Please shorten this text to ${CRAWL_NOTES_MAXLENGTH} or less characters.`
)
);
textarea.helpText =
overMax === 1
? msg(str`${overMax} character over limit`)
: msg(str`${overMax} characters over limit`);
} else {
textarea.setCustomValidity("");
textarea.helpText = crawlNotesHelpText;
}
}}
></sl-textarea>
<btrix-tag-input <btrix-tag-input
.initialTags=${this.crawl.tags} .initialTags=${this.crawl.tags}
.tagOptions=${this.tagOptions} .tagOptions=${this.tagOptions}
@ -1086,16 +1137,30 @@ export class CrawlDetail extends LiteElement {
} }
} }
private openDetailEditor() { private openMetadataEditor() {
this.fetchTags(); this.fetchTags();
this.openDialogName = "details"; this.openDialogName = "details";
} }
private async onSubmitDetails(e: SubmitEvent) { private async onSubmitMetadata(e: SubmitEvent) {
e.preventDefault(); e.preventDefault();
const formEl = e.target as HTMLFormElement;
if (!(await this.checkFormValidity(formEl))) return;
const { crawlNotes } = serialize(formEl);
if (
crawlNotes === (this.crawl!.notes ?? "") &&
JSON.stringify(this.tagsToSave) === JSON.stringify(this.crawl!.tags)
) {
// No changes have been made
this.openDialogName = undefined;
return;
}
const params = { const params = {
tags: this.tagsToSave, tags: this.tagsToSave,
notes: crawlNotes,
}; };
this.isSubmittingUpdate = true; this.isSubmittingUpdate = true;
@ -1131,6 +1196,11 @@ export class CrawlDetail extends LiteElement {
this.isSubmittingUpdate = false; this.isSubmittingUpdate = false;
} }
async checkFormValidity(formEl: HTMLFormElement) {
await this.updateComplete;
return !formEl.querySelector("[data-invalid]");
}
private async scale(value: Crawl["scale"]) { private async scale(value: Crawl["scale"]) {
this.isSubmittingUpdate = true; this.isSubmittingUpdate = true;

View File

@ -112,6 +112,8 @@ const theme = css`
sl-select::part(form-control-help-text) { sl-select::part(form-control-help-text) {
margin-top: var(--sl-spacing-x-small); margin-top: var(--sl-spacing-x-small);
font-weight: 400; font-weight: 400;
/* Enable controlling help text text alignment from parent */
text-align: var(--help-text-align, left);
} }
/* Elevate select and buttons */ /* Elevate select and buttons */

View File

@ -26,7 +26,8 @@ export type Crawl = {
fileCount?: number; fileCount?: number;
fileSize?: number; fileSize?: number;
completions?: number; completions?: number;
tags?: string[]; tags: string[];
notes: string | null;
}; };
type ScopeType = type ScopeType =