diff --git a/pages/admin/loading.ts b/pages/admin/loading.ts index e484c14..9b547b4 100644 --- a/pages/admin/loading.ts +++ b/pages/admin/loading.ts @@ -8,11 +8,6 @@ export async function refreshState() { await Promise.all([ (async () => state.drops.reviews = await API.admin.drops.list(DropType.UnderReview))(), (async () => state.drops.publishing = await API.admin.drops.list(DropType.Publishing))(), - (async () => state.drops.published = await API.admin.drops.list(DropType.Published))(), - (async () => state.drops.private = await API.admin.drops.list(DropType.Private))(), - (async () => state.drops.rejected = await API.admin.drops.list(DropType.ReviewDeclined))(), - (async () => state.drops.drafts = await API.admin.drops.list(DropType.Unsubmitted))(), - (async () => state.users = await API.admin.users.list())(), (async () => state.groups = await API.admin.groups.list())(), (async () => state.payouts = await API.admin.payouts.list())(), (async () => state.files = await API.admin.files.list())(), diff --git a/pages/admin/state.ts b/pages/admin/state.ts index ea57c80..462c2b9 100644 --- a/pages/admin/state.ts +++ b/pages/admin/state.ts @@ -12,7 +12,6 @@ export const state = asState({ rejected: | "loading">"loading", drafts: | "loading">"loading", }, - users: | "loading">"loading", groups: | "loading">"loading", payouts: | "loading">"loading", oauth: | "loading">"loading", @@ -20,6 +19,7 @@ export const state = asState({ servers: | "loading">"loading", wallets: | "loading">"loading", transcripts: | "loading">"loading", + search: <({ type: "transcript", val: Transcript} | {type: "drop", val: Drop} | {type: "server", val: Server} | {type: "user", val: ProfileData})[]>[], }); export const reviewState = asState({ diff --git a/pages/admin/views/entryReview.ts b/pages/admin/views/entryReview.ts index b6c087e..0507d8a 100644 --- a/pages/admin/views/entryReview.ts +++ b/pages/admin/views/entryReview.ts @@ -6,7 +6,7 @@ import { sheetStack, showPreviewImage } from "../../_legacy/helper.ts"; export function ReviewEntry(x: Drop) { return Entry({ title: x.title ?? "(no drop name)", - subtitle: `${x.release ?? "(no release date)"} - ${x.user} - ${x.upc ?? "(no upc number)"} - ${x._id}` + subtitle: `release: ${x.release ?? "(no release date)"} - user: ${x.user} - upc: ${x.upc ?? "(no upc number)"} - id: ${x._id} - type: ${x.type}` }) .addClass("small") .addSuffix(Button("Review") diff --git a/pages/admin/views/entryUser.ts b/pages/admin/views/entryUser.ts index 7978ce8..e93ff59 100644 --- a/pages/admin/views/entryUser.ts +++ b/pages/admin/views/entryUser.ts @@ -2,15 +2,6 @@ import { Entry } from "webgen/mod.ts"; import { Group } from "../../../spec/music.ts"; import { ProfileData, showProfilePicture } from "../../_legacy/helper.ts"; -export function UserEntry(x: ProfileData) { - return Entry({ - title: x.profile.username, - subtitle: `${x._id} - ${x.profile.email}` - }) - .addClass("small") - .addPrefix(showProfilePicture(x)); -} - export function GroupEntry(x: Group) { return Entry({ title: x.displayName, diff --git a/pages/admin/views/menu.ts b/pages/admin/views/menu.ts index d2d79ca..bdaea12 100644 --- a/pages/admin/views/menu.ts +++ b/pages/admin/views/menu.ts @@ -1,14 +1,18 @@ -import { API, HeavyList, loadMore, Navigation, placeholder } from "shared/mod.ts"; +import { debounce } from "https://deno.land/std@0.220.1/async/debounce.ts"; +import loader from "https://esm.sh/@monaco-editor/loader@1.4.0"; +import { API, HeavyList, loadMore, Navigation, placeholder, stupidErrorAlert } from "shared/mod.ts"; import { sumOf } from "std/collections/mod.ts"; -import { asState, Box, Button, Color, Grid, Horizontal, isMobile, Label, ref, SheetDialog, Spacer, Table, TextInput, Vertical } from "webgen/mod.ts"; -import { DropType } from "../../../spec/music.ts"; -import { activeUser, sheetStack } from "../../_legacy/helper.ts"; +import { asState, Box, Button, Color, Custom, Entry, Grid, Horizontal, isMobile, Items, Label, lazyInit, ref, SheetDialog, Spacer, Table, TextInput, Vertical } from "webgen/mod.ts"; +import { Drop, DropType, Server, Transcript } from "../../../spec/music.ts"; +import { activeUser, ProfileData, sheetStack, showProfilePicture } from "../../_legacy/helper.ts"; import { upload } from "../loading.ts"; import { state } from "../state.ts"; import { ReviewEntry } from "./entryReview.ts"; -import { GroupEntry, UserEntry } from "./entryUser.ts"; +import { GroupEntry } from "./entryUser.ts"; import { entryFile, entryOAuth, entryWallet, transcriptMenu } from "./list.ts"; +const lazyMonaco = lazyInit(() => loader.init()); + export const adminMenu = Navigation({ title: ref`Hi ${activeUser.$username} 👋`, categories: [ @@ -40,6 +44,55 @@ export const adminMenu = Navigation({ } ]) }, + { + id: "search", + title: ref`Search`, + children: [ + TextInput("text", "Search").onChange(debounce(async (data) => { + state.search = asState(await API.admin.search(data ?? "").then(stupidErrorAlert)); + }, 1000)), + Items(state.$search.map(it => it as ({ type: "transcript", val: Transcript; } | { type: "drop", val: Drop; } | { type: "server", val: Server; } | { type: "user", val: ProfileData; })[]), it => { + switch (it.type) { + case "transcript": + return Entry( + { + title: it.val.with, + subtitle: it.type + } + ); + case "drop": + return ReviewEntry(it.val) + case "server": + return Entry( + { + title: it.val._id, + subtitle: it.type + } + ); + case "user": + return Entry({ + title: it.val.profile.username, + subtitle: `${it.val._id} - ${it.val.profile.email}` + }) + .addClass("small") + .onPromiseClick(async () => { + const monaco = await lazyMonaco(); + const box = document.createElement("div"); + const editor = monaco.editor.create(box, { + value: JSON.stringify(it.val, null, 2), + language: "json", + theme: "vs-dark", + automaticLayout: true, + }); + + + SheetDialog(sheetStack, "User", Custom(box).setHeight("800px").setWidth("1200px")).open(); + }) + .addPrefix(showProfilePicture(it.val)); + } + }) + ] + }, { id: "drops", title: ref`Drops`, @@ -60,47 +113,7 @@ export const adminMenu = Navigation({ HeavyList(state.drops.$publishing, it => ReviewEntry(it)) .enablePaging((offset, limit) => loadMore(state.drops.$publishing, () => API.admin.drops.list(DropType.Publishing, offset, limit))) ] - }, - { - id: "published", - title: ref`Published`, - children: [ - HeavyList(state.drops.$published, it => ReviewEntry(it)) - .enablePaging((offset, limit) => loadMore(state.drops.$published, () => API.admin.drops.list(DropType.Published, offset, limit))) - ] - }, - { - id: "private", - title: ref`Private`, - children: [ - HeavyList(state.drops.$private, it => ReviewEntry(it)) - .enablePaging((offset, limit) => loadMore(state.drops.$private, () => API.admin.drops.list(DropType.Private, offset, limit))) - ] - }, - { - id: "rejected", - title: ref`Rejected`, - children: [ - HeavyList(state.drops.$rejected, it => ReviewEntry(it)) - .enablePaging((offset, limit) => loadMore(state.drops.$rejected, () => API.admin.drops.list(DropType.ReviewDeclined, offset, limit))) - ] - }, - { - id: "drafts", - title: ref`Drafts`, - children: [ - HeavyList(state.drops.$drafts, it => ReviewEntry(it)) - .enablePaging((offset, limit) => loadMore(state.drops.$drafts, () => API.admin.drops.list(DropType.Unsubmitted, offset, limit))) - ] - }, - ] - }, - { - id: "users", - title: ref`User`, - children: [ - HeavyList(state.$users, val => UserEntry(val)) - .enablePaging((offset, limit) => loadMore(state.$users, () => API.admin.users.list(offset, limit))) + } ] }, { diff --git a/pages/shared/restSpec.ts b/pages/shared/restSpec.ts index 76e4a96..e06311c 100644 --- a/pages/shared/restSpec.ts +++ b/pages/shared/restSpec.ts @@ -241,6 +241,11 @@ export const API = { .then(none()) }), admin: ({ + search: (query: string) => fetch(`${API.BASE_URL}admin/search?query=${query}`, { + headers: headers(API.getToken()) + }) + .then(json()) + .catch(reject), files: { list: (offset: number | undefined = undefined) => { const paging = new URLSearchParams();