Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/permissioning system #305

Open
wants to merge 51 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
9bc8ebb
feat: add category ui
aliassan Jul 3, 2024
79fe314
feat: add entitlement parameters
aliassan Jul 10, 2024
06a9957
feat: ui single page view
aliassan Jul 10, 2024
80a2150
Merge pull request #247 from globe-and-citizen/feat/permissioning-sys…
aliassan Jul 10, 2024
569723b
Merge branch 'develop' of https://github.com/globe-and-citizen/cnc-po…
aliassan Jul 11, 2024
33e1cd5
feat: add permissioning system models
aliassan Jul 12, 2024
3c079c4
feat: get entitlement types
aliassan Jul 15, 2024
1a4e06f
feat: permissioning system api
aliassan Jul 19, 2024
f2a9f5b
Merge pull request #278 from globe-and-citizen/develop
hermannleboss Jul 27, 2024
be28800
Merge pull request #279 from globe-and-citizen/feature/permissioning-…
hermannleboss Jul 27, 2024
a93190b
style: make formating consistent
aliassan Jul 29, 2024
6204f85
refactor: seperate routes
aliassan Jul 29, 2024
130ee99
Merge branch 'feat/PS/backend' of https://github.com/globe-and-citize…
aliassan Jul 29, 2024
0ac8f37
Merge pull request #259 from globe-and-citizen/feat/PS/backend
aliassan Jul 30, 2024
b7108b4
Merge branch 'develop' of https://github.com/globe-and-citizen/cnc-po…
aliassan Jul 30, 2024
c7627fb
Merge branch 'feature/permissioning-system' of https://github.com/glo…
aliassan Jul 30, 2024
150d699
fix: use heroicons
aliassan Jul 30, 2024
f0a3d4f
feat: add entitlement value forms
aliassan Jul 30, 2024
d0ed08e
feat: connect role forms
aliassan Jul 30, 2024
e27391f
feat: connect role views
aliassan Jul 30, 2024
94fdfd9
feat: add role types
aliassan Jul 30, 2024
7689fc0
feat: add form error message component
aliassan Jul 30, 2024
8b14519
refactor: refactor role controllers
aliassan Jul 30, 2024
f68083c
Merge branch 'develop' of https://github.com/globe-and-citizen/cnc-po…
aliassan Jul 30, 2024
f8a0cab
Merge branch 'develop' of https://github.com/globe-and-citizen/cnc-po…
aliassan Jul 30, 2024
95ace59
Merge branch 'feature/permissioning-system' of https://github.com/glo…
aliassan Jul 30, 2024
8e787be
chore: remove comments and logs
aliassan Jul 30, 2024
b33b57b
refactor: roles form structure
aliassan Aug 1, 2024
928f10c
refactor: role categories views structure
aliassan Aug 1, 2024
9c475d0
fix: remove dark classes
aliassan Aug 1, 2024
d446d12
refactor: use useCustomFetch naming convention
aliassan Aug 2, 2024
6c59006
Merge branch 'feat/PS/connect-front-and-backend' of https://github.co…
aliassan Aug 2, 2024
168e1c8
fix: make border visible
aliassan Aug 2, 2024
6503b36
fix: add response
aliassan Aug 2, 2024
e402ff3
style: prettier
aliassan Aug 2, 2024
6e660ab
feat: add role category reset
aliassan Aug 5, 2024
ef31c63
chore: remove comments
aliassan Aug 6, 2024
d9bd8a8
Merge pull request #285 from globe-and-citizen/feat/PS/connect-front-…
aliassan Aug 6, 2024
ab2a0ff
Merge branch 'develop' of https://github.com/globe-and-citizen/cnc-po…
aliassan Aug 6, 2024
968dc96
feat: update get team response to include roles
aliassan Aug 8, 2024
503d9fc
feat: add add member roles form
aliassan Aug 8, 2024
ba8a9d7
feat: add assigner sign contract
aliassan Aug 14, 2024
1b728ba
refactor: remove logic from form
aliassan Aug 15, 2024
f7aca9b
refactor: add contract parameter
aliassan Aug 15, 2024
9e27715
feat: add form validation
aliassan Aug 15, 2024
b679022
Merge branch 'develop' of https://github.com/globe-and-citizen/cnc-po…
aliassan Aug 16, 2024
38b73b1
Merge branch 'feature/permissioning-system' of https://github.com/glo…
aliassan Aug 16, 2024
19de3be
refactor: move logic to member section
aliassan Aug 17, 2024
066df7a
Merge pull request #296 from globe-and-citizen/feat/assign-user-roles
aliassan Aug 22, 2024
ca6dbab
Merge branch 'develop' of https://github.com/globe-and-citizen/cnc-po…
aliassan Oct 10, 2024
b8619be
Merge branch 'develop' of https://github.com/globe-and-citizen/cnc-po…
aliassan Oct 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/src/components/AddResourceCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<div class="card bg-green-100 flex justify-center items-center border">
<div class="card-body flex justify-center items-center">
<span class="font-bold">{{ props.text }}</span>

<div class="w-5 h-5 cursor-pointer" @click="emits('openAddResourceModal')">
<PlusCircleIcon class="size-6" />
</div>
</div>
</div>
</template>

<script setup lang="ts">
import { PlusCircleIcon } from '@heroicons/vue/24/outline'
const emits = defineEmits(['openAddResourceModal'])
const props = defineProps(['text'])
</script>
13 changes: 12 additions & 1 deletion app/src/components/TheDrawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@
Transactions
</RouterLink>
</li>
<li>
<RouterLink to="/roles">
<IdentificationIcon class="size-6" />
Roles
</RouterLink>
</li>
</ul>
</div>
</template>
Expand All @@ -56,7 +62,12 @@ li {
</style>

<script setup lang="ts">
import { HomeIcon, UsersIcon, ClipboardDocumentListIcon } from '@heroicons/vue/24/outline'
import {
HomeIcon,
UsersIcon,
ClipboardDocumentListIcon,
IdentificationIcon
} from '@heroicons/vue/24/outline'
import { computed } from 'vue'

interface User {
Expand Down
56 changes: 56 additions & 0 deletions app/src/components/forms/roles/AddEntitlementForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<template>
<div class="space-y-2">
<label class="input input-bordered flex items-center gap-2 input-md mt-4">
<span class="w-24">Type</span>
<select v-model="entitlement.entitlementTypeId" class="grow bg-white">
<option v-for="item in availableTypes" :key="item.id" :value="item.id">
{{ item.name }}
</option>
</select>
</label>
<label
class="input input-bordered flex items-center gap-2 input-md"
:class="{ 'input-error': $v.$errors.length }"
>
<span class="w-24">Value</span>
<EntitlementValueForm v-model="entitlement" />
</label>
<FormErrorMessage v-if="$v.$errors.length">
<div v-for="error of $v.$errors" :key="error.$uid">
{{ error.$message }}
</div>
</FormErrorMessage>
</div>
</template>

<script setup lang="ts">
import { ref, type ComputedRef, watch } from 'vue'
import EntitlementValueForm from './entitlement-value/EntitlementValueForm.vue'
import { useVuelidate } from '@vuelidate/core'
import FormErrorMessage from '../../ui/FormErrorMessage.vue'

const entitlement = defineModel({
default: {
entitlementTypeId: 0,
value: '',
isInit: true //so entitlement value isn't cleared on load
}
})

const $v = useVuelidate()

const props = defineProps<{
availableTypes: ComputedRef<{ id: number; name: string }[]>
}>()

const availableTypes = ref(props.availableTypes)

watch(
() => entitlement.value.entitlementTypeId,
(newType, oldType) => {
if (!entitlement.value.isInit && newType !== oldType && oldType !== 0) {
entitlement.value.value = ''
}
}
)
</script>
286 changes: 286 additions & 0 deletions app/src/components/forms/roles/AddRoleCategoryForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
<template>
<div>
<h1 class="font-bold text-2xl">{{ isNew ? 'Create' : 'Update' }} Role Category</h1>
<hr class="mt-4" />
</div>

<div class="max-h-[70vh] overflow-y-auto p-2">
<!--General Inputs-->
<section class="flex flex-col gap-2">
<label
class="input input-bordered flex items-center gap-2 input-md mt-4"
:class="{ 'input-error': $v.roleCategory.name.$errors.length }"
>
<span class="w-24">Name</span>
<input
type="text"
class="grow"
placeholder="Enter a role category name"
v-model="roleCategory.name"
@input="
async () => {
await $v.$validate()
}
"
/>
</label>
<FormErrorMessage v-if="$v.roleCategory.name.$errors.length">
<div v-for="error of $v.roleCategory.name.$errors" :key="error.$uid">
{{ error.$message }}
</div>
</FormErrorMessage>

<label class="input input-bordered flex items-center gap-2 input-md">
<span class="w-24">Description</span>
<input
type="text"
class="grow"
placeholder="Enter a short description"
v-model="roleCategory.description"
/>
</label>
</section>

<div v-if="props.isNew">
<!--Roles-->
<section class="mt-10">
<div
v-for="(input, index) in roleCategory.roles"
:key="index"
class="collapse collapse-plus bg-base-200 border mt-2"
>
<input type="radio" name="my-accordion-3" />
<div class="collapse-title text-xl font-medium">
Role - {{ input.name ? input.name : index + 1 }}
</div>
<div class="collapse-content">
<AddRoleForm v-model="roleCategory.roles[index]" />
</div>
</div>
</section>

<!--Roles Add Remove Roles Buttons-->
<div class="flex justify-end pt-3">
<div
class="w-6 h-6 cursor-pointer"
@click="
() => {
if (roleCategory.roles.length > 1) {
roleCategory.roles.pop()
}
}
"
>
<MinusCircleIcon class="size-6" />
</div>
<div
class="w-6 h-6 cursor-pointer"
@click="
() => {
roleCategory.roles.push({
name: '',
description: '',
entitlements: [
{
entitlementTypeId: 0,
value: ''
}
]
})
}
"
>
<PlusCircleIcon class="size-6" />
</div>
</div>
</div>

<!--Role Category Entitlements-->
<section class="join join-vertical w-full mt-10">
<div
v-for="(input, index) in roleCategory.entitlements"
:key="index"
class="collapse collapse-arrow join-item border-base-300 border"
>
<input type="radio" name="category-entitlement-accordion" />
<div class="collapse-title text-l font-medium">
Category Entitlement -
{{ getEntitlementName(input.entitlementTypeId as unknown as number) ?? index + 1 }}
</div>
<div class="collapse-content">
<AddEntitlementForm
v-model="roleCategory.entitlements[index]"
:available-types="getAvailableTypes(index)"
/>
</div>
</div>
</section>

<!--Role Category Entitlements Add Remove Buttons-->
<div class="flex justify-end pt-3">
<div
class="w-6 h-6 cursor-pointer"
@click="
() => {
if (roleCategory.entitlements.length > 1) {
roleCategory.entitlements.pop()
}
}
"
>
<MinusCircleIcon class="size-6" />
</div>
<div
class="w-6 h-6 cursor-pointer"
@click="
() => {
roleCategory.entitlements.push({
entitlementTypeId: 0,
value: ''
})
}
"
>
<PlusCircleIcon class="size-6" />
</div>
</div>
</div>
<!--Submit Button-->
<div class="modal-action justify-center">
<!-- if there is a button in form, it will close the modal -->
<LoadingButton v-if="isLoading" color="primary min-w-24" />
<button class="btn btn-primary" @click="handleClickCreate" v-else-if="isNew">Create</button>
<button v-else class="btn btn-primary" @click="handleClickUpdate">Update</button>
<button class="btn btn-active" @click="emits('closeModal')">Cancel</button>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { PlusCircleIcon, MinusCircleIcon } from '@heroicons/vue/24/outline'
import FormErrorMessage from '@/components/ui/FormErrorMessage.vue'
import LoadingButton from '@/components/ui/LoadingButton.vue'
import AddRoleForm from './AddRoleForm.vue'
import AddEntitlementForm from './AddEntitlementForm.vue'
import { useCustomFetch } from '@/composables/useCustomFetch'
import { useVuelidate } from '@vuelidate/core'
import { required } from '@vuelidate/validators'

const roleCategory = defineModel({
default: {
name: '',
description: '',
roles: [
{
name: '',
description: '',
entitlements: [
{
entitlementTypeId: 0,
value: ''
}
]
}
],
entitlements: [
{
entitlementTypeId: 0,
value: ''
}
]
}
})

//#region validation
const rules = {
roleCategory: {
name: { required }
}
}

const $v = useVuelidate(rules, { roleCategory })
//#endregion validation

const roleCategoryEndPoint = ref('')

const {
//isFetching: isCreateRoleCategoryFetching,
//error: isCreateRoleCategoryError,
execute: executeCreateRoleCategory /*,
data: _roleCategory*/
} = useCustomFetch(`role-category/`, {
immediate: false
})
.post(roleCategory)
.json()

const {
//error: isGetEntTypesError,
execute: executeFetchEntitlementTypes,
data: _entTypes
} = useCustomFetch<{ success: boolean; entTypes: { id: number; name: string } }>(
`entitlement/types`,
{
immediate: false
}
)
.get()
.json()

const {
execute: executeUpdateRoleCategory
} = useCustomFetch(roleCategoryEndPoint, {
immediate: false
})
.put(roleCategory)
.json()

const getAvailableTypes = (index: number) => {
return computed(() => {
const selectedTypes = roleCategory.value.entitlements.map(
(entitlement) => entitlement.entitlementTypeId
)

return _entTypes.value?.entTypes.filter(
(type: { id: number; name: string }) =>
type.id === -1 ||
!selectedTypes.includes(type.id) ||
roleCategory.value.entitlements[index].entitlementTypeId === type.id
)
})
}

const getEntitlementName = (typeId: number) => {
const entitlement = _entTypes.value?.entTypes.find(
(ent: { id: number; name: string }) => ent.id === typeId
)
return entitlement ? entitlement.name : undefined
}

const handleClickCreate = async () => {
await $v.value.$validate()
if ($v.value.$errors.length) {
console.log('Errors found, aborting submission: ', $v.value)
return
}
await executeCreateRoleCategory()
emits('createRoleCategory')
}

const handleClickUpdate = async () => {
roleCategoryEndPoint.value = `role-category`
await executeUpdateRoleCategory()
emits('closeModal')
emits('reload')
}

const emits = defineEmits(['createRoleCategory', 'searchUsers', 'closeModal', 'reload'])
const props = defineProps<{
isNew?: boolean
categoryId?: number
isLoading: boolean
}>()

onMounted(async () => {
await executeFetchEntitlementTypes()
})
</script>
Loading
Loading