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') }}
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 >
385404<script setup lang="ts">
386405import {
387406 mdiDelete ,
407+ mdiFilterVariant ,
388408 mdiFormatListBulletedSquare ,
389409 mdiPencil ,
390410 mdiViewGridOutline ,
@@ -395,9 +415,11 @@ import { t } from '@nextcloud/l10n'
395415import NcActionButton from ' @nextcloud/vue/components/NcActionButton'
396416import NcActions from ' @nextcloud/vue/components/NcActions'
397417import NcButton from ' @nextcloud/vue/components/NcButton'
418+ import NcChip from ' @nextcloud/vue/components/NcChip'
398419import NcDialog from ' @nextcloud/vue/components/NcDialog'
399420import NcIconSvgWrapper from ' @nextcloud/vue/components/NcIconSvgWrapper'
400421import NcNoteCard from ' @nextcloud/vue/components/NcNoteCard'
422+ import NcPopover from ' @nextcloud/vue/components/NcPopover'
401423import NcSettingsSection from ' @nextcloud/vue/components/NcSettingsSection'
402424import NcTextField from ' @nextcloud/vue/components/NcTextField'
403425
@@ -429,6 +451,7 @@ const recentSelectionGesture = ref<{ surface: 'cards' | 'list', key: string, at:
429451const crudSearch = ref (' ' )
430452const crudScopeFilter = ref <' all' | ' system' | ' group' | ' user' >(' all' )
431453const crudPage = ref (1 )
454+ const popoverBoundary = document .getElementById (' app-content-vue' ) ?? document .body
432455const CRUD_PAGE_SIZE = 20
433456
434457const 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+
598631const 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