dylanebert's picture
dylanebert HF Staff
ensure valid arrays
6aa9047
raw
history blame
12.4 kB
<script lang="ts">
import { onMount } from "svelte";
import SvelteTable, { type TableColumn } from "svelte-table";
import Row from "./Row";
import EditButtonComponent from "./EditButtonComponent.svelte";
import EditModal from "./EditModal.svelte";
import { fetchRows, addEntry } from "./bridge";
import { statusMessage } from "./store";
let rows: Row[] = [];
let columns: TableColumn<Row>[] = [
{
key: "Name",
title: "Name",
value: (v: Row) => v.Name || v.Project || v.Code || v.Paper || "N/A",
sortable: true,
renderValue: (v: Row) => {
let url;
if (v.Project) {
url = v.Project;
} else if (v.Code) {
url = v.Code;
} else if (v.Paper) {
url = v.Paper;
} else if (v.Space) {
url = v.Space;
} else if (v.Model) {
url = v.Model;
} else if (v.Dataset) {
url = v.Dataset;
}
let name = v.Name || url || "";
let renderName = name;
if (name.length > 64) {
renderName = name.slice(0, 60) + "...";
}
return `<a href="${url}" target="_blank" title="${name}">${renderName}</a>`;
},
searchValue: (v: Row) => {
let searchValue = v.Name || "";
if (v.Project) {
searchValue += " " + v.Project;
}
if (v.Code) {
searchValue += " " + v.Code;
}
if (v.Paper) {
searchValue += " " + v.Paper;
}
if (v.Space) {
searchValue += " " + v.Space;
}
if (v.Model) {
searchValue += " " + v.Model;
}
if (v.Dataset) {
searchValue += " " + v.Dataset;
}
return searchValue;
},
parseHTML: true,
hideFilterHeader: true,
},
{
key: "Date",
title: "Date",
value: (v: Row) => v.Date || "",
sortable: true,
searchValue: (v: Row) => v.Date || "",
renderValue: (v: Row) => {
if (!v.Date) return "";
let renderDate = v.Date;
// Convert ISO to YYYY-MM-DD
if (v.Date.includes("T")) {
renderDate = v.Date.split("T")[0];
}
return `<span title="${v.Date}">${renderDate}</span>`;
},
parseHTML: true,
},
{
key: "Orgs",
title: "Orgs",
value: (v: Row) => v.Orgs.join(", "),
sortable: true,
searchValue: (v: Row) => v.Orgs.join(" "),
renderValue: (v: Row) => {
let orgs = v.Orgs.join(", ");
let renderOrgs = v.Orgs.join(", ");
if (orgs.length > 24) {
renderOrgs = renderOrgs.slice(0, 20) + "...";
}
return `<span title="${orgs}">${renderOrgs}</span>`;
},
parseHTML: true,
},
{
key: "Authors",
title: "Authors",
value: (v: Row) => v.Authors.join(", "),
sortable: true,
searchValue: (v: Row) => v.Authors.join(" "),
renderValue: (v: Row) => {
let authors = v.Authors.join(", ");
let renderAuthors = v.Authors.join(", ");
if (authors.length > 24) {
renderAuthors = renderAuthors.slice(0, 20) + "...";
}
return `<span title="${authors}">${renderAuthors}</span>`;
},
parseHTML: true,
},
{
key: "Paper",
title: "Paper",
value: (v: Row) => v.Paper || "",
sortable: true,
searchValue: (v: Row) => v.Paper || "",
renderValue: (v: Row) => {
if (!v.Paper) return "";
const url = v.Paper;
let name = v.Paper;
if (url.includes("arxiv.org/")) {
name = `arxiv/${url.split("arxiv.org/")[1]}`;
} else if (url.includes("huggingface.co/papers/")) {
name = `hf/${url.split("huggingface.co/papers/")[1]}`;
}
let displayName = name.replace(".pdf", "");
if (displayName.length > 24) {
displayName = displayName.slice(0, 20) + "...";
}
return `<a href="${url}" target="_blank" title="${name}">${displayName}</a>`;
},
parseHTML: true,
},
{
key: "Code",
title: "Code",
value: (v: Row) => v.CodeStatus || v.Code || "",
sortable: true,
searchValue: (v: Row) => {
let searchValue = v.Code || "";
if (v.CodeStatus === "Coming Soon") {
searchValue += " Coming Soon";
} else if (v.CodeStatus === "No") {
searchValue += " No";
}
return searchValue;
},
renderValue: (v: Row) => {
let codeUrl;
let codeDisplay;
if (v.Code) {
codeUrl = v.Code;
if (v.Code.includes("github.com")) {
codeDisplay = `git/${v.Code.split("github.com/")[1].slice(0, 16)}`;
} else {
codeDisplay = v.Code.slice(0, 16) + "...";
}
}
if (v.CodeStatus === "Coming Soon") {
codeDisplay = "Coming Soon";
} else if (v.CodeStatus === "No") {
codeDisplay = "No";
}
if (!codeDisplay) {
return "";
}
if (codeUrl) {
return `<a href="${codeUrl}" target="_blank" title="${codeUrl}">${codeDisplay}</a>`;
}
return codeDisplay;
},
parseHTML: true,
},
{
key: "Space",
title: "Space",
value: (v: Row) => v.Space || "",
sortable: true,
searchValue: (v: Row) => v.Space || "",
renderValue: (v: Row) => {
if (!v.Space) return "";
if (v.Space.includes("huggingface.co")) {
return `<a href="${v.Space}" target="_blank">hf/${v.Space.split("huggingface.co/")[1].slice(
0,
16
)}</a>`;
}
return `<a href="${v.Space}" target="_blank" title="${v.Space}">${v.Space.slice(0, 16)}...</a>`;
},
parseHTML: true,
},
{
key: "Model",
title: "Model",
value: (v: Row) => v.Model || "",
sortable: true,
searchValue: (v: Row) => v.Model || "",
renderValue: (v: Row) => {
if (!v.Model) return "";
if (v.Model.includes("huggingface.co")) {
return `<a href="${v.Model}" target="_blank">hf/${v.Model.split("huggingface.co/")[1].slice(
0,
16
)}</a>`;
}
return `<a href="${v.Model}" target="_blank" title="${v.Model}">${v.Model.slice(0, 16)}...</a>`;
},
parseHTML: true,
},
{
key: "Dataset",
title: "Dataset",
value: (v: Row) => v.Dataset || "",
sortable: true,
searchValue: (v: Row) => v.Dataset || "",
renderValue: (v: Row) => {
if (!v.Dataset) return "";
if (v.Dataset.includes("huggingface.co")) {
return `<a href="${v.Dataset}" target="_blank">hf/${v.Dataset.split("huggingface.co/")[1].slice(
0,
16
)}</a>`;
} else if (v.Dataset.includes("drive.google.com")) {
return `<a href="${v.Dataset}" target="_blank">drive/${v.Dataset.split(
"drive.google.com/"
)[1].slice(0, 16)}</a>`;
} else if (v.Dataset.includes("github.com")) {
return `<a href="${v.Dataset}" target="_blank">git/${v.Dataset.split("github.com/")[1].slice(
0,
16
)}</a>`;
}
return `<a href="${v.Dataset}" target="_blank" title="${v.Dataset}">${v.Dataset.slice(0, 16)}...</a>`;
},
parseHTML: true,
},
{
key: "ReachedOut",
title: "Reached Out",
value: (v: Row) => (v.Tags.includes("ReachedOut") ? "\u2705" : ""),
sortable: true,
filterValue: (v: Row) => (v.Tags.includes("ReachedOut") ? "Yes" : "No"),
filterOptions: ["Yes", "No"],
},
{
key: "Edit",
title: "",
value: (v: Row) => "",
sortable: false,
renderComponent: EditButtonComponent,
hideFilterHeader: true,
},
];
let selection: Record<string | number, any> = {};
let overrideSelection = false;
let searchValue = "";
$: {
if (searchValue !== "") {
selection = { Name: searchValue };
overrideSelection = true;
} else {
if (overrideSelection) {
selection = {};
overrideSelection = false;
}
}
}
onMount(async () => {
rows = (await fetchRows()) || [];
});
async function newEntry() {
const row = await addEntry(selection);
if (!row) return;
rows = [row, ...rows];
}
function handleRowUpdated(event: Event) {
const updatedRow = (event as CustomEvent).detail;
const rowIndex = rows.findIndex(
(row) =>
row.Code === updatedRow.Code || row.Paper === updatedRow.Paper || row.Project === updatedRow.Project
);
if (rowIndex !== -1) {
rows[rowIndex] = updatedRow;
} else {
console.error("Row not found");
}
}
function handleRowDeleted(event: Event) {
const deletedRow = (event as CustomEvent).detail;
const rowIndex = rows.findIndex(
(row) =>
row.Code === deletedRow.Code || row.Paper === deletedRow.Paper || row.Project === deletedRow.Project
);
if (rowIndex !== -1) {
rows = [...rows.slice(0, rowIndex), ...rows.slice(rowIndex + 1)];
} else {
console.error("Row not found");
}
}
let fetching = false;
let isModalOpen = false;
</script>
{#if !import.meta.env.VITE_HF_TOKEN}
<div style="text-align: center; margin-top: 1rem;">
<p>Missing VITE_HF_TOKEN environment variable</p>
</div>
{:else if fetching}
<div style="text-align: center; margin-top: 1rem;">
<p>{@html $statusMessage}</p>
</div>
{:else}
<div style="text-align: center; margin-top: 1rem;">
<input
type="text"
placeholder="Enter relevant project, code, paper, space, model, or dataset URL"
style="width: 100%; max-width: 512px;"
bind:value={searchValue}
/>
<button on:click={newEntry}>New Entry</button>
</div>
{#if statusMessage}
<div style="text-align: center; margin-top: 0.5rem;">
{#if !isModalOpen}
{@html $statusMessage}
{/if}
</div>
{/if}
<!--spacer-->
<div style="height: 1rem;" />
<SvelteTable {columns} {rows} bind:filterSelections={selection} />
{/if}
<EditModal bind:isOpen={isModalOpen} on:rowUpdated={handleRowUpdated} on:rowDeleted={handleRowDeleted} />