Skip to content

Commit

Permalink
Merge pull request #211 from bcgov/SC3687
Browse files Browse the repository at this point in the history
Add tab navigation and aria labels for permissions model
  • Loading branch information
TimCsaky authored Jun 12, 2024
2 parents 348fa6c + 04d6c23 commit 006527d
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 15 deletions.
8 changes: 8 additions & 0 deletions frontend/src/components/bucket/BucketPermission.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ onBeforeMount(async () => {
<Button
class="mt-1 mb-4"
@click="showSearchUsers = true"
@keyup.enter="showSearchUsers = true"
>
<font-awesome-icon
icon="fa-solid fa-user-plus"
Expand All @@ -99,6 +100,7 @@ onBeforeMount(async () => {
:rows-per-page-options="[10, 20, 50]"
sort-field="fullName"
:sort-order="1"
aria-label="Bucket Permissions"
>
<template #empty>
<div class="flex justify-content-center">
Expand All @@ -108,6 +110,7 @@ onBeforeMount(async () => {
<Column
field="fullName"
header="Name"
aria-labelledby="upload_checkbox"
/>
<Column
field="idpName"
Expand All @@ -122,6 +125,7 @@ onBeforeMount(async () => {
<Checkbox
v-model="data.create"
input-id="create"
aria-label="upload"
:binary="true"
@update:model-value="(value: boolean) => updateBucketPermission(value, data.userId, Permissions.CREATE)"
/>
Expand All @@ -136,6 +140,7 @@ onBeforeMount(async () => {
<Checkbox
v-model="data.read"
input-id="read"
aria-label="Read"
:binary="true"
@update:model-value="(value: boolean) => updateBucketPermission(value, data.userId, Permissions.READ)"
/>
Expand All @@ -150,6 +155,7 @@ onBeforeMount(async () => {
<Checkbox
v-model="data.update"
input-id="update"
aria-label="Update"
:binary="true"
@update:model-value="(value: boolean) => updateBucketPermission(value, data.userId, Permissions.UPDATE)"
/>
Expand All @@ -164,6 +170,7 @@ onBeforeMount(async () => {
<Checkbox
v-model="data.delete"
input-id="delete"
aria-label="delete"
:binary="true"
@update:model-value="(value: boolean) => updateBucketPermission(value, data.userId, Permissions.DELETE)"
/>
Expand All @@ -189,6 +196,7 @@ onBeforeMount(async () => {
<Button
class="p-button-lg p-button-text"
severity="danger"
aria-label="remove"
@click="removeBucketUser(data.userId)"
>
<font-awesome-icon icon="fa-solid fa-user-xmark" />
Expand Down
23 changes: 19 additions & 4 deletions frontend/src/components/bucket/BucketTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { BucketChildConfig, BucketPermission, BucketTableBucketName } from '@/co
import { Spinner } from '@/components/layout';
import { SyncButton, ShareButton } from '@/components/common';
import { Button, Column, Dialog, TreeTable, useConfirm } from '@/lib/primevue';
import { useAppStore, useAuthStore, useBucketStore, usePermissionStore } from '@/store';
import { useAppStore, useAuthStore, useBucketStore, useNavStore, usePermissionStore } from '@/store';
import { DELIMITER, Permissions } from '@/utils/constants';
import { getBucketPath, joinPath } from '@/utils/utils';
import { getBucketPath, joinPath, onDialogHide } from '@/utils/utils';
import type { TreeTableExpandedKeys } from 'primevue/treetable';
import type { Ref } from 'vue';
Expand All @@ -20,6 +20,7 @@ const permissionStore = usePermissionStore();
const { getIsLoading } = storeToRefs(useAppStore());
const { getUserId } = storeToRefs(useAuthStore());
const { getBuckets } = storeToRefs(bucketStore);
const { focusedElement } = storeToRefs(useNavStore());
// State
const expandedKeys: Ref<TreeTableExpandedKeys> = ref({});
Expand Down Expand Up @@ -58,6 +59,7 @@ const showPermissions = async (bucketId: string, bucketName: string) => {
permissionsVisible.value = true;
permissionsBucketId.value = bucketId;
permissionBucketName.value = bucketName;
focusedElement.value = document.activeElement;
};
const confirmDeleteBucket = (bucketId: string) => {
Expand Down Expand Up @@ -313,6 +315,7 @@ watch(getBuckets, () => {
</Button>
<Button
v-if="permissionStore.isBucketActionAllowed(node.data.bucketId, getUserId, Permissions.MANAGE)"
id="folder_permissions"
v-tooltip.bottom="'Folder permissions'"
class="p-button-lg p-button-text"
aria-label="Folder permissions"
Expand Down Expand Up @@ -353,21 +356,33 @@ watch(getBuckets, () => {

<!-- eslint-disable vue/no-v-model-argument -->
<Dialog
id="permissions_dialog"
v-model:visible="permissionsVisible"
:draggable="false"
:modal="true"
class="bcbox-info-dialog"
aria-labelledby="permissions_label"
aria-describedby="permissions_desc"
@after-hide="onDialogHide"
>
<!-- eslint-enable vue/no-v-model-argument -->
<template #header>
<font-awesome-icon
icon="fas fa-users"
fixed-width
/>
<span class="p-dialog-title">Folder permissions</span>
<span
id="permissions_label"
class="p-dialog-title"
>
Folder permissions
</span>
</template>

<h3 class="bcbox-info-dialog-subhead">
<h3
id="permissions_desc"
class="bcbox-info-dialog-subhead"
>
{{ permissionBucketName }}
</h3>

Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/form/SearchUsers.vue
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ onMounted(() => {

<template>
<div>
<div v-if="getConfig.idpList.length <= 3">
<div
<ul v-if="getConfig.idpList.length <= 3">
<li
v-for="idp of getConfig.idpList"
:key="idp.idp"
class="field-radiobutton mt-1"
Expand All @@ -128,8 +128,8 @@ onMounted(() => {
@click="onReset"
/>
<label :for="idp.idp">{{ idp.name }}</label>
</div>
</div>
</li>
</ul>
<div v-else>
<Dropdown
v-model="selectedIDP"
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/components/object/ObjectPermission.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ onBeforeMount(() => {
<Button
class="mt-1 mb-4"
@click="showSearchUsers = true"
@keyup.enter="showSearchUsers = true"
>
<font-awesome-icon
icon="fa-solid fa-user-plus"
Expand All @@ -104,6 +105,7 @@ onBeforeMount(() => {
current-page-report-template="{first}-{last} of {totalRecords}"
:rows-per-page-options="[10, 20, 50]"
sort-field="fullName"
aria-label="File Permissions"
:sort-order="1"
>
<template #empty>
Expand Down Expand Up @@ -146,6 +148,7 @@ onBeforeMount(() => {
<Checkbox
v-model="data.update"
input-id="update"
aria-label="update"
:binary="true"
@update:model-value="(value: boolean) => updateObjectPermission(value, data.userId, Permissions.UPDATE)"
/>
Expand All @@ -160,6 +163,7 @@ onBeforeMount(() => {
<Checkbox
v-model="data.delete"
input-id="delete"
aria-label="delete"
:binary="true"
@update:model-value="(value: boolean) => updateObjectPermission(value, data.userId, Permissions.DELETE)"
/>
Expand All @@ -174,6 +178,7 @@ onBeforeMount(() => {
<Checkbox
v-model="data.manage"
input-id="manage"
aria-label="manage"
:binary="true"
@update:model-value="(value: boolean) => updateObjectPermission(value, data.userId, Permissions.MANAGE)"
/>
Expand All @@ -184,7 +189,9 @@ onBeforeMount(() => {
<Button
class="p-button-lg p-button-text"
severity="danger"
aria-label="remove"
@click="removeObjectUser(data.userId)"
@keyup.enter="removeObjectUser(data.userId)"
>
<font-awesome-icon icon="fa-solid fa-user-xmark" />
</Button>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/object/ObjectPublicToggle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ watch(props, () => {
<template>
<InputSwitch
v-model="isPublic"
aria-label="Toggle to make public"
:disabled="
!(
usePermissionStore().isUserElevatedRights() &&
Expand Down
22 changes: 19 additions & 3 deletions frontend/src/components/object/ObjectTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import {
} from '@/components/object';
import { SyncButton, ShareButton } from '@/components/common';
import { Button, Column, DataTable, Dialog, InputText, useToast } from '@/lib/primevue';
import { useAuthStore, useObjectStore, usePermissionStore } from '@/store';
import { useAuthStore, useObjectStore, useNavStore, usePermissionStore } from '@/store';
import { Permissions, RouteNames } from '@/utils/constants';
import { onDialogHide } from '@/utils/utils';
import { ButtonMode } from '@/utils/enums';
import { formatDateLong } from '@/utils/formatters';
import { objectService } from '@/services';
Expand Down Expand Up @@ -50,6 +51,7 @@ const emit = defineEmits(['show-object-info']);
const objectStore = useObjectStore();
const permissionStore = usePermissionStore();
const { getUserId } = storeToRefs(useAuthStore());
const { focusedElement } = storeToRefs(useNavStore());
// State
const permissionsVisible = ref(false);
Expand Down Expand Up @@ -83,6 +85,7 @@ async function showPermissions(objectId: string) {
permissionsVisible.value = true;
permissionsObjectId.value = objectId;
permissionsObjectName.value = objectStore.getObject(objectId)?.name;
focusedElement.value = document.activeElement;
}
onMounted(() => {
Expand Down Expand Up @@ -339,6 +342,7 @@ const selectedFilters = (payload: any) => {
v-if="
permissionStore.isObjectActionAllowed(data.id, getUserId, Permissions.MANAGE, props.bucketId as string)
"
id="file_permissions"
v-tooltip.bottom="'File permissions'"
class="p-button-lg p-button-text"
aria-label="File permissions"
Expand Down Expand Up @@ -376,21 +380,33 @@ const selectedFilters = (payload: any) => {

<!-- eslint-disable vue/no-v-model-argument -->
<Dialog
id="permissions_dialog"
v-model:visible="permissionsVisible"
:draggable="false"
:modal="true"
class="bcbox-info-dialog"
aria-labelledby="permissions_label"
aria-describedby="permissions_desc"
@after-hide="onDialogHide"
>
<!-- eslint-enable vue/no-v-model-argument -->
<template #header>
<font-awesome-icon
icon="fas fa-users"
fixed-width
/>
<span class="p-dialog-title">File Permissions</span>
<span
id="permissions_label"
class="p-dialog-title"
>
File Permissions
</span>
</template>

<h3 class="bcbox-info-dialog-subhead">
<h3
id="permissions_desc"
class="bcbox-info-dialog-subhead"
>
{{ permissionsObjectName }}
</h3>

Expand Down
4 changes: 3 additions & 1 deletion frontend/src/store/navStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { RouteLocationNormalized } from 'vue-router';
export type NavStoreState = {
home: Ref<Object>;
items: Ref<Array<any>>;
focusedElement: Ref<any>;
};

export const useNavStore = defineStore('nav', () => {
Expand All @@ -16,7 +17,8 @@ export const useNavStore = defineStore('nav', () => {
label: 'Home',
to: '/'
}),
items: ref([])
items: ref([]),
focusedElement: ref(null)
};

// Getters
Expand Down
18 changes: 15 additions & 3 deletions frontend/src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { storeToRefs } from 'pinia';

import { DELIMITER } from '@/utils/constants';
import ConfigService from '@/services/configService';
import { ExcludeTypes } from '@/utils/enums';
import type { Bucket } from '@/types';
import { useNavStore } from '@/store';

/**
* @function differential
Expand Down Expand Up @@ -126,9 +129,7 @@ export function setDispositionHeader(filename: string) {
* @returns {string} full canonical url or path to bucket
*/
export function getBucketPath(bucket: Bucket, justPath = false): string {
return justPath ?
`${bucket.bucket}/${bucket.key}` :
`${bucket.endpoint}/${bucket.bucket}/${bucket.key}`;
return justPath ? `${bucket.bucket}/${bucket.key}` : `${bucket.endpoint}/${bucket.bucket}/${bucket.key}`;
}

/**
Expand All @@ -141,3 +142,14 @@ export function getLastSegment(path: string) {
const p = path.replace(/\/+$/, '');
return p.slice(p.lastIndexOf('/') + 1);
}

/**
* @function onDialogHide
* Return focus to the button which trigger model visibility
* @type {focusedElement} stores dom element which needs to be focused
*/
export function onDialogHide() {
const { focusedElement } = storeToRefs(useNavStore());
focusedElement.value?.focus();
focusedElement.value = null;
}

0 comments on commit 006527d

Please sign in to comment.