From 48c50ee5f1598a82bd3b870e527224a892700d07 Mon Sep 17 00:00:00 2001
From: DeathKaioken
Date: Sat, 6 Dec 2025 12:34:04 +0100
Subject: [PATCH] refactor: matrix stuff
---
.../detail/components/searchModal.tsx | 11 ++-
.../admin/matrix-management/detail/page.tsx | 84 ++++++++++++++++---
src/app/admin/matrix-management/page.tsx | 52 ++++++++++--
src/app/personal-matrix/hooks/getStats.ts | 9 +-
4 files changed, 130 insertions(+), 26 deletions(-)
diff --git a/src/app/admin/matrix-management/detail/components/searchModal.tsx b/src/app/admin/matrix-management/detail/components/searchModal.tsx
index 11c7dba..81c2177 100644
--- a/src/app/admin/matrix-management/detail/components/searchModal.tsx
+++ b/src/app/admin/matrix-management/detail/components/searchModal.tsx
@@ -443,20 +443,20 @@ export default function SearchModal({
{advanced && (
@@ -342,6 +345,32 @@ export default function MatrixDetailPage() {
// const isUnlimited = !serverMaxDepth || serverMaxDepth <= 0;
const isUnlimited = policyMaxDepth == null || policyMaxDepth <= 0 // NEW
+ const policyDepth = (policyMaxDepth && policyMaxDepth > 0) ? policyMaxDepth : null
+ const perLevelCounts = useMemo(() => {
+ const m = new Map()
+ users.forEach(u => {
+ if (u.level != null && u.level >= 0) {
+ m.set(u.level, (m.get(u.level) || 0) + 1)
+ }
+ })
+ return m
+ }, [users])
+ const totalNonRoot = useMemo(() => users.filter(u => (u.level ?? 0) > 0).length, [users])
+ const fillMetrics = useMemo(() => {
+ if (!policyDepth) return { label: 'N/A (unlimited policy)', highestFull: 'N/A' }
+ let capacitySum = 0
+ let highestFullLevel: number | null = null
+ for (let k = 1; k <= policyDepth; k++) {
+ const cap = Math.pow(5, k)
+ capacitySum += cap
+ const lvlCount = perLevelCounts.get(k) || 0
+ if (lvlCount >= cap) highestFullLevel = k
+ }
+ if (capacitySum === 0) return { label: 'N/A', highestFull: 'N/A' }
+ const pct = Math.round((totalNonRoot / capacitySum) * 100 * 100) / 100
+ return { label: `${pct}%`, highestFull: highestFullLevel == null ? 'None' : `L${highestFullLevel}` }
+ }, [policyDepth, perLevelCounts, totalNonRoot])
+
return (
{/* Smooth refresh overlay */}
@@ -372,15 +401,28 @@ export default function MatrixDetailPage() {
Top node: {topNodeEmail}
- {/* CHANGED: capacity clarification */}
- Children/node: non‑root 5, root unlimited
+ Root: unlimited immediate children (sequential positions)
+
+
+ Non-root: 5 children (positions 1–5)
- Max depth: {isUnlimited ? 'Unlimited' : policyMaxDepth}
+ Policy depth (DB): {isUnlimited ? 'Unlimited' : policyMaxDepth}
+
+
+ Fetch depth (client slice): {DEFAULT_FETCH_DEPTH}
+
+ {serverMaxDepth != null && (
+
+ Server-reported max depth: {serverMaxDepth}
+
+ )}
+
+ Root children: {rootChildrenCount} (unlimited)
- Root children: {rootChildrenCount} (Unlimited)
+ Displayed slots under root (positions 1–5): {displayedRootSlots}/5
@@ -426,7 +468,7 @@ export default function MatrixDetailPage() {
{/* Small stats (CHANGED wording) */}
-
+
Total users fetched
{users.length}
@@ -443,6 +485,14 @@ export default function MatrixDetailPage() {
Policy Max Depth
{isUnlimited ? 'Unlimited' : policyMaxDepth}
+
+
Fill %
+
{fillMetrics.label}
+
+
+
Highest full level
+
{fillMetrics.highestFull}
+
{/* Unlimited hierarchical tree (replaces dynamic levels + grouped level list) */}
@@ -463,6 +513,14 @@ export default function MatrixDetailPage() {
+ {/* Vacancies placeholder */}
+
+
Vacancies
+
+ Pending backend wiring to MatrixController.listVacancies. This section will surface empty slots and allow reassignment.
+
+
+
{/* Add Users Modal */}
{ addToMatrix(u) }}
/>
diff --git a/src/app/admin/matrix-management/page.tsx b/src/app/admin/matrix-management/page.tsx
index a61820a..c9ca9e4 100644
--- a/src/app/admin/matrix-management/page.tsx
+++ b/src/app/admin/matrix-management/page.tsx
@@ -62,8 +62,9 @@ export default function MatrixManagementPage() {
const [forcePrompt, setForcePrompt] = useState<{ name: string; email: string } | null>(null)
const [createSuccess, setCreateSuccess] = useState<{ name: string; email: string } | null>(null)
- const [policyFilter, setPolicyFilter] = useState<'unlimited'|'five'>('unlimited') // NEW
- const [sortByUsers, setSortByUsers] = useState<'asc'|'desc'>('desc') // NEW
+ const [policyFilter, setPolicyFilter] = useState<'all'|'unlimited'|'five'>('all') // CHANGED
+ const [sortByUsers, setSortByUsers] = useState<'asc'|'desc'>('desc')
+ const [sortByPolicy, setSortByPolicy] = useState<'none'|'asc'|'desc'>('none') // NEW
const [mutatingId, setMutatingId] = useState(null) // NEW
const loadStats = async () => {
@@ -220,11 +221,20 @@ export default function MatrixManagementPage() {
let list = [...matrices]
list = list.filter(m => {
const unlimited = !m.policyMaxDepth || m.policyMaxDepth <= 0
+ if (policyFilter === 'all') return true
return policyFilter === 'unlimited' ? unlimited : (!unlimited && m.policyMaxDepth === 5)
})
- list.sort((a,b) => sortByUsers === 'asc' ? (a.usersCount - b.usersCount) : (b.usersCount - a.usersCount))
+ list.sort((a,b) => {
+ if (sortByPolicy !== 'none') {
+ const pa = (!a.policyMaxDepth || a.policyMaxDepth <= 0) ? Infinity : a.policyMaxDepth
+ const pb = (!b.policyMaxDepth || b.policyMaxDepth <= 0) ? Infinity : b.policyMaxDepth
+ const diff = sortByPolicy === 'asc' ? pa - pb : pb - pa
+ if (diff !== 0) return diff
+ }
+ return sortByUsers === 'asc' ? (a.usersCount - b.usersCount) : (b.usersCount - a.usersCount)
+ })
return list
- }, [matrices, policyFilter, sortByUsers])
+ }, [matrices, policyFilter, sortByUsers, sortByPolicy])
const StatCard = ({
icon: Icon,
@@ -284,6 +294,28 @@ export default function MatrixManagementPage() {
+ {/* Filters */}
+
+
+ Policy filter:
+
+
+
+
+
+ Sort:
+
+
+
+
+
{/* Error banner for stats */}
{statsError && (
@@ -321,9 +353,12 @@ export default function MatrixManagementPage() {
{m.name}
-
-
- Max depth: {(!m.policyMaxDepth || m.policyMaxDepth <= 0) ? 'Unlimited' : m.policyMaxDepth}
+
+
+ Policy: {(!m.policyMaxDepth || m.policyMaxDepth <= 0) ? 'Unlimited' : m.policyMaxDepth}
+
+
+ Root: unlimited immediate children (sequential), non-root: 5 children (positions 1–5)
@@ -356,6 +391,9 @@ export default function MatrixManagementPage() {
? (m.status === 'active' ? 'Deactivating…' : 'Activating…')
: (m.status === 'active' ? 'Deactivate' : 'Activate')}
+
+ State change will affect add/remove operations.
+