feat: remove Administration workspace — keep only Verwaltung + Suche

- Delete all ops page components (ReviewQueue, AIMonitoring, Governance,
  SourceMonitoring, ActivityTimeline, SignalPipeline)
- Remove OPERATIONS workspace from AppShell config, nav order, path detection
- Remove all /ops/* routes from App.tsx
- Remove WorkspaceType.OPERATIONS from allowedWorkspaces in authService,
  sessionStore, permissions
- Keep MarketIntelligence page (already moved to /supply/market-intelligence)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-19 20:32:41 +02:00
parent d22e72f945
commit d15a13e485
378 changed files with 35441 additions and 42 deletions
@@ -0,0 +1,99 @@
import {
DQ_HIGH, DQ_MEDIUM,
CONF_HIGH, CONF_MEDIUM,
SCORE_STRONG, SCORE_MODERATE,
PROB_HIGH, PROB_MEDIUM,
} from './constants'
// ── Formatting ────────────────────────────────────────────────────────────────
export function formatCHF(amount: number, decimals = 0): string {
return new Intl.NumberFormat('de-CH', {
style: 'currency',
currency: 'CHF',
minimumFractionDigits: decimals,
maximumFractionDigits: decimals,
}).format(amount)
}
export function formatArea(sqm: number): string {
return `${new Intl.NumberFormat('de-CH').format(sqm)}`
}
export function formatPercent(value: number, decimals = 0): string {
return `${(value * 100).toFixed(decimals)} %`
}
export function formatDate(iso: string): string {
return new Intl.DateTimeFormat('de-CH', { day: '2-digit', month: '2-digit', year: 'numeric' }).format(new Date(iso))
}
export function formatRelativeDate(iso: string): string {
const diff = Date.now() - new Date(iso).getTime()
const hours = Math.floor(diff / 3_600_000)
if (hours < 1) return 'Gerade eben'
if (hours < 24) return `vor ${hours} Stunde${hours === 1 ? '' : 'n'}`
const days = Math.floor(hours / 24)
if (days < 7) return `vor ${days} Tag${days === 1 ? '' : 'en'}`
return formatDate(iso)
}
// ── Color helpers (return MUI color token strings) ────────────────────────────
export function dataQualityColor(score: number): 'success' | 'warning' | 'error' {
if (score >= DQ_HIGH) return 'success'
if (score >= DQ_MEDIUM) return 'warning'
return 'error'
}
export function confidenceColor(score: number): 'success' | 'primary' | 'warning' {
if (score >= CONF_HIGH) return 'success'
if (score >= CONF_MEDIUM) return 'primary'
return 'warning'
}
export function matchScoreColor(score: number): 'success' | 'warning' | 'error' {
if (score >= SCORE_STRONG) return 'success'
if (score >= SCORE_MODERATE) return 'warning'
return 'error'
}
export function probabilityColor(prob: number): 'success' | 'warning' | 'error' {
if (prob >= PROB_HIGH) return 'success'
if (prob >= PROB_MEDIUM) return 'warning'
return 'error'
}
// Hex color variants for use in sx (when MUI color tokens aren't enough)
export function dataQualityHex(score: number): string {
if (score >= DQ_HIGH) return '#1a7a4a'
if (score >= DQ_MEDIUM) return '#d97706'
return '#c0392b'
}
export function confidenceHex(score: number): string {
if (score >= CONF_HIGH) return '#1a7a4a'
if (score >= CONF_MEDIUM) return '#1e3a5f'
return '#d97706'
}
export function probabilityHex(prob: number): string {
if (prob >= PROB_HIGH) return '#1a7a4a'
if (prob >= PROB_MEDIUM) return '#d97706'
return '#c0392b'
}
// ── Misc ──────────────────────────────────────────────────────────────────────
export function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max)
}
export function average(values: number[]): number {
if (values.length === 0) return 0
return values.reduce((a, b) => a + b, 0) / values.length
}
export function truncate(str: string, maxLen: number): string {
return str.length <= maxLen ? str : str.slice(0, maxLen - 1) + '…'
}