Skip to content

Commit a0a692f

Browse files
committed
feat(policy-workbench): simplify signing order header and feedback
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent 17175d5 commit a0a692f

1 file changed

Lines changed: 84 additions & 78 deletions

File tree

src/views/Settings/PolicyWorkbench/RealPolicyWorkbench.vue

Lines changed: 84 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -156,27 +156,30 @@
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
@@ -245,13 +248,6 @@
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" />
@@ -263,7 +259,6 @@
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>
@@ -272,17 +267,12 @@
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" />
@@ -301,7 +291,7 @@
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)
483473
const removalFeedbackTimeout = ref<number | null>(null)
484474
const lastPress = ref<{ surface: 'cards' | 'list', key: string, x: number, y: number } | null>(null)
485475
const recentSelectionGesture = ref<{ surface: 'cards' | 'list', key: string, at: number } | null>(null)
476+
const openRuleActionsKey = ref<string | null>(null)
486477
const crudSearch = ref('')
487478
const crudScopeFilter = ref<'all' | 'system' | 'group' | 'user'>('all')
488479
const crudPage = ref(1)
@@ -491,6 +482,7 @@ const CRUD_PAGE_SIZE = 20
491482
const DRAG_OPEN_THRESHOLD_PX = 6
492483
const SELECTION_GUARD_WINDOW_MS = 400
493484
const CATALOG_LAYOUT_CONFIG_KEY = 'policy_workbench_catalog_compact_view'
485+
const REMOVAL_FEEDBACK_DURATION_MS = 6000
494486
495487
const 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+
647641
function 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+
722722
const 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+
10351039
function 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
10741081
async 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

Comments
 (0)