// Pure render helpers for PluginAssetPanels.vue (ADR-010 get_asset_panels, Path // A). Kept separate from the .vue so the mapping logic - which turns a plugin's // JSON panel declaration + its endpoint data into rendered rows - is unit // tested directly (same pattern as geenforce/entryForm.js). export function subst(text, assetid) { return String(text).replace('{assetid}', assetid) } // Panel endpoints are declared absolute (/api/...); the api instance already // carries the /api base, so strip it before fetching through the instance. export function toApiPath(endpoint, assetid) { return subst(endpoint, assetid).replace(/^\/api(?=\/)/, '') } export function formatValue(value, spec = {}) { if (value === null || value === undefined || value === '') return '' if (spec.format === 'date') { const raw = String(value) return new Date(raw + (raw.length === 10 ? 'T00:00:00' : '')).toLocaleDateString() } if (typeof value === 'boolean') return value ? 'Yes' : 'No' return value } export function humanize(key) { return key.charAt(0).toUpperCase() + key.slice(1) } export function rows(panel) { const data = panel._data if (Array.isArray(data)) return data if (data && Array.isArray(data.rows)) return data.rows if (data && Array.isArray(data.items)) return data.items return [] } export function mapTitle(panel, item) { const key = panel.map && panel.map.title return key ? item[key] : '' } export function mapBadge(panel, item) { const badge = panel.map && panel.map.badge if (!badge) return null const raw = item[badge.label] const label = (badge.labelmap && badge.labelmap[raw]) || raw return { label, color: badge.color ? item[badge.color] : undefined } } export function mapMeta(panel, item) { const meta = (panel.map && panel.map.meta) || [] return meta .map((spec) => { const value = formatValue(item[spec.key], spec) if (value === '') return null const text = spec.label ? `${spec.label} ${value}` : value return { text, mono: !!spec.mono } }) .filter(Boolean) } export function manageLink(panel, assetid) { return panel.manage ? subst(panel.manage.to, assetid) : null } export function keyvalueFields(panel) { const data = panel._data if (data && Array.isArray(data.fields)) { return data.fields.map((f) => ({ label: f.label, value: formatValue(f.value, f), mono: !!f.mono, })) } if (data && typeof data === 'object' && !Array.isArray(data)) { return Object.entries(data).map(([k, v]) => ({ label: humanize(k), value: formatValue(v), })) } return [] } export function tableColumns(panel) { if (Array.isArray(panel.columns) && panel.columns.length) { return panel.columns.map((c) => ({ key: c.key, label: c.label || humanize(c.key) })) } const first = rows(panel)[0] if (!first) return [] return Object.keys(first).map((k) => ({ key: k, label: humanize(k) })) } export function cell(row, col) { return formatValue(row[col.key], col) } export function badges(panel) { const data = panel._data const list = Array.isArray(data) ? data : (data && data.badges) || [] return list.map((b) => ({ label: b.label, color: b.color })) } export function panelVisible(panel) { if (panel.render === 'list') return rows(panel).length > 0 || !!panel.empty if (panel.render === 'keyvalue') return keyvalueFields(panel).length > 0 if (panel.render === 'table') return rows(panel).length > 0 if (panel.render === 'badge') return badges(panel).length > 0 return false }