import { LitElement, html, css, type PropertyValues } from "lit"; import { property, state } from "lit/decorators.js"; import { wrapCss, apiPrefix } from "./misc"; import fasArrowUp from "@fortawesome/fontawesome-free/svgs/solid/angle-double-up.svg"; import fasArrowDown from "@fortawesome/fontawesome-free/svgs/solid/angle-double-down.svg"; import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg"; import type { ItemType } from "./types"; import "./item-info"; // =========================================================================== class ItemIndex extends LitElement { @property({ type: Array }) items: ItemType[] = []; @property({ type: String }) query = ""; @property({ type: Array }) filteredItems: ItemType[] = []; @property({ type: Array }) sortedItems: ItemType[] = []; @property({ type: Boolean }) hideHeader = false; @property({ type: String }) dateName = "Date Loaded"; @property({ type: String }) headerName = "Loaded Archives"; @state() // eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme protected _deleting: any = {}; private get typeFilter() { return ""; } private get indexParams() { return ""; } constructor() { super(); this.hideHeader = localStorage.getItem("index:hideHeader") === "1"; } get sortKeys() { return [ { key: "title", name: "Title" }, { key: "sourceUrl", name: "Source" }, { key: "ctime", name: this.dateName }, { key: "size", name: "Total Size" }, ]; } firstUpdated() { // TODO: Fix this the next time the file is edited. // eslint-disable-next-line @typescript-eslint/no-floating-promises this.loadItems(); } updated(changedProperties: PropertyValues) { if (changedProperties.has("hideHeader")) { localStorage.setItem("index:hideHeader", this.hideHeader ? "1" : "0"); } if (changedProperties.has("items") || changedProperties.has("query")) { this.filter(); } } filter() { if (!this.query) { this.filteredItems = this.items; return; } this.filteredItems = []; for (const item of this.items) { if ( item.sourceUrl.indexOf(this.query) >= 0 || (item.filename && item.filename.indexOf(this.query) >= 0) || Boolean(item.loadUrl && item.loadUrl.indexOf(this.query) >= 0) || (item.title && item.title.indexOf(this.query) >= 0) ) { this.filteredItems.push(item); } } } async loadItems() { const resp = await fetch(`${apiPrefix}/coll-index?${this.indexParams}`); try { if (resp.status !== 200) { throw new Error("Invalid API Response, Retry"); } const json = await resp.json(); this.items = json.colls.map((item: ItemType) => { item.title = item.title ?? item.filename; return item; }); this._deleting = {}; this.sortedItems = []; } catch (e) { // likely no sw registered yet, or waiting for new sw to register, retry again // TODO: Fix this the next time the file is edited. // eslint-disable-next-line @typescript-eslint/promise-function-async setTimeout(() => this.loadItems(), 500); } } // @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'event' implicitly has an 'any' type. async onDeleteItem(event) { event.preventDefault(); event.stopPropagation(); // TODO: Fix this the next time the file is edited. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!this.sortedItems) { return; } const index = Number(event.currentTarget.getAttribute("data-coll-index")); const item = this.sortedItems[index]; // TODO: Fix this the next time the file is edited. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!item || this._deleting[item.sourceUrl]) { return; } this._deleting[item.sourceUrl] = true; this.requestUpdate(); const resp = await fetch(`${apiPrefix}/c/${item.id}`, { method: "DELETE" }); if (resp.status === 200) { const json = await resp.json(); this.items = json.colls; } return false; } static get styles() { return wrapCss(ItemIndex.compStyles); } static get compStyles() { return css` :host { overflow-y: auto; min-width: 0; } .size { margin-right: 20px; } .extra-padding { padding: 2em; } .no-top-padding { padding-top: 1em; } .panel-heading { font-size: 0.85rem; } .is-loading { line-height: 1.5em; height: 1.5em; border: 0px; background-color: transparent !important; width: auto; } div.panel.is-light { margin-bottom: 2em; } fa-icon { vertical-align: middle; } .panel-color { background-color: rgb(210, 249, 214); } .copy { color: black; margin: 0px; margin: 0; line-height: 0.4em; padding: 6px; border-radius: 10px; position: absolute; } .copy:active { background-color: lightgray; } .sort-header { padding: 0.3rem 0.3rem 0.3rem 0; display: flex; flex-direction: row; flex-flow: row wrap; } .sort-header .control { flex: auto; padding-left: 0.3rem; width: initial; } wr-sorter { padding: 0.3rem; } a.button.is-small.collapse { border-radius: 6px; } .icon.is-left { margin-left: 0.5rem; } .coll-block { position: relative; } .delete-button { width: 32px; position: absolute; top: 10px; right: 10px; } #sort-select::after { display: none; } header { transform: translate(0px, 0px); transition: all 0.5s ease 0s; visibility: visible; display: flex; flex-direction: column; } header.closed { transform: translate(0, -100%); transition: all 0.5s ease 0s; visibility: visible; height: 269px; margin-top: -269px; } `; } renderHeader() { return html`

${this.headerName}

`; } renderSearchHeader() { return ""; } render() { const hasHeader = this.childElementCount > 0; return html`
${hasHeader ? html` ` : ""}
${this.renderHeader()} ${this.items.length ? html`
${this.renderSearchHeader()}
${// TODO: Fix this the next time the file is edited. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition this.sortedItems?.map( (item, i) => html`
${this.renderItemInfo(item)} ${!this._deleting[item.sourceUrl] ? html` ` : html` Deleting `}
`, )}
` : html`
${ // TODO: Fix this the next time the file is edited. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition this.sortedItems === null ? html`Loading Archives...` : this.renderEmpty() }
`}
`; } renderItemInfo(item: ItemType) { return html``; } renderEmpty() { return html`

Don't have any web archives yet? Check out ArchiveWeb.page to save pages as you browse the web, or sign up for Browsertrix to archive entire websites with automated crawling!

`; } } customElements.define("wr-item-index", ItemIndex); export { ItemIndex };