feat(review): remove species picker; species stays from Measure
Species is chosen on the merged Measure screen; the Review select was a duplicate. Keep species_id on the slab from createSlab (Capture→draft→Woo) and gate Create title from the hydrated value without offering edit.
This commit is contained in:
@@ -118,7 +118,7 @@ export type Capture =
|
||||
axis: Axis; // editable tape until Calculate; frozen after results
|
||||
lengthEighths: Eighths;
|
||||
thicknessEighths: Eighths;
|
||||
/** Woo species leaf id; optional until Review. Persisted on draft + createSlab. */
|
||||
/** Woo species leaf id; set on Measure. Persisted on draft + createSlab; Review does not edit. */
|
||||
speciesId: number | null;
|
||||
results: Measures | null;
|
||||
/** Capture-order sibling results from the post-Calculate batch pass. */
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { PhotosReadyLineupItem } from '../capture/photosReadyLineup';
|
||||
export interface CalibratedCapture {
|
||||
lengthIn: number;
|
||||
thicknessIn: number;
|
||||
/** Woo species leaf from Measure; null if unset. Review can still change. */
|
||||
/** Woo species leaf from Measure; null if unset. Review does not edit. */
|
||||
speciesId: number | null;
|
||||
sqft: number;
|
||||
bdft: number;
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
};
|
||||
|
||||
// --- Derived taxonomy option lists (resolve by slug, never hardcoded ids) ---
|
||||
let speciesOpts: Opt[] = [];
|
||||
let woodCatGroups: import('./MultiSelect.svelte').Group[] = [];
|
||||
let edgeOpts: Opt[] = [];
|
||||
let figureOpts: Opt[] = [];
|
||||
@@ -47,10 +46,9 @@
|
||||
function deriveOptions() {
|
||||
if (!tax) return;
|
||||
const cats: TaxCategory[] = tax.categories;
|
||||
// Resolve the two top-level groupers BY SLUG (QUALITY-105 / METADATA-5 — never
|
||||
// hardcode live Woo term ids): `species` → species options; `wcat` → wood
|
||||
// categories. Both are parent_id:null groupers; their children are the leaves.
|
||||
const speciesGrouper = cats.find((c) => c.parent_id === null && c.slug === 'species');
|
||||
// Resolve the wood-category grouper BY SLUG (QUALITY-105 / METADATA-5 — never
|
||||
// hardcode live Woo term ids). Species is chosen on Measure and is not editable
|
||||
// on Review; only `wcat` leaves are listed here.
|
||||
const wcatGrouper = cats.find((c) => c.parent_id === null && c.slug === 'wcat');
|
||||
const childrenOf = (g: TaxCategory | undefined): TaxCategory[] =>
|
||||
g ? cats.filter((c) => c.parent_id === g.id) : [];
|
||||
@@ -67,7 +65,6 @@
|
||||
return { id: t.id, name: t.name, ai: false, lowIn: Number.isFinite(lowIn) ? lowIn : undefined };
|
||||
});
|
||||
};
|
||||
speciesOpts = childrenOf(speciesGrouper).map((c) => ({ id: c.id, name: c.name, ai: false }));
|
||||
// Wood categories: parent/child grouped (METADATA-10 — parents group only, never
|
||||
// assigned). Each direct child of `wcat` that has its own children becomes a parent
|
||||
// group with those children as leaves; a child with no children is a leaf under the
|
||||
@@ -94,12 +91,14 @@
|
||||
}
|
||||
|
||||
// --- Editable model (mirrors the live slab) ---
|
||||
// Species is set on Measure / createSlab — Review only reads it (no picker).
|
||||
// Kept as a string so canCreateTitle can gate on a non-empty value from hydrate.
|
||||
let speciesSel: string = '';
|
||||
// #90: single-selects bind a STRING var to the native <select>, because
|
||||
// <option value={id}> coerces the option value to a string. Binding a
|
||||
// `number | ''` var directly to those string values is the classic
|
||||
// number/string mismatch that leaves the selected option blank after AI
|
||||
// prefill or reload. `Number(...)` at commit normalizes back.
|
||||
let speciesSel: string = '';
|
||||
let edgeSel: string = '';
|
||||
let gradeSel: string = '';
|
||||
let woodCatIds: number[] = [];
|
||||
@@ -126,9 +125,10 @@
|
||||
let reviewBusy = false;
|
||||
let reviewError = '';
|
||||
// #89: explicit "Create" actions. `createBusy` covers the deterministic
|
||||
// title/short-desc generation; `canCreateTitle` is its gate (species + ≥1 wood
|
||||
// category). `canCreateDesc` gates the AI long-description on title+short-desc
|
||||
// being populated AND the content LLM being enabled.
|
||||
// title/short-desc generation; `canCreateTitle` is its gate (species already
|
||||
// on the slab from Measure + ≥1 wood category). `canCreateDesc` gates the AI
|
||||
// long-description on title+short-desc being populated AND the content LLM
|
||||
// being enabled.
|
||||
let createBusy = false;
|
||||
let createError = '';
|
||||
$: canCreateTitle =
|
||||
@@ -345,7 +345,6 @@
|
||||
}
|
||||
|
||||
// AI-marked option views (legacy Call 1 badges; Call 1 disabled on this branch).
|
||||
$: speciesOptsView = speciesOpts.map((o) => ({ ...o, ai: aiRecommendations.includes(o.id) }));
|
||||
$: woodCatGroupsView = woodCatGroups.map((g) => ({
|
||||
parent: g.parent,
|
||||
leaves: g.leaves.map((o) => ({ ...o, ai: aiRecommendations.includes(o.id) })),
|
||||
@@ -390,8 +389,9 @@
|
||||
if (probe.title && title === '') title = probe.title;
|
||||
if (probe.short_description && shortDescription === '') shortDescription = probe.short_description;
|
||||
|
||||
// species_id intentionally omitted — set at createSlab from Measure; Review
|
||||
// must not clear or re-edit it.
|
||||
const patch = {
|
||||
species_id: speciesSel === '' ? null : Number(speciesSel),
|
||||
wood_category_ids: woodCatIds,
|
||||
edge_type_term_id: edgeSel === '' ? null : Number(edgeSel),
|
||||
figure_term_ids: figureIds,
|
||||
@@ -539,11 +539,9 @@
|
||||
// option matches the bound value. Idempotent: only writes when they differ.
|
||||
async function syncSelects() {
|
||||
await tick();
|
||||
if (speciesEl && speciesEl.value !== speciesSel) speciesEl.value = speciesSel;
|
||||
if (edgeEl && edgeEl.value !== edgeSel) edgeEl.value = edgeSel;
|
||||
if (gradeEl && gradeEl.value !== gradeSel) gradeEl.value = gradeSel;
|
||||
}
|
||||
let speciesEl: HTMLSelectElement | undefined;
|
||||
let edgeEl: HTMLSelectElement | undefined;
|
||||
let gradeEl: HTMLSelectElement | undefined;
|
||||
/** Wood categories: toggle leaf + keep primary valid (REVIEW-15 / wireframe #90). */
|
||||
@@ -652,17 +650,7 @@
|
||||
{/if}
|
||||
|
||||
<!-- Call 1 OUT (overnight-whole-app): Suggest-with-AI removed. Call 2 generateContent stays. -->
|
||||
|
||||
<!-- Species (single, AI-assist) -->
|
||||
<div class="field">
|
||||
<label class="lbl" for="species">Species <span class="ai">AI assist</span></label>
|
||||
<select id="species" class="sel" data-testid="species" bind:this={speciesEl} bind:value={speciesSel} on:change={commitReview}>
|
||||
<option value="">— select —</option>
|
||||
{#each speciesOpts as o (o.id)}
|
||||
<option value={o.id} data-ai={aiRecommendations.includes(o.id) ? 'true' : ''}>{o.name}{aiRecommendations.includes(o.id) ? ' (AI)' : ''}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
<!-- Species: chosen on Measure; no Review picker (value stays on the slab from createSlab). -->
|
||||
|
||||
<!-- Wood categories (multi + inline primary radio set, REVIEW-15 / #90 wireframe) -->
|
||||
<div class="field" data-testid="wood-cat-field">
|
||||
|
||||
Reference in New Issue
Block a user