@@ -547,10 +547,10 @@ import NcTextField from '@nextcloud/vue/components/NcTextField'
547547
548548import { usePoliciesStore } from ' ../../../../store/policies'
549549import { useUserConfigStore } from ' ../../../../store/userconfig.js'
550- import { realDefinitions } from ' ../settings/realDefinitions'
551- import type { RealPolicySettingCategory } from ' ../settings/realTypes'
552550import PolicyRuleEditorPanel from ' ../PolicyRuleEditorPanel.vue'
553551import { createRealPolicyWorkbenchState } from ' ../useRealPolicyWorkbench'
552+ import { useCatalogCrudTable } from ' ./composables/useCatalogCrudTable'
553+ import { useCatalogPresentation } from ' ./composables/useCatalogPresentation'
554554import { useCatalogState } from ' ./composables/useCatalogState'
555555import { useCatalogInteractions } from ' ./composables/useCatalogInteractions'
556556import { useNavigation } from ' ./composables/useNavigation'
@@ -573,10 +573,6 @@ const isRemovingRule = ref(false)
573573const removalFeedback = ref <string | null >(null )
574574const removalFeedbackTimeout = ref <number | null >(null )
575575const openRuleActionsKey = ref <string | null >(null )
576- const crudSearch = ref (' ' )
577- const crudScopeFilter = ref <' all' | ' system' | ' group' | ' user' >(' all' )
578- const crudPage = ref (1 )
579- const scopeFilterOpen = ref (false )
580576const isRtl = ref (false )
581577
582578// Initialize catalog state composable
@@ -593,87 +589,39 @@ const {
593589 getFilter : () => catalogState .settingsFilter .value ,
594590 onOpenSetting : (key ) => state .openSetting (key as never ),
595591})
596-
597- const CRUD_PAGE_SIZE = 20
598- const REMOVAL_FEEDBACK_DURATION_MS = 6000
599-
600- const CATEGORY_ORDER: RealPolicySettingCategory [] = [
601- ' who-can-sign' ,
602- ' how-signing-works' ,
603- ' signer-experience' ,
604- ' what-gets-recorded' ,
605- ' time-and-limits' ,
606- ' trust-and-verification' ,
607- ' system-behavior' ,
608- ]
609-
610- const categoryLabel = (category : RealPolicySettingCategory ): string => {
611- switch (category ) {
612- case ' who-can-sign' :
613- return t (' libresign' , ' Who can sign documents' )
614- case ' how-signing-works' :
615- return t (' libresign' , ' How signing works' )
616- case ' signer-experience' :
617- return t (' libresign' , ' What the signer sees' )
618- case ' what-gets-recorded' :
619- return t (' libresign' , ' What gets recorded' )
620- case ' time-and-limits' :
621- return t (' libresign' , ' Time and limits' )
622- case ' trust-and-verification' :
623- return t (' libresign' , ' Trust and verification' )
624- case ' system-behavior' :
625- return t (' libresign' , ' System behavior' )
626- default :
627- return t (' libresign' , ' Other' )
628- }
629- }
630-
631- const categoryBySettingKey = computed <Record <string , RealPolicySettingCategory >>(() => {
632- const map: Record <string , RealPolicySettingCategory > = {}
633- for (const definition of Object .values (realDefinitions )) {
634- map [definition .key ] = definition .category ?? ' system-behavior'
635- }
636-
637- return map
592+ const {
593+ filteredSettingSummaries,
594+ visibleCategorySections,
595+ effectiveCatalogLayout,
596+ hasActiveFilter,
597+ hasVisibleCategorySections,
598+ showCategoryNavigation,
599+ catalogViewButtonLabel,
600+ catalogCollapseButtonLabel,
601+ } = useCatalogPresentation ({
602+ visibleSettingSummaries: computed (() => state .visibleSettingSummaries ),
603+ settingsFilter: catalogState .settingsFilter ,
604+ catalogLayout: catalogState .catalogLayout ,
605+ isCatalogCollapsed: catalogState .isCatalogCollapsed ,
606+ isSmallViewport ,
638607})
639-
640- const filteredSettingSummaries = computed (() => {
641- const normalized = catalogState .settingsFilter .value .trim ().toLowerCase ()
642- if (! normalized ) {
643- return state .visibleSettingSummaries
644- }
645-
646- return state .visibleSettingSummaries .filter ((summary ) => {
647- return [summary .title , summary .context ?? ' ' , summary .description , summary .defaultSummary ]
648- .some ((value ) => value .toLowerCase ().includes (normalized ))
649- })
608+ const {
609+ crudSearch,
610+ crudScopeFilter,
611+ crudPage,
612+ scopeFilterOpen,
613+ crudPageCount,
614+ pagedCrudRows,
615+ activeScopeFilterChip,
616+ crudScopeLabel,
617+ onCrudSearchChange,
618+ setCrudScopeFilter,
619+ } = useCatalogCrudTable ({
620+ state ,
621+ summarizeRuleValue ,
650622})
651623
652- const visibleCategorySections = computed < Array <{
653- key: RealPolicySettingCategory ,
654- id: string ,
655- label: string ,
656- summaries: typeof filteredSettingSummaries .value ,
657- }>> (() => {
658- const grouped = new Map <RealPolicySettingCategory , typeof filteredSettingSummaries .value >()
659- for (const category of CATEGORY_ORDER ) {
660- grouped .set (category , [])
661- }
662-
663- for (const summary of filteredSettingSummaries .value ) {
664- const category = categoryBySettingKey .value [summary .key ] ?? ' system-behavior'
665- grouped .get (category )?.push (summary )
666- }
667-
668- return CATEGORY_ORDER
669- .map ((category ) => ({
670- key: category ,
671- id: ` policy-category-${category } ` ,
672- label: categoryLabel (category ),
673- summaries: grouped .get (category ) ?? [],
674- }))
675- .filter ((category ) => category .summaries .length > 0 )
676- })
624+ const REMOVAL_FEEDBACK_DURATION_MS = 6000
677625
678626const navigation = useNavigation (visibleCategorySections )
679627
@@ -688,20 +636,6 @@ const activeEditorProps = computed<Record<string, unknown>>(() => {
688636
689637 return state .activeDefinition .resolveEditorProps ?.(activePolicy , baseEditorProps ) ?? baseEditorProps
690638})
691- const effectiveCatalogLayout = computed (() => isSmallViewport .value ? ' cards' : catalogState .catalogLayout .value )
692- const hasActiveFilter = computed (() => catalogState .settingsFilter .value .trim ().length > 0 )
693- const hasVisibleCategorySections = computed (() => visibleCategorySections .value .length > 0 )
694- const showCategoryNavigation = computed (() => hasVisibleCategorySections .value )
695- const catalogViewButtonLabel = computed (() => {
696- return effectiveCatalogLayout .value === ' cards'
697- ? t (' libresign' , ' Switch to compact view' )
698- : t (' libresign' , ' Switch to card view' )
699- })
700- const catalogCollapseButtonLabel = computed (() => {
701- return catalogState .isCatalogCollapsed .value
702- ? t (' libresign' , ' Expand settings categories' )
703- : t (' libresign' , ' Collapse settings categories' )
704- })
705639
706640const selectedTargetOptions = computed (() => {
707641 if (! state .editorDraft ) {
@@ -711,93 +645,6 @@ const selectedTargetOptions = computed(() => {
711645 return state .availableTargets .filter ((option ) => state .editorDraft ?.targetIds .includes (option .id ))
712646})
713647
714- type CrudScope = ' system' | ' group' | ' user'
715- type CrudRow = {
716- key: string ,
717- ruleId: string | null ,
718- scope: CrudScope ,
719- targetLabel: string ,
720- valueLabel: string ,
721- canRemove: boolean ,
722- }
723-
724- const filteredCrudRows = computed <CrudRow []>(() => {
725- const rows: CrudRow [] = []
726- const systemRule = state .inheritedSystemRule
727- if (systemRule && state .hasGlobalDefault ) {
728- rows .push ({
729- key: systemRule .id ,
730- ruleId: systemRule .id ,
731- scope: ' system' ,
732- targetLabel: t (' libresign' , ' Default (everyone)' ),
733- valueLabel: state .summary ?.currentBaseValue ?? t (' libresign' , ' Not configured' ),
734- canRemove: Boolean (systemRule .id ),
735- })
736- }
737-
738- for (const rule of state .visibleGroupRules ) {
739- rows .push ({
740- key: rule .id ,
741- ruleId: rule .id ,
742- scope: ' group' ,
743- targetLabel: state .resolveTargetLabel (' group' , rule .targetId || ' ' ),
744- valueLabel: summarizeRuleValue (rule .value ),
745- canRemove: true ,
746- })
747- }
748-
749- for (const rule of state .visibleUserRules ) {
750- rows .push ({
751- key: rule .id ,
752- ruleId: rule .id ,
753- scope: ' user' ,
754- targetLabel: state .resolveTargetLabel (' user' , rule .targetId || ' ' ),
755- valueLabel: summarizeRuleValue (rule .value ),
756- canRemove: true ,
757- })
758- }
759-
760- const scopePriority: Record <CrudScope , number > = {
761- user: 0 ,
762- group: 1 ,
763- system: 2 ,
764- }
765-
766- rows .sort ((left , right ) => {
767- const priorityDiff = scopePriority [left .scope ] - scopePriority [right .scope ]
768- if (priorityDiff !== 0 ) {
769- return priorityDiff
770- }
771-
772- return left .targetLabel .localeCompare (right .targetLabel )
773- })
774-
775- const normalized = crudSearch .value .trim ().toLowerCase ()
776-
777- return rows .filter ((row ) => {
778- if (crudScopeFilter .value !== ' all' && row .scope !== crudScopeFilter .value ) {
779- return false
780- }
781-
782- if (! normalized ) {
783- return true
784- }
785-
786- const scope = crudScopeLabel (row .scope ).toLowerCase ()
787- return [scope , row .targetLabel .toLowerCase (), row .valueLabel .toLowerCase ()]
788- .some ((value ) => value .includes (normalized ))
789- })
790- })
791-
792- const crudPageCount = computed (() => Math .max (1 , Math .ceil (filteredCrudRows .value .length / CRUD_PAGE_SIZE )))
793- const pagedCrudRows = computed (() => {
794- if (crudPage .value > crudPageCount .value ) {
795- crudPage .value = crudPageCount .value
796- }
797-
798- const start = (crudPage .value - 1 ) * CRUD_PAGE_SIZE
799- return filteredCrudRows .value .slice (start , start + CRUD_PAGE_SIZE )
800- })
801648
802649const ruleDialogTitle = computed (() => {
803650 if (! state .editorDraft ) {
@@ -964,16 +811,6 @@ const createScopeOptions = computed<Array<{
964811 })
965812})
966813
967- const activeScopeFilterChip = computed (() => {
968- if (crudScopeFilter .value === ' all' ) {
969- return ' '
970- }
971-
972- return t (' libresign' , ' Scope: {scope}' , {
973- scope: crudScopeLabel (crudScopeFilter .value ),
974- })
975- })
976-
977814const defaultSourceLabel = computed (() => {
978815 return state .hasGlobalDefault
979816 ? t (' libresign' , ' custom' )
@@ -1134,33 +971,6 @@ function resolveSignatureFlowMode(value: unknown): 'parallel' | 'ordered_numeric
1134971 return null
1135972}
1136973
1137- function crudScopeLabel(scope : CrudScope ) {
1138- if (scope === ' system' ) {
1139- return t (' libresign' , ' Everyone' )
1140- }
1141-
1142- if (scope === ' group' ) {
1143- return t (' libresign' , ' Group' )
1144- }
1145-
1146- return t (' libresign' , ' User' )
1147- }
1148-
1149- function onCrudSearchChange(value : string | number ) {
1150- crudSearch .value = String (value ?? ' ' )
1151- crudPage .value = 1
1152- }
1153-
1154- function setCrudScopeFilter(value : ' all' | ' system' | ' group' | ' user' , selected : boolean ) {
1155- if (! selected ) {
1156- return
1157- }
1158-
1159- crudScopeFilter .value = value
1160- crudPage .value = 1
1161- scopeFilterOpen .value = false
1162- }
1163-
1164974function requestCreateRule() {
1165975 if (! hasCreatableScope .value || saveStatus .value === ' saving' ) {
1166976 return
0 commit comments