aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/mbf/internal/pkgserver/ui
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/mbf/internal/pkgserver/ui')
-rw-r--r--cmd/mbf/internal/pkgserver/ui/index.html58
-rw-r--r--cmd/mbf/internal/pkgserver/ui/index.ts331
-rw-r--r--cmd/mbf/internal/pkgserver/ui/style.css21
-rw-r--r--cmd/mbf/internal/pkgserver/ui/tsconfig.json8
-rw-r--r--cmd/mbf/internal/pkgserver/ui/ui.go9
-rw-r--r--cmd/mbf/internal/pkgserver/ui/ui_full.go21
-rw-r--r--cmd/mbf/internal/pkgserver/ui/ui_stub.go7
7 files changed, 0 insertions, 455 deletions
diff --git a/cmd/mbf/internal/pkgserver/ui/index.html b/cmd/mbf/internal/pkgserver/ui/index.html
deleted file mode 100644
index 6a5d72b4..00000000
--- a/cmd/mbf/internal/pkgserver/ui/index.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <link rel="stylesheet" href="style.css">
- <link rel="icon" href="https://hakurei.app/favicon.ico"/>
- <title>Rosa OS Packages</title>
- <script src="index.js"></script>
-</head>
-<body>
-<h1>Rosa OS Packages</h1>
-<div class="top-controls" id="top-controls-regular">
- <p>Showing entries <span id="entry-counter"></span>.</p>
- <span id="search-bar">
- <label for="search">Search: </label>
- <input type="text" name="search" id="search"/>
- <button onclick="doSearch()">Find</button>
- <label for="include-desc">Include descriptions: </label>
- <input type="checkbox" name="include-desc" id="include-desc" checked/>
- </span>
- <div><label for="count">Entries per page: </label><select name="count" id="count">
- <option value="10">10</option>
- <option value="20">20</option>
- <option value="30">30</option>
- <option value="50">50</option>
- </select></div>
- <div><label for="sort">Sort by: </label><select name="sort" id="sort">
- <option value="0">Definition (ascending)</option>
- <option value="1">Definition (descending)</option>
- <option value="2">Name (ascending)</option>
- <option value="3">Name (descending)</option>
- <option value="4">Size (ascending)</option>
- <option value="5">Size (descending)</option>
- </select></div>
-</div>
-<div class="top-controls" id="search-top-controls" hidden>
- <p>Showing search results <span id="search-entry-counter"></span> for query "<span id="search-query"></span>".</p>
- <button onclick="exitSearch()">Back</button>
- <div><label for="search-count">Entries per page: </label><select name="search-count" id="search-count">
- <option value="10">10</option>
- <option value="20">20</option>
- <option value="30">30</option>
- <option value="50">50</option>
- </select></div>
- <p>Sorted by best match</p>
-</div>
-<div class="page-controls"><a href="javascript:prevPage()">&laquo; Previous</a> <input type="text" class="page-number" value="1"/> <a href="javascript:nextPage()">Next &raquo;</a></div>
-<table id="pkg-list">
- <tr><td>Loading...</td></tr>
-</table>
-<div class="page-controls"><a href="javascript:prevPage()">&laquo; Previous</a> <input type="text" class="page-number" value="1"/> <a href="javascript:nextPage()">Next &raquo;</a></div>
-<footer>
- <p>&copy;<a href="https://hakurei.app/">Hakurei</a> (<span id="hakurei-version">unknown</span>). Licensed under the MIT license.</p>
-</footer>
-<script>main();</script>
-</body>
-</html>
diff --git a/cmd/mbf/internal/pkgserver/ui/index.ts b/cmd/mbf/internal/pkgserver/ui/index.ts
deleted file mode 100644
index 0784b81f..00000000
--- a/cmd/mbf/internal/pkgserver/ui/index.ts
+++ /dev/null
@@ -1,331 +0,0 @@
-interface PackageIndexEntry {
- name: string
- size?: number
- description?: string
- website?: string
- version?: string
- report?: boolean
-}
-
-function entryToHTML(entry: PackageIndexEntry | SearchResult): HTMLTableRowElement {
- let v = entry.version != null ? `<span>${escapeHtml(entry.version)}</span>` : ""
- let s = entry.size != null && entry.size > 0 ? `<p>Size: ${toByteSizeString(entry.size)} (${entry.size})</p>` : ""
- let n: string
- let d: string
- if ('name_matches' in entry) {
- n = `<h2>${nameMatches(entry as SearchResult)} ${v}</h2>`
- } else {
- n = `<h2>${escapeHtml(entry.name)} ${v}</h2>`
- }
- if ('desc_matches' in entry && STATE.getIncludeDescriptions()) {
- d = descMatches(entry as SearchResult)
- } else {
- d = (entry as PackageIndexEntry).description != null ? `<p>${escapeHtml((entry as PackageIndexEntry).description)}</p>` : ""
- }
- let w = entry.website != null ? `<a href="${encodeURI(entry.website)}">Website</a>` : ""
- let r = entry.report ? `Log (<a href=\"${encodeURI('/api/v1/status/' + entry.name)}\">View</a> | <a href=\"${encodeURI('/status/' + entry.name)}\">Download</a>)` : ""
- let row = <HTMLTableRowElement>(document.createElement('tr'))
- row.innerHTML = `<td>
- ${n}
- ${d}
- ${s}
- ${w}
- ${r}
- </td>`
- return row
-}
-
-function nameMatches(sr: SearchResult): string {
- return markMatches(sr.name, sr.name_matches)
-}
-
-function descMatches(sr: SearchResult): string {
- return markMatches(sr.description!, sr.desc_matches)
-}
-
-function markMatches(str: string, indices: [number, number][]): string {
- if (indices == null) {
- return str
- }
- let out: string = ""
- let j = 0
- for (let i = 0; i < str.length; i++) {
- if (j < indices.length) {
- if (i === indices[j][0]) {
- out += `<mark>${escapeHtmlChar(str[i])}`
- continue
- }
- if (i === indices[j][1]) {
- out += `</mark>${escapeHtmlChar(str[i])}`
- j++
- continue
- }
- }
- out += escapeHtmlChar(str[i])
- }
- if (indices[j] !== undefined) {
- out += "</mark>"
- }
- return out
-}
-
-function toByteSizeString(bytes: number): string {
- if (bytes == null) return `unspecified`
- if (bytes < 1024) return `${bytes}B`
- if (bytes < Math.pow(1024, 2)) return `${(bytes / 1024).toFixed(2)}kiB`
- if (bytes < Math.pow(1024, 3)) return `${(bytes / Math.pow(1024, 2)).toFixed(2)}MiB`
- if (bytes < Math.pow(1024, 4)) return `${(bytes / Math.pow(1024, 3)).toFixed(2)}GiB`
- if (bytes < Math.pow(1024, 5)) return `${(bytes / Math.pow(1024, 4)).toFixed(2)}TiB`
- return "not only is it big, it's large"
-}
-
-const API_VERSION = 1
-const ENDPOINT = `/api/v${API_VERSION}`
-
-interface InfoPayload {
- count?: number
- hakurei_version?: string
-}
-
-async function infoRequest(): Promise<InfoPayload> {
- const res = await fetch(`${ENDPOINT}/info`)
- const payload = await res.json()
- return payload as InfoPayload
-}
-
-interface GetPayload {
- values?: PackageIndexEntry[]
-}
-
-enum SortOrders {
- DeclarationAscending,
- DeclarationDescending,
- NameAscending,
- NameDescending
-}
-
-async function getRequest(limit: number, index: number, sort: SortOrders): Promise<GetPayload> {
- const res = await fetch(`${ENDPOINT}/get?limit=${limit}&index=${index}&sort=${sort.valueOf()}`)
- const payload = await res.json()
- return payload as GetPayload
-}
-
-interface SearchResult extends PackageIndexEntry {
- name_matches: [number, number][]
- desc_matches: [number, number][]
- score: number
-}
-
-interface SearchPayload {
- count?: number
- values?: SearchResult[]
-}
-
-async function searchRequest(limit: number, index: number, search: string, desc: boolean): Promise<SearchPayload> {
- const res = await fetch(`${ENDPOINT}/search?limit=${limit}&index=${index}&search=${encodeURIComponent(search)}&desc=${desc}`)
- if (!res.ok) {
- exitSearch()
- alert("invalid search query!")
- return Promise.reject(res.statusText)
- }
- const payload = await res.json()
- return payload as SearchPayload
-}
-
-class State {
- entriesPerPage: number = 10
- entryIndex: number = 0
- maxTotal: number = 0
- maxEntries: number = 0
- sort: SortOrders = SortOrders.DeclarationAscending
- search: boolean = false
-
- getEntriesPerPage(): number {
- return this.entriesPerPage
- }
-
- setEntriesPerPage(entriesPerPage: number) {
- this.entriesPerPage = entriesPerPage
- this.setEntryIndex(Math.floor(this.getEntryIndex() / entriesPerPage) * entriesPerPage)
- }
-
- getEntryIndex(): number {
- return this.entryIndex
- }
-
- setEntryIndex(entryIndex: number) {
- this.entryIndex = entryIndex
- this.updatePage()
- this.updateRange()
- this.updateListings()
- }
-
- getMaxTotal(): number {
- return this.maxTotal
- }
-
- setMaxTotal(max: number) {
- this.maxTotal = max
- }
-
- getSortOrder(): SortOrders {
- return this.sort
- }
-
- setSortOrder(sortOrder: SortOrders) {
- this.sort = sortOrder
- this.setEntryIndex(0)
- }
-
- updatePage() {
- let page = Math.ceil(((this.getEntryIndex() + this.getEntriesPerPage()) - 1) / this.getEntriesPerPage())
- for (let e of document.getElementsByClassName("page-number")) {
- (e as HTMLInputElement).value = String(page)
- }
- }
-
- updateRange() {
- let max = Math.min(this.getEntryIndex() + this.getEntriesPerPage(), this.getMaxTotal())
- document.getElementById("entry-counter")!.textContent = `${this.getEntryIndex() + 1}-${max} of ${this.getMaxTotal()}`
- if (this.search) {
- document.getElementById("search-entry-counter")!.textContent = `${this.getEntryIndex() + 1}-${max} of ${this.maxTotal}/${this.maxEntries}`
- document.getElementById("search-query")!.innerHTML = `<code>${escapeHtml(this.getSearchQuery())}</code>`
- }
- }
-
- getSearchQuery(): string {
- let queryString = document.getElementById("search")!;
- return (queryString as HTMLInputElement).value
- }
-
- getIncludeDescriptions(): boolean {
- let includeDesc = document.getElementById("include-desc")!;
- return (includeDesc as HTMLInputElement).checked
- }
-
- updateListings() {
- if (this.search) {
- searchRequest(this.getEntriesPerPage(), this.getEntryIndex(), this.getSearchQuery(), this.getIncludeDescriptions())
- .then(res => {
- let table = document.getElementById("pkg-list")!
- table.innerHTML = ''
- for (let row of res.values!) {
- table.appendChild(entryToHTML(row))
- }
- STATE.maxTotal = res.count!
- STATE.updateRange()
- if(res.count! < 1) {
- exitSearch()
- alert("no results found!")
- }
- })
- } else {
- getRequest(this.getEntriesPerPage(), this.getEntryIndex(), this.getSortOrder())
- .then(res => {
- let table = document.getElementById("pkg-list")!
- table.innerHTML = ''
- for (let row of res.values!) {
- table.appendChild(entryToHTML(row))
- }
- })
- }
- }
-}
-
-let STATE: State
-
-
-function lastPageIndex(): number {
- return Math.floor(STATE.getMaxTotal() / STATE.getEntriesPerPage()) * STATE.getEntriesPerPage()
-}
-
-function setPage(page: number) {
- STATE.setEntryIndex(Math.max(0, Math.min(STATE.getEntriesPerPage() * (page - 1), lastPageIndex())))
-}
-
-
-function escapeHtml(str?: string): string {
- let out: string = ''
- if (str == undefined) return ""
- for (let i = 0; i < str.length; i++) {
- out += escapeHtmlChar(str[i])
- }
- return out
-}
-
-function escapeHtmlChar(char: string): string {
- if (char.length != 1) return char
- switch (char[0]) {
- case '&':
- return "&amp;"
- case '<':
- return "&lt;"
- case '>':
- return "&gt;"
- case '"':
- return "&quot;"
- case "'":
- return "&apos;"
- default:
- return char
- }
-}
-
-function firstPage() {
- STATE.setEntryIndex(0)
-}
-
-function prevPage() {
- let index = STATE.getEntryIndex()
- STATE.setEntryIndex(Math.max(0, index - STATE.getEntriesPerPage()))
-}
-
-function lastPage() {
- STATE.setEntryIndex(lastPageIndex())
-}
-
-function nextPage() {
- let index = STATE.getEntryIndex()
- STATE.setEntryIndex(Math.min(lastPageIndex(), index + STATE.getEntriesPerPage()))
-}
-
-function doSearch() {
- document.getElementById("top-controls-regular")!.toggleAttribute("hidden");
- document.getElementById("search-top-controls")!.toggleAttribute("hidden");
- STATE.search = true;
- STATE.setEntryIndex(0);
-}
-
-function exitSearch() {
- document.getElementById("top-controls-regular")!.toggleAttribute("hidden");
- document.getElementById("search-top-controls")!.toggleAttribute("hidden");
- STATE.search = false;
- STATE.setMaxTotal(STATE.maxEntries)
- STATE.setEntryIndex(0)
-}
-
-function main() {
- STATE = new State()
- infoRequest()
- .then(res => {
- STATE.maxEntries = res.count!
- STATE.setMaxTotal(STATE.maxEntries)
- document.getElementById("hakurei-version")!.textContent = res.hakurei_version!
- STATE.updateRange()
- STATE.updateListings()
- })
- for (let e of document.getElementsByClassName("page-number")) {
- e.addEventListener("change", (_) => {
- setPage(parseInt((e as HTMLInputElement).value))
- })
- }
- document.getElementById("count")?.addEventListener("change", (event) => {
- STATE.setEntriesPerPage(parseInt((event.target as HTMLSelectElement).value))
- })
- document.getElementById("sort")?.addEventListener("change", (event) => {
- STATE.setSortOrder(parseInt((event.target as HTMLSelectElement).value))
- })
- document.getElementById("search")?.addEventListener("keyup", (event) => {
- if (event.key === 'Enter') doSearch()
- })
-} \ No newline at end of file
diff --git a/cmd/mbf/internal/pkgserver/ui/style.css b/cmd/mbf/internal/pkgserver/ui/style.css
deleted file mode 100644
index b4f281ac..00000000
--- a/cmd/mbf/internal/pkgserver/ui/style.css
+++ /dev/null
@@ -1,21 +0,0 @@
-.page-number {
- width: 2em;
- text-align: center;
-}
-.page-number {
- width: 2em;
- text-align: center;
-}
-
-@media (prefers-color-scheme: dark) {
- html {
- background-color: #2c2c2c;
- color: ghostwhite;
- }
-}
-@media (prefers-color-scheme: light) {
- html {
- background-color: #d3d3d3;
- color: black;
- }
-} \ No newline at end of file
diff --git a/cmd/mbf/internal/pkgserver/ui/tsconfig.json b/cmd/mbf/internal/pkgserver/ui/tsconfig.json
deleted file mode 100644
index 24df4936..00000000
--- a/cmd/mbf/internal/pkgserver/ui/tsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2024",
- "strict": true,
- "alwaysStrict": true,
- "outDir": "static"
- }
-} \ No newline at end of file
diff --git a/cmd/mbf/internal/pkgserver/ui/ui.go b/cmd/mbf/internal/pkgserver/ui/ui.go
deleted file mode 100644
index 3fc0d89c..00000000
--- a/cmd/mbf/internal/pkgserver/ui/ui.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Package ui holds the static web UI.
-package ui
-
-import "net/http"
-
-// Register arranges for mux to serve the embedded frontend.
-func Register(mux *http.ServeMux) {
- mux.Handle("GET /", http.FileServer(http.FS(static)))
-}
diff --git a/cmd/mbf/internal/pkgserver/ui/ui_full.go b/cmd/mbf/internal/pkgserver/ui/ui_full.go
deleted file mode 100644
index 564787dc..00000000
--- a/cmd/mbf/internal/pkgserver/ui/ui_full.go
+++ /dev/null
@@ -1,21 +0,0 @@
-//go:build frontend
-
-package ui
-
-import (
- "embed"
- "io/fs"
-)
-
-//go:generate tsc
-//go:generate cp index.html style.css static
-//go:embed static
-var _static embed.FS
-
-var static = func() fs.FS {
- if f, err := fs.Sub(_static, "static"); err != nil {
- panic(err)
- } else {
- return f
- }
-}()
diff --git a/cmd/mbf/internal/pkgserver/ui/ui_stub.go b/cmd/mbf/internal/pkgserver/ui/ui_stub.go
deleted file mode 100644
index daf010f8..00000000
--- a/cmd/mbf/internal/pkgserver/ui/ui_stub.go
+++ /dev/null
@@ -1,7 +0,0 @@
-//go:build !frontend
-
-package ui
-
-import "testing/fstest"
-
-var static fstest.MapFS