gigafibre-fsm/apps/ops/src/composables/usePermissionMatrix.js
louispaulb 24b5644da4 refactor: extract composables from 5 largest files — net -1950 lines from main components
DispatchPage.vue: 1320→1217 lines
  - Extract SbModal.vue + SbContextMenu.vue reusable components
  - Extract useAbsenceResize composable
  - Extract dispatch constants to config/dispatch.js

ProjectWizard.vue: 1185→673 lines (-43%)
  - Extract useWizardPublish composable (270-line publish function)
  - Extract useWizardCatalog composable
  - Extract wizard-constants.js (step labels, options, categories)

SettingsPage.vue: 1172→850 lines (-27%)
  - Extract usePermissionMatrix composable
  - Extract useUserGroups composable
  - Extract useLegacySync composable

ClientDetailPage.vue: 1169→864 lines (-26%)
  - Extract useClientData composable (loadCustomer broken into sub-functions)
  - Extract useEquipmentActions composable
  - Extract client-constants.js + erp-pdf.js utility

checkout.js: 639→408 lines (-36%)
  - Extract address-search.js module
  - Extract otp.js module
  - Extract email-templates.js module
  - Extract project-templates.js module
  - Add erpQuery() helper to DRY repeated URL construction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 17:57:24 -04:00

124 lines
3.9 KiB
JavaScript

import { ref, reactive, computed } from 'vue'
import { Notify } from 'quasar'
import { usePermissions } from './usePermissions'
export function usePermissionMatrix () {
const { HUB_URL } = usePermissions()
const permTab = ref('users')
const permLoading = ref(false)
const permSaving = ref(false)
const permDirty = ref(false)
const permGroups = ref([])
const permCapabilities = ref([])
const permMatrix = reactive({})
const allGroupNames = computed(() => permGroups.value.map(g => g.name))
const permCategories = computed(() => [...new Set(permCapabilities.value.map(c => c.category))])
const permCapsByCategory = computed(() => {
const map = {}
for (const c of permCapabilities.value) {
if (!map[c.category]) map[c.category] = []
map[c.category].push(c)
}
return map
})
async function loadPerms () {
permLoading.value = true
try {
const res = await fetch(HUB_URL + '/auth/groups')
const data = await res.json()
permGroups.value = data.groups
permCapabilities.value = data.capabilities
for (const g of data.groups) {
permMatrix[g.name] = {}
for (const cap of data.capabilities) {
permMatrix[g.name][cap.key] = g.permissions[cap.key] === true
}
}
} catch (e) {
Notify.create({ type: 'negative', message: 'Erreur chargement permissions: ' + e.message })
} finally {
permLoading.value = false
}
}
async function saveAllPerms () {
permSaving.value = true
try {
for (const g of permGroups.value) {
await fetch(HUB_URL + '/auth/groups/' + encodeURIComponent(g.name) + '/permissions', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(permMatrix[g.name]),
})
}
permDirty.value = false
Notify.create({ type: 'positive', message: 'Permissions sauvegardees', timeout: 2000 })
} catch (e) {
Notify.create({ type: 'negative', message: 'Erreur: ' + e.message })
} finally {
permSaving.value = false
}
}
async function saveGroupPerms (groupName) {
permSaving.value = true
try {
await fetch(HUB_URL + '/auth/groups/' + encodeURIComponent(groupName) + '/permissions', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(permMatrix[groupName]),
})
permDirty.value = false
Notify.create({ type: 'positive', message: `Permissions "${groupName}" sauvegardees`, timeout: 2000 })
} catch (e) {
Notify.create({ type: 'negative', message: 'Erreur: ' + e.message })
} finally {
permSaving.value = false
}
}
function countGroupPerms (g) {
return Object.values(permMatrix[g.name] || {}).filter(Boolean).length
}
function effectivePerm (user, capKey) {
if (typeof user.overrides[capKey] === 'boolean') return user.overrides[capKey]
for (const gName of user.groups) {
if (permMatrix[gName]?.[capKey]) return true
}
return false
}
async function setUserOverride (user, capKey, value) {
if (value === true || value === false) {
user.overrides[capKey] = value
} else {
delete user.overrides[capKey]
}
const clean = {}
for (const [k, v] of Object.entries(user.overrides)) {
if (typeof v === 'boolean') clean[k] = v
}
try {
await fetch(HUB_URL + '/auth/users/' + encodeURIComponent(user.email) + '/overrides', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(clean),
})
} catch (e) {
Notify.create({ type: 'negative', message: 'Erreur override: ' + e.message })
}
}
return {
permTab, permLoading, permSaving, permDirty,
permGroups, permCapabilities, permMatrix,
allGroupNames, permCategories, permCapsByCategory,
loadPerms, saveAllPerms, saveGroupPerms, countGroupPerms,
effectivePerm, setUserOverride,
}
}