v7.20.1 — Directory Get save-on-demand: explicit Save button (left of Open in editor) files fetched scripts into root/user created/OVE-Directory; no more auto-save on Get
This commit is contained in:
parent
65d4f91be6
commit
1afece5a9b
4 changed files with 155 additions and 29 deletions
|
|
@ -5,13 +5,14 @@
|
|||
// type, its date, and its star rating. Visitors rate entries 1–5 (one vote
|
||||
// per script per visitor, enforced upstream), see the live average to the
|
||||
// right of the stars, sort the whole list by Name / Type / Date / Rating,
|
||||
// and "Get" any entry: the hash string is fetched, decoded back into the
|
||||
// exact script, and filed in this browser's preset tree under
|
||||
// "root/user created/OVE-Directory" -- from where it opens in the editor.
|
||||
// v7.20: each entry card is compact -- the Get button sits at the card's
|
||||
// top right with the date immediately to its left, so the rating row never
|
||||
// wraps the button onto its own line (the card dropped from ~126 px to
|
||||
// ~94 px at the sidebar width).
|
||||
// and "Get" any entry: the hash string is fetched and decoded back into the
|
||||
// exact script. v7.20: each entry card is compact -- the Get button sits at
|
||||
// the card's top right with the date immediately to its left, so the rating
|
||||
// row never wraps the button onto its own line (the card dropped from
|
||||
// ~126 px to ~94 px at the sidebar width). v7.20.1: Get no longer files the
|
||||
// script into the preset tree automatically -- the panel carries an
|
||||
// explicit Save button (left of Open in editor) that places the preset
|
||||
// under "root/user created/OVE-Directory" on demand, deduped by content.
|
||||
|
||||
'use client'
|
||||
|
||||
|
|
@ -24,6 +25,7 @@ import {
|
|||
FileCode2,
|
||||
Loader2,
|
||||
RefreshCw,
|
||||
Save,
|
||||
Star,
|
||||
TriangleAlert,
|
||||
} from 'lucide-react'
|
||||
|
|
@ -78,8 +80,10 @@ interface GotPanel {
|
|||
hash: string
|
||||
script: string
|
||||
compiles: boolean
|
||||
savedAs: string
|
||||
alreadyHad: boolean
|
||||
/** Name the preset was saved under; null until the Save button is hit. */
|
||||
savedAs: string | null
|
||||
/** Whether a content-identical preset was already in the folder; null unsaved. */
|
||||
alreadyHad: boolean | null
|
||||
}
|
||||
|
||||
// ── one directory row ─────────────────────────────────────────────────────
|
||||
|
|
@ -148,6 +152,7 @@ function DirRow({
|
|||
got,
|
||||
onVote,
|
||||
onGet,
|
||||
onSave,
|
||||
}: {
|
||||
entry: DirMeta
|
||||
myVote: number
|
||||
|
|
@ -156,6 +161,7 @@ function DirRow({
|
|||
got: GotPanel | null
|
||||
onVote: (stars: number) => void
|
||||
onGet: () => void
|
||||
onSave: () => void
|
||||
}) {
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
|
|
@ -205,7 +211,7 @@ function DirRow({
|
|||
variant="outline"
|
||||
onClick={onGet}
|
||||
className="h-7 gap-1 border-zinc-700 px-2.5 text-[11px]"
|
||||
title="Fetch this script: it's saved to this browser's presets and can open in the editor"
|
||||
title="Fetch this script -- then Save it to your presets or open it in the editor"
|
||||
>
|
||||
{got ? <Check className="size-3.5 text-emerald-400" aria-hidden /> : <Download className="size-3.5" aria-hidden />}
|
||||
{got ? 'Get again' : 'Get'}
|
||||
|
|
@ -213,6 +219,8 @@ function DirRow({
|
|||
)}
|
||||
</span>
|
||||
</div>
|
||||
{/* v7.20.1 -- the whole card body below stays identical; only the
|
||||
got-panel footer grows the Save button. */}
|
||||
|
||||
<div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1.5">
|
||||
<StarRow entry={entry} myVote={myVote} busy={voting} onVote={onVote} />
|
||||
|
|
@ -225,13 +233,20 @@ function DirRow({
|
|||
{got && (
|
||||
<div className="mt-3 space-y-2 border-t border-zinc-800 pt-3">
|
||||
<p className="text-[11px] leading-relaxed text-zinc-400">
|
||||
{got.alreadyHad ? (
|
||||
{got.savedAs ? (
|
||||
got.alreadyHad ? (
|
||||
<>You already had this exact script -- no duplicate was made.</>
|
||||
) : (
|
||||
<>
|
||||
Saved to your presets as <span className="text-emerald-300">{got.savedAs}</span> in{' '}
|
||||
<span className="font-mono">{DOWNLOAD_FOLDER}</span>.
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
Fetched -- not saved yet. Hit <span className="text-emerald-300">Save</span> to keep it in{' '}
|
||||
<span className="font-mono">{DOWNLOAD_FOLDER}</span>, or open it in the editor.
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
<div className="space-y-1">
|
||||
|
|
@ -262,6 +277,31 @@ function DirRow({
|
|||
<FileCode2 className="size-3.5 shrink-0" aria-hidden />
|
||||
{got.compiles ? 'Decodes and compiles OK' : "Decodes, but doesn't compile (yet)"}
|
||||
</p>
|
||||
{/* v7.20.1 -- Save (left) places the preset into the user's
|
||||
"user created/OVE-Directory" folder; Open in editor (right)
|
||||
just loads the script text into the editor. After saving, the
|
||||
button turns into a static Saved badge (the content-twin check
|
||||
makes repeat saves a no-op anyway). */}
|
||||
<span className="flex shrink-0 items-center gap-2">
|
||||
{got.savedAs ? (
|
||||
<span
|
||||
role="status"
|
||||
title={`This preset is in ${DOWNLOAD_FOLDER}`}
|
||||
className="flex h-8 items-center gap-1.5 rounded-md border border-emerald-400/30 bg-emerald-400/10 px-3 text-xs font-semibold text-emerald-300"
|
||||
>
|
||||
<Check className="size-3.5" aria-hidden /> Saved
|
||||
</span>
|
||||
) : (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={onSave}
|
||||
className="h-8 gap-1.5 border-emerald-400/40 bg-emerald-400/10 px-3 text-xs font-semibold text-emerald-300 hover:bg-emerald-400/20 hover:text-emerald-200"
|
||||
title={`Save this preset into ${DOWNLOAD_FOLDER}`}
|
||||
>
|
||||
<Save className="size-3.5" aria-hidden /> Save
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={openInEditor}
|
||||
|
|
@ -270,6 +310,7 @@ function DirRow({
|
|||
>
|
||||
<FileCode2 className="size-3.5" aria-hidden /> Open in editor
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -348,6 +389,8 @@ export function DirectoryTab() {
|
|||
[voting, toast],
|
||||
)
|
||||
|
||||
// v7.20.1 -- Get only fetches + decodes + previews. The Save button (per
|
||||
// row, in the got panel) does the filing into the preset tree on demand.
|
||||
const get = useCallback(
|
||||
async (entry: DirMeta) => {
|
||||
if (getting !== null) return
|
||||
|
|
@ -357,21 +400,19 @@ export function DirectoryTab() {
|
|||
const decoded = decodeScriptHash(full.hash)
|
||||
if (!decoded.ok) throw new Error('The stored share string did not decode -- it may be corrupted.')
|
||||
const v = validateScript(decoded.script)
|
||||
const save = saveDownloadedPreset(decoded.script, entry.name)
|
||||
if (!save.ok) throw new Error(save.error ?? 'Could not save to this browser.')
|
||||
setGot((prev) => ({
|
||||
...prev,
|
||||
[entry.id]: {
|
||||
hash: full.hash,
|
||||
script: decoded.script,
|
||||
compiles: v.ok,
|
||||
savedAs: save.preset?.name ?? entry.name,
|
||||
alreadyHad: Boolean(save.alreadyHad),
|
||||
savedAs: null,
|
||||
alreadyHad: null,
|
||||
},
|
||||
}))
|
||||
toast({
|
||||
title: save.alreadyHad ? 'Already in your presets' : 'Saved to your presets',
|
||||
description: `"${save.preset?.name ?? entry.name}" -- open it in the editor from the panel below, or hit Apply after switching to the Script tab.`,
|
||||
title: 'Fetched from the directory',
|
||||
description: `"${entry.name}" -- Save it to your presets or open it in the editor.`,
|
||||
})
|
||||
} catch (e) {
|
||||
toast({
|
||||
|
|
@ -386,6 +427,36 @@ export function DirectoryTab() {
|
|||
[getting, toast],
|
||||
)
|
||||
|
||||
// v7.20.1 -- the explicit Save: files the fetched script into this
|
||||
// browser's preset tree under root/user created/OVE-Directory, deduped
|
||||
// by exact content (a twin already in the folder is reported, not copied).
|
||||
// Synchronous (localStorage), so no busy state to track.
|
||||
const save = useCallback(
|
||||
(entry: DirMeta) => {
|
||||
const panel = got[entry.id]
|
||||
if (!panel || panel.savedAs) return
|
||||
const res = saveDownloadedPreset(panel.script, entry.name)
|
||||
if (!res.ok) {
|
||||
toast({
|
||||
title: 'Save failed',
|
||||
description: res.error ?? 'Could not save to this browser.',
|
||||
variant: 'destructive',
|
||||
})
|
||||
return
|
||||
}
|
||||
const savedAs = res.preset?.name ?? entry.name
|
||||
setGot((prev) => ({
|
||||
...prev,
|
||||
[entry.id]: { ...panel, savedAs, alreadyHad: Boolean(res.alreadyHad) },
|
||||
}))
|
||||
toast({
|
||||
title: res.alreadyHad ? 'Already in your presets' : 'Saved to your presets',
|
||||
description: `"${savedAs}" in ${DOWNLOAD_FOLDER}.`,
|
||||
})
|
||||
},
|
||||
[got, toast],
|
||||
)
|
||||
|
||||
const online = status?.status === 'ok'
|
||||
|
||||
return (
|
||||
|
|
@ -492,6 +563,7 @@ export function DirectoryTab() {
|
|||
got={got[entry.id] ?? null}
|
||||
onVote={(stars) => void vote(entry, stars)}
|
||||
onGet={() => void get(entry)}
|
||||
onSave={() => save(entry)}
|
||||
/>
|
||||
))}
|
||||
<p className="flex items-center justify-center gap-1.5 pt-1 text-center font-mono text-[11px] text-zinc-600">
|
||||
|
|
|
|||
|
|
@ -39,6 +39,16 @@ export interface ReleaseNote {
|
|||
}
|
||||
|
||||
export const RELEASE_NOTES: ReleaseNote[] = [
|
||||
{
|
||||
version: '7.20.1',
|
||||
name: 'Directory Gets save on demand',
|
||||
changes: [
|
||||
{
|
||||
kind: 'improved',
|
||||
text: 'Getting a script from the Directory no longer drops it into the preset tree on its own. The Get panel now has a Save button right beside Open in editor -- I fetch first, look over the share string and the compile status, and only when I hit Save does the preset land in root/user created/OVE-Directory. Saving twice never makes a duplicate, and the button settles into a quiet Saved badge once it\'s filed.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
version: '7.20.0',
|
||||
name: 'Paste-to-decode + a compact Directory',
|
||||
|
|
|
|||
|
|
@ -12,6 +12,22 @@
|
|||
// warns in the console when the two drift apart.
|
||||
//
|
||||
// History:
|
||||
// 7.20.1 — Directory Get save-on-demand (user request): clicking Get on a
|
||||
// directory entry no longer files the script into the preset tree
|
||||
// automatically -- the got panel now carries an explicit Save
|
||||
// button, placed left of "Open in editor" in the panel footer,
|
||||
// that places the preset under root/user created/OVE-Directory on
|
||||
// demand (saveDownloadedPreset, deduped by exact content so repeat
|
||||
// saves never make a duplicate; an identical twin already in the
|
||||
// folder is reported as "Already in your presets", no copy).
|
||||
// After saving, the button becomes a static "Saved" badge. Get
|
||||
// itself now only fetches + decodes + previews (toast "Fetched
|
||||
// from the directory"); Open in editor stays exactly as it was
|
||||
// (loads the script text into the editor, saves nothing). GotPanel's
|
||||
// savedAs/alreadyHad became string|null / boolean|null (null until
|
||||
// the Save button is hit). Version bump with matching release note;
|
||||
// EMBEDDED_SEED_VERSION untouched (7.19.0 -- the library did not
|
||||
// change).
|
||||
// 7.20 — Paste-to-decode + compact Directory cards (user request, three
|
||||
// items). (1) Script editor: pasting a share string straight into
|
||||
// the editor textarea now decodes it in place -- onPaste runs
|
||||
|
|
@ -674,4 +690,4 @@
|
|||
|
||||
export const APP_NAME = 'Open Visualization Engine'
|
||||
export const APP_SHORT = 'OVE'
|
||||
export const APP_VERSION = '7.20.0'
|
||||
export const APP_VERSION = '7.20.1'
|
||||
|
|
|
|||
28
worklog.md
28
worklog.md
|
|
@ -2849,3 +2849,31 @@ The persistence chain is now end-to-end: every future sandbox reprovision restor
|
|||
|
||||
Stage Summary:
|
||||
- PUSH DELIVERED: origin/zai-dev now at 631642d+ (v7.18.0 + v7.19.0 x2 + v7.20.0 + worklogs), authenticated with the operator-supplied scoped token, which was used once as a throwaway HTTP header and never stored anywhere. origin/main remains protected at bbbee3c -- merging zai-dev into main (PR or local merge + push from an authorized lane) is the one remaining operator-side step if they want main current.
|
||||
|
||||
---
|
||||
Task ID: 58
|
||||
Agent: main (Z.ai Code)
|
||||
Task: v7.20.1 (user request): "On the Directory tab, when the user clicks the 'Get' button, there needs to be a 'Save' button to the left of the 'Open in Editor' button that will place the preset into the users 'user created' 'OVE-Directory' path. With this, let's bump the version to 7.20.1."
|
||||
|
||||
Behavior change (directory-tab.tsx):
|
||||
- Get is now fetch + decode + preview ONLY: the got panel opens with "Fetched -- not saved yet. Hit Save to keep it in root/user created/OVE-Directory, or open it in the editor." and the toast "Fetched from the directory". saveDownloadedPreset moved out of the get callback entirely.
|
||||
- New explicit Save button in the panel footer, LEFT of "Open in editor" (outline + emerald accent + lucide Save icon, title "Save this preset into root/user created/OVE-Directory"). It calls a new save callback: saveDownloadedPreset(script, entry.name) -- the existing v7.11 helper that files the preset under root/user created/OVE-Directory with unique-name numbering, deduped by exact content. Toast "Saved to your presets" / "Already in your presets"; the panel intro flips to the saved wording; the button becomes a static "Saved ✓" badge (role=status) so it cannot double-fire. "Open in editor" is unchanged: loads the script text into the editor, saves nothing.
|
||||
- GotPanel.savedAs/alreadyHad became string|null / boolean|null (null until Save is hit). Get-again resets them to null (Save button returns; the content-twin dedup keeps re-saves no-ops).
|
||||
- Mid-task bug caught by E2E: first edit round added onSave to the props TYPE but not the destructuring -> ReferenceError "onSave is not defined" crashed the DirectoryTab render the moment a got panel appeared (articles vanished; a stale-Fast-Refresh red herring initially pointed elsewhere). One-line fix; lint clean after.
|
||||
|
||||
Version: version.ts APP_VERSION 7.20.0 -> 7.20.1 + full history entry; release-notes.ts 7.20.1 "Directory Gets save on demand" (improved, first person, plain double minus). EMBEDDED_SEED_VERSION untouched at 7.19.0 (library unchanged, no re-seed).
|
||||
|
||||
BROWSER E2E (agent-browser, ALL PASS after the fix):
|
||||
- Baseline: OVE-Directory folder empty in localStorage; title v7.20.1.
|
||||
- Get on Aqua-Burst: panel intro "Fetched -- not saved yet...", buttons in order [Copy, Save, Open in editor] (Save LEFT of Open in editor verified by index), localStorage still empty -- no auto-save.
|
||||
- Save: localStorage gains "Aqua-Burst" under root/user created/OVE-Directory; panel intro "Saved to your presets as Aqua-Burst in root/user created/OVE-Directory."; Save button replaced by the "Saved" badge; Open in editor still present.
|
||||
- Get again: panel resets to unsaved with the Save button back; Save again -> "You already had this exact script -- no duplicate was made.", folder still exactly 1 preset (content-twin dedup held).
|
||||
- Toasts confirmed live: "Fetched from the directory | 'Aqua-Burst' -- Save it to your presets or open it in the editor." and "Already in your presets | 'Aqua-Burst' in root/user created/OVE-Directory."
|
||||
- Open in editor: switches to the Script tab with the decoded script loaded (2,663 chars, name + [frame] sections).
|
||||
- Presets tab: root -> user created -> OVE-Directory -> Aqua-Burst ("Your preset, stored in this browser") -- the exact path requested.
|
||||
- What's New: 7.20.1 "Directory Gets save on demand" CURRENT, 7.20.0 below it. No console errors; footer flush (docH 577 = innerH 577, footer bottom = docH), no horizontal scroll; bun run lint clean; dev.log all 200s (list + status + two script fetches).
|
||||
|
||||
Delivery: committed and pushed to origin/zai-dev with the operator's token from Task 57 (same one-off http.extraheader pattern, never stored).
|
||||
|
||||
Stage Summary:
|
||||
- v7.20.1 shipped: Directory Gets are save-on-demand. The Get panel's new Save button (left of Open in editor) places the fetched script into root/user created/OVE-Directory on click, deduped by content, with a Saved badge confirming it; Get itself no longer auto-files anything. Verified end-to-end in the browser and pushed to the remote.
|
||||
|
|
|
|||
Loading…
Reference in a new issue