Separate mapping changes from view-stale: show Reprocess prompt instead of Generate
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ca266f2839
commit
9ab2052f2b
@ -33,6 +33,7 @@ export default function App() {
|
|||||||
// Sets of names whose dfv view is out of sync with current definitions
|
// Sets of names whose dfv view is out of sync with current definitions
|
||||||
const [staleSources, setStaleSources] = useState(new Set())
|
const [staleSources, setStaleSources] = useState(new Set())
|
||||||
const [staleStacks, setStaleStacks] = useState(new Set())
|
const [staleStacks, setStaleStacks] = useState(new Set())
|
||||||
|
const [reprocessSources, setReprocessSources] = useState(new Set())
|
||||||
const [generating, setGenerating] = useState({}) // { 'source:name': true }
|
const [generating, setGenerating] = useState({}) // { 'source:name': true }
|
||||||
|
|
||||||
async function handleLogin(user, pass) {
|
async function handleLogin(user, pass) {
|
||||||
@ -56,6 +57,7 @@ export default function App() {
|
|||||||
setSources([])
|
setSources([])
|
||||||
setStaleSources(new Set())
|
setStaleSources(new Set())
|
||||||
setStaleStacks(new Set())
|
setStaleStacks(new Set())
|
||||||
|
setReprocessSources(new Set())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load initial stale state from DB once on login
|
// Load initial stale state from DB once on login
|
||||||
@ -70,6 +72,17 @@ export default function App() {
|
|||||||
function markSourceStale(name) {
|
function markSourceStale(name) {
|
||||||
setStaleSources(prev => new Set([...prev, name]))
|
setStaleSources(prev => new Set([...prev, name]))
|
||||||
}
|
}
|
||||||
|
function markNeedsReprocess(name) {
|
||||||
|
setReprocessSources(prev => new Set([...prev, name]))
|
||||||
|
}
|
||||||
|
async function handleReprocessSource(name) {
|
||||||
|
setGenerating(g => ({ ...g, [`rp:${name}`]: true }))
|
||||||
|
try {
|
||||||
|
await api.reprocess(name)
|
||||||
|
setReprocessSources(prev => { const n = new Set(prev); n.delete(name); return n })
|
||||||
|
} catch (e) { alert(e.message) }
|
||||||
|
finally { setGenerating(g => { const n = { ...g }; delete n[`rp:${name}`]; return n }) }
|
||||||
|
}
|
||||||
function markStackStale(name) {
|
function markStackStale(name) {
|
||||||
setStaleStacks(prev => new Set([...prev, name]))
|
setStaleStacks(prev => new Set([...prev, name]))
|
||||||
}
|
}
|
||||||
@ -214,6 +227,23 @@ export default function App() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{reprocessSources.size > 0 && (
|
||||||
|
<div className="bg-blue-50 border-b border-blue-200 px-4 py-1.5 text-xs text-blue-800 flex flex-wrap items-center gap-x-3 gap-y-1">
|
||||||
|
<span className="font-medium">Mappings updated:</span>
|
||||||
|
{[...reprocessSources].map(name => (
|
||||||
|
<span key={name} className="flex items-center gap-1">
|
||||||
|
{name}
|
||||||
|
<button
|
||||||
|
onClick={() => handleReprocessSource(name)}
|
||||||
|
disabled={generating[`rp:${name}`]}
|
||||||
|
className="px-1.5 py-0.5 rounded bg-blue-200 hover:bg-blue-300 disabled:opacity-50 font-medium"
|
||||||
|
>
|
||||||
|
{generating[`rp:${name}`] ? '…' : 'Reprocess'}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex-1 overflow-auto">
|
<div className="flex-1 overflow-auto">
|
||||||
<Routes>
|
<Routes>
|
||||||
@ -221,7 +251,7 @@ export default function App() {
|
|||||||
<Route path="/sources" element={<Sources source={source} sources={sources} setSources={setSources} setSource={setSource} />} />
|
<Route path="/sources" element={<Sources source={source} sources={sources} setSources={setSources} setSource={setSource} />} />
|
||||||
<Route path="/import" element={<Import source={source} />} />
|
<Route path="/import" element={<Import source={source} />} />
|
||||||
<Route path="/rules" element={<Rules source={source} onStale={markSourceStale} />} />
|
<Route path="/rules" element={<Rules source={source} onStale={markSourceStale} />} />
|
||||||
<Route path="/mappings" element={<Mappings source={source} onStale={markSourceStale} />} />
|
<Route path="/mappings" element={<Mappings source={source} onNeedsReprocess={markNeedsReprocess} />} />
|
||||||
<Route path="/remap" element={<Remap />} />
|
<Route path="/remap" element={<Remap />} />
|
||||||
<Route path="/records" element={<Records source={source} />} />
|
<Route path="/records" element={<Records source={source} />} />
|
||||||
<Route path="/pivot" element={<Pivot source={source} />} />
|
<Route path="/pivot" element={<Pivot source={source} />} />
|
||||||
|
|||||||
@ -109,7 +109,7 @@ function SortHeader({ col, label, sortBy, onSort, className = '' }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Mappings({ source, onStale }) {
|
export default function Mappings({ source, onNeedsReprocess }) {
|
||||||
const [rules, setRules] = useState([])
|
const [rules, setRules] = useState([])
|
||||||
const [selectedRule, setSelectedRule] = useState('')
|
const [selectedRule, setSelectedRule] = useState('')
|
||||||
const [allValues, setAllValues] = useState([])
|
const [allValues, setAllValues] = useState([])
|
||||||
@ -268,7 +268,7 @@ export default function Mappings({ source, onStale }) {
|
|||||||
valueKey(x.extracted_value) === k ? { ...x, is_mapped: true, mapping_id: created.id, output } : x
|
valueKey(x.extracted_value) === k ? { ...x, is_mapped: true, mapping_id: created.id, output } : x
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
onStale?.(source)
|
onNeedsReprocess?.(source)
|
||||||
setDrafts(d => { const n = { ...d }; delete n[k]; return n })
|
setDrafts(d => { const n = { ...d }; delete n[k]; return n })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(err.message)
|
alert(err.message)
|
||||||
@ -315,7 +315,7 @@ export default function Mappings({ source, onStale }) {
|
|||||||
setSaving(s => ({ ...s, [k]: false }))
|
setSaving(s => ({ ...s, [k]: false }))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
onStale?.(source)
|
onNeedsReprocess?.(source)
|
||||||
setSelected(new Set())
|
setSelected(new Set())
|
||||||
setBulkDraft({})
|
setBulkDraft({})
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ export default function Mappings({ source, onStale }) {
|
|||||||
if (!row.mapping_id) return
|
if (!row.mapping_id) return
|
||||||
try {
|
try {
|
||||||
await api.deleteMapping(row.mapping_id)
|
await api.deleteMapping(row.mapping_id)
|
||||||
onStale?.(source)
|
onNeedsReprocess?.(source)
|
||||||
setAllValues(av => av.map(x =>
|
setAllValues(av => av.map(x =>
|
||||||
valueKey(x.extracted_value) === valueKey(row.extracted_value)
|
valueKey(x.extracted_value) === valueKey(row.extracted_value)
|
||||||
? { ...x, is_mapped: false, mapping_id: null, output: null }
|
? { ...x, is_mapped: false, mapping_id: null, output: null }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user