Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions frontend/docs/docs/user-guide/workflow-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,12 @@ You can use a tool like [crontab.guru](https://crontab.guru/) to check Cron synt

Cron schedules are always in [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time).

## Collections

### Auto-Add to Collection

Search for and specify [collections](collection.md) that this crawl workflow should automatically add archived items to as soon as crawling finishes. Canceled and Failed crawls will not be added to collections.

## Metadata

Describe and organize your crawl workflow and the resulting archived items.
Expand All @@ -407,7 +413,3 @@ Leave optional notes about the workflow's configuration.
### Tags

Apply tags to the workflow. Tags applied to the workflow will propagate to every crawl created with it at the time of crawl creation.

### Collection Auto-Add

Search for and specify [collections](collection.md) that this crawl workflow should automatically add archived items to as soon as crawling finishes. Canceled and Failed crawls will not be added to collections.
77 changes: 18 additions & 59 deletions frontend/src/components/ui/config-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import {
import { labelFor } from "@/strings/crawl-workflows/labels";
import scopeTypeLabel from "@/strings/crawl-workflows/scopeType";
import sectionStrings from "@/strings/crawl-workflows/section";
import type { Collection } from "@/types/collection";
import { WorkflowScopeType, type StorageSeedFile } from "@/types/workflow";
import { isApiError } from "@/utils/api";
import { unescapeCustomPrefix } from "@/utils/crawl-workflows/unescapeCustomPrefix";
import { DEPTH_SUPPORTED_SCOPES, isPageScopeType } from "@/utils/crawler";
import { humanizeSchedule } from "@/utils/cron";
Expand Down Expand Up @@ -60,13 +58,9 @@ export class ConfigDetails extends BtrixElement {
maxPagesPerCrawl?: number;
};

@state()
private collections: Collection[] = [];

async connectedCallback() {
super.connectedCallback();
void this.fetchOrgDefaults();
await this.fetchCollections();
}

render() {
Expand Down Expand Up @@ -313,6 +307,24 @@ export class ConfigDetails extends BtrixElement {
)}
`,
})}
${when(!this.hideMetadata, () =>
this.renderSection({
id: "collection",
heading: sectionStrings.collections,
renderDescItems: () => html`
${this.renderSetting(
html`<span class="mb-1 inline-block"
>${msg("Auto-Add to Collection")}</span
>`,
crawlConfig?.autoAddCollections.length
? html`<btrix-linked-collections
.collectionIds=${crawlConfig.autoAddCollections}
></btrix-linked-collections>`
: undefined,
)}
`,
}),
)}
${when(!this.hideMetadata, () =>
this.renderSection({
id: "crawl-metadata",
Expand All @@ -338,21 +350,6 @@ export class ConfigDetails extends BtrixElement {
)
: [],
)}
${this.renderSetting(
msg("Collections"),
this.collections.length
? this.collections.map(
(coll) =>
html`<sl-tag class="mr-2 mt-1" variant="neutral">
${coll.name}
<span class="font-monostyle pl-1 text-xs">
(${this.localize.number(coll.crawlCount)}
${pluralOf("items", coll.crawlCount)})
</span>
</sl-tag>`,
)
: undefined,
)}
`,
}),
)}
Expand Down Expand Up @@ -633,44 +630,6 @@ export class ConfigDetails extends BtrixElement {
`;
}

private async fetchCollections() {
if (this.crawlConfig?.autoAddCollections) {
try {
await this.getCollections();
} catch (e) {
this.notify.toast({
message:
isApiError(e) && e.statusCode === 404
? msg("Collections not found.")
: msg(
"Sorry, couldn't retrieve Collection details at this time.",
),
variant: "danger",
icon: "exclamation-octagon",
id: "collection-fetch-status",
});
}
}
}

private async getCollections() {
const collections: Collection[] = [];
const orgId = this.crawlConfig?.oid;

if (this.crawlConfig?.autoAddCollections && orgId) {
for (const collectionId of this.crawlConfig.autoAddCollections) {
const data = await this.api.fetch<Collection | undefined>(
`/orgs/${orgId}/collections/${collectionId}`,
);
if (data) {
collections.push(data);
}
}
}
this.collections = collections;
this.requestUpdate();
}

// TODO Consolidate with workflow-editor
private async fetchOrgDefaults() {
try {
Expand Down
19 changes: 10 additions & 9 deletions frontend/src/features/archived-items/item-metadata-editor.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { localized, msg } from "@lit/localize";
import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js";
import Fuse from "fuse.js";
import { html } from "lit";
import { customElement, property, state } from "lit/decorators.js";

import { BtrixElement } from "@/classes/BtrixElement";
import type {
TagInputEvent,
Tags,
Expand All @@ -12,7 +14,6 @@ import { type CollectionsChangeEvent } from "@/features/collections/collections-
import type { ArchivedItem } from "@/types/crawler";
import { type WorkflowTag, type WorkflowTags } from "@/types/workflow";
import { maxLengthValidator } from "@/utils/form";
import LiteElement, { html } from "@/utils/LiteElement";

/**
* Usage:
Expand All @@ -30,7 +31,7 @@ import LiteElement, { html } from "@/utils/LiteElement";
*/
@customElement("btrix-item-metadata-editor")
@localized()
export class CrawlMetadataEditor extends LiteElement {
export class CrawlMetadataEditor extends BtrixElement {
@property({ type: Object })
crawl?: ArchivedItem;

Expand Down Expand Up @@ -78,7 +79,7 @@ export class CrawlMetadataEditor extends LiteElement {
render() {
return html`
<btrix-dialog
.label=${msg("Edit Metadata")}
.label=${msg("Edit Archived Item")}
.open=${this.open}
@sl-show=${() => (this.isDialogVisible = true)}
@sl-after-hide=${() => (this.isDialogVisible = false)}
Expand Down Expand Up @@ -125,11 +126,11 @@ export class CrawlMetadataEditor extends LiteElement {
@tags-change=${(e: TagsChangeEvent) =>
(this.tagsToSave = e.detail.tags)}
></btrix-tag-input>
<div class="mt-4">
<div class="mt-7">
<btrix-collections-add
.initialCollections=${this.crawl.collectionIds}
.configId=${"temp"}
label=${msg("Add to Collection")}
label=${msg("Include in Collection")}
@collections-change=${(e: CollectionsChangeEvent) =>
(this.collectionsToSave = e.detail.collections)}
>
Expand Down Expand Up @@ -166,7 +167,7 @@ export class CrawlMetadataEditor extends LiteElement {
private async fetchTags() {
if (!this.crawl) return;
try {
const { tags } = await this.apiFetch<WorkflowTags>(
const { tags } = await this.api.fetch<WorkflowTags>(
`/orgs/${this.crawl.oid}/crawlconfigs/tagCounts`,
);

Expand Down Expand Up @@ -220,7 +221,7 @@ export class CrawlMetadataEditor extends LiteElement {
this.isSubmittingUpdate = true;

try {
const data = await this.apiFetch<{ updated: boolean }>(
const data = await this.api.fetch<{ updated: boolean }>(
`/orgs/${this.crawl.oid}/all-crawls/${this.crawl.id}`,
{
method: "PATCH",
Expand All @@ -233,15 +234,15 @@ export class CrawlMetadataEditor extends LiteElement {
}

this.dispatchEvent(new CustomEvent("updated"));
this.notify({
this.notify.toast({
message: msg("Successfully saved crawl details."),
variant: "success",
icon: "check2-circle",
id: "crawl-details-update-status",
});
this.requestClose();
} catch (e) {
this.notify({
this.notify.toast({
message: msg("Sorry, couldn't save crawl details at this time."),
variant: "danger",
icon: "exclamation-octagon",
Expand Down
73 changes: 12 additions & 61 deletions frontend/src/features/collections/collections-add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import queryString from "query-string";

import { BtrixElement } from "@/classes/BtrixElement";
import type { Combobox } from "@/components/ui/combobox";
import type { BtrixRemoveLinkedCollectionEvent } from "@/features/collections/linked-collections/types";
import type {
APIPaginatedList,
APIPaginationQuery,
Expand Down Expand Up @@ -51,9 +52,6 @@ export class CollectionsAdd extends BtrixElement {
@property({ type: String })
emptyText?: string;

@state()
private collectionsData: { [id: string]: Collection } = {};

@state()
private collectionIds: string[] = [];

Expand Down Expand Up @@ -89,7 +87,6 @@ export class CollectionsAdd extends BtrixElement {
this.collectionIds = this.initialCollections;
}
super.connectedCallback();
void this.initializeCollectionsFromIds();
}

disconnectedCallback() {
Expand All @@ -99,7 +96,7 @@ export class CollectionsAdd extends BtrixElement {
render() {
return html`<div>
<label class="form-label">
${this.label || msg("Collection Auto-Add")}
${this.label || msg("Add to Collection")}
</label>
<div class="mb-2 rounded-lg border bg-neutral-50 p-2">
${this.renderSearch()}
Expand All @@ -109,9 +106,15 @@ export class CollectionsAdd extends BtrixElement {
this.collectionIds.length
? html`
<div class="mb-2">
<ul class="contents">
${this.collectionIds.map(this.renderCollectionItem, this)}
</ul>
<btrix-linked-collections
.collectionIds=${this.collectionIds}
removable
@btrix-remove=${(e: BtrixRemoveLinkedCollectionEvent) => {
const { id } = e.detail.item;

this.removeCollection(id);
}}
></btrix-linked-collections>
</div>
`
: this.emptyText
Expand Down Expand Up @@ -142,12 +145,6 @@ export class CollectionsAdd extends BtrixElement {
);
if (coll) {
const { id } = coll;
if (!(this.collectionsData[id] as Collection | undefined)) {
this.collectionsData = {
...this.collectionsData,
[id]: (await this.getCollection(id))!,
};
}
this.collectionIds = [...this.collectionIds, id];
void this.dispatchChange();
}
Expand Down Expand Up @@ -225,35 +222,7 @@ export class CollectionsAdd extends BtrixElement {
});
}

private renderCollectionItem(id: string) {
const collection = this.collectionsData[id] as Collection | undefined;
return html`<li class="mt-1 rounded-sm border p-1 pl-3">
<div
class="${collection
? "opacity-100"
: "opacity-0"} flex flex-row items-center justify-between gap-2 transition-opacity delay-75"
>
<div class="grow justify-self-stretch truncate">
${collection?.name}
</div>
<div class="font-monostyle text-right text-xs text-neutral-500">
${msg(str`${collection?.crawlCount || 0} items`)}
</div>
<sl-icon-button
name="x-lg"
label=${msg("Remove from auto-add")}
data-key=${id}
?disabled=${!collection}
@click=${this.removeCollection}
>
</sl-icon-button>
</div>
</li>`;
}

private removeCollection(event: Event) {
const target = event.currentTarget as HTMLElement;
const collectionId = target.getAttribute("data-key");
private removeCollection(collectionId: string) {
if (collectionId) {
const collIdIndex = this.collectionIds.indexOf(collectionId);
if (collIdIndex > -1) {
Expand Down Expand Up @@ -325,24 +294,6 @@ export class CollectionsAdd extends BtrixElement {
return data;
}

private async initializeCollectionsFromIds() {
this.collectionIds.forEach(async (id) => {
const data = await this.getCollection(id);
if (data) {
this.collectionsData = {
...this.collectionsData,
[id]: data,
};
}
});
}

private readonly getCollection = async (
collId: string,
): Promise<Collection | undefined> => {
return this.api.fetch(`/orgs/${this.orgId}/collections/${collId}`);
};

private async dispatchChange() {
await this.updateComplete;
this.dispatchEvent(
Expand Down
1 change: 1 addition & 0 deletions frontend/src/features/collections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import("./collection-edit-dialog");
import("./collection-create-dialog");
import("./collection-initial-view-dialog");
import("./collection-workflow-list");
import("./linked-collections");
import("./select-collection-access");
import("./select-collection-page");
import("./share-collection");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./linked-collections";
Loading
Loading