-
Notifications
You must be signed in to change notification settings - Fork 2
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
feat: #1655 restrict client selection when d admins assign roles #1701
Merged
craigyu
merged 6 commits into
main
from
feat/1655-restrict-client-selection-when-d-admins-assign-roles
Dec 18, 2024
Merged
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
42e2c91
fix: table row height
craigyu c64c300
feat: multi client select
craigyu 6bf28b6
feat: single FC selected as default
craigyu 56fb63e
Merge branch 'main' into feat/1655-restrict-client-selection-when-d-a…
craigyu e464995
Merge branch 'main' into feat/1655-restrict-client-selection-when-d-a…
craigyu ed09b3b
fix: unused import
craigyu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
167 changes: 167 additions & 0 deletions
167
frontend/src/components/AddPermissions/ForestClientSelectTable.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
<script setup lang="ts"> | ||
import DataTable from "primevue/datatable"; | ||
import Column from "primevue/column"; | ||
import Checkbox from "primevue/checkbox"; | ||
import RadioButton from "primevue/radiobutton"; | ||
import { AdminMgmtApiService } from "@/services/ApiServiceFactory"; | ||
import { useQuery } from "@tanstack/vue-query"; | ||
import { Field, useField } from "vee-validate"; | ||
import { computed, inject, watch, type Ref } from "vue"; | ||
import { APP_PERMISSION_FORM_KEY } from "@/constants/InjectionKeys"; | ||
import type { AppPermissionFormType } from "@/views/AddAppPermission/utils"; | ||
import Label from "../UI/Label.vue"; | ||
import SubsectionTitle from "../UI/SubsectionTitle.vue"; | ||
import { getForestClientsUnderApp } from "@/utils/AuthUtils"; | ||
import type { FamForestClientBase } from "fam-admin-mgmt-api/model"; | ||
import ErrorText from "../UI/ErrorText.vue"; | ||
|
||
const formData = inject<Ref<AppPermissionFormType>>(APP_PERMISSION_FORM_KEY); | ||
|
||
if (!formData) { | ||
throw new Error("formData is required but not provided"); | ||
} | ||
|
||
const props = defineProps<{ | ||
appId: number; | ||
fieldId: string; | ||
}>(); | ||
|
||
const { validate: validateForestClients } = useField(props.fieldId); | ||
|
||
const adminUserAccessQuery = useQuery({ | ||
queryKey: ["admin-user-access"], | ||
queryFn: () => | ||
AdminMgmtApiService.adminUserAccessesApi | ||
.adminUserAccessPrivilege() | ||
.then((res) => res.data), | ||
select: (data) => getForestClientsUnderApp(props.appId, data), | ||
refetchOnMount: true, | ||
}); | ||
|
||
const availableForestClients = computed<FamForestClientBase[]>(() => { | ||
const data = adminUserAccessQuery.data.value; | ||
return data ?? []; | ||
}); | ||
|
||
watch( | ||
availableForestClients, | ||
() => { | ||
if (availableForestClients.value.length === 1) { | ||
formData.value.forestClients = availableForestClients.value; | ||
} | ||
}, | ||
{ immediate: true } | ||
); | ||
|
||
const isForestClientSelected = (client: FamForestClientBase) => | ||
formData.value.forestClients.some( | ||
(selectedClient) => | ||
selectedClient.forest_client_number === client.forest_client_number | ||
); | ||
|
||
const toggleForestClient = (client: FamForestClientBase) => { | ||
const index = formData.value.forestClients.findIndex( | ||
(selectedClient) => | ||
selectedClient.forest_client_number === client.forest_client_number | ||
); | ||
if (index >= 0) { | ||
// Remove client if already selected | ||
formData.value.forestClients.splice(index, 1); | ||
} else { | ||
// Add client if not selected | ||
formData.value.forestClients.push(client); | ||
} | ||
// Validate again to remove resolved error if there is any | ||
validateForestClients(); | ||
}; | ||
</script> | ||
|
||
<template> | ||
<div class="foresnt-client-select-table-container"> | ||
<SubsectionTitle | ||
title="Restrict access by organizations" | ||
subtitle="Select one or more organizations for this to access" | ||
/> | ||
|
||
<Field | ||
:name="props.fieldId" | ||
v-slot="{ errorMessage }" | ||
v-model="formData.forestClients" | ||
> | ||
<Label label-text="Organizations" required /> | ||
|
||
<ErrorText | ||
v-if="errorMessage" | ||
show-icon | ||
:error-msg="errorMessage" | ||
/> | ||
|
||
<!-- Table section --> | ||
<DataTable class="fam-table" :value="availableForestClients"> | ||
<template #empty>No organization available</template> | ||
|
||
<Column v-if="availableForestClients.length === 1" header=""> | ||
<template #body="{ data }"> | ||
<RadioButton | ||
class="fam-checkbox" | ||
:value="data" | ||
v-model="formData.forestClients[0]" | ||
readonly | ||
/> | ||
</template> | ||
</Column> | ||
|
||
<Column v-else header=""> | ||
<template #body="{ data }"> | ||
<Checkbox | ||
class="fam-checkbox" | ||
:binary="true" | ||
:model-value="isForestClientSelected(data)" | ||
@change="toggleForestClient(data)" | ||
/> | ||
</template> | ||
</Column> | ||
|
||
<Column header="Name" field="client_name" /> | ||
|
||
<Column header="Client number" field="forest_client_number" /> | ||
</DataTable> | ||
</Field> | ||
</div> | ||
</template> | ||
|
||
<style lang="scss"> | ||
.foresnt-client-select-table-container { | ||
.error-text-container { | ||
padding: 0; | ||
height: fit-content; | ||
margin-bottom: 0.5rem; | ||
} | ||
|
||
.subsection-title-container { | ||
margin: 1.5rem 0; | ||
} | ||
|
||
.input-with-verify-button { | ||
.add-organization-button { | ||
width: 12rem; | ||
} | ||
} | ||
|
||
.fam-table { | ||
.p-datatable-emptymessage { | ||
background-color: var(--layer-01); | ||
} | ||
} | ||
|
||
.fam-checkbox { | ||
display: flex; | ||
flex-direction: row; | ||
align-items: center; | ||
.p-checkbox-box { | ||
width: 1rem; | ||
height: 1rem; | ||
} | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ import { | |
AdminRoleAuthGroup, | ||
type AdminUserAccessResponse, | ||
type FamAuthGrantDto, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused import. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. man we need a linter installed |
||
type FamForestClientBase, | ||
} from "fam-admin-mgmt-api/model"; | ||
|
||
/** | ||
|
@@ -55,3 +56,45 @@ export const isUserDelegatedAdminOnly = ( | |
|
||
return !isAppAdmin && isDelegatedAdmin; | ||
}; | ||
|
||
/** | ||
* Retrieves the list of forest clients associated with a specific application | ||
* for which the user is a delegated admin. | ||
* | ||
* @param {number} appId - The ID of the application to retrieve forest clients for. | ||
* @param {AdminUserAccessResponse} [userAccess] - The response containing user access information. | ||
* @returns {FamForestClientBase[]} An array of forest clients if the user is a delegated admin | ||
* for the specified application; returns an empty array if the user does not have delegated admin access | ||
* or if the userAccess data is invalid. | ||
* | ||
*/ | ||
export const getForestClientsUnderApp = ( | ||
appId: number, | ||
userAccess?: AdminUserAccessResponse | ||
): FamForestClientBase[] | null => { | ||
if ( | ||
!userAccess || | ||
!isSelectedAppAuthorized( | ||
AdminRoleAuthGroup.DelegatedAdmin, | ||
appId, | ||
userAccess | ||
) | ||
) { | ||
return []; | ||
} | ||
|
||
const forestClients: FamForestClientBase[] = | ||
userAccess.access | ||
.find( | ||
(grantDto) => | ||
grantDto.auth_key === AdminRoleAuthGroup.DelegatedAdmin | ||
) | ||
?.grants.find( | ||
(grantDetailDto) => grantDetailDto.application.id === appId | ||
) | ||
?.roles?.flatMap( | ||
(roleGrantDto) => roleGrantDto.forest_clients ?? [] | ||
) || []; | ||
|
||
return forestClients; | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really sure how this
validate
works...Just curious, how does
useField(props.fieldId)
know what to validate?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's validating the based on the field id provided
in this case it's
forestClients
inside the validation logic