156156 <div class =" policy-workbench__dialog" >
157157 <div class =" policy-workbench__main" >
158158 <header class =" policy-workbench__dialog-header" >
159- <h2 >{{ state.activeDefinition.title }}</h2 >
160- <p class =" policy-workbench__dialog-description" >{{ state.activeDefinition.description }}</p >
159+ <p class =" policy-workbench__dialog-description" >{{ dialogDescription }}</p >
161160 </header >
162161
163- <p
162+ <NcNoteCard
164163 v-if =" removalFeedback"
164+ type =" success"
165165 class =" policy-workbench__removal-feedback"
166166 aria-live =" polite" >
167167 {{ removalFeedback }}
168- </p >
168+ </NcNoteCard >
169169
170- <div v-if =" state.summary" class =" policy-workbench__summary-line policy-workbench__summary-line--crud" >
171- <span class =" policy-workbench__summary-caption" >{{ t('libresign', 'Default:') }}</span >
172- <strong class =" policy-workbench__summary-value-compact" >{{ state.summary.currentBaseValue }}</strong >
173- <span class =" policy-workbench__summary-source-inline" >
174- ({{ state.hasGlobalDefault ? t('libresign', 'custom default') : t('libresign', 'system default') }})
175- </span >
170+ <div v-if =" state.summary" class =" policy-workbench__default-inline" >
171+ <span class =" policy-workbench__default-inline-label" >{{ t('libresign', 'Default:') }}</span >
172+ <strong class =" policy-workbench__default-inline-value" >{{ state.summary.currentBaseValue }}</strong >
173+ <span class =" policy-workbench__default-inline-source" >({{ defaultSourceLabel }})</span >
174+ <NcButton
175+ v-if =" state.viewMode === 'system-admin'"
176+ variant =" tertiary"
177+ size =" small"
178+ class =" policy-workbench__default-inline-action"
179+ @click =" state.startEditor({ scope: 'system' })" >
180+ {{ t('libresign', 'Change') }}
181+ </NcButton >
176182 </div >
177- <p v-if =" state.summary" class =" policy-workbench__effective-result" >
178- {{ t('libresign', 'Effective result: {value}', { value: state.summary.currentBaseValue }) }}
179- </p >
180183
181184 <div class =" policy-workbench__table-toolbar-row policy-workbench__table-toolbar-row--crud" >
182185 <NcAppNavigationSearch
245248 {{ t('libresign', 'Some users may not allow user overrides because their group rule requires inheritance.') }}
246249 </p >
247250
248- <div v-if =" !state.inheritedSystemRule && state.viewMode === 'system-admin'" class =" policy-workbench__global-default-hint" >
249- <p >{{ t('libresign', 'No instance default is configured. This setting currently uses the system default.') }}</p >
250- <NcButton variant =" primary" size =" small" @click =" state.startEditor({ scope: 'system' })" >
251- {{ t('libresign', 'Set instance default') }}
252- </NcButton >
253- </div >
254-
255251 <div class =" policy-workbench__table-scroll" >
256252 <div class =" policy-workbench__table-priority-note" role =" note" aria-live =" polite" >
257253 <NcIconSvgWrapper :path =" mdiInformationOutline" :size =" 16" />
263259 <th >{{ t('libresign', 'Type') }}</th >
264260 <th >{{ t('libresign', 'Target') }}</th >
265261 <th >{{ t('libresign', 'Value') }}</th >
266- <th >{{ t('libresign', 'Behavior') }}</th >
267262 <th >{{ t('libresign', 'Actions') }}</th >
268263 </tr >
269264 </thead >
272267 <td >{{ crudScopeLabel(row.scope) }}</td >
273268 <td >{{ row.targetLabel }}</td >
274269 <td >{{ row.valueLabel }}</td >
275- <td class =" policy-workbench__status" >
276- <span
277- class =" policy-workbench__status-label"
278- :class =" { 'policy-workbench__status--inherit': row.inheritanceLabel === t('libresign', 'Enforced') }"
279- :title =" row.inheritanceLabel === t('libresign', 'Enforced') ? t('libresign', 'User cannot change this rule.') : t('libresign', 'User can choose the signing order.')" >
280- {{ row.inheritanceLabel }}
281- </span >
282- </td >
283270 <td class =" policy-workbench__table-actions" >
284271 <template v-if =" row .ruleId " >
285- <NcActions :aria-label =" t('libresign', 'Rule actions')" >
272+ <NcActions
273+ :aria-label =" t('libresign', 'Rule actions')"
274+ :open =" openRuleActionsKey === row.key"
275+ @update:open =" updateRuleActionsOpen(row.key, $event)" >
286276 <NcActionButton @click =" handleEditRule(row.scope, row.ruleId)" >
287277 <template #icon >
288278 <NcIconSvgWrapper :path =" mdiPencil" :size =" 16" />
301291 </td >
302292 </tr >
303293 <tr v-if =" pagedCrudRows.length === 0" >
304- <td colspan =" 5 " class =" policy-workbench__table-empty" >{{ t('libresign', 'No rules match the current filters.') }}</td >
294+ <td colspan =" 4 " class =" policy-workbench__table-empty" >{{ t('libresign', 'No rules match the current filters.') }}</td >
305295 </tr >
306296 </tbody >
307297 </table >
@@ -483,6 +473,7 @@ const removalFeedback = ref<string | null>(null)
483473const removalFeedbackTimeout = ref <number | null >(null )
484474const lastPress = ref <{ surface: ' cards' | ' list' , key: string , x: number , y: number } | null >(null )
485475const recentSelectionGesture = ref <{ surface: ' cards' | ' list' , key: string , at: number } | null >(null )
476+ const openRuleActionsKey = ref <string | null >(null )
486477const crudSearch = ref (' ' )
487478const crudScopeFilter = ref <' all' | ' system' | ' group' | ' user' >(' all' )
488479const crudPage = ref (1 )
@@ -491,6 +482,7 @@ const CRUD_PAGE_SIZE = 20
491482const DRAG_OPEN_THRESHOLD_PX = 6
492483const SELECTION_GUARD_WINDOW_MS = 400
493484const CATALOG_LAYOUT_CONFIG_KEY = ' policy_workbench_catalog_compact_view'
485+ const REMOVAL_FEEDBACK_DURATION_MS = 6000
494486
495487const filteredSettingSummaries = computed (() => {
496488 const normalized = settingsFilter .value .trim ().toLowerCase ()
@@ -529,7 +521,6 @@ type CrudRow = {
529521 scope: CrudScope ,
530522 targetLabel: string ,
531523 valueLabel: string ,
532- inheritanceLabel: string ,
533524 canRemove: boolean ,
534525}
535526
@@ -543,7 +534,6 @@ const filteredCrudRows = computed<CrudRow[]>(() => {
543534 scope: ' system' ,
544535 targetLabel: t (' libresign' , ' Default (instance-wide)' ),
545536 valueLabel: state .summary ?.currentBaseValue ?? t (' libresign' , ' Not configured' ),
546- inheritanceLabel: systemRule .allowChildOverride === false ? t (' libresign' , ' Enforced' ) : t (' libresign' , ' User can choose' ),
547537 canRemove: Boolean (systemRule .id && state .hasGlobalDefault ),
548538 })
549539 }
@@ -555,7 +545,6 @@ const filteredCrudRows = computed<CrudRow[]>(() => {
555545 scope: ' group' ,
556546 targetLabel: state .resolveTargetLabel (' group' , rule .targetId || ' ' ),
557547 valueLabel: summarizeRuleValue (rule .value ),
558- inheritanceLabel: rule .allowChildOverride ? t (' libresign' , ' User can choose' ) : t (' libresign' , ' Enforced' ),
559548 canRemove: true ,
560549 })
561550 }
@@ -567,9 +556,6 @@ const filteredCrudRows = computed<CrudRow[]>(() => {
567556 scope: ' user' ,
568557 targetLabel: state .resolveTargetLabel (' user' , rule .targetId || ' ' ),
569558 valueLabel: summarizeRuleValue (rule .value ),
570- inheritanceLabel: resolveSignatureFlowMode (rule .value as never ) === ' none'
571- ? t (' libresign' , ' User can choose' )
572- : t (' libresign' , ' Enforced' ),
573559 canRemove: true ,
574560 })
575561 }
@@ -601,7 +587,7 @@ const filteredCrudRows = computed<CrudRow[]>(() => {
601587 }
602588
603589 const scope = crudScopeLabel (row .scope ).toLowerCase ()
604- return [scope , row .targetLabel .toLowerCase (), row .valueLabel .toLowerCase (), row . inheritanceLabel . toLowerCase () ]
590+ return [scope , row .targetLabel .toLowerCase (), row .valueLabel .toLowerCase ()]
605591 .some ((value ) => value .includes (normalized ))
606592 })
607593})
@@ -644,6 +630,14 @@ const editorHelp = computed(() => {
644630 return t (' libresign' , ' Overrides group and instance rules for selected users.' )
645631})
646632
633+ const dialogDescription = computed (() => {
634+ if (state .activeDefinition ?.key === ' signature_flow' ) {
635+ return t (' libresign' , ' Control how signers complete documents.' )
636+ }
637+
638+ return state .activeDefinition ?.description || ' '
639+ })
640+
647641function scopeCreateDisabledReason(scope : ' system' | ' group' | ' user' ) {
648642 if (scope === ' group' ) {
649643 return state .createGroupOverrideDisabledReason || ' '
@@ -719,6 +713,12 @@ const activeScopeFilterChip = computed(() => {
719713 })
720714})
721715
716+ const defaultSourceLabel = computed (() => {
717+ return state .hasGlobalDefault
718+ ? t (' libresign' , ' custom' )
719+ : t (' libresign' , ' system' )
720+ })
721+
722722const pendingRemovalMessage = computed (() => {
723723 if (! pendingRemoval .value ) {
724724 return ' '
@@ -1032,7 +1032,12 @@ function promptRuleRemoval(ruleId: string, scope: 'system' | 'group' | 'user', t
10321032 pendingRemoval .value = { ruleId , scope , targetLabel , help }
10331033}
10341034
1035+ function updateRuleActionsOpen(ruleKey : string , open : boolean ) {
1036+ openRuleActionsKey .value = open ? ruleKey : (openRuleActionsKey .value === ruleKey ? null : openRuleActionsKey .value )
1037+ }
1038+
10351039function closeOpenActionsMenu() {
1040+ openRuleActionsKey .value = null
10361041 const activeElement = document .activeElement
10371042 if (activeElement instanceof HTMLElement ) {
10381043 activeElement .blur ()
@@ -1069,6 +1074,8 @@ function confirmDiscardDialog() {
10691074 if (action === ' close-setting' ) {
10701075 state .closeSetting ()
10711076 }
1077+
1078+ openRuleActionsKey .value = null
10721079}
10731080
10741081async function confirmRuleRemoval() {
@@ -1093,7 +1100,7 @@ async function confirmRuleRemoval() {
10931100 removalFeedbackTimeout .value = window .setTimeout (() => {
10941101 removalFeedback .value = null
10951102 removalFeedbackTimeout .value = null
1096- }, 2200 )
1103+ }, REMOVAL_FEEDBACK_DURATION_MS )
10971104
10981105 pendingRemoval .value = null
10991106 } finally {
@@ -1145,6 +1152,7 @@ onBeforeUnmount(() => {
11451152 }
11461153
11471154 pendingDiscardAction .value = null
1155+ openRuleActionsKey .value = null
11481156 showCreateScopeDialog .value = false
11491157 selectedCreateScope .value = null
11501158})
@@ -1823,12 +1831,41 @@ onBeforeUnmount(() => {
18231831 color : var (--color-text-maxcontrast );
18241832 }
18251833
1826- & __effective-result {
1827- margin : -0.2rem 0 0.6rem ;
1828- font-size : 0.84rem ;
1834+ & __default-inline {
1835+ display : inline-flex ;
1836+ align-items : center ;
1837+ gap : 0.35rem ;
1838+ flex-wrap : wrap ;
1839+ margin : 0.05rem 0 0.55rem ;
1840+ font-size : 0.9rem ;
1841+ line-height : 1.3 ;
1842+ }
1843+
1844+ & __default-inline-label {
1845+ font-weight : 600 ;
1846+ color : var (--color-main-text );
1847+ }
1848+
1849+ & __default-inline-value {
1850+ font-weight : 700 ;
1851+ color : var (--color-main-text );
1852+ }
1853+
1854+ & __default-inline-source {
18291855 color : var (--color-text-maxcontrast );
18301856 }
18311857
1858+ & __default-inline-action {
1859+ margin-inline-start : 0.35rem ;
1860+
1861+ :deep (.button-vue ) {
1862+ min-height : auto ;
1863+ padding : 0.05rem 0.35rem ;
1864+ font-size : 0.84rem ;
1865+ font-weight : 600 ;
1866+ }
1867+ }
1868+
18321869 & __summary-wrap {
18331870 :deep (.notecard ) {
18341871 margin : 0 ;
@@ -2203,35 +2240,6 @@ onBeforeUnmount(() => {
22032240 color : var (--color-text-maxcontrast );
22042241 }
22052242
2206- & __status--inherit {
2207- color : var (--color-main-text );
2208- }
2209-
2210- & __global-default-hint {
2211- display : flex ;
2212- align-items : flex-start ;
2213- justify-content : flex-start ;
2214- flex-direction : column ;
2215- gap : 0.75rem ;
2216- padding : 0.7rem 0.8rem ;
2217- margin-bottom : 0.55rem ;
2218- border : 1px solid color-mix (in srgb , var (--color-primary-element ) 22% , var (--color-border-maxcontrast ));
2219- border-radius : 10px ;
2220- background : color-mix (in srgb , var (--color-primary-element ) 7% , var (--color-main-background ));
2221-
2222- p {
2223- margin : 0 ;
2224- font-size : 0.86rem ;
2225- line-height : 1.45 ;
2226- color : var (--color-main-text );
2227- }
2228-
2229- :deep (.button-vue ) {
2230- white-space : nowrap ;
2231- font-weight : 600 ;
2232- }
2233- }
2234-
22352243 & __create-scope-hint {
22362244 margin : -0.35rem 0 0 ;
22372245 font-size : 0.84rem ;
@@ -2612,13 +2620,11 @@ onBeforeUnmount(() => {
26122620 }
26132621
26142622 & __removal-feedback {
2615- margin : 0 ;
2616- padding : 0.65rem 0.8rem ;
2617- border : 1px solid color-mix (in srgb , var (--color-success ) 36% , transparent );
2618- border-radius : 10px ;
2619- background : color-mix (in srgb , var (--color-success ) 12% , var (--color-main-background ));
2620- color : var (--color-main-text );
2621- font-size : 0.88rem ;
2623+ margin : 0 0 0.2rem ;
2624+
2625+ :deep (.notecard ) {
2626+ margin : 0 ;
2627+ }
26222628 }
26232629
26242630 & __saving-overlay {
0 commit comments