feat(iace): surface OSHA distance anchor in Maßnahmen tab (name-resolved)
Makes the OSHA minimum-distance anchor visible per measure in a project without a DB schema change or re-seed: persisted mitigations store the measure NAME verbatim (not the catalog ID), and measure names are unique across the 578-entry library (pinned by test), so a name→ID resolver bridges the gap. Backend: MeasureIDByName + MinimumDistancesForMeasureName/LinksForMeasureName; /iace/minimum-distances now accepts ?measure_name=; link table enriched with measure_name for one-request UI matching. Frontend: useMinimumDistances loads the link table once and keys it by name; OshaDistanceNote renders the anchor (value/CFR/license/EU-hint/relation) on the matching measure group in the Maßnahmen tab. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -200,6 +200,7 @@ func GetMinimumDistanceByID(id string) (MinimumDistance, bool) {
|
||||
// OSHA entry is offered as the public-domain pendant for independent check.
|
||||
type MeasureDistanceLink struct {
|
||||
MeasureID string `json:"measure_id"`
|
||||
MeasureName string `json:"measure_name,omitempty"` // resolved from the library for name-based UI matching
|
||||
DistanceIDs []string `json:"distance_ids"`
|
||||
Relation string `json:"relation"`
|
||||
Note string `json:"note,omitempty"`
|
||||
@@ -216,7 +217,7 @@ const (
|
||||
// ISO value (e.g. M340 robot teach speed, M368 air-receiver wall) are NOT
|
||||
// linked — that would imply a public-domain anchor that does not exist.
|
||||
func AllMeasureDistanceLinks() []MeasureDistanceLink {
|
||||
return []MeasureDistanceLink{
|
||||
links := []MeasureDistanceLink{
|
||||
{
|
||||
MeasureID: "M600",
|
||||
DistanceIDs: []string{"MD_OSHA_217_PSDI"},
|
||||
@@ -236,6 +237,18 @@ func AllMeasureDistanceLinks() []MeasureDistanceLink {
|
||||
Note: "OSHA §1910.212(a)(5) Luefterschutz (max. 12 mm Spaltoeffnung) als Public-Domain-Pendant zu ISO 13857.",
|
||||
},
|
||||
}
|
||||
// Enrich each link with the measure name so a name-based UI (persisted
|
||||
// mitigations carry the name, not the ID) can match without a second lookup.
|
||||
lib := GetProtectiveMeasureLibrary()
|
||||
for i := range links {
|
||||
for _, m := range lib {
|
||||
if m.ID == links[i].MeasureID {
|
||||
links[i].MeasureName = m.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
||||
// LinksForMeasure returns the distance links declared for one measure.
|
||||
@@ -263,3 +276,33 @@ func MinimumDistancesForMeasure(measureID string) []MinimumDistance {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// MeasureIDByName resolves a protective-measure name to its catalog ID. Measure
|
||||
// names are unique across the library (verified by test), so a PERSISTED
|
||||
// mitigation — which stores the measure name verbatim but NOT the catalog ID —
|
||||
// can still be joined to its OSHA distance link without a DB schema change or a
|
||||
// re-seed. This is the bridge that lets a project's measures surface the anchor.
|
||||
func MeasureIDByName(name string) (string, bool) {
|
||||
for _, m := range GetProtectiveMeasureLibrary() {
|
||||
if m.Name == name {
|
||||
return m.ID, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// MinimumDistancesForMeasureName resolves OSHA distances by measure NAME.
|
||||
func MinimumDistancesForMeasureName(name string) []MinimumDistance {
|
||||
if id, ok := MeasureIDByName(name); ok {
|
||||
return MinimumDistancesForMeasure(id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LinksForMeasureName resolves distance links by measure NAME.
|
||||
func LinksForMeasureName(name string) []MeasureDistanceLink {
|
||||
if id, ok := MeasureIDByName(name); ok {
|
||||
return LinksForMeasure(id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user