Skip to content

Commit 9b9f1c2

Browse files
committed
feat(policy): adopt files-style scope filters with popover and chips
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent ae57b63 commit 9b9f1c2

1 file changed

Lines changed: 71 additions & 24 deletions

File tree

src/views/Settings/PolicyWorkbench/RealPolicyWorkbench.vue

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -181,27 +181,42 @@
181181
:label="t('libresign', 'Search rules')"
182182
:placeholder="t('libresign', 'Search by scope, target, or value')"
183183
@update:modelValue="onCrudSearchChange" />
184-
<div class="policy-workbench__scope-filter">
185-
<p class="policy-workbench__scope-filter-label">{{ t('libresign', 'Filter table by scope') }}</p>
186-
<div class="policy-workbench__filter-inline">
187-
<label class="policy-workbench__filter-option">
188-
<input type="radio" name="crudScope" :checked="crudScopeFilter === 'all'" @change="setCrudScopeFilter('all', true)" />
189-
<span>{{ t('libresign', 'All scopes') }}</span>
190-
</label>
191-
<label class="policy-workbench__filter-option">
192-
<input type="radio" name="crudScope" :checked="crudScopeFilter === 'system'" @change="setCrudScopeFilter('system', true)" />
193-
<span>{{ t('libresign', 'Instance') }}</span>
194-
</label>
195-
<label class="policy-workbench__filter-option">
196-
<input type="radio" name="crudScope" :checked="crudScopeFilter === 'group'" @change="setCrudScopeFilter('group', true)" />
197-
<span>{{ t('libresign', 'Group') }}</span>
198-
</label>
199-
<label class="policy-workbench__filter-option">
200-
<input type="radio" name="crudScope" :checked="crudScopeFilter === 'user'" @change="setCrudScopeFilter('user', true)" />
201-
<span>{{ t('libresign', 'User') }}</span>
202-
</label>
203-
</div>
204-
</div>
184+
<NcPopover :boundary="popoverBoundary">
185+
<template #trigger>
186+
<NcButton :aria-label="t('libresign', 'Filters')" :pressed="crudScopeFilter !== 'all'" variant="tertiary">
187+
<template #icon>
188+
<NcIconSvgWrapper :path="mdiFilterVariant" />
189+
</template>
190+
{{ t('libresign', 'Filters') }}
191+
</NcButton>
192+
</template>
193+
<template #default>
194+
<div class="policy-workbench__crud-filter-popover">
195+
<p class="policy-workbench__crud-filter-title">{{ t('libresign', 'Scope') }}</p>
196+
<div class="policy-workbench__crud-filter-options">
197+
<label class="policy-workbench__filter-option">
198+
<input type="radio" name="crudScope" :checked="crudScopeFilter === 'all'" @change="setCrudScopeFilter('all', true)" />
199+
<span>{{ t('libresign', 'All scopes') }}</span>
200+
</label>
201+
<label class="policy-workbench__filter-option">
202+
<input type="radio" name="crudScope" :checked="crudScopeFilter === 'system'" @change="setCrudScopeFilter('system', true)" />
203+
<span>{{ t('libresign', 'Instance') }}</span>
204+
</label>
205+
<label class="policy-workbench__filter-option">
206+
<input type="radio" name="crudScope" :checked="crudScopeFilter === 'group'" @change="setCrudScopeFilter('group', true)" />
207+
<span>{{ t('libresign', 'Group') }}</span>
208+
</label>
209+
<label class="policy-workbench__filter-option">
210+
<input type="radio" name="crudScope" :checked="crudScopeFilter === 'user'" @change="setCrudScopeFilter('user', true)" />
211+
<span>{{ t('libresign', 'User') }}</span>
212+
</label>
213+
</div>
214+
<NcButton v-if="crudScopeFilter !== 'all'" variant="tertiary" @click="setCrudScopeFilter('all', true)">
215+
{{ t('libresign', 'Clear filter') }}
216+
</NcButton>
217+
</div>
218+
</template>
219+
</NcPopover>
205220
<div v-if="state.viewMode === 'system-admin'" class="policy-workbench__crud-create">
206221
<NcButton variant="primary" size="small" :disabled="!hasCreatableScope" :title="createRuleDisabledReason || undefined" @click="requestCreateRule()">
207222
{{ t('libresign', 'Create rule') }}
@@ -212,6 +227,10 @@
212227
</div>
213228
</div>
214229

230+
<div v-if="activeScopeFilterChip" class="policy-workbench__crud-filter-chips">
231+
<NcChip :aria-label-close="t('libresign', 'Remove filter')" :text="activeScopeFilterChip" @close="setCrudScopeFilter('all', true)" />
232+
</div>
233+
215234
<p v-if="state.createUserOverrideDisabledReason" class="policy-workbench__table-note">
216235
{{ t('libresign', 'Some users may not allow user overrides because their group rule requires inheritance.') }}
217236
</p>
@@ -385,6 +404,7 @@
385404
<script setup lang="ts">
386405
import {
387406
mdiDelete,
407+
mdiFilterVariant,
388408
mdiFormatListBulletedSquare,
389409
mdiPencil,
390410
mdiViewGridOutline,
@@ -395,9 +415,11 @@ import { t } from '@nextcloud/l10n'
395415
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
396416
import NcActions from '@nextcloud/vue/components/NcActions'
397417
import NcButton from '@nextcloud/vue/components/NcButton'
418+
import NcChip from '@nextcloud/vue/components/NcChip'
398419
import NcDialog from '@nextcloud/vue/components/NcDialog'
399420
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
400421
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
422+
import NcPopover from '@nextcloud/vue/components/NcPopover'
401423
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
402424
import NcTextField from '@nextcloud/vue/components/NcTextField'
403425
@@ -429,6 +451,7 @@ const recentSelectionGesture = ref<{ surface: 'cards' | 'list', key: string, at:
429451
const crudSearch = ref('')
430452
const crudScopeFilter = ref<'all' | 'system' | 'group' | 'user'>('all')
431453
const crudPage = ref(1)
454+
const popoverBoundary = document.getElementById('app-content-vue') ?? document.body
432455
const CRUD_PAGE_SIZE = 20
433456
434457
const DRAG_OPEN_THRESHOLD_PX = 6
@@ -595,6 +618,16 @@ const createRuleDisabledReason = computed(() => {
595618
return ''
596619
})
597620
621+
const activeScopeFilterChip = computed(() => {
622+
if (crudScopeFilter.value === 'all') {
623+
return ''
624+
}
625+
626+
return t('libresign', 'Scope: {scope}', {
627+
scope: crudScopeLabel(crudScopeFilter.value),
628+
})
629+
})
630+
598631
const pendingRemovalMessage = computed(() => {
599632
if (!pendingRemoval.value) {
600633
return ''
@@ -1030,13 +1063,15 @@ onBeforeUnmount(() => {
10301063
color: var(--color-text-maxcontrast);
10311064
}
10321065
1033-
&__scope-filter {
1066+
&__crud-filter-popover {
10341067
display: flex;
10351068
flex-direction: column;
1036-
gap: 0.25rem;
1069+
gap: calc(var(--default-grid-baseline) / 2);
1070+
padding: calc(var(--default-grid-baseline) / 2);
1071+
min-width: calc(7 * var(--default-clickable-area));
10371072
}
10381073
1039-
&__scope-filter-label {
1074+
&__crud-filter-title {
10401075
margin: 0;
10411076
font-size: 0.78rem;
10421077
font-weight: 600;
@@ -1045,6 +1080,18 @@ onBeforeUnmount(() => {
10451080
color: var(--color-text-maxcontrast);
10461081
}
10471082
1083+
&__crud-filter-options {
1084+
display: flex;
1085+
flex-direction: column;
1086+
gap: 0.4rem;
1087+
}
1088+
1089+
&__crud-filter-chips {
1090+
display: flex;
1091+
align-items: center;
1092+
margin-top: 0.5rem;
1093+
}
1094+
10481095
&__settings-grid {
10491096
margin-top: 1rem;
10501097
display: grid;

0 commit comments

Comments
 (0)