Files
neo/frontend/components/ObjectAccessSettings.vue
Francisco Gaona 88f656c3f5 WIP - permissions
2025-12-28 05:43:03 +01:00

263 lines
9.2 KiB
Vue

<template>
<div class="space-y-6">
<div v-if="loading" class="text-center py-8">Loading access settings...</div>
<div v-else class="space-y-6">
<!-- Global Access Model -->
<Card>
<CardHeader>
<CardTitle>Global Access Model</CardTitle>
<CardDescription>
Define the default access control model for this object
</CardDescription>
</CardHeader>
<CardContent class="space-y-4">
<div class="space-y-2">
<Label>Access Model</Label>
<Select v-model="accessModel">
<SelectTrigger>
<SelectValue placeholder="Select access model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="public">Public - Anyone can access</SelectItem>
<SelectItem value="owner">Owner Only - Only record owner can access</SelectItem>
<SelectItem value="mixed">Mixed - Owner plus role/share-based access</SelectItem>
</SelectContent>
</Select>
<p class="text-sm text-muted-foreground">
<span v-if="accessModel === 'public'">
All users can access records by default
</span>
<span v-else-if="accessModel === 'owner'">
Only the record owner can access records
</span>
<span v-else-if="accessModel === 'mixed'">
Record owner has access, plus role-based and sharing rules apply
</span>
</p>
</div>
<div class="space-y-2">
<Label>Owner Field</Label>
<Input v-model="ownerField" placeholder="ownerId" />
<p class="text-sm text-muted-foreground">
The field name that stores the record owner's ID
</p>
</div>
<div class="space-y-3">
<Label>Public Permissions</Label>
<div class="space-y-2">
<div class="flex items-center space-x-2">
<Checkbox
id="public-read"
v-model:checked="publicRead"
/>
<Label for="public-read" class="cursor-pointer font-normal">Public Read</Label>
</div>
<div class="flex items-center space-x-2">
<Checkbox
id="public-create"
v-model:checked="publicCreate"
/>
<Label for="public-create" class="cursor-pointer font-normal">Public Create</Label>
</div>
<div class="flex items-center space-x-2">
<Checkbox
id="public-update"
v-model:checked="publicUpdate"
/>
<Label for="public-update" class="cursor-pointer font-normal">Public Update</Label>
</div>
<div class="flex items-center space-x-2">
<Checkbox
id="public-delete"
v-model:checked="publicDelete"
/>
<Label for="public-delete" class="cursor-pointer font-normal">Public Delete</Label>
</div>
</div>
</div>
</CardContent>
</Card>
<!-- Field-Level Permissions -->
<Card>
<CardHeader>
<CardTitle>Field-Level Permissions</CardTitle>
<CardDescription>
Set default read/write permissions for individual fields
</CardDescription>
</CardHeader>
<CardContent>
<div class="space-y-2">
<div
v-for="field in fields"
:key="field.apiName"
class="flex items-center justify-between p-3 border rounded-lg"
>
<div class="flex-1">
<div class="font-medium">{{ field.label }}</div>
<div class="text-sm text-muted-foreground">{{ field.apiName }}</div>
</div>
<div class="flex items-center gap-4">
<div class="flex items-center space-x-2">
<Checkbox
:id="`${field.apiName}-read`"
:checked="getFieldPermission(field.apiName, 'read')"
@update:checked="(val) => setFieldPermission(field.apiName, 'read', val)"
/>
<Label :for="`${field.apiName}-read`" class="cursor-pointer">Read</Label>
</div>
<div class="flex items-center space-x-2">
<Checkbox
:id="`${field.apiName}-write`"
:checked="getFieldPermission(field.apiName, 'write')"
@update:checked="(val) => setFieldPermission(field.apiName, 'write', val)"
/>
<Label :for="`${field.apiName}-write`" class="cursor-pointer">Write</Label>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
<!-- Save Button -->
<div class="flex justify-end">
<Button @click="saveChanges" :disabled="saving">
{{ saving ? 'Saving...' : 'Save Changes' }}
</Button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Checkbox } from '@/components/ui/checkbox'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
interface Props {
objectApiName: string
fields: any[]
}
const props = defineProps<Props>()
const emit = defineEmits(['updated'])
const { api } = useApi()
const { toast } = useToast()
const loading = ref(true)
const saving = ref(false)
const accessModel = ref<string>('owner')
const publicRead = ref<boolean>(false)
const publicCreate = ref<boolean>(false)
const publicUpdate = ref<boolean>(false)
const publicDelete = ref<boolean>(false)
const ownerField = ref<string>('ownerId')
const fieldPermissions = ref<Record<string, { defaultReadable: boolean; defaultWritable: boolean }>>({})
const fetchAccessConfig = async () => {
try {
loading.value = true
const data = await api.get(`/setup/objects/${props.objectApiName}/access`)
accessModel.value = data.accessModel || 'owner'
publicRead.value = Boolean(data.publicRead)
publicCreate.value = Boolean(data.publicCreate)
publicUpdate.value = Boolean(data.publicUpdate)
publicDelete.value = Boolean(data.publicDelete)
ownerField.value = data.ownerField || 'ownerId'
// Initialize field permissions from field definitions
fieldPermissions.value = {}
if (data.fields && data.fields.length > 0) {
data.fields.forEach((field: any) => {
fieldPermissions.value[field.apiName] = {
defaultReadable: Boolean(field.defaultReadable ?? true),
defaultWritable: Boolean(field.defaultWritable ?? true),
}
})
} else {
// Initialize all fields with default permissions
props.fields.forEach((field) => {
fieldPermissions.value[field.apiName] = {
defaultReadable: true,
defaultWritable: true,
}
})
}
} catch (e: any) {
console.error('Error fetching access config:', e)
toast.error('Failed to load access settings')
} finally {
loading.value = false
}
}
const getFieldPermission = (fieldKey: string, type: 'read' | 'write'): boolean => {
const perms = fieldPermissions.value[fieldKey]
if (!perms) return true
const value = type === 'read' ? perms.defaultReadable : perms.defaultWritable
return Boolean(value)
}
const setFieldPermission = (fieldKey: string, type: 'read' | 'write', value: boolean) => {
if (!fieldPermissions.value[fieldKey]) {
fieldPermissions.value[fieldKey] = { defaultReadable: true, defaultWritable: true }
}
if (type === 'read') {
fieldPermissions.value[fieldKey].defaultReadable = Boolean(value)
} else {
fieldPermissions.value[fieldKey].defaultWritable = Boolean(value)
}
}
const saveChanges = async () => {
try {
saving.value = true
// Ensure all values are proper booleans
const payload = {
accessModel: accessModel.value,
publicRead: Boolean(publicRead.value),
publicCreate: Boolean(publicCreate.value),
publicUpdate: Boolean(publicUpdate.value),
publicDelete: Boolean(publicDelete.value),
ownerField: ownerField.value,
}
// Update global access config
await api.put(`/setup/objects/${props.objectApiName}/access`, payload)
// Update field permissions
const fieldPermsArray = Object.entries(fieldPermissions.value).map(([fieldKey, perms]) => ({
fieldKey,
defaultReadable: perms.defaultReadable,
defaultWritable: perms.defaultWritable,
}))
await api.put(`/setup/objects/${props.objectApiName}/field-permissions`, fieldPermsArray)
toast.success('Access settings saved successfully')
emit('updated')
} catch (e: any) {
console.error('Error saving access config:', e)
toast.error('Failed to save access settings')
} finally {
saving.value = false
}
}
onMounted(() => {
fetchAccessConfig()
})
</script>