feat(library,bins): inline bin creation in the left rail
Library's Bins section now always renders (not just when bins exist) with a + button that prompts for a name and POSTs /api/v1/bins with the open project's id. Bins re-fetch on project change so the rail shows project-scoped bins when a project is open, or global view otherwise. Bins list now hydrates from local state instead of stale ZAMPP_DATA so newly-created bins appear without a full reload. Without an open project the + button is dimmed with a helpful tooltip — "Open a project to create a bin".
This commit is contained in:
parent
7170a9945c
commit
13906cd0fe
1 changed files with 63 additions and 16 deletions
|
|
@ -1,7 +1,45 @@
|
|||
// screens-library.jsx
|
||||
|
||||
function Library({ navigate, onOpenAsset, openProject }) {
|
||||
const { BINS, PROJECTS } = window.ZAMPP_DATA;
|
||||
const PROJECTS = window.ZAMPP_DATA?.PROJECTS || [];
|
||||
const [bins, setBins] = React.useState(window.ZAMPP_DATA?.BINS || []);
|
||||
const BINS = bins; // legacy local name; keep so the rest of the function reads unchanged
|
||||
|
||||
// Re-fetch bins on mount + whenever the open project changes; surfaces
|
||||
// every-project bins when the global view is on, project-scoped otherwise.
|
||||
React.useEffect(() => {
|
||||
const qs = openProject ? '?project_id=' + openProject.id : '';
|
||||
window.ZAMPP_API.fetch('/bins' + qs)
|
||||
.then(list => {
|
||||
const normalized = (list || []).map(b => ({
|
||||
...b,
|
||||
count: b.asset_count != null ? b.asset_count : (b.count || 0),
|
||||
icon: b.type || 'grid',
|
||||
}));
|
||||
if (!openProject) window.ZAMPP_DATA.BINS = normalized;
|
||||
setBins(normalized);
|
||||
})
|
||||
.catch(() => {});
|
||||
}, [openProject]);
|
||||
|
||||
const createBin = () => {
|
||||
if (!openProject) {
|
||||
window.alert('Open a project first (Projects → click a project), then create a bin inside it.');
|
||||
return;
|
||||
}
|
||||
const name = prompt('Bin name', '');
|
||||
if (!name || !name.trim()) return;
|
||||
window.ZAMPP_API.fetch('/bins', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ project_id: openProject.id, name: name.trim() }),
|
||||
})
|
||||
.then(() => {
|
||||
// Re-fetch project-scoped list to get the count column.
|
||||
window.ZAMPP_API.fetch('/bins?project_id=' + openProject.id)
|
||||
.then(list => setBins((list || []).map(b => ({ ...b, count: b.asset_count || 0, icon: b.type || 'grid' }))));
|
||||
})
|
||||
.catch(e => window.alert('Could not create bin: ' + e.message));
|
||||
};
|
||||
const [view, setView] = React.useState('grid');
|
||||
const [filter, setFilter] = React.useState('all');
|
||||
const [search, setSearch] = React.useState(window._dfPendingSearch || '');
|
||||
|
|
@ -79,22 +117,31 @@ function Library({ navigate, onOpenAsset, openProject }) {
|
|||
})}
|
||||
</div>
|
||||
</div>
|
||||
{BINS.length > 0 && (
|
||||
<div>
|
||||
<h4>Bins</h4>
|
||||
<div className="rail-list">
|
||||
{BINS.map(function(b) {
|
||||
return (
|
||||
<div key={b.id} className="rail-item">
|
||||
<Icon name={binIcon(b.icon)} size={13} className="rail-icon" />
|
||||
<span>{b.name}</span>
|
||||
<span className="rail-count">{b.count}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<h4 style={{ flex: 1, margin: 0 }}>Bins</h4>
|
||||
<button className="icon-btn" onClick={createBin}
|
||||
title={openProject ? 'Create bin in this project' : 'Open a project to create a bin'}
|
||||
style={{ opacity: openProject ? 1 : 0.5 }}>
|
||||
<Icon name="plus" size={11} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div className="rail-list">
|
||||
{BINS.length === 0 ? (
|
||||
<div style={{ fontSize: 11, color: 'var(--text-3)', padding: '6px 8px', fontStyle: 'italic' }}>
|
||||
{openProject ? 'No bins yet — click + to create one.' : 'Open a project to manage bins.'}
|
||||
</div>
|
||||
) : BINS.map(function(b) {
|
||||
return (
|
||||
<div key={b.id} className="rail-item">
|
||||
<Icon name={binIcon(b.icon)} size={13} className="rail-icon" />
|
||||
<span>{b.name}</span>
|
||||
<span className="rail-count">{b.count}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Smart filters</h4>
|
||||
<div className="rail-list">
|
||||
|
|
|
|||
Loading…
Reference in a new issue