@epic-web/workshop-app 6.78.2 → 6.78.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/client/assets/cache-BymCGtPO.js +2 -0
- package/build/client/assets/cache-BymCGtPO.js.map +1 -0
- package/build/client/assets/{manifest-5068a5dd.js → manifest-27726850.js} +1 -1
- package/build/server/index.js +156 -47
- package/build/server/index.js.map +1 -1
- package/package.json +3 -3
- package/build/client/assets/cache-muVFgDkV.js +0 -2
- package/build/client/assets/cache-muVFgDkV.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epic-web/workshop-app",
|
|
3
|
-
"version": "6.78.
|
|
3
|
+
"version": "6.78.3",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"@epic-web/invariant": "^1.0.0",
|
|
43
43
|
"@epic-web/remember": "^1.1.0",
|
|
44
44
|
"@epic-web/restore-scroll": "^2.0.0",
|
|
45
|
-
"@epic-web/workshop-presence": "6.78.
|
|
46
|
-
"@epic-web/workshop-utils": "6.78.
|
|
45
|
+
"@epic-web/workshop-presence": "6.78.3",
|
|
46
|
+
"@epic-web/workshop-utils": "6.78.3",
|
|
47
47
|
"@mdx-js/mdx": "^3.1.1",
|
|
48
48
|
"@mux/mux-player-react": "^3.10.2",
|
|
49
49
|
"@nasa-gcn/remix-seo": "^2.0.1",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{h as D}from"./chunk-4LKRSAEJ-5b-X0-W6.js";import{w as O,f as k,d as P}from"./chunk-JZWAC4HX-BRaE0UIv.js";import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{r as p}from"./index-CqIc3cxq.js";import{C as I}from"./client-only-CTGgqT3G.js";import{i as $,I as R,B as E}from"./button-BNnUtmu5.js";import{I as x,f as N,e as M,c as F,h as z,i as Y,b as B,j as T,k as L}from"./misc-DNNpiA4n.js";import{L as V}from"./launch-editor-CODm6xV9.js";import"./pe-FSGstb4x.js";import"./progress-bar-CPpSmw1y.js";import"./root-loader-DCpknoYz.js";function W({selectedWorkshops:s,availableWorkshops:d,currentWorkshopId:n}){const[i,t]=P(),o=(a,u)=>{const c=u?[...s,a]:s.filter(j=>j!==a),m=new URLSearchParams(i);c.length>0?m.set("workshops",c.join(",")):m.delete("workshops"),t(m)};return e.jsxs("div",{className:"mb-6",children:[e.jsx("h3",{className:"mb-3 text-lg font-semibold",children:"Workshop Filter"}),e.jsx("div",{className:"flex flex-wrap gap-3",children:d.map(a=>e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:s.includes(a),onChange:u=>o(a,u.target.checked),className:"rounded"}),e.jsxs("span",{className:`text-sm ${a===n?"text-primary font-bold":""}`,children:[a," ",a===n?"(current)":null]})]},a))})]})}function H({filterQuery:s}){const[d,n]=P(),[i,t]=p.useState(s),o=p.useRef(null);p.useEffect(()=>{t(s)},[s]);const a=c=>{const m=new URLSearchParams(d);c?m.set("q",c):m.delete("q"),n(m)},u=()=>{t(""),a(""),o.current?.focus()};return e.jsxs("div",{className:"mb-6",children:[e.jsx("h3",{className:"mb-3 text-lg font-semibold",children:"Search Cache Entries"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{ref:o,type:"text",placeholder:"Search by key or cache name...",value:i,onChange:c=>{t(c.target.value),a(c.target.value)},className:"border-border bg-background text-foreground focus:ring-ring flex-1 rounded-md border px-3 py-2 focus:ring-2 focus:outline-none"}),i?e.jsx(R,{onClick:u,title:"Clear search",children:e.jsx(x,{name:"Close",className:"h-4 w-4"})}):null]})]})}function J({workshopId:s,cacheName:d,filename:n,currentValue:i,entryKey:t}){const o=k(),[a,u]=p.useState(JSON.stringify(i,null,2)),[c,m]=p.useState(!1),j=()=>{o.submit({intent:"update-entry",workshopId:s,cacheName:d,filename:n,newValue:a},{method:"POST"}),m(!1)},l=h=>{u(h),m(h!==JSON.stringify(i,null,2))},r=()=>{u(JSON.stringify(i,null,2)),m(!1)};return e.jsxs("details",{className:"mt-2",children:[e.jsx("summary",{className:"text-muted-foreground hover:text-foreground cursor-pointer text-sm",children:"Edit entry details"}),e.jsxs("div",{className:"border-border bg-muted mt-2 space-y-3 rounded border p-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium",children:"Key:"}),e.jsx("code",{className:"bg-background rounded border px-2 py-1 text-sm",children:t})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium",children:"Value:"}),e.jsx("textarea",{value:a,onChange:h=>l(h.target.value),className:"resize-vertical border-border bg-background text-foreground focus:ring-ring h-32 w-full rounded border p-2 font-mono text-sm focus:ring-2 focus:outline-none",placeholder:"Enter JSON value..."})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(E,{varient:"primary",onClick:j,disabled:!c||o.state!=="idle",children:o.state!=="idle"?"Saving...":"Save"}),e.jsx(E,{varient:"mono",onClick:r,disabled:!c,children:"Reset"})]})]})]})}function K({skippedFiles:s,workshopId:d,cacheName:n}){const i=k();return s.length===0?null:e.jsxs("div",{className:"border-warning bg-warning mt-4 rounded border p-3",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2",children:[e.jsx(x,{name:"TriangleAlert",className:"text-warning-foreground h-4 w-4"}),e.jsxs("h5",{className:"text-warning-foreground font-medium",children:["Skipped Files (",s.length,")"]})]}),e.jsx("p",{className:"text-warning-foreground/80 mb-3 text-sm",children:"These cache files were skipped because they exceed the 3MB size limit:"}),e.jsx("div",{className:"space-y-2",children:s.map(t=>e.jsxs("div",{className:"border-warning/20 bg-warning/5 flex items-center justify-between rounded border p-2",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"text-warning-foreground truncate font-mono text-sm font-medium",children:t.filename}),e.jsxs("div",{className:"text-warning-foreground/70 text-xs",children:[t.error," • Size:"," ",e.jsx("span",{title:`${t.size} bytes`,children:N(t.size)})]})]}),e.jsx("div",{className:"ml-2 flex shrink-0",children:e.jsx(v,{onConfirm:()=>{i.submit({intent:"delete-entry",workshopId:d,cacheName:n,filename:t.filename},{method:"POST"})},title:"Delete large cache file",className:"text-destructive-foreground hover:bg-destructive/20 hover:text-destructive-foreground",children:e.jsx(x,{name:"Remove",className:"h-4 w-4"})})})]},t.filename))})]})}const ne=O(function({loaderData:d}){const n=k(),i=(l,r,h)=>{n.submit({intent:"delete-entry",workshopId:l,cacheName:r,filename:h},{method:"POST"})},t=(l,r)=>{n.submit({intent:"delete-cache",workshopId:l,cacheName:r},{method:"POST"})},o=l=>{n.submit({intent:"delete-workshop-cache",workshopId:l},{method:"POST"})},{currentWorkshopId:a,filteredCaches:u,filterQuery:c,selectedWorkshops:m,availableWorkshops:j}=d;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"mb-2 text-2xl font-bold",children:"Cache Management"}),e.jsxs("p",{className:"text-muted-foreground",children:["Current Workshop:"," ",e.jsx("span",{className:"text-foreground font-semibold",children:a})]})]}),e.jsx(W,{selectedWorkshops:m,availableWorkshops:j,currentWorkshopId:a}),e.jsx(H,{filterQuery:c}),n.data?.status==="success"?e.jsx("div",{className:"border-border bg-success text-success-foreground rounded border p-4",children:n.data.message}):null,n.data?.status==="error"?e.jsx("div",{className:"border-border bg-destructive text-destructive-foreground rounded border p-4",children:n.data.error}):null,u.length===0?e.jsx("div",{className:"text-muted-foreground py-8 text-center",children:"No caches found matching your criteria."}):null,e.jsx("div",{className:"space-y-6",children:u.map(l=>e.jsxs("details",{open:l.workshopId===a,children:[e.jsx("summary",{className:"border-border bg-card hover:bg-accent cursor-pointer rounded-lg border p-4",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("h3",{className:"text-card-foreground flex items-center gap-2 text-lg font-semibold",children:[e.jsx(x,{name:"Files",className:"h-5 w-5"}),l.workshopId==="global"?"Global Caches":l.workshopId,l.workshopId===a?e.jsx("span",{className:"bg-primary text-primary-foreground rounded px-2 py-1 text-xs",children:"Current"}):null]}),e.jsx(v,{onConfirm:()=>o(l.workshopId),title:"Delete all workshop caches",children:e.jsx(x,{name:"Remove",className:"h-4 w-4"})})]})}),e.jsx("div",{className:"mt-4 space-y-4 pl-4",children:l.caches.map(r=>{const h=r.entries.reduce((f,g)=>f+(g.size||0),0),b=(r.skippedFiles||[]).reduce((f,g)=>f+g.size,0),w=h+b;return e.jsxs("details",{className:"bg-muted rounded-md",children:[e.jsx("summary",{className:"hover:bg-accent cursor-pointer p-3",children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("h4",{className:"text-muted-foreground flex items-center gap-2 font-medium",children:[e.jsx(x,{name:"Files",className:"h-4 w-4"}),r.name,e.jsxs("span",{className:"text-sm",children:["(",r.entries.length," entr",r.entries.length===1?"y":"ies",")"]}),w>0?e.jsxs("span",{className:"text-muted-foreground text-sm",children:["•"," ",e.jsx("span",{title:`${w} bytes`,children:N(w)})," ","total",b>0?e.jsxs("span",{className:"text-warning",children:[" ","(",e.jsx("span",{title:`${b} bytes`,children:N(b)})," ","skipped)"]}):null]}):null]}),e.jsx(v,{onConfirm:()=>t(l.workshopId,r.name),title:"Delete cache",children:e.jsx(x,{name:"Remove",className:"h-4 w-4"})})]})}),e.jsxs("div",{className:"p-3 pt-0",children:[r.entries.length===0?e.jsx("p",{className:"text-muted-foreground text-sm",children:"No entries match your search."}):null,r.skippedFiles&&r.skippedFiles.length>0?e.jsx(K,{skippedFiles:r.skippedFiles,workshopId:l.workshopId,cacheName:r.name}):null,e.jsx("div",{className:"space-y-2",children:r.entries.map(({key:f,entry:g,filename:y,size:S,filepath:C})=>e.jsxs("div",{className:"border-border bg-background rounded border p-3",children:[e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"mb-1 flex items-center gap-2",children:[e.jsx("div",{className:"truncate font-mono text-sm font-medium",title:f,children:f}),S?e.jsx("span",{className:"bg-muted text-muted-foreground inline-flex items-center rounded px-1.5 py-0.5 text-xs whitespace-nowrap",title:`${S} bytes`,children:N(S)}):null]}),e.jsx(U,{metadata:g.metadata})]}),e.jsxs("div",{className:"ml-4 flex shrink-0 gap-1",children:[e.jsx("a",{href:D("/admin/cache/*",{"*":`${l.workshopId}/${r.name}/${y}`}),target:"_blank",rel:"noopener noreferrer",className:"border-border bg-background text-foreground hover:bg-muted focus:ring-ring inline-flex h-8 w-8 items-center justify-center rounded border focus:ring-2 focus:outline-none",title:"View JSON",children:e.jsx(x,{name:"ExternalLink",className:"h-4 w-4"})}),C?e.jsx(V,{file:C,className:$,children:e.jsx(x,{name:"Files",className:"h-4 w-4",title:"Open in editor"})}):null,e.jsx(v,{onConfirm:()=>i(l.workshopId,r.name,y),title:"Delete entry",children:e.jsx(x,{name:"Remove",className:"h-4 w-4"})})]})]}),e.jsx(J,{workshopId:l.workshopId,cacheName:r.name,filename:y,currentValue:g.value,entryKey:f})]},f))})]})]},r.name)})})]},l.workshopId))})]})});function U({metadata:s}){const d=z(),[,n]=p.useState(Date.now()),i=Y(s);B(()=>{n(Date.now())},1e3);const t=d(s.createdTime),o=i?L(i):{text:"Never",isExpired:!1,isExpiringSoon:!1};return e.jsxs("div",{className:"text-muted-foreground flex flex-col gap-1 text-xs",children:[e.jsxs("div",{children:["Created: ",t.format("MMM D, YYYY HH:mm:ss")," ",e.jsx(I,{children:()=>`(${t.fromNow()})`})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[s.ttl!==void 0&&s.ttl!==null?e.jsxs("span",{children:["TTL:"," ",s.ttl===1/0?"Forever":e.jsx("span",{title:`${s.ttl}ms`,children:T(s.ttl)})]}):null,s.swr!==void 0?e.jsxs("span",{children:["SWR:"," ",e.jsx("span",{title:`${s.swr}ms`,children:T(s.swr)})]}):null,e.jsx("div",{className:`inline-flex w-auto rounded-full px-2 py-[2px] font-medium ${o.isExpired?"bg-destructive text-destructive-foreground":o.isExpiringSoon?"bg-warning text-warning-foreground":"text-foreground"}`,children:i?e.jsxs(e.Fragment,{children:["Expires: ",d(i).format("MMM D, YYYY HH:mm:ss")," (",e.jsx("span",{className:"tabular-nums",children:e.jsx(I,{children:()=>o.text})}),")"]}):"Expires: Never"})]})]})}function v({onConfirm:s,children:d,className:n,...i}){const t=M();return e.jsx(R,{...t.getButtonProps({onClick:t.doubleCheck?s:void 0,...i}),className:F(t.doubleCheck?"bg-destructive text-destructive-foreground":null,n),children:t.doubleCheck?"✓":d})}export{ne as default};
|
|
2
|
-
//# sourceMappingURL=cache-muVFgDkV.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache-muVFgDkV.js","sources":["../../../app/routes/admin+/cache.tsx"],"sourcesContent":["import {\n\tdeleteCacheEntry,\n\tdeleteWorkshopCache,\n\tgetAllWorkshopCaches,\n\tgetGlobalCaches,\n\tglobalCacheDirectoryExists,\n\tupdateCacheEntry,\n} from '@epic-web/workshop-utils/cache.server'\nimport { getEnv } from '@epic-web/workshop-utils/env.server'\nimport { getErrorMessage } from '@epic-web/workshop-utils/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { href, useFetcher, useSearchParams } from 'react-router'\nimport { ClientOnly } from 'remix-utils/client-only'\nimport { z } from 'zod'\nimport {\n\tButton,\n\tIconButton,\n\ticonButtonClassName,\n} from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport {\n\tcalculateExpirationTime,\n\tcn,\n\tensureUndeployed,\n\tformatDuration,\n\tformatFileSize,\n\tformatTimeRemaining,\n\tuseDayjs,\n\tuseDoubleCheck,\n\tuseInterval,\n} from '#app/utils/misc.tsx'\nimport { type Route } from './+types/cache.ts'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tensureUndeployed()\n\tconst currentWorkshopId = getEnv().EPICSHOP_WORKSHOP_INSTANCE_ID\n\tconst allWorkshopCaches = await getAllWorkshopCaches()\n\tconst globalCaches = await getGlobalCaches()\n\tconst allCaches = [...allWorkshopCaches, ...globalCaches]\n\n\tconst url = new URL(request.url)\n\tconst filterQuery = url.searchParams.get('q') || ''\n\n\t// Ensure 'global' is always in available workshops if global cache directory exists\n\tconst availableWorkshopIds = new Set(allCaches.map((w) => w.workshopId))\n\tconst globalDirExists = await globalCacheDirectoryExists()\n\tif (globalDirExists) {\n\t\tavailableWorkshopIds.add('global')\n\t}\n\n\tconst selectedWorkshops = url.searchParams\n\t\t.get('workshops')\n\t\t?.split(',')\n\t\t.filter(Boolean) || [\n\t\tcurrentWorkshopId,\n\t\t...(globalDirExists ? ['global'] : []),\n\t]\n\n\t// Filter caches based on search query and selected workshops\n\tconst filteredCaches = allCaches\n\t\t.filter(\n\t\t\t(workshopCache) =>\n\t\t\t\tselectedWorkshops.includes(workshopCache.workshopId) ||\n\t\t\t\tselectedWorkshops.length === 0,\n\t\t)\n\t\t.map((workshopCache) => ({\n\t\t\t...workshopCache,\n\t\t\tcaches: workshopCache.caches\n\t\t\t\t.map((cache) => ({\n\t\t\t\t\t...cache,\n\t\t\t\t\tentries: cache.entries.filter(\n\t\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t\tfilterQuery === '' ||\n\t\t\t\t\t\t\tentry.key.toLowerCase().includes(filterQuery.toLowerCase()) ||\n\t\t\t\t\t\t\tcache.name.toLowerCase().includes(filterQuery.toLowerCase()),\n\t\t\t\t\t),\n\t\t\t\t}))\n\t\t\t\t.filter((cache) => cache.entries.length > 0 || filterQuery === ''),\n\t\t}))\n\t\t.filter(\n\t\t\t(workshopCache) => workshopCache.caches.length > 0 || filterQuery === '',\n\t\t)\n\n\treturn {\n\t\tcurrentWorkshopId,\n\t\tallWorkshopCaches: allCaches,\n\t\tfilteredCaches,\n\t\tfilterQuery,\n\t\tselectedWorkshops,\n\t\tavailableWorkshops: Array.from(availableWorkshopIds),\n\t}\n}\n\nconst ActionSchema = z.discriminatedUnion('intent', [\n\tz.object({\n\t\tintent: z.literal('delete-entry'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t\tfilename: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('delete-cache'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('delete-workshop-cache'),\n\t\tworkshopId: z.string(),\n\t}),\n\tz.object({\n\t\tintent: z.literal('update-entry'),\n\t\tworkshopId: z.string(),\n\t\tcacheName: z.string(),\n\t\tfilename: z.string(),\n\t\tnewValue: z.string(),\n\t}),\n])\n\nexport async function action({ request }: Route.ActionArgs) {\n\tensureUndeployed()\n\n\tconst formData = await request.formData()\n\tconst rawData = Object.fromEntries(formData.entries())\n\tconst result = ActionSchema.safeParse(rawData)\n\n\tif (!result.success) {\n\t\treturn { status: 'error', error: 'Invalid request' } as const\n\t}\n\n\tconst data = result.data\n\n\ttry {\n\t\tswitch (data.intent) {\n\t\t\tcase 'delete-entry': {\n\t\t\t\tconst path = `${data.workshopId}/${data.cacheName}/${data.filename}`\n\t\t\t\tawait deleteCacheEntry(path)\n\t\t\t\treturn { status: 'success', message: 'Cache entry deleted' } as const\n\t\t\t}\n\t\t\tcase 'delete-cache': {\n\t\t\t\tawait deleteWorkshopCache(data.workshopId, data.cacheName)\n\t\t\t\treturn { status: 'success', message: 'Cache deleted' } as const\n\t\t\t}\n\t\t\tcase 'delete-workshop-cache': {\n\t\t\t\tawait deleteWorkshopCache(data.workshopId)\n\t\t\t\treturn { status: 'success', message: 'Workshop cache deleted' } as const\n\t\t\t}\n\t\t\tcase 'update-entry': {\n\t\t\t\tconst path = `${data.workshopId}/${data.cacheName}/${data.filename}`\n\t\t\t\ttry {\n\t\t\t\t\tconst parsedValue = JSON.parse(data.newValue)\n\t\t\t\t\tawait updateCacheEntry(path, parsedValue)\n\t\t\t\t\treturn { status: 'success', message: 'Cache entry updated' } as const\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\terror: getErrorMessage(error, 'Invalid JSON value'),\n\t\t\t\t\t} as const\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconsole.error('Cache action error:', error)\n\t\treturn { status: 'error', error: 'Operation failed' } as const\n\t}\n}\n\nfunction WorkshopChooser({\n\tselectedWorkshops,\n\tavailableWorkshops,\n\tcurrentWorkshopId,\n}: {\n\tselectedWorkshops: string[]\n\tavailableWorkshops: string[]\n\tcurrentWorkshopId: string\n}) {\n\tconst [searchParams, setSearchParams] = useSearchParams()\n\n\tconst handleWorkshopChange = (workshop: string, checked: boolean) => {\n\t\tconst newSelected = checked\n\t\t\t? [...selectedWorkshops, workshop]\n\t\t\t: selectedWorkshops.filter((w) => w !== workshop)\n\n\t\tconst params = new URLSearchParams(searchParams)\n\t\tif (newSelected.length > 0) {\n\t\t\tparams.set('workshops', newSelected.join(','))\n\t\t} else {\n\t\t\tparams.delete('workshops')\n\t\t}\n\t\tsetSearchParams(params)\n\t}\n\n\treturn (\n\t\t<div className=\"mb-6\">\n\t\t\t<h3 className=\"mb-3 text-lg font-semibold\">Workshop Filter</h3>\n\t\t\t<div className=\"flex flex-wrap gap-3\">\n\t\t\t\t{availableWorkshops.map((workshop) => (\n\t\t\t\t\t<label key={workshop} className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tchecked={selectedWorkshops.includes(workshop)}\n\t\t\t\t\t\t\tonChange={(e) => handleWorkshopChange(workshop, e.target.checked)}\n\t\t\t\t\t\t\tclassName=\"rounded\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclassName={`text-sm ${workshop === currentWorkshopId ? 'text-primary font-bold' : ''}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{workshop} {workshop === currentWorkshopId ? '(current)' : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction SearchFilter({ filterQuery }: { filterQuery: string }) {\n\tconst [searchParams, setSearchParams] = useSearchParams()\n\tconst [inputValue, setInputValue] = useState(filterQuery)\n\tconst inputRef = useRef<HTMLInputElement>(null)\n\n\t// Update input value when filterQuery changes (e.g., from URL)\n\tuseEffect(() => {\n\t\tsetInputValue(filterQuery)\n\t}, [filterQuery])\n\n\tconst handleSearch = (query: string) => {\n\t\tconst params = new URLSearchParams(searchParams)\n\t\tif (query) {\n\t\t\tparams.set('q', query)\n\t\t} else {\n\t\t\tparams.delete('q')\n\t\t}\n\t\tsetSearchParams(params)\n\t}\n\n\tconst handleClear = () => {\n\t\tsetInputValue('')\n\t\thandleSearch('')\n\t\tinputRef.current?.focus()\n\t}\n\n\treturn (\n\t\t<div className=\"mb-6\">\n\t\t\t<h3 className=\"mb-3 text-lg font-semibold\">Search Cache Entries</h3>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t<input\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tplaceholder=\"Search by key or cache name...\"\n\t\t\t\t\tvalue={inputValue}\n\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\tsetInputValue(e.target.value)\n\t\t\t\t\t\thandleSearch(e.target.value)\n\t\t\t\t\t}}\n\t\t\t\t\tclassName=\"border-border bg-background text-foreground focus:ring-ring flex-1 rounded-md border px-3 py-2 focus:ring-2 focus:outline-none\"\n\t\t\t\t/>\n\t\t\t\t{inputValue ? (\n\t\t\t\t\t<IconButton onClick={handleClear} title=\"Clear search\">\n\t\t\t\t\t\t<Icon name=\"Close\" className=\"h-4 w-4\" />\n\t\t\t\t\t</IconButton>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Inline entry editor component\nfunction InlineEntryEditor({\n\tworkshopId,\n\tcacheName,\n\tfilename,\n\tcurrentValue,\n\tentryKey,\n}: {\n\tworkshopId: string\n\tcacheName: string\n\tfilename: string\n\tcurrentValue: any\n\tentryKey: string\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst [editValue, setEditValue] = useState(\n\t\tJSON.stringify(currentValue, null, 2),\n\t)\n\tconst [hasChanges, setHasChanges] = useState(false)\n\n\tconst handleSave = () => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'update-entry',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t\tfilename,\n\t\t\t\tnewValue: editValue,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t\tsetHasChanges(false)\n\t}\n\n\tconst handleChange = (value: string) => {\n\t\tsetEditValue(value)\n\t\tsetHasChanges(value !== JSON.stringify(currentValue, null, 2))\n\t}\n\n\tconst handleReset = () => {\n\t\tsetEditValue(JSON.stringify(currentValue, null, 2))\n\t\tsetHasChanges(false)\n\t}\n\n\treturn (\n\t\t<details className=\"mt-2\">\n\t\t\t<summary className=\"text-muted-foreground hover:text-foreground cursor-pointer text-sm\">\n\t\t\t\tEdit entry details\n\t\t\t</summary>\n\t\t\t<div className=\"border-border bg-muted mt-2 space-y-3 rounded border p-3\">\n\t\t\t\t<div>\n\t\t\t\t\t<label className=\"mb-1 block text-sm font-medium\">Key:</label>\n\t\t\t\t\t<code className=\"bg-background rounded border px-2 py-1 text-sm\">\n\t\t\t\t\t\t{entryKey}\n\t\t\t\t\t</code>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<label className=\"mb-1 block text-sm font-medium\">Value:</label>\n\t\t\t\t\t<textarea\n\t\t\t\t\t\tvalue={editValue}\n\t\t\t\t\t\tonChange={(e) => handleChange(e.target.value)}\n\t\t\t\t\t\tclassName=\"resize-vertical border-border bg-background text-foreground focus:ring-ring h-32 w-full rounded border p-2 font-mono text-sm focus:ring-2 focus:outline-none\"\n\t\t\t\t\t\tplaceholder=\"Enter JSON value...\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvarient=\"primary\"\n\t\t\t\t\t\tonClick={handleSave}\n\t\t\t\t\t\tdisabled={!hasChanges || fetcher.state !== 'idle'}\n\t\t\t\t\t>\n\t\t\t\t\t\t{fetcher.state !== 'idle' ? 'Saving...' : 'Save'}\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button varient=\"mono\" onClick={handleReset} disabled={!hasChanges}>\n\t\t\t\t\t\tReset\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</details>\n\t)\n}\n\nfunction SkippedFilesSection({\n\tskippedFiles,\n\tworkshopId,\n\tcacheName,\n}: {\n\tskippedFiles: Array<{\n\t\tfilename: string\n\t\terror: string\n\t\tsize: number\n\t\tskipped: true\n\t}>\n\tworkshopId: string\n\tcacheName: string\n}) {\n\tconst fetcher = useFetcher<typeof action>()\n\n\tif (skippedFiles.length === 0) return null\n\n\treturn (\n\t\t<div className=\"border-warning bg-warning mt-4 rounded border p-3\">\n\t\t\t<div className=\"mb-2 flex items-center gap-2\">\n\t\t\t\t<Icon\n\t\t\t\t\tname=\"TriangleAlert\"\n\t\t\t\t\tclassName=\"text-warning-foreground h-4 w-4\"\n\t\t\t\t/>\n\t\t\t\t<h5 className=\"text-warning-foreground font-medium\">\n\t\t\t\t\tSkipped Files ({skippedFiles.length})\n\t\t\t\t</h5>\n\t\t\t</div>\n\t\t\t<p className=\"text-warning-foreground/80 mb-3 text-sm\">\n\t\t\t\tThese cache files were skipped because they exceed the 3MB size limit:\n\t\t\t</p>\n\t\t\t<div className=\"space-y-2\">\n\t\t\t\t{skippedFiles.map((skippedFile) => (\n\t\t\t\t\t<div\n\t\t\t\t\t\tkey={skippedFile.filename}\n\t\t\t\t\t\tclassName=\"border-warning/20 bg-warning/5 flex items-center justify-between rounded border p-2\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t<div className=\"text-warning-foreground truncate font-mono text-sm font-medium\">\n\t\t\t\t\t\t\t\t{skippedFile.filename}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"text-warning-foreground/70 text-xs\">\n\t\t\t\t\t\t\t\t{skippedFile.error} • Size:{' '}\n\t\t\t\t\t\t\t\t<span title={`${skippedFile.size} bytes`}>\n\t\t\t\t\t\t\t\t\t{formatFileSize(skippedFile.size)}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"ml-2 flex shrink-0\">\n\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\tonConfirm={() => {\n\t\t\t\t\t\t\t\t\tvoid fetcher.submit(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tintent: 'delete-entry',\n\t\t\t\t\t\t\t\t\t\t\tworkshopId,\n\t\t\t\t\t\t\t\t\t\t\tcacheName,\n\t\t\t\t\t\t\t\t\t\t\tfilename: skippedFile.filename,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{ method: 'POST' },\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\ttitle=\"Delete large cache file\"\n\t\t\t\t\t\t\t\tclassName=\"text-destructive-foreground hover:bg-destructive/20 hover:text-destructive-foreground\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nexport default function CacheManagement({ loaderData }: Route.ComponentProps) {\n\tconst fetcher = useFetcher<typeof action>()\n\n\tconst deleteEntry = (\n\t\tworkshopId: string,\n\t\tcacheName: string,\n\t\tfilename: string,\n\t) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-entry',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t\tfilename,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst deleteCache = (workshopId: string, cacheName: string) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-cache',\n\t\t\t\tworkshopId,\n\t\t\t\tcacheName,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst deleteWorkshopCache = (workshopId: string) => {\n\t\tvoid fetcher.submit(\n\t\t\t{\n\t\t\t\tintent: 'delete-workshop-cache',\n\t\t\t\tworkshopId,\n\t\t\t},\n\t\t\t{ method: 'POST' },\n\t\t)\n\t}\n\n\tconst {\n\t\tcurrentWorkshopId,\n\t\tfilteredCaches,\n\t\tfilterQuery,\n\t\tselectedWorkshops,\n\t\tavailableWorkshops,\n\t} = loaderData\n\n\treturn (\n\t\t<div className=\"space-y-6\">\n\t\t\t<div>\n\t\t\t\t<h2 className=\"mb-2 text-2xl font-bold\">Cache Management</h2>\n\t\t\t\t<p className=\"text-muted-foreground\">\n\t\t\t\t\tCurrent Workshop:{' '}\n\t\t\t\t\t<span className=\"text-foreground font-semibold\">\n\t\t\t\t\t\t{currentWorkshopId}\n\t\t\t\t\t</span>\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<WorkshopChooser\n\t\t\t\tselectedWorkshops={selectedWorkshops}\n\t\t\t\tavailableWorkshops={availableWorkshops}\n\t\t\t\tcurrentWorkshopId={currentWorkshopId}\n\t\t\t/>\n\n\t\t\t<SearchFilter filterQuery={filterQuery} />\n\n\t\t\t{fetcher.data?.status === 'success' ? (\n\t\t\t\t<div className=\"border-border bg-success text-success-foreground rounded border p-4\">\n\t\t\t\t\t{fetcher.data.message}\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{fetcher.data?.status === 'error' ? (\n\t\t\t\t<div className=\"border-border bg-destructive text-destructive-foreground rounded border p-4\">\n\t\t\t\t\t{fetcher.data.error}\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{filteredCaches.length === 0 ? (\n\t\t\t\t<div className=\"text-muted-foreground py-8 text-center\">\n\t\t\t\t\tNo caches found matching your criteria.\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t<div className=\"space-y-6\">\n\t\t\t\t{filteredCaches.map((workshopCache) => (\n\t\t\t\t\t<details\n\t\t\t\t\t\tkey={workshopCache.workshopId}\n\t\t\t\t\t\topen={workshopCache.workshopId === currentWorkshopId}\n\t\t\t\t\t>\n\t\t\t\t\t\t<summary className=\"border-border bg-card hover:bg-accent cursor-pointer rounded-lg border p-4\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t\t<h3 className=\"text-card-foreground flex items-center gap-2 text-lg font-semibold\">\n\t\t\t\t\t\t\t\t\t<Icon name=\"Files\" className=\"h-5 w-5\" />\n\t\t\t\t\t\t\t\t\t{workshopCache.workshopId === 'global'\n\t\t\t\t\t\t\t\t\t\t? 'Global Caches'\n\t\t\t\t\t\t\t\t\t\t: workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t{workshopCache.workshopId === currentWorkshopId ? (\n\t\t\t\t\t\t\t\t\t\t<span className=\"bg-primary text-primary-foreground rounded px-2 py-1 text-xs\">\n\t\t\t\t\t\t\t\t\t\t\tCurrent\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\tdeleteWorkshopCache(workshopCache.workshopId)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\ttitle=\"Delete all workshop caches\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</summary>\n\n\t\t\t\t\t\t<div className=\"mt-4 space-y-4 pl-4\">\n\t\t\t\t\t\t\t{workshopCache.caches.map((cache) => {\n\t\t\t\t\t\t\t\tconst totalSize = cache.entries.reduce(\n\t\t\t\t\t\t\t\t\t(sum, entry) => sum + (entry.size || 0),\n\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst skippedSize = (cache.skippedFiles || []).reduce(\n\t\t\t\t\t\t\t\t\t(sum, file) => sum + file.size,\n\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst grandTotal = totalSize + skippedSize\n\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<details key={cache.name} className=\"bg-muted rounded-md\">\n\t\t\t\t\t\t\t\t\t\t<summary className=\"hover:bg-accent cursor-pointer p-3\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t\t\t\t\t\t<h4 className=\"text-muted-foreground flex items-center gap-2 font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Files\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t{cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t({cache.entries.length} entr\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{cache.entries.length === 1 ? 'y' : 'ies'})\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{grandTotal > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t•{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span title={`${grandTotal} bytes`}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(grandTotal)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttotal\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{skippedSize > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-warning\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span title={`${skippedSize} bytes`}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(skippedSize)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>{' '}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tskipped)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t</h4>\n\t\t\t\t\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdeleteCache(workshopCache.workshopId, cache.name)\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Delete cache\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</summary>\n\n\t\t\t\t\t\t\t\t\t\t<div className=\"p-3 pt-0\">\n\t\t\t\t\t\t\t\t\t\t\t{cache.entries.length === 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-muted-foreground text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t\tNo entries match your search.\n\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t\t\t\t{cache.skippedFiles && cache.skippedFiles.length > 0 ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<SkippedFilesSection\n\t\t\t\t\t\t\t\t\t\t\t\t\tskippedFiles={cache.skippedFiles}\n\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopId={workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t\t\t\t\tcacheName={cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t\t\t\t\t\t{cache.entries.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\t({ key, entry, filename, size, filepath }) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-background rounded border p-3\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-start justify-between\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mb-1 flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"truncate font-mono text-sm font-medium\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{size ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"bg-muted text-muted-foreground inline-flex items-center rounded px-1.5 py-0.5 text-xs whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle={`${size} bytes`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(size)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<CacheMetadata metadata={entry.metadata} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"ml-4 flex shrink-0 gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thref={href('/admin/cache/*', {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'*': `${workshopCache.workshopId}/${cache.name}/${filename}`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-border bg-background text-foreground hover:bg-muted focus:ring-ring inline-flex h-8 w-8 items-center justify-center rounded border focus:ring-2 focus:outline-none\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"View JSON\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"ExternalLink\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{filepath ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfile={filepath}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={iconButtonClassName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname=\"Files\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Open in editor\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<DoubleCheckButton\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonConfirm={() =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdeleteEntry(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopCache.workshopId,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcache.name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfilename,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Delete entry\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Remove\" className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</DoubleCheckButton>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<InlineEntryEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tworkshopId={workshopCache.workshopId}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcacheName={cache.name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfilename={filename}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcurrentValue={entry.value}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tentryKey={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</details>\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</details>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Component for displaying cache metadata with live countdown\nfunction CacheMetadata({\n\tmetadata,\n}: {\n\tmetadata: {\n\t\tcreatedTime: number\n\t\tttl?: number | null\n\t\tswr?: number\n\t}\n}) {\n\tconst dayjs = useDayjs()\n\tconst [, setCurrentTime] = useState(Date.now())\n\tconst expirationTime = calculateExpirationTime(metadata)\n\n\t// Update time every second for live countdown\n\tuseInterval(() => {\n\t\tsetCurrentTime(Date.now())\n\t}, 1000)\n\n\tconst createdDate = dayjs(metadata.createdTime)\n\tconst timeRemaining = expirationTime\n\t\t? formatTimeRemaining(expirationTime)\n\t\t: { text: 'Never', isExpired: false, isExpiringSoon: false }\n\n\treturn (\n\t\t<div className=\"text-muted-foreground flex flex-col gap-1 text-xs\">\n\t\t\t<div>\n\t\t\t\tCreated: {createdDate.format('MMM D, YYYY HH:mm:ss')}{' '}\n\t\t\t\t<ClientOnly>{() => `(${createdDate.fromNow()})`}</ClientOnly>\n\t\t\t</div>\n\t\t\t<div className=\"flex flex-wrap items-center gap-3\">\n\t\t\t\t{metadata.ttl !== undefined && metadata.ttl !== null ? (\n\t\t\t\t\t<span>\n\t\t\t\t\t\tTTL:{' '}\n\t\t\t\t\t\t{metadata.ttl === Infinity ? (\n\t\t\t\t\t\t\t'Forever'\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<span title={`${metadata.ttl}ms`}>\n\t\t\t\t\t\t\t\t{formatDuration(metadata.ttl)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t{metadata.swr !== undefined ? (\n\t\t\t\t\t<span>\n\t\t\t\t\t\tSWR:{' '}\n\t\t\t\t\t\t<span title={`${metadata.swr}ms`}>\n\t\t\t\t\t\t\t{formatDuration(metadata.swr)}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t<div\n\t\t\t\t\tclassName={`inline-flex w-auto rounded-full px-2 py-[2px] font-medium ${\n\t\t\t\t\t\ttimeRemaining.isExpired\n\t\t\t\t\t\t\t? 'bg-destructive text-destructive-foreground'\n\t\t\t\t\t\t\t: timeRemaining.isExpiringSoon\n\t\t\t\t\t\t\t\t? 'bg-warning text-warning-foreground'\n\t\t\t\t\t\t\t\t: 'text-foreground'\n\t\t\t\t\t}`}\n\t\t\t\t>\n\t\t\t\t\t{expirationTime ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\tExpires: {dayjs(expirationTime).format('MMM D, YYYY HH:mm:ss')} (\n\t\t\t\t\t\t\t<span className=\"tabular-nums\">\n\t\t\t\t\t\t\t\t<ClientOnly>{() => timeRemaining.text}</ClientOnly>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'Expires: Never'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// Double-check delete button\nfunction DoubleCheckButton({\n\tonConfirm,\n\tchildren,\n\tclassName,\n\t...props\n}: React.ComponentPropsWithoutRef<'button'> & {\n\tonConfirm: () => void\n}) {\n\tconst doubleCheck = useDoubleCheck()\n\n\treturn (\n\t\t<IconButton\n\t\t\t{...doubleCheck.getButtonProps({\n\t\t\t\tonClick: doubleCheck.doubleCheck ? onConfirm : undefined,\n\t\t\t\t...props,\n\t\t\t})}\n\t\t\tclassName={cn(\n\t\t\t\tdoubleCheck.doubleCheck\n\t\t\t\t\t? 'bg-destructive text-destructive-foreground'\n\t\t\t\t\t: null,\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{doubleCheck.doubleCheck ? '✓' : children}\n\t\t</IconButton>\n\t)\n}\n"],"names":["WorkshopChooser","selectedWorkshops","availableWorkshops","currentWorkshopId","searchParams","setSearchParams","useSearchParams","handleWorkshopChange","workshop","checked","newSelected","filter","w","params","URLSearchParams","length","set","join","delete","jsxs","className","children","jsx","map","type","includes","onChange","e","target","SearchFilter","filterQuery","inputValue","setInputValue","useState","inputRef","useRef","useEffect","handleSearch","query","handleClear","current","focus","ref","placeholder","value","IconButton","onClick","title","Icon","name","InlineEntryEditor","workshopId","cacheName","filename","currentValue","entryKey","fetcher","useFetcher","editValue","setEditValue","JSON","stringify","hasChanges","setHasChanges","handleSave","submit","intent","newValue","method","handleChange","handleReset","Button","varient","disabled","state","SkippedFilesSection","skippedFiles","skippedFile","error","size","formatFileSize","DoubleCheckButton","onConfirm","cache","_UNSAFE_withComponentProps","loaderData","deleteEntry","deleteCache","deleteWorkshopCache","filteredCaches","data","status","message","workshopCache","open","caches","totalSize","entries","reduce","sum","entry","skippedSize","file","grandTotal","key","filepath","CacheMetadata","metadata","href","rel","LaunchEditor","iconButtonClassName","dayjs","useDayjs","setCurrentTime","Date","now","expirationTime","calculateExpirationTime","useInterval","createdDate","createdTime","timeRemaining","formatTimeRemaining","text","isExpired","isExpiringSoon","format","ClientOnly","fromNow","ttl","Infinity","formatDuration","swr","Fragment","props","doubleCheck","useDoubleCheck","getButtonProps","cn"],"mappings":"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"}
|