@anzusystems/common-admin 2.0.0-rc.4 → 2.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/AnzuSystemsCommonAdmin.d.ts +42 -32
- package/dist/AnzuSystemsCommonAdmin.js.map +1 -1
- package/dist/common-admin.css +1 -1
- package/dist/common-admin.js +282 -282
- package/dist/domains/anzuUser/api/anzuUserApi.d.ts +9 -12
- package/dist/domains/anzuUser/api/anzuUserApi.js.map +1 -1
- package/dist/domains/anzuUser/components/AAnzuUserDatatable.js.map +1 -1
- package/dist/domains/anzuUser/components/AAnzuUserDatatable.vue.d.ts +38 -44
- package/dist/domains/anzuUser/components/AAnzuUserDatatable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AAnzuUserFilter.js.map +1 -1
- package/dist/domains/anzuUser/components/AAnzuUserFilter.vue.d.ts +12 -13
- package/dist/domains/anzuUser/components/AAnzuUserFilter.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AAnzuUserForm.js.map +1 -1
- package/dist/domains/anzuUser/components/AAnzuUserForm.vue.d.ts +18 -20
- package/dist/domains/anzuUser/components/AAnzuUserForm.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AAnzuUserRoleAutocomplete.js.map +1 -1
- package/dist/domains/anzuUser/components/AAnzuUserRoleAutocomplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserBulkActionDialog.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserBulkActionDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserCopyPermissionsDialog.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserCopyPermissionsDialog.vue.d.ts +2 -3
- package/dist/domains/anzuUser/components/AUserCopyPermissionsDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserCreateInSystemButton.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserCreateInSystemButton.vue.d.ts +9 -15
- package/dist/domains/anzuUser/components/AUserCreateInSystemButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserEnabledSwitch.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserEnabledSwitch.vue.d.ts +8 -7
- package/dist/domains/anzuUser/components/AUserEnabledSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserManageButton.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserManageButton.vue.d.ts +0 -1
- package/dist/domains/anzuUser/components/AUserManageButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserMetadataForm.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserMetadataForm.vue.d.ts +8 -9
- package/dist/domains/anzuUser/components/AUserMetadataForm.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserMetadataRepairDialog.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserMetadataRepairDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserOtherSystemsTable.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserOtherSystemsTable.vue.d.ts +1 -2
- package/dist/domains/anzuUser/components/AUserOtherSystemsTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserSystemOverview.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserSystemOverview.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserSystemPanel.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserSystemPanel.vue.d.ts +2 -2
- package/dist/domains/anzuUser/components/AUserSystemPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserSystemStatusChip.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserSystemStatusChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserTabsShell.js.map +1 -1
- package/dist/domains/anzuUser/components/AUserTabsShell.vue.d.ts +17 -22
- package/dist/domains/anzuUser/components/AUserTabsShell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/anzuUser/composables/anzuUserActions.d.ts +5 -9
- package/dist/domains/anzuUser/composables/anzuUserActions.js.map +1 -1
- package/dist/domains/anzuUser/composables/anzuUserValidations.d.ts +4 -6
- package/dist/domains/anzuUser/composables/anzuUserValidations.js.map +1 -1
- package/dist/domains/anzuUser/composables/cachedAnzuUsers.d.ts +3 -3
- package/dist/domains/anzuUser/composables/cachedAnzuUsers.js.map +1 -1
- package/dist/domains/anzuUser/composables/userCrossSystemSearch.d.ts +2 -4
- package/dist/domains/anzuUser/composables/userCrossSystemSearch.js.map +1 -1
- package/dist/domains/anzuUser/composables/userCrossSystemWrites.d.ts +5 -11
- package/dist/domains/anzuUser/composables/userCrossSystemWrites.js.map +1 -1
- package/dist/domains/anzuUser/composables/userSystemDescriptor.d.ts +33 -57
- package/dist/domains/anzuUser/composables/userSystemDescriptor.js.map +1 -1
- package/dist/domains/anzuUser/composables/userSystemProbe.d.ts +7 -27
- package/dist/domains/anzuUser/composables/userSystemProbe.js.map +1 -1
- package/dist/domains/anzuUser/filter/anzuUserFilter.d.ts +6 -16
- package/dist/domains/anzuUser/filter/anzuUserFilter.js.map +1 -1
- package/dist/domains/anzuUser/store/anzuUserStore.d.ts +1 -5
- package/dist/domains/anzuUser/store/anzuUserStore.js.map +1 -1
- package/dist/domains/anzuUser/store/userCrossSystemStore.d.ts +3 -14
- package/dist/domains/anzuUser/store/userCrossSystemStore.js.map +1 -1
- package/dist/domains/anzuUser/utils/userMetadataDiff.d.ts +7 -19
- package/dist/domains/anzuUser/utils/userMetadataDiff.js.map +1 -1
- package/dist/domains/anzuUser/utils/userSystemState.d.ts +12 -30
- package/dist/domains/anzuUser/utils/userSystemState.js.map +1 -1
- package/dist/domains/anzuUser/utils/userTabs.d.ts +1 -3
- package/dist/domains/anzuUser/utils/userTabs.js.map +1 -1
- package/dist/domains/api/composables/defineApiClient.d.ts +4 -8
- package/dist/domains/api/composables/defineApiClient.js.map +1 -1
- package/dist/domains/api/composables/request.d.ts +18 -48
- package/dist/domains/api/composables/request.js.map +1 -1
- package/dist/domains/api/composables/useApiFetchByIds.d.ts +7 -21
- package/dist/domains/api/composables/useApiFetchByIds.js.map +1 -1
- package/dist/domains/api/composables/useApiFetchItems.d.ts +18 -57
- package/dist/domains/api/composables/useApiFetchItems.js.map +1 -1
- package/dist/domains/api/composables/useApiFetchList.d.ts +7 -23
- package/dist/domains/api/composables/useApiFetchList.js.map +1 -1
- package/dist/domains/api/composables/useApiFetchListBatch.d.ts +5 -22
- package/dist/domains/api/composables/useApiFetchListBatch.js.map +1 -1
- package/dist/domains/api/composables/useApiQueryBuilder.js.map +1 -1
- package/dist/domains/api/composables/useApiRequest.d.ts +16 -39
- package/dist/domains/api/composables/useApiRequest.js.map +1 -1
- package/dist/domains/api/utils/apiErrors.d.ts +28 -55
- package/dist/domains/api/utils/apiErrors.js.map +1 -1
- package/dist/domains/api/utils/listBody.d.ts +22 -43
- package/dist/domains/api/utils/listBody.js.map +1 -1
- package/dist/domains/auth/components/Acl.js.map +1 -1
- package/dist/domains/auth/components/Acl.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/auth/composables/aclAllowed.d.ts +2 -3
- package/dist/domains/auth/composables/aclAllowed.js.map +1 -1
- package/dist/domains/auth/composables/defineAuth.js.map +1 -1
- package/dist/domains/auth/composables/refreshSession.d.ts +10 -13
- package/dist/domains/auth/composables/refreshSession.js.map +1 -1
- package/dist/domains/cached/components/ACachedChip.js.map +1 -1
- package/dist/domains/cached/components/ACachedChip.vue.d.ts +13 -11
- package/dist/domains/cached/components/ACachedChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/cached/components/ACachedUserChip.js +1 -1
- package/dist/domains/cached/components/ACachedUserChip.js.map +1 -1
- package/dist/domains/cached/components/ACachedUserChip.vue.d.ts +3 -3
- package/dist/domains/cached/components/ACachedUserChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/cached/composables/createUserAndTimeTrackingFields.d.ts +9 -9
- package/dist/domains/cached/composables/createUserAndTimeTrackingFields.js.map +1 -1
- package/dist/domains/cached/composables/defineCached.d.ts +13 -11
- package/dist/domains/cached/composables/defineCached.js.map +1 -1
- package/dist/domains/cached/composables/useCachedItem.d.ts +7 -8
- package/dist/domains/cached/composables/useCachedItem.js.map +1 -1
- package/dist/domains/collab/components/ACollabLockedByUser.js.map +1 -1
- package/dist/domains/collab/components/ACollabLockedByUser.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/collab/composables/collabAnyDataChange.js.map +1 -1
- package/dist/domains/collab/composables/collabField.d.ts +5 -3
- package/dist/domains/collab/composables/collabField.js.map +1 -1
- package/dist/domains/collab/composables/collabInit.js +58 -54
- package/dist/domains/collab/composables/collabInit.js.map +1 -1
- package/dist/domains/collab/composables/collabRecovery.d.ts +49 -0
- package/dist/domains/collab/composables/collabRecovery.js +99 -0
- package/dist/domains/collab/composables/collabRecovery.js.map +1 -0
- package/dist/domains/collab/composables/collabRoom.js +106 -106
- package/dist/domains/collab/composables/collabRoom.js.map +1 -1
- package/dist/domains/collab/composables/collabState.d.ts +11 -4
- package/dist/domains/collab/composables/collabState.js +34 -25
- package/dist/domains/collab/composables/collabState.js.map +1 -1
- package/dist/domains/collab/composables/commonAdminCollabOptions.d.ts +4 -2
- package/dist/domains/collab/types/Collab.d.ts +31 -5
- package/dist/domains/collab/types/Collab.js +23 -11
- package/dist/domains/collab/types/Collab.js.map +1 -1
- package/dist/domains/customDataForm/components/ACustomDataForm.js.map +1 -1
- package/dist/domains/customDataForm/components/ACustomDataForm.vue.d.ts +7 -5
- package/dist/domains/customDataForm/components/ACustomDataForm.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/customDataForm/components/ACustomDataFormElement.js.map +1 -1
- package/dist/domains/customDataForm/components/ACustomDataFormElement.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/customDataForm/components/ACustomDataFormHiddenPart.js.map +1 -1
- package/dist/domains/customDataForm/components/ACustomDataFormHiddenPart.vue.d.ts +5 -3
- package/dist/domains/customDataForm/components/ACustomDataFormHiddenPart.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/customDataForm/composables/useCustomDataForm.js.map +1 -1
- package/dist/domains/customDataForm/types/CustomDataForm.d.ts +4 -1
- package/dist/domains/dam/api/damAssetApi.d.ts +7 -7
- package/dist/domains/dam/api/damAssetApi.js.map +1 -1
- package/dist/domains/dam/api/damAssetLicenceApi.d.ts +1 -1
- package/dist/domains/dam/api/damAssetLicenceApi.js.map +1 -1
- package/dist/domains/dam/api/damConstants.js.map +1 -1
- package/dist/domains/dam/api/damEndPoints.js.map +1 -1
- package/dist/domains/dam/api/damImageApi.js.map +1 -1
- package/dist/domains/dam/api/uploadApi.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetCustomMetadataForm.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetCustomMetadataForm.vue.d.ts +7 -5
- package/dist/domains/dam/assetDetail/components/AssetCustomMetadataForm.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailDialog.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailDialogFrame.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailDialogFrame.vue.d.ts +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailDialogFrame.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailSidebarActionsWrapper.vue.d.ts +5 -3
- package/dist/domains/dam/assetDetail/components/AssetDetailSidebarFrame.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailSidebarFrame.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailSidebarMetadata.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailSidebarMetadata.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailSidebarROI.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetDetailSidebarROI.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetFileInfoPanel.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetFileInfoPanel.vue.d.ts +1 -1
- package/dist/domains/dam/assetDetail/components/AssetFileInfoPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetImage.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetImage.vue.d.ts +1 -1
- package/dist/domains/dam/assetDetail/components/AssetImage.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetImageMetaIcons.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetImageMetaIcons.vue.d.ts +2 -2
- package/dist/domains/dam/assetDetail/components/AssetImageMetaIcons.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetInfobox.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetInfobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetMetadata.js.map +1 -1
- package/dist/domains/dam/assetDetail/components/AssetMetadata.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetDetail/composables/assetDetailExtSystem.d.ts +5 -6
- package/dist/domains/dam/assetDetail/composables/assetDetailExtSystem.js.map +1 -1
- package/dist/domains/dam/assetDetail/composables/assetDetailView.d.ts +10 -10
- package/dist/domains/dam/assetDetail/composables/assetDetailView.js.map +1 -1
- package/dist/domains/dam/assetDetail/store/assetDetailStore.js.map +1 -1
- package/dist/domains/dam/assetDetail/utils/assetMetadataMayStillChange.d.ts +4 -3
- package/dist/domains/dam/assetDetail/utils/assetMetadataMayStillChange.js.map +1 -1
- package/dist/domains/dam/assetSelect/api/damPodcastApi.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AAssetListInner.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AAssetListInner.vue.d.ts +789 -787
- package/dist/domains/dam/assetSelect/components/AAssetListInner.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AAssetSelect.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AAssetSelect.vue.d.ts +395 -393
- package/dist/domains/dam/assetSelect/components/AAssetSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AAssetSelectMedia.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AAssetSelectMedia.vue.d.ts +14 -12
- package/dist/domains/dam/assetSelect/components/AAssetSelectMedia.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AssetDistributionServiceNameFilter.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AssetDistributionServiceNameFilter.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AssetSelectListBar.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AssetSelectListBar.vue.d.ts +9 -7
- package/dist/domains/dam/assetSelect/components/AssetSelectListBar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AssetSelectTableRowItem.js.map +1 -1
- package/dist/domains/dam/assetSelect/components/AssetSelectTableRowItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/assetSelect/composables/assetSelectListActions.js.map +1 -1
- package/dist/domains/dam/assetSelect/store/assetSelectStore.js.map +1 -1
- package/dist/domains/dam/author/api/authorApi.js.map +1 -1
- package/dist/domains/dam/author/components/AuthorCreateButton.js.map +1 -1
- package/dist/domains/dam/author/components/AuthorCreateButton.vue.d.ts +1 -1
- package/dist/domains/dam/author/components/AuthorCreateButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteCachedAuthorChip.js.map +1 -1
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteCachedAuthorChip.vue.d.ts +9 -6
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteCachedAuthorChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteCachedAuthorChipConflicts.js.map +1 -1
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteCachedAuthorChipConflicts.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteWithCached.js +1 -1
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteWithCached.js.map +1 -1
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteWithCached.vue.d.ts +2 -2
- package/dist/domains/dam/author/components/AuthorRemoteAutocompleteWithCached.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/author/components/DamAuthorFilterRemoteAutocomplete.js.map +1 -1
- package/dist/domains/dam/author/components/DamAuthorFilterRemoteAutocomplete.vue.d.ts +1 -1
- package/dist/domains/dam/author/components/DamAuthorFilterRemoteAutocomplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/author/composables/cachedAuthors.d.ts +5 -4
- package/dist/domains/dam/author/composables/cachedAuthors.js.map +1 -1
- package/dist/domains/dam/author/composables/cachedUsers.d.ts +5 -4
- package/dist/domains/dam/author/composables/cachedUsers.js.map +1 -1
- package/dist/domains/dam/author/composables/damAuthorConfig.d.ts +2 -2
- package/dist/domains/dam/author/composables/damAuthorConfig.js.map +1 -1
- package/dist/domains/dam/components/DamAdminAssetLink.js.map +1 -1
- package/dist/domains/dam/components/DamAdminAssetLink.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/composables/commonAdminCoreDamOptions.d.ts +10 -8
- package/dist/domains/dam/composables/commonAdminCoreDamOptions.js.map +1 -1
- package/dist/domains/dam/composables/damConfigName.d.ts +8 -9
- package/dist/domains/dam/composables/damConfigName.js.map +1 -1
- package/dist/domains/dam/composables/damNotifications.d.ts +9 -9
- package/dist/domains/dam/composables/damNotifications.js.map +1 -1
- package/dist/domains/dam/composables/damNotificationsConnection.d.ts +4 -4
- package/dist/domains/dam/composables/damNotificationsConnection.js.map +1 -1
- package/dist/domains/dam/composables/damNotificationsEventBus.d.ts +2 -2
- package/dist/domains/dam/composables/damNotificationsEventBus.js.map +1 -1
- package/dist/domains/dam/composables/extSystemIdForCached.d.ts +5 -4
- package/dist/domains/dam/composables/extSystemIdForCached.js.map +1 -1
- package/dist/domains/dam/config/api/damAssetCustomFormApi.js.map +1 -1
- package/dist/domains/dam/config/api/damConfigApi.js.map +1 -1
- package/dist/domains/dam/config/composables/damConfigState.d.ts +5 -5
- package/dist/domains/dam/config/composables/damConfigState.js.map +1 -1
- package/dist/domains/dam/config/store/damConfigStore.d.ts +5 -4
- package/dist/domains/dam/config/store/damConfigStore.js.map +1 -1
- package/dist/domains/dam/config/utils/damFilterUserAllowedUploadConfigs.d.ts +3 -1
- package/dist/domains/dam/config/utils/damFilterUserAllowedUploadConfigs.js.map +1 -1
- package/dist/domains/dam/cropper/components/ACropper.js.map +1 -1
- package/dist/domains/dam/cropper/components/ACropper.vue.d.ts +8 -16
- package/dist/domains/dam/cropper/components/ACropper.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/cropper/components/DamAssetImageRoiSelect.js.map +1 -1
- package/dist/domains/dam/cropper/components/DamAssetImageRoiSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/cropper/store/imageRoiStore.d.ts +9 -12
- package/dist/domains/dam/cropper/store/imageRoiStore.js.map +1 -1
- package/dist/domains/dam/cropper/utils/cropperGeometry.d.ts +24 -38
- package/dist/domains/dam/cropper/utils/cropperGeometry.js.map +1 -1
- package/dist/domains/dam/cropper/utils/cropperJsService.d.ts +3 -7
- package/dist/domains/dam/cropper/utils/cropperJsService.js +10 -3
- package/dist/domains/dam/cropper/utils/cropperJsService.js.map +1 -1
- package/dist/domains/dam/cropper/utils/cropperTypes.d.ts +3 -6
- package/dist/domains/dam/cropper/utils/damAssetImageRoiSelectLoader.d.ts +5 -5
- package/dist/domains/dam/cropper/utils/damAssetImageRoiSelectLoader.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImageMediaWidget.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImageMediaWidget.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImagePublicInput.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImagePublicInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImageWidget.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImageWidget.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImageWidgetMultiple.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImageWidgetMultiple.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/AImageWidgetSimple.vue.d.ts +43 -41
- package/dist/domains/dam/imageWidget/components/AMediaWidgetSimple.vue.d.ts +31 -29
- package/dist/domains/dam/imageWidget/components/ImageDetailDialogMetadata.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageDetailDialogMetadata.vue.d.ts +29 -27
- package/dist/domains/dam/imageWidget/components/ImageDetailDialogMetadata.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageMassOperations.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageMassOperations.vue.d.ts +1 -1
- package/dist/domains/dam/imageWidget/components/ImageMassOperations.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageMediaWidgetInner.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageMediaWidgetInner.vue.d.ts +68 -66
- package/dist/domains/dam/imageWidget/components/ImageMediaWidgetInner.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageWidgetInner.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageWidgetInner.vue.d.ts +402 -400
- package/dist/domains/dam/imageWidget/components/ImageWidgetInner.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageWidgetMultipleInner.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageWidgetMultipleInner.vue.d.ts +384 -382
- package/dist/domains/dam/imageWidget/components/ImageWidgetMultipleInner.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageWidgetMultipleItem.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageWidgetMultipleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageWidgetMultipleLimitDialog.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/ImageWidgetMultipleLimitDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/imageWidget/components/MediaWidgetSimpleDialog.vue.d.ts +7 -5
- package/dist/domains/dam/imageWidget/composables/commonAdminImageOptions.js.map +1 -1
- package/dist/domains/dam/imageWidget/composables/imageApiCms.js.map +1 -1
- package/dist/domains/dam/imageWidget/composables/imageDialogDamAuthors.d.ts +11 -13
- package/dist/domains/dam/imageWidget/composables/imageDialogDamAuthors.js.map +1 -1
- package/dist/domains/dam/imageWidget/composables/useImageMassOperations.js.map +1 -1
- package/dist/domains/dam/imageWidget/store/imageMediaWidgetStore.js.map +1 -1
- package/dist/domains/dam/imageWidget/store/imageStore.js.map +1 -1
- package/dist/domains/dam/imageWidget/utils/damImage.d.ts +5 -6
- package/dist/domains/dam/imageWidget/utils/damImage.js.map +1 -1
- package/dist/domains/dam/imageWidget/utils/fieldLockTurns.d.ts +1 -2
- package/dist/domains/dam/imageWidget/utils/fieldLockTurns.js.map +1 -1
- package/dist/domains/dam/imageWidget/utils/imageSaves.d.ts +10 -14
- package/dist/domains/dam/imageWidget/utils/imageSaves.js.map +1 -1
- package/dist/domains/dam/imageWidget/utils/metadataToImageMap.js.map +1 -1
- package/dist/domains/dam/imageWidget/utils/waitLimit.d.ts +4 -6
- package/dist/domains/dam/imageWidget/utils/waitLimit.js.map +1 -1
- package/dist/domains/dam/keyword/api/keywordApi.js.map +1 -1
- package/dist/domains/dam/keyword/components/DamKeywordFilterRemoteAutocomplete.js.map +1 -1
- package/dist/domains/dam/keyword/components/DamKeywordFilterRemoteAutocomplete.vue.d.ts +1 -1
- package/dist/domains/dam/keyword/components/DamKeywordFilterRemoteAutocomplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/keyword/components/KeywordRemoteAutocompleteCachedKeywordChip.js.map +1 -1
- package/dist/domains/dam/keyword/components/KeywordRemoteAutocompleteCachedKeywordChip.vue.d.ts +8 -5
- package/dist/domains/dam/keyword/components/KeywordRemoteAutocompleteCachedKeywordChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/keyword/components/KeywordRemoteAutocompleteWithCached.js +1 -1
- package/dist/domains/dam/keyword/components/KeywordRemoteAutocompleteWithCached.js.map +1 -1
- package/dist/domains/dam/keyword/components/KeywordRemoteAutocompleteWithCached.vue.d.ts +2 -2
- package/dist/domains/dam/keyword/components/KeywordRemoteAutocompleteWithCached.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/keyword/composables/cachedKeywords.d.ts +5 -4
- package/dist/domains/dam/keyword/composables/cachedKeywords.js.map +1 -1
- package/dist/domains/dam/keyword/composables/damKeywordConfig.d.ts +2 -2
- package/dist/domains/dam/keyword/composables/damKeywordConfig.js.map +1 -1
- package/dist/domains/dam/types/Asset.d.ts +1 -1
- package/dist/domains/dam/types/Asset.js.map +1 -1
- package/dist/domains/dam/types/UploadQueue.d.ts +5 -4
- package/dist/domains/dam/types/UploadQueue.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/AssetCustomMetadataFormMassOperations.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/AssetCustomMetadataFormMassOperations.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/AssetQueueSelectedSidebar.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/AssetQueueSelectedSidebar.vue.d.ts +2 -2
- package/dist/domains/dam/uploadQueue/components/AssetQueueSelectedSidebar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialog.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingle.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingle.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingleSidebar.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingleSidebar.vue.d.ts +6 -4
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingleSidebar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingleSidebarMetadata.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingleSidebarMetadata.vue.d.ts +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingleSidebarMetadata.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingleSidebarMetadataContent.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueDialogSingleSidebarMetadataContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueEditable.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueEditable.vue.d.ts +6 -6
- package/dist/domains/dam/uploadQueue/components/UploadQueueEditable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueItemEditable.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/UploadQueueItemEditable.vue.d.ts +13 -13
- package/dist/domains/dam/uploadQueue/components/UploadQueueItemEditable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/uploadQueue/components/uploadQueueBindings.d.ts +13 -13
- package/dist/domains/dam/uploadQueue/components/uploadQueueBindings.js.map +1 -1
- package/dist/domains/dam/uploadQueue/composables/damUploadChunkSize.d.ts +2 -2
- package/dist/domains/dam/uploadQueue/composables/damUploadChunkSize.js.map +1 -1
- package/dist/domains/dam/uploadQueue/composables/uploadMeter.d.ts +12 -12
- package/dist/domains/dam/uploadQueue/composables/uploadMeter.js.map +1 -1
- package/dist/domains/dam/uploadQueue/composables/uploadQueueItemRefresh.d.ts +5 -5
- package/dist/domains/dam/uploadQueue/composables/uploadQueueItemRefresh.js.map +1 -1
- package/dist/domains/dam/uploadQueue/composables/uploadService.d.ts +2 -3
- package/dist/domains/dam/uploadQueue/composables/uploadService.js.map +1 -1
- package/dist/domains/dam/uploadQueue/composables/useUploadQueueDialog.d.ts +5 -4
- package/dist/domains/dam/uploadQueue/composables/useUploadQueueDialog.js.map +1 -1
- package/dist/domains/dam/uploadQueue/core/uploadQueueCore.d.ts +3 -2
- package/dist/domains/dam/uploadQueue/core/uploadQueueCore.js.map +1 -1
- package/dist/domains/dam/uploadQueue/core/uploadQueueCoreTypes.d.ts +8 -5
- package/dist/domains/dam/uploadQueue/core/uploadQueueCoreTypes.js.map +1 -1
- package/dist/domains/dam/uploadQueue/core/uploadQueueFill.d.ts +3 -3
- package/dist/domains/dam/uploadQueue/core/uploadQueueFill.js.map +1 -1
- package/dist/domains/dam/uploadQueue/presets/queuePresets.d.ts +8 -5
- package/dist/domains/dam/uploadQueue/presets/queuePresets.js.map +1 -1
- package/dist/domains/dam/uploadQueue/presets/uploadPresets.d.ts +15 -13
- package/dist/domains/dam/uploadQueue/presets/uploadPresets.js.map +1 -1
- package/dist/domains/dam/uploadQueue/settlement/uploadPollSchedule.d.ts +7 -7
- package/dist/domains/dam/uploadQueue/settlement/uploadPollSchedule.js.map +1 -1
- package/dist/domains/dam/uploadQueue/settlement/uploadPoller.d.ts +4 -4
- package/dist/domains/dam/uploadQueue/settlement/uploadPoller.js.map +1 -1
- package/dist/domains/dam/uploadQueue/settlement/uploadSettle.d.ts +28 -30
- package/dist/domains/dam/uploadQueue/settlement/uploadSettle.js.map +1 -1
- package/dist/domains/dam/uploadQueue/settlement/uploadSettlement.d.ts +2 -2
- package/dist/domains/dam/uploadQueue/settlement/uploadSettlement.js.map +1 -1
- package/dist/domains/dam/uploadQueue/settlement/uploadSettlementRuntime.d.ts +2 -2
- package/dist/domains/dam/uploadQueue/settlement/uploadSettlementRuntime.js.map +1 -1
- package/dist/domains/dam/uploadQueue/settlement/uploadSettlementTypes.d.ts +63 -73
- package/dist/domains/dam/uploadQueue/settlement/uploadSettlementTypes.js.map +1 -1
- package/dist/domains/dam/uploadQueue/store/uploadQueuesStore.d.ts +8 -9
- package/dist/domains/dam/uploadQueue/store/uploadQueuesStore.js.map +1 -1
- package/dist/domains/dam/user/api/userApi.d.ts +2 -2
- package/dist/domains/dam/user/api/userApi.js.map +1 -1
- package/dist/domains/dam/user/components/DamDistributionServiceSelect.js.map +1 -1
- package/dist/domains/dam/user/components/DamDistributionServiceSelect.vue.d.ts +1 -1
- package/dist/domains/dam/user/components/DamDistributionServiceSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/user/components/DamExternalProviderAssetSelect.js.map +1 -1
- package/dist/domains/dam/user/components/DamExternalProviderAssetSelect.vue.d.ts +1 -1
- package/dist/domains/dam/user/components/DamExternalProviderAssetSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/user/components/DamUserRemoteAutocomplete.js.map +1 -1
- package/dist/domains/dam/user/components/DamUserRemoteAutocomplete.vue.d.ts +1 -1
- package/dist/domains/dam/user/components/DamUserRemoteAutocomplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/dam/user/composables/damUserSelectActions.d.ts +1 -1
- package/dist/domains/dam/user/composables/damUserSelectActions.js.map +1 -1
- package/dist/domains/dam/user/types/DamDistributionServiceType.d.ts +2 -2
- package/dist/domains/dam/user/types/DamDistributionServiceType.js.map +1 -1
- package/dist/domains/dam/user/types/DamExternalProviderAssetType.d.ts +1 -1
- package/dist/domains/dam/user/types/DamExternalProviderAssetType.js.map +1 -1
- package/dist/domains/filters/bookmarks/components/FilterBookmarkDialog.js.map +1 -1
- package/dist/domains/filters/bookmarks/components/FilterBookmarkDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/bookmarks/store/bookmarksStore.d.ts +3 -3
- package/dist/domains/filters/bookmarks/store/bookmarksStore.js.map +1 -1
- package/dist/domains/filters/components/AFilterDatetimePicker.js.map +1 -1
- package/dist/domains/filters/components/AFilterDatetimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/components/AFilterInteger.js.map +1 -1
- package/dist/domains/filters/components/AFilterInteger.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/components/AFilterString.js.map +1 -1
- package/dist/domains/filters/components/AFilterString.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/components/AFilterTimeInterval.js +1 -1
- package/dist/domains/filters/components/AFilterTimeInterval.js.map +1 -1
- package/dist/domains/filters/components/AFilterTimeInterval.vue.d.ts +5 -3
- package/dist/domains/filters/components/AFilterTimeInterval.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/components/AFilterValueObjectOptionsSelect.js.map +1 -1
- package/dist/domains/filters/components/AFilterValueObjectOptionsSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/components/AFilterWrapper.vue.d.ts +17 -15
- package/dist/domains/filters/components/AFilterWrapperSidebar.vue.d.ts +5 -3
- package/dist/domains/filters/components/FiltersSelected.js.map +1 -1
- package/dist/domains/filters/components/FiltersSelected.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/composables/filterFactory.d.ts +16 -26
- package/dist/domains/filters/composables/filterFactory.js +38 -31
- package/dist/domains/filters/composables/filterFactory.js.map +1 -1
- package/dist/domains/filters/datatable/components/ADatatableOrdering.js.map +1 -1
- package/dist/domains/filters/datatable/components/ADatatableOrdering.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/domains/filters/datatable/components/ADatatableOrdering.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/datatable/components/ADatatablePagination.js.map +1 -1
- package/dist/domains/filters/datatable/components/ADatatablePagination.vue_vue_type_script_setup_true_lang.js +2 -4
- package/dist/domains/filters/datatable/components/ADatatablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/filters/utils/filterInjectionKeys.js.map +1 -1
- package/dist/domains/form/components/AFormDatetimePicker.js.map +1 -1
- package/dist/domains/form/components/AFormDatetimePicker.vue.d.ts +7 -5
- package/dist/domains/form/components/AFormDatetimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/form/components/AFormFlagDatetimePicker.js.map +1 -1
- package/dist/domains/form/components/AFormFlagDatetimePicker.vue.d.ts +7 -5
- package/dist/domains/form/components/AFormFlagDatetimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/form/components/AFormSwitch.vue.d.ts +7 -5
- package/dist/domains/form/components/AFormTextField.js.map +1 -1
- package/dist/domains/form/components/AFormTextField.vue.d.ts +9 -7
- package/dist/domains/form/components/AFormTextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/form/components/AFormTextarea.vue.d.ts +13 -11
- package/dist/domains/form/components/AFormValueObjectOptionsSelect.vue.d.ts +7 -5
- package/dist/domains/form/components/ASystemEntityScope.vue.d.ts +5 -3
- package/dist/domains/job/api/jobApi.js.map +1 -1
- package/dist/domains/job/components/AJobDetailCommon.vue.d.ts +5 -3
- package/dist/domains/listEditor/components/AListEditor.js.map +1 -1
- package/dist/domains/listEditor/components/AListEditor.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/listEditor/components/ANestedSortableListEditor.js.map +1 -1
- package/dist/domains/listEditor/components/ANestedSortableListEditor.vue.d.ts +2 -3
- package/dist/domains/listEditor/components/ANestedSortableListEditor.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/listEditor/components/ASortableListEditor.js.map +1 -1
- package/dist/domains/listEditor/components/ASortableListEditor.vue.d.ts +2 -3
- package/dist/domains/listEditor/components/ASortableListEditor.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/listEditor/composables/useListEditorController.d.ts +4 -5
- package/dist/domains/listEditor/composables/useListEditorController.js.map +1 -1
- package/dist/domains/listEditor/composables/useNestedListEditor.d.ts +3 -4
- package/dist/domains/listEditor/composables/useNestedListEditor.js.map +1 -1
- package/dist/domains/listEditor/composables/useNestedListEditorController.d.ts +5 -4
- package/dist/domains/listEditor/composables/useNestedListEditorController.js.map +1 -1
- package/dist/domains/listEditor/composables/useReorderMode.js.map +1 -1
- package/dist/domains/listEditor/types/listEditorTypes.d.ts +2 -2
- package/dist/domains/listEditor/utils/listEditorLoader.d.ts +5 -5
- package/dist/domains/listEditor/utils/listEditorLoader.js.map +1 -1
- package/dist/domains/listEditor/utils/resolveCompactText.js.map +1 -1
- package/dist/domains/log/api/logApi.d.ts +2 -3
- package/dist/domains/log/api/logApi.js.map +1 -1
- package/dist/domains/log/components/ALogDatatable.js.map +1 -1
- package/dist/domains/log/components/ALogDatatable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/log/components/ALogDetailView.js.map +1 -1
- package/dist/domains/log/components/ALogDetailView.vue.d.ts +1 -1
- package/dist/domains/log/components/ALogDetailView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/log/components/ALogFilter.js.map +1 -1
- package/dist/domains/log/components/ALogFilter.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/log/components/ALogListView.js.map +1 -1
- package/dist/domains/log/components/ALogListView.vue.d.ts +1 -1
- package/dist/domains/log/components/ALogListView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/log/composables/logActions.d.ts +4 -5
- package/dist/domains/log/composables/logActions.js.map +1 -1
- package/dist/domains/log/composables/logType.d.ts +6 -7
- package/dist/domains/log/composables/logType.js.map +1 -1
- package/dist/domains/log/filter/logFilter.d.ts +8 -11
- package/dist/domains/log/filter/logFilter.js.map +1 -1
- package/dist/domains/permission/components/APermissionEditor.js.map +1 -1
- package/dist/domains/permission/components/APermissionEditor.vue.d.ts +4 -4
- package/dist/domains/permission/components/APermissionEditor.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/permission/composables/permissionActions.d.ts +3 -6
- package/dist/domains/permission/composables/permissionActions.js.map +1 -1
- package/dist/domains/permission/config/api/permissionConfigApi.d.ts +2 -2
- package/dist/domains/permission/config/api/permissionConfigApi.js.map +1 -1
- package/dist/domains/permission/config/composables/permissionConfigActions.d.ts +3 -7
- package/dist/domains/permission/config/composables/permissionConfigActions.js.map +1 -1
- package/dist/domains/permission/config/store/permissionConfigStore.d.ts +2 -4
- package/dist/domains/permission/config/store/permissionConfigStore.js.map +1 -1
- package/dist/domains/permission/group/api/permissionGroupApi.d.ts +8 -10
- package/dist/domains/permission/group/api/permissionGroupApi.js.map +1 -1
- package/dist/domains/permission/group/components/APermissionGroupDatatable.js.map +1 -1
- package/dist/domains/permission/group/components/APermissionGroupDatatable.vue.d.ts +12 -10
- package/dist/domains/permission/group/components/APermissionGroupDatatable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/permission/group/components/APermissionGroupDetail.js.map +1 -1
- package/dist/domains/permission/group/components/APermissionGroupDetail.vue.d.ts +21 -22
- package/dist/domains/permission/group/components/APermissionGroupDetail.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/permission/group/components/APermissionGroupManage.js.map +1 -1
- package/dist/domains/permission/group/components/APermissionGroupManage.vue.d.ts +21 -22
- package/dist/domains/permission/group/components/APermissionGroupManage.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/permission/group/composables/cachedPermissionGroups.js.map +1 -1
- package/dist/domains/permission/group/composables/permissionGroupActions.d.ts +6 -8
- package/dist/domains/permission/group/composables/permissionGroupActions.js.map +1 -1
- package/dist/domains/permission/group/composables/permissionGroupValidations.d.ts +2 -3
- package/dist/domains/permission/group/composables/permissionGroupValidations.js.map +1 -1
- package/dist/domains/permission/group/filter/permissionGroupFilter.d.ts +2 -3
- package/dist/domains/permission/group/filter/permissionGroupFilter.js.map +1 -1
- package/dist/domains/permission/group/store/permissionGroupStore.d.ts +3 -6
- package/dist/domains/permission/group/store/permissionGroupStore.js.map +1 -1
- package/dist/domains/remoteAutocomplete/components/AFilterRemoteAutocomplete.js.map +1 -1
- package/dist/domains/remoteAutocomplete/components/AFilterRemoteAutocomplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/remoteAutocomplete/components/AFilterRemoteAutocompleteWithMinimal.js.map +1 -1
- package/dist/domains/remoteAutocomplete/components/AFilterRemoteAutocompleteWithMinimal.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/remoteAutocomplete/components/AFormRemoteAutocomplete.js.map +1 -1
- package/dist/domains/remoteAutocomplete/components/AFormRemoteAutocomplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/remoteAutocomplete/components/AFormRemoteAutocompleteWithCached.vue.d.ts +5 -3
- package/dist/domains/remoteAutocomplete/composables/createRemoteAutocomplete.d.ts +11 -13
- package/dist/domains/remoteAutocomplete/composables/createRemoteAutocomplete.js.map +1 -1
- package/dist/domains/subjectSelect/components/AFilterWrapperSubjectSelect.vue.d.ts +13 -11
- package/dist/domains/subjectSelect/components/ASubjectSelect.js.map +1 -1
- package/dist/domains/subjectSelect/components/ASubjectSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/subjectSelect/composables/useSubjectSelect.js +53 -51
- package/dist/domains/subjectSelect/composables/useSubjectSelect.js.map +1 -1
- package/dist/domains/system/appShell/components/AActionbar.vue.d.ts +7 -5
- package/dist/domains/system/appShell/components/ALayoutSwitch.js.map +1 -1
- package/dist/domains/system/appShell/components/ALayoutSwitch.vue.d.ts +7 -5
- package/dist/domains/system/appShell/components/ALayoutSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/system/appShell/composables/teleportSlot.d.ts +0 -1
- package/dist/domains/system/appShell/composables/teleportSlot.js.map +1 -1
- package/dist/domains/system/components/AAlerts.js.map +1 -1
- package/dist/domains/system/components/AAlerts.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/system/composables/alerts.js.map +1 -1
- package/dist/domains/system/composables/breadcrumbs.d.ts +3 -3
- package/dist/domains/system/composables/breadcrumbs.js.map +1 -1
- package/dist/domains/system/composables/languageSettings.js.map +1 -1
- package/dist/domains/system/composables/loginStatus.js.map +1 -1
- package/dist/domains/system/composables/navigationError.d.ts +6 -8
- package/dist/domains/system/composables/navigationError.js.map +1 -1
- package/dist/domains/system/composables/pageNavigation.d.ts +9 -10
- package/dist/domains/system/composables/pageNavigation.js.map +1 -1
- package/dist/domains/system/composables/recordActions.d.ts +14 -22
- package/dist/domains/system/composables/recordActions.js.map +1 -1
- package/dist/domains/system/composables/recordPage.d.ts +23 -38
- package/dist/domains/system/composables/recordPage.js.map +1 -1
- package/dist/domains/system/composables/routeHistory.d.ts +4 -5
- package/dist/domains/system/composables/routeHistory.js.map +1 -1
- package/dist/domains/system/composables/sentry.js.map +1 -1
- package/dist/domains/system/composables/useDebugFeatures.d.ts +3 -6
- package/dist/domains/system/composables/useDebugFeatures.js.map +1 -1
- package/dist/domains/system/store/datatablePageStore.d.ts +8 -1
- package/dist/domains/system/store/datatablePageStore.js +10 -3
- package/dist/domains/system/store/datatablePageStore.js.map +1 -1
- package/dist/domains/system/systemBar/components/ASystemBar.js.map +1 -1
- package/dist/domains/system/systemBar/components/ASystemBar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/system/systemBar/utils/appReload.d.ts +5 -5
- package/dist/domains/system/systemBar/utils/appReload.js.map +1 -1
- package/dist/domains/ui/buttons/action/components/AActionCloseButtonHistory.js.map +1 -1
- package/dist/domains/ui/buttons/action/components/AActionCloseButtonHistory.vue.d.ts +2 -3
- package/dist/domains/ui/buttons/action/components/AActionCloseButtonHistory.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/buttons/action/components/AActionDeleteButton.js.map +1 -1
- package/dist/domains/ui/buttons/action/components/AActionDeleteButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/buttons/components/ABtnSplit.vue.d.ts +9 -7
- package/dist/domains/ui/components/AAvatarColorPicker.js.map +1 -1
- package/dist/domains/ui/components/AAvatarColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/components/ACard.js.map +1 -1
- package/dist/domains/ui/components/ACard.vue.d.ts +7 -3
- package/dist/domains/ui/components/ACard.vue_vue_type_script_setup_true_lang.js +6 -2
- package/dist/domains/ui/components/ACard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/components/ACardLoader.js.map +1 -1
- package/dist/domains/ui/components/ACardLoader.vue.d.ts +1 -0
- package/dist/domains/ui/components/ACardLoader.vue_vue_type_script_setup_true_lang.js +13 -7
- package/dist/domains/ui/components/ACardLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/components/AChipNoLink.vue.d.ts +5 -3
- package/dist/domains/ui/components/ACopyText.vue.d.ts +9 -7
- package/dist/domains/ui/components/ACreateDialog.js.map +1 -1
- package/dist/domains/ui/components/ACreateDialog.vue.d.ts +11 -9
- package/dist/domains/ui/components/ACreateDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/components/ADialogToolbar.vue.d.ts +5 -3
- package/dist/domains/ui/components/ARow.vue.d.ts +5 -3
- package/dist/domains/ui/components/ATimeTrackingFields.js.map +1 -1
- package/dist/domains/ui/components/ATimeTrackingFields.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/components/AUserAndTimeTrackingFields.js.map +1 -1
- package/dist/domains/ui/components/AUserAndTimeTrackingFields.vue.d.ts +3 -5
- package/dist/domains/ui/components/AUserAndTimeTrackingFields.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/datetime/components/ADatetimePicker.js +1 -1
- package/dist/domains/ui/datetime/components/ADatetimePicker.js.map +1 -1
- package/dist/domains/ui/datetime/components/ADatetimePicker.vue.d.ts +5 -3
- package/dist/domains/ui/datetime/components/ADatetimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/file/components/AFileDropzone.js.map +1 -1
- package/dist/domains/ui/file/components/AFileDropzone.vue.d.ts +1 -1
- package/dist/domains/ui/file/components/AFileDropzone.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/file/components/AFileInput.js.map +1 -1
- package/dist/domains/ui/file/components/AFileInput.vue.d.ts +9 -7
- package/dist/domains/ui/file/components/AFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/file/components/AFileInputDialog.js.map +1 -1
- package/dist/domains/ui/file/components/AFileInputDialog.vue.d.ts +9 -7
- package/dist/domains/ui/file/components/AFileInputDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/file/composables/dropzone.js.map +1 -1
- package/dist/domains/ui/file/composables/formatAndSizeCheck.js.map +1 -1
- package/dist/domains/ui/view/components/AGenericView.vue.d.ts +7 -5
- package/dist/domains/ui/view/components/ALoginView.js +1 -1
- package/dist/domains/ui/view/components/ALoginView.js.map +1 -1
- package/dist/domains/ui/view/components/ALoginView.vue.d.ts +5 -3
- package/dist/domains/ui/view/components/ALoginView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/view/components/ALogoutView.js.map +1 -1
- package/dist/domains/ui/view/components/ALogoutView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/ui/view/components/ANotFoundView.js.map +1 -1
- package/dist/domains/ui/view/components/ANotFoundView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/domains/unsavedGuard/composables/useUnsavedChangesGuard.d.ts +6 -7
- package/dist/domains/unsavedGuard/composables/useUnsavedChangesGuard.js.map +1 -1
- package/dist/lib.d.ts +2 -2
- package/dist/plugins/commonVuetifyConfig.d.ts +3 -3
- package/dist/plugins/commonVuetifyConfig.js.map +1 -1
- package/dist/plugins/i18n.d.ts +4 -5
- package/dist/plugins/i18n.js.map +1 -1
- package/dist/plugins/pluginOptions.d.ts +4 -2
- package/dist/plugins/pluginOptions.js.map +1 -1
- package/dist/plugins/webfontloader.js.map +1 -1
- package/dist/shared/error/AnzuApiCancelledError.d.ts +5 -8
- package/dist/shared/error/AnzuApiCancelledError.js.map +1 -1
- package/dist/shared/error/AnzuError.d.ts +3 -5
- package/dist/shared/error/AnzuError.js.map +1 -1
- package/dist/shared/error/AuthUnavailableError.d.ts +3 -3
- package/dist/shared/error/AuthUnavailableError.js.map +1 -1
- package/dist/shared/error/isInCauseChain.d.ts +2 -2
- package/dist/shared/error/isInCauseChain.js.map +1 -1
- package/dist/shared/types/UserAndTimeTracking.d.ts +5 -5
- package/dist/shared/types/Validation.d.ts +4 -5
- package/dist/shared/types/common.d.ts +1 -3
- package/dist/shared/types/globalComponents.d.ts +5 -6
- package/dist/shared/utils/common.js.map +1 -1
- package/dist/shared/utils/datetime.d.ts +0 -1
- package/dist/shared/utils/datetime.js.map +1 -1
- package/dist/shared/utils/datetimePickerValue.d.ts +4 -7
- package/dist/shared/utils/datetimePickerValue.js.map +1 -1
- package/dist/shared/utils/development.d.ts +3 -3
- package/dist/shared/utils/development.js.map +1 -1
- package/dist/shared/utils/envConfig.d.ts +4 -4
- package/dist/shared/utils/envConfig.js.map +1 -1
- package/dist/shared/utils/json.d.ts +1 -1
- package/dist/shared/utils/json.js.map +1 -1
- package/dist/shared/utils/userAndTimeTracking.d.ts +5 -7
- package/dist/shared/utils/userAndTimeTracking.js.map +1 -1
- package/dist/shared/validators/vuelidate/common/useValidateHexColor.d.ts +3 -5
- package/dist/shared/validators/vuelidate/common/useValidateHexColor.js.map +1 -1
- package/dist/testing/appShell.d.ts +11 -11
- package/dist/testing/appShell.js.map +1 -1
- package/dist/testing/closeButtons.d.ts +9 -11
- package/dist/testing/closeButtons.js.map +1 -1
- package/dist/testing/declaredDependencies.d.ts +7 -7
- package/dist/testing/declaredDependencies.js.map +1 -1
- package/dist/testing/generatedRoutes.d.ts +6 -11
- package/dist/testing/generatedRoutes.js.map +1 -1
- package/dist/testing/routeHistory.d.ts +5 -12
- package/dist/testing/routeHistory.js.map +1 -1
- package/dist/testing/sortableLists.d.ts +16 -21
- package/dist/testing/sortableLists.js.map +1 -1
- package/dist/testing/typedRouter.d.ts +0 -1
- package/dist/testing/typedRouter.js.map +1 -1
- package/package.json +26 -26
- package/src/eslint/adminConfig.mjs +19 -27
- package/src/eslint/globalComponentNames.mjs +3 -4
- package/src/eslint/oxlint.mjs +7 -20
- package/src/eslint/plugin.d.mts +2 -4
- package/src/eslint/plugin.mjs +18 -34
- package/src/eslint/validRouteName.mjs +6 -7
- package/src/vite/devWatch.mjs +30 -43
- package/src/vite/index.d.mts +5 -5
- package/src/vite/sentry.mjs +7 -12
- package/src/vite/sourcemaps.mjs +4 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AUserTabsShell.js","names":["_sfc_main","AUserTabsShell_vue_vue_type_script_setup_true_lang_default","AUserTabsShell_default"],"sources":["../../../../src/domains/anzuUser/components/AUserTabsShell.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { computed, onMounted, provide, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useAlerts } from '@/domains/system/composables/alerts'\nimport { useAnzuUserFactory } from '@/domains/anzuUser/factory/AnzuUserFactory'\nimport { cloneDeep, isNull, isUndefined } from '@/shared/utils/common'\nimport { BulkOutcome } from '@/domains/anzuUser/store/userCrossSystemStore'\nimport { useUserCrossSystemWrites } from '@/domains/anzuUser/composables/userCrossSystemWrites'\nimport AUnsavedConfirmDialog from '@/domains/unsavedGuard/components/AUnsavedConfirmDialog.vue'\nimport { useUnsavedChangesGuard } from '@/domains/unsavedGuard/composables/useUnsavedChangesGuard'\nimport AUserOtherSystemsTable from '@/domains/anzuUser/components/AUserOtherSystemsTable.vue'\nimport AUserSystemPanel from '@/domains/anzuUser/components/AUserSystemPanel.vue'\nimport { type AnyUserSystemDescriptor, descriptorMayWrite } from '@/domains/anzuUser/composables/userSystemDescriptor'\nimport type { AnzuUser, BaseUser } from '@/shared/types/AnzuUser'\nimport type { IntegerId } from '@/shared/types/common'\nimport { UserSystemRefreshHookKey, type UserSystemRefreshHook } from '@/domains/anzuUser/composables/userSystemProbe'\nimport { OTHER_SYSTEMS_TAB } from '@/domains/anzuUser/utils/userTabs'\n\nconst props = withDefaults(\n defineProps<{\n userId: IntegerId\n /** Which tab carries the owning form, i.e. gets the slot. */\n owner: string\n /**\n * The tabs, in the order they are drawn, plus \"other systems\" appended by this component.\n *\n * A prop and not something derived from the descriptor array, because the list depends on the\n * route rather than on what the admin owns: admin-inhouse owns four systems and has two tabs,\n * since the system is part of the path.\n */\n ownedTabs: string[]\n /** Every system this admin can reach. The \"other systems\" tab lists the ones not in a tab. */\n descriptors: AnyUserSystemDescriptor[]\n /**\n * \"After a 401, refresh once and try again.\"\n *\n * The library cannot decide this for itself: the mechanism exists only in the apps, and each\n * one does it differently -- inhouse `refreshSession`, cms and contentHub their own\n * `refresh-token` call. Without it an expired token renders as \"no account in this system\",\n * which is the one confusion decision 16 forbids. Every panel this shell draws gets it.\n */\n refreshHook?: UserSystemRefreshHook | undefined\n readonly?: boolean\n /**\n * Whether the owning form holds edits that have not been saved.\n *\n * It drives two things. The dot on the owning tab, so the operator can see it from the other\n * tabs -- the Save button itself is visible everywhere, by decision, because a button that\n * disappeared would read as \"this is read-only\". And the guard below, which is the only thing\n * standing between unsaved work and the button in a panel that leaves the page: switching a tab\n * is not navigation, so nothing else ever asks.\n */\n unsavedChanges?: boolean\n /** Query key for the deep link. */\n tabQueryKey?: string\n }>(),\n {\n refreshHook: undefined,\n readonly: false,\n unsavedChanges: false,\n tabQueryKey: 'tab',\n }\n)\n\nconst emit = defineEmits<{\n /** After an account was created in another system, so a page can react if it wants to. */\n (e: 'created', descriptor: AnyUserSystemDescriptor): void\n}>()\n\nconst activeTab = defineModel<string>('activeTab', { required: false, default: '' })\n\nconst { t } = useI18n()\nconst route = useRoute()\nconst router = useRouter()\n\nconst bySystem = computed(() => new Map(props.descriptors.map((item) => [item.system, item])))\n\nconst tabs = computed(() => [...props.ownedTabs, OTHER_SYSTEMS_TAB])\n\nconst otherDescriptors = computed(() => props.descriptors.filter((item) => !props.ownedTabs.includes(item.system)))\n\nconst labelFor = (system: string) => bySystem.value.get(system)?.label ?? system\n\nconst isValidTab = (value: unknown): value is string => typeof value === 'string' && tabs.value.includes(value)\n\nonMounted(() => {\n const fromUrl = route.query[props.tabQueryKey]\n // An unknown tab -- a system dropped out of the configuration since the link was sent -- is\n // ignored without a word and the owning tab opens. An error here would help nobody.\n activeTab.value = isValidTab(fromUrl) ? fromUrl : props.owner\n})\n\nwatch(activeTab, (value) => {\n if (!isValidTab(value)) return\n // `replace`, not `push`: with `push` the back button would walk through the tabs instead of\n // leaving the page.\n void router.replace({ query: { ...route.query, [props.tabQueryKey]: value } })\n})\n\n/**\n * Registered here rather than in the page, because this is the component the leaving happens from:\n * an internal \"manage in X\" is a router link inside a panel, and `onBeforeRouteLeave` has to be\n * bound somewhere inside the route. An external one opens a new tab and leaves this page standing,\n * so it needs no guard at all.\n */\nconst unsavedSource = computed(() => props.unsavedChanges)\nconst { hasUnsavedChanges, dirtyLabels, promptOpen, resolvePrompt } = useUnsavedChangesGuard({\n sources: [unsavedSource],\n})\n\nconst otherSystems = ref<InstanceType<typeof AUserOtherSystemsTable> | null>(null)\nconst ownedPanels = ref<InstanceType<typeof AUserSystemPanel>[]>([])\n\n/**\n * Creating this person's account in another system.\n *\n * Handled here rather than by the page, because the panel that offers it is here and the whole\n * operation is the library's: read the owning system's record, copy the metadata, post it. The\n * page would only be passing it through.\n */\nconst writes = useUserCrossSystemWrites()\nconst { createAnzuUser } = useAnzuUserFactory()\nconst { showError, showRecordWas } = useAlerts()\n\n// Only when there is one: the panel's own `inject` default is `undefined`, and providing that\n// explicitly would say \"there is a hook\" to anything that merely checks for the key.\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (!isUndefined(props.refreshHook)) provide(UserSystemRefreshHookKey, props.refreshHook)\n\nconst ownerDescriptor = computed(() => bySystem.value.get(props.owner))\n/**\n * The owning system's record as the server holds it, not as the form does.\n *\n * Read when the panels are, so the owning tab costs nothing, and read again before each POST: a\n * switch flipped in the form and not saved must not be copied into another system, where in blog\n * and forum it would mean a working public account. That is the whole point of the fix commit this\n * rule comes from.\n */\nconst sourceUser = ref<AnzuUser | null>(null)\nconst creatingSystem = ref<string | null>(null)\n\nconst loadSource = async () => {\n const descriptor = ownerDescriptor.value\n if (isUndefined(descriptor)) return\n sourceUser.value = await writes.readSourceUser(descriptor, props.userId)\n}\n\n/** Copying a person into another system copies whether they are switched on. Roles stay empty. */\nconst createEnabled = computed(() => sourceUser.value?.enabled === true)\n\nconst onCreate = async (descriptor: AnyUserSystemDescriptor, metadata: BaseUser) => {\n const owner = ownerDescriptor.value\n if (isUndefined(owner)) return\n creatingSystem.value = descriptor.system\n try {\n const source = await writes.readSourceUser(owner, props.userId)\n if (isNull(source)) {\n showError(t('common.userSystem.create.sourceUnreadable', { system: labelFor(owner.system) }))\n return\n }\n // The dialog has already promised one of two sentences -- created ready to use, or created\n // switched off -- from the copy read when the panels were. If the server no longer says that,\n // the promise was wrong, and in blog and forum the difference is a working public account. The\n // commonest way to get here is that first read having failed, which leaves `sourceUser` null\n // and the dialog saying \"disabled\" about an account that is on. Nothing is written until the\n // corrected row has been confirmed again.\n if (source.enabled !== createEnabled.value) {\n sourceUser.value = source\n showError(t('common.userSystem.create.sourceChanged'))\n return\n }\n // The create right may have gone while the source was read; nothing is offered then, so nothing is said.\n if (!descriptorMayWrite(descriptor, 'create')) return\n // From the library factory, never assembled by hand: a body of base fields alone would have the\n // backend fill in `ROLE_USER`, leaving an account with a role nobody granted.\n //\n // The metadata is the dialog's, not the source's: the form was validated against the target's\n // profile and the operator may have filled in what the source leaves empty -- blog fills\n // `person` for nobody, and a system that requires it would get a record its own form refuses\n // to save. The id and `enabled` still come from the fresh read.\n const body = createAnzuUser(descriptor.system)\n body.id = source.id\n body.email = metadata.email\n body.person = cloneDeep(metadata.person)\n body.avatar = cloneDeep(metadata.avatar)\n body.enabled = source.enabled\n const result = await writes.createInSystem(descriptor, body)\n if (result.outcome !== BulkOutcome.Done) {\n // Silence here read as success: the row was re-probed, still said \"absent\", and nothing\n // explained why. The per-admin pages this replaces reported every write.\n showError(labelFor(descriptor.system) + ': ' + t('common.userSystem.bulk.outcome.' + result.outcome))\n return\n }\n showRecordWas('created')\n emit('created', descriptor)\n otherSystems.value?.refreshSystem(descriptor.system)\n ownedPanels.value.forEach((panel) => panel?.refresh())\n } finally {\n creatingSystem.value = null\n }\n}\n\n/**\n * Called by the page after the owning form saved.\n *\n * `VWindowItem` takes only `hasContent` from `useLazy` and hides the panel with `v-show`, so once a\n * panel is mounted it is never unmounted and never re-fetches on its own. Without this the panel\n * would keep showing what it read before the save -- and the create-in-another-system action,\n * which reads from it, would copy that stale snapshot.\n *\n * Deliberately not a refetch on every tab activation: that would turn cheap tab switching into\n * eight calls each time, which is the cost the pseudo-tab was dropped to avoid.\n */\nconst refresh = () => {\n void loadSource()\n otherSystems.value?.refresh()\n ownedPanels.value.forEach((panel) => panel?.refresh())\n}\n\n// Read alongside the panels, on the first activation of a tab that is not the owning one -- so the\n// owning tab still costs no foreign call at all.\nwatch(\n activeTab,\n (value) => {\n // `isValidTab` first: before the mount hook settles it, the model is an empty string, and\n // treating that as \"not the owning tab\" would fetch on the owning tab too -- the one call this\n // whole lazy arrangement exists to avoid.\n if (!isValidTab(value) || value === props.owner) return\n if (isNull(sourceUser.value)) void loadSource()\n },\n { immediate: true }\n)\n\ndefineExpose({ refresh })\n</script>\n\n<template>\n <div>\n <!--\n No tab navigates. Every one of them redraws the content, and what leaves the page is the\n Manage button inside a panel -- which is an anchor. `VTab` renders `role=\"tab\"` and could not\n carry a navigation semantically.\n -->\n <VTabs\n v-model=\"activeTab\"\n data-cy=\"user-tabs\"\n >\n <VTab\n v-for=\"tab in tabs\"\n :key=\"tab\"\n :value=\"tab\"\n :data-cy=\"`user-tab-${tab}`\"\n >\n {{ tab === OTHER_SYSTEMS_TAB ? t('common.userSystem.tab.otherSystems') : labelFor(tab) }}\n <!-- The owning tab says it holds unsaved work; the Save button itself is always visible. -->\n <VIcon\n v-if=\"tab === owner && hasUnsavedChanges\"\n class=\"ml-1\"\n size=\"x-small\"\n color=\"warning\"\n icon=\"mdi-circle\"\n data-cy=\"user-tab-unsaved\"\n />\n </VTab>\n </VTabs>\n <VWindow\n v-model=\"activeTab\"\n class=\"mt-4\"\n >\n <VWindowItem\n v-for=\"tab in ownedTabs\"\n :key=\"tab\"\n :value=\"tab\"\n >\n <!-- The owning system of the current route: the full form. -->\n <slot v-if=\"tab === owner\" />\n <!--\n Another system this admin owns, but whose route is not open: a probe with a summary and a\n Manage button, exactly like any other system. No tab takes the operator anywhere.\n -->\n <AUserSystemPanel\n v-else-if=\"!isUndefined(bySystem.get(tab))\"\n ref=\"ownedPanels\"\n :descriptor=\"bySystem.get(tab)!\"\n :user-id=\"userId\"\n :readonly=\"readonly\"\n :create-enabled=\"createEnabled\"\n :source=\"sourceUser\"\n :creating=\"creatingSystem === tab\"\n @create=\"onCreate\"\n />\n </VWindowItem>\n <VWindowItem :value=\"OTHER_SYSTEMS_TAB\">\n <!--\n Lazy by construction: `VWindowItem` renders its content on first activation, so opening a\n user costs no foreign calls at all.\n -->\n <AUserOtherSystemsTable\n ref=\"otherSystems\"\n :descriptors=\"otherDescriptors\"\n :user-id=\"userId\"\n :readonly=\"readonly\"\n :create-enabled=\"createEnabled\"\n :source=\"sourceUser\"\n :creating-system=\"creatingSystem\"\n @create=\"onCreate\"\n />\n </VWindowItem>\n </VWindow>\n <AUnsavedConfirmDialog\n v-model=\"promptOpen\"\n :dirty-labels=\"dirtyLabels\"\n @resolve=\"resolvePrompt\"\n />\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"AUserTabsShell.js","names":["_sfc_main","AUserTabsShell_vue_vue_type_script_setup_true_lang_default","AUserTabsShell_default"],"sources":["../../../../src/domains/anzuUser/components/AUserTabsShell.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { computed, onMounted, provide, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useAlerts } from '@/domains/system/composables/alerts'\nimport { useAnzuUserFactory } from '@/domains/anzuUser/factory/AnzuUserFactory'\nimport { cloneDeep, isNull, isUndefined } from '@/shared/utils/common'\nimport { BulkOutcome } from '@/domains/anzuUser/store/userCrossSystemStore'\nimport { useUserCrossSystemWrites } from '@/domains/anzuUser/composables/userCrossSystemWrites'\nimport AUnsavedConfirmDialog from '@/domains/unsavedGuard/components/AUnsavedConfirmDialog.vue'\nimport { useUnsavedChangesGuard } from '@/domains/unsavedGuard/composables/useUnsavedChangesGuard'\nimport AUserOtherSystemsTable from '@/domains/anzuUser/components/AUserOtherSystemsTable.vue'\nimport AUserSystemPanel from '@/domains/anzuUser/components/AUserSystemPanel.vue'\nimport { type AnyUserSystemDescriptor, descriptorMayWrite } from '@/domains/anzuUser/composables/userSystemDescriptor'\nimport type { AnzuUser, BaseUser } from '@/shared/types/AnzuUser'\nimport type { IntegerId } from '@/shared/types/common'\nimport { UserSystemRefreshHookKey, type UserSystemRefreshHook } from '@/domains/anzuUser/composables/userSystemProbe'\nimport { OTHER_SYSTEMS_TAB } from '@/domains/anzuUser/utils/userTabs'\n\nconst props = withDefaults(\n defineProps<{\n userId: IntegerId\n /** Which tab carries the owning form, i.e. gets the slot. */\n owner: string\n /**\n * The tabs in draw order. This component appends \"other systems\".\n * A prop, not derived from descriptors, because it depends on the route. admin-inhouse\n * owns four systems but has two tabs, since the system is part of the path.\n */\n ownedTabs: string[]\n /** Every system this admin can reach. The \"other systems\" tab lists the ones not in a tab. */\n descriptors: AnyUserSystemDescriptor[]\n /**\n * After a 401, refresh once and retry.\n * Each app refreshes differently (inhouse `refreshSession`, cms and contentHub a\n * `refresh-token` call), so the library cannot do it. Without it an expired token shows as \"no\n * account in this system\", which decision 16 forbids. Every panel in this shell receives it.\n */\n refreshHook?: UserSystemRefreshHook | undefined\n readonly?: boolean\n /**\n * Whether the owning form has unsaved edits.\n * It drives the dot on the owning tab. The Save button stays visible\n * everywhere, because a hidden button would read as read-only.\n * It also drives the leave guard. Switching tabs is not navigation,\n * so nothing else asks before a panel button leaves the page.\n */\n unsavedChanges?: boolean\n tabQueryKey?: string\n }>(),\n {\n refreshHook: undefined,\n readonly: false,\n unsavedChanges: false,\n tabQueryKey: 'tab',\n }\n)\n\nconst emit = defineEmits<{\n /** After an account was created in another system, so a page can react if it wants to. */\n (e: 'created', descriptor: AnyUserSystemDescriptor): void\n}>()\n\nconst activeTab = defineModel<string>('activeTab', { required: false, default: '' })\n\nconst { t } = useI18n()\nconst route = useRoute()\nconst router = useRouter()\n\nconst bySystem = computed(() => new Map(props.descriptors.map((item) => [item.system, item])))\n\nconst tabs = computed(() => [...props.ownedTabs, OTHER_SYSTEMS_TAB])\n\nconst otherDescriptors = computed(() => props.descriptors.filter((item) => !props.ownedTabs.includes(item.system)))\n\nconst labelFor = (system: string) => bySystem.value.get(system)?.label ?? system\n\nconst isValidTab = (value: unknown): value is string => typeof value === 'string' && tabs.value.includes(value)\n\nonMounted(() => {\n const fromUrl = route.query[props.tabQueryKey]\n // An unknown tab, for example a system removed from the configuration\n // since the link was sent, is ignored silently and the owning tab opens.\n activeTab.value = isValidTab(fromUrl) ? fromUrl : props.owner\n})\n\nwatch(activeTab, (value) => {\n if (!isValidTab(value)) return\n // `replace`, not `push`: with `push` the back button would walk through the tabs instead of\n // leaving the page.\n void router.replace({ query: { ...route.query, [props.tabQueryKey]: value } })\n})\n\n/**\n * Registered here, not in the page, because an internal \"manage in X\" link inside a\n * panel leaves from here and `onBeforeRouteLeave` must be bound inside the route.\n * An external link opens a new tab and needs no guard.\n */\nconst unsavedSource = computed(() => props.unsavedChanges)\nconst { hasUnsavedChanges, dirtyLabels, promptOpen, resolvePrompt } = useUnsavedChangesGuard({\n sources: [unsavedSource],\n})\n\nconst otherSystems = ref<InstanceType<typeof AUserOtherSystemsTable> | null>(null)\nconst ownedPanels = ref<InstanceType<typeof AUserSystemPanel>[]>([])\n\n/**\n * Creating this person's account in another system.\n * Handled here because the panel offering it lives here and the\n * operation belongs to the library. The page would only pass it through.\n */\nconst writes = useUserCrossSystemWrites()\nconst { createAnzuUser } = useAnzuUserFactory()\nconst { showError, showRecordWas } = useAlerts()\n\n// Provide only when present. Providing `undefined` explicitly would signal a hook to code that only checks for the key.\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (!isUndefined(props.refreshHook)) provide(UserSystemRefreshHookKey, props.refreshHook)\n\nconst ownerDescriptor = computed(() => bySystem.value.get(props.owner))\n/**\n * The owning system's record as the server holds it, not as the form does.\n * Read together with the panels, so the owning tab costs nothing, and read again before each POST. An unsaved\n * switch in the form must not be copied, because in blog and forum it would mean a working public account.\n */\nconst sourceUser = ref<AnzuUser | null>(null)\nconst creatingSystem = ref<string | null>(null)\n\nconst loadSource = async () => {\n const descriptor = ownerDescriptor.value\n if (isUndefined(descriptor)) return\n sourceUser.value = await writes.readSourceUser(descriptor, props.userId)\n}\n\n/** Copying a person into another system copies whether they are switched on. Roles stay empty. */\nconst createEnabled = computed(() => sourceUser.value?.enabled === true)\n\nconst onCreate = async (descriptor: AnyUserSystemDescriptor, metadata: BaseUser) => {\n const owner = ownerDescriptor.value\n if (isUndefined(owner)) return\n creatingSystem.value = descriptor.system\n try {\n const source = await writes.readSourceUser(owner, props.userId)\n if (isNull(source)) {\n showError(t('common.userSystem.create.sourceUnreadable', { system: labelFor(owner.system) }))\n return\n }\n // The dialog already promised \"created ready to use\" or \"created switched off\" from the earlier read. If the\n // server now disagrees, the promise was wrong, and in blog and forum that means a working public account.\n // Usually the first read failed, leaving `sourceUser` null and the dialog saying \"disabled\"\n // for an enabled account. Nothing is written until the corrected row is confirmed again.\n if (source.enabled !== createEnabled.value) {\n sourceUser.value = source\n showError(t('common.userSystem.create.sourceChanged'))\n return\n }\n // The create right may have been lost while the source was read. Nothing is offered then, so nothing is reported.\n if (!descriptorMayWrite(descriptor, 'create')) return\n // Built by the library factory, never by hand. A body of base fields\n // alone makes the backend add `ROLE_USER`, a role nobody granted.\n // Metadata comes from the dialog, validated against the target's profile. The source may leave fields empty\n // (blog never fills `person`) that the target requires. The id and `enabled` come from the fresh read.\n const body = createAnzuUser(descriptor.system)\n body.id = source.id\n body.email = metadata.email\n body.person = cloneDeep(metadata.person)\n body.avatar = cloneDeep(metadata.avatar)\n body.enabled = source.enabled\n const result = await writes.createInSystem(descriptor, body)\n if (result.outcome !== BulkOutcome.Done) {\n // Without this message the failure looked like success: the\n // re-probed row still said \"absent\" with no explanation.\n showError(labelFor(descriptor.system) + ': ' + t('common.userSystem.bulk.outcome.' + result.outcome))\n return\n }\n showRecordWas('created')\n emit('created', descriptor)\n otherSystems.value?.refreshSystem(descriptor.system)\n ownedPanels.value.forEach((panel) => panel?.refresh())\n } finally {\n creatingSystem.value = null\n }\n}\n\n/**\n * Called by the page after the owning form saved.\n * `VWindowItem` hides panels with `v-show`, so a mounted panel never re-fetches by itself. Without\n * this it shows pre-save data, and create-in-another-system would copy that stale snapshot.\n * Not a refetch on every tab activation: that would cost eight calls per tab switch.\n */\nconst refresh = () => {\n void loadSource()\n otherSystems.value?.refresh()\n ownedPanels.value.forEach((panel) => panel?.refresh())\n}\n\n// Read on the first activation of a non-owning tab, so the owning tab makes no foreign call.\nwatch(\n activeTab,\n (value) => {\n // `isValidTab` first: before mount settles, the model is an empty string.\n // Treating it as a non-owning tab would fetch on the owning tab too.\n if (!isValidTab(value) || value === props.owner) return\n if (isNull(sourceUser.value)) void loadSource()\n },\n { immediate: true }\n)\n\ndefineExpose({ refresh })\n</script>\n\n<template>\n <div>\n <!--\n No tab navigates. Tabs only switch content, and leaving the page is done by the Manage\n anchor inside a panel. `VTab` renders `role=\"tab\"` and cannot carry navigation semantically.\n -->\n <VTabs\n v-model=\"activeTab\"\n data-cy=\"user-tabs\"\n >\n <VTab\n v-for=\"tab in tabs\"\n :key=\"tab\"\n :value=\"tab\"\n :data-cy=\"`user-tab-${tab}`\"\n >\n {{ tab === OTHER_SYSTEMS_TAB ? t('common.userSystem.tab.otherSystems') : labelFor(tab) }}\n <!-- The owning tab says it holds unsaved work; the Save button itself is always visible. -->\n <VIcon\n v-if=\"tab === owner && hasUnsavedChanges\"\n class=\"ml-1\"\n size=\"x-small\"\n color=\"warning\"\n icon=\"mdi-circle\"\n data-cy=\"user-tab-unsaved\"\n />\n </VTab>\n </VTabs>\n <VWindow\n v-model=\"activeTab\"\n class=\"mt-4\"\n >\n <VWindowItem\n v-for=\"tab in ownedTabs\"\n :key=\"tab\"\n :value=\"tab\"\n >\n <!-- The owning system of the current route: the full form. -->\n <slot v-if=\"tab === owner\" />\n <!--\n Another system this admin owns whose route is not open: a probe\n with a summary and a Manage button, like any other system.\n -->\n <AUserSystemPanel\n v-else-if=\"!isUndefined(bySystem.get(tab))\"\n ref=\"ownedPanels\"\n :descriptor=\"bySystem.get(tab)!\"\n :user-id=\"userId\"\n :readonly=\"readonly\"\n :create-enabled=\"createEnabled\"\n :source=\"sourceUser\"\n :creating=\"creatingSystem === tab\"\n @create=\"onCreate\"\n />\n </VWindowItem>\n <VWindowItem :value=\"OTHER_SYSTEMS_TAB\">\n <!-- `VWindowItem` renders content on first activation, so opening a user makes no foreign calls. -->\n <AUserOtherSystemsTable\n ref=\"otherSystems\"\n :descriptors=\"otherDescriptors\"\n :user-id=\"userId\"\n :readonly=\"readonly\"\n :create-enabled=\"createEnabled\"\n :source=\"sourceUser\"\n :creating-system=\"creatingSystem\"\n @create=\"onCreate\"\n />\n </VWindowItem>\n </VWindow>\n <AUnsavedConfirmDialog\n v-model=\"promptOpen\"\n :dirty-labels=\"dirtyLabels\"\n @resolve=\"resolvePrompt\"\n />\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -6,46 +6,41 @@ type __VLS_Props = {
|
|
|
6
6
|
/** Which tab carries the owning form, i.e. gets the slot. */
|
|
7
7
|
owner: string;
|
|
8
8
|
/**
|
|
9
|
-
* The tabs
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* route rather than on what the admin owns: admin-inhouse owns four systems and has two tabs,
|
|
13
|
-
* since the system is part of the path.
|
|
9
|
+
* The tabs in draw order. This component appends "other systems".
|
|
10
|
+
* A prop, not derived from descriptors, because it depends on the route. admin-inhouse
|
|
11
|
+
* owns four systems but has two tabs, since the system is part of the path.
|
|
14
12
|
*/
|
|
15
13
|
ownedTabs: string[];
|
|
16
14
|
/** Every system this admin can reach. The "other systems" tab lists the ones not in a tab. */
|
|
17
15
|
descriptors: AnyUserSystemDescriptor[];
|
|
18
16
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* `refresh-token` call. Without it an expired token renders as "no account in this system",
|
|
24
|
-
* which is the one confusion decision 16 forbids. Every panel this shell draws gets it.
|
|
17
|
+
* After a 401, refresh once and retry.
|
|
18
|
+
* Each app refreshes differently (inhouse `refreshSession`, cms and contentHub a
|
|
19
|
+
* `refresh-token` call), so the library cannot do it. Without it an expired token shows as "no
|
|
20
|
+
* account in this system", which decision 16 forbids. Every panel in this shell receives it.
|
|
25
21
|
*/
|
|
26
22
|
refreshHook?: UserSystemRefreshHook | undefined;
|
|
27
23
|
readonly?: boolean;
|
|
28
24
|
/**
|
|
29
|
-
* Whether the owning form
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* standing between unsaved work and the button in a panel that leaves the page: switching a tab
|
|
35
|
-
* is not navigation, so nothing else ever asks.
|
|
25
|
+
* Whether the owning form has unsaved edits.
|
|
26
|
+
* It drives the dot on the owning tab. The Save button stays visible
|
|
27
|
+
* everywhere, because a hidden button would read as read-only.
|
|
28
|
+
* It also drives the leave guard. Switching tabs is not navigation,
|
|
29
|
+
* so nothing else asks before a panel button leaves the page.
|
|
36
30
|
*/
|
|
37
31
|
unsavedChanges?: boolean;
|
|
38
|
-
/** Query key for the deep link. */
|
|
39
32
|
tabQueryKey?: string;
|
|
40
33
|
};
|
|
41
34
|
type __VLS_ModelProps = {
|
|
42
35
|
'activeTab'?: string;
|
|
43
36
|
};
|
|
44
37
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
45
|
-
declare
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
declare const __VLS_template: () => {
|
|
39
|
+
__VLS_Slots: {
|
|
40
|
+
default?: (props: {}) => any;
|
|
41
|
+
};
|
|
48
42
|
};
|
|
43
|
+
type __VLS_Slots = ReturnType<typeof __VLS_template>['__VLS_Slots'];
|
|
49
44
|
declare const __VLS_base: import('vue').DefineComponent<__VLS_PublicProps, {
|
|
50
45
|
refresh: () => void;
|
|
51
46
|
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
package/dist/domains/anzuUser/components/AUserTabsShell.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AUserTabsShell.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","_component_VTabs","_withCtx","_Fragment","_renderList","_createBlock","_component_VTab","_createTextVNode","_toDisplayString","_unref","_component_VIcon","_createCommentVNode","_component_VWindow","_component_VWindowItem","_renderSlot","AUserSystemPanel","AUserOtherSystemsTable","AUnsavedConfirmDialog","_isRef","AUnsavedConfirmDialog_default","AUserSystemPanel_default","AUserOtherSystemsTable_default","AUserTabsShell_vue_vue_type_script_setup_true_lang_default","\"activeTab\"","\"activeTabModifiers\"","__expose","__emit","props","__props","emit","activeTab","useModel","useI18n","route","useRoute","router","useRouter","bySystem","computed","item","tabs","OTHER_SYSTEMS_TAB","otherDescriptors","labelFor","system","isValidTab","value","onMounted","fromUrl","watch","unsavedSource","useUnsavedChangesGuard","otherSystems","ref","ownedPanels","writes","useUserCrossSystemWrites","useAnzuUserFactory","useAlerts","isUndefined","provide","UserSystemRefreshHookKey","ownerDescriptor","sourceUser","creatingSystem","loadSource","descriptor","createEnabled","onCreate","owner","source","isNull","t","showError","descriptorMayWrite","body","createAnzuUser","metadata","cloneDeep","result","BulkOutcome","showRecordWas","panel","openBlock","createElementBlock","createVNode","VTabs","_cache","$event","withCtx","Fragment","renderList","createBlock","VTab","tab","createTextVNode","toDisplayString","unref","hasUnsavedChanges","VIcon","createCommentVNode","VWindow","VWindowItem","renderSlot","_ctx","promptOpen","isRef","dirtyLabels","resolvePrompt"],"sources":["../../../../src/domains/anzuUser/components/AUserTabsShell.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { computed, onMounted, provide, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useAlerts } from '@/domains/system/composables/alerts'\nimport { useAnzuUserFactory } from '@/domains/anzuUser/factory/AnzuUserFactory'\nimport { cloneDeep, isNull, isUndefined } from '@/shared/utils/common'\nimport { BulkOutcome } from '@/domains/anzuUser/store/userCrossSystemStore'\nimport { useUserCrossSystemWrites } from '@/domains/anzuUser/composables/userCrossSystemWrites'\nimport AUnsavedConfirmDialog from '@/domains/unsavedGuard/components/AUnsavedConfirmDialog.vue'\nimport { useUnsavedChangesGuard } from '@/domains/unsavedGuard/composables/useUnsavedChangesGuard'\nimport AUserOtherSystemsTable from '@/domains/anzuUser/components/AUserOtherSystemsTable.vue'\nimport AUserSystemPanel from '@/domains/anzuUser/components/AUserSystemPanel.vue'\nimport { type AnyUserSystemDescriptor, descriptorMayWrite } from '@/domains/anzuUser/composables/userSystemDescriptor'\nimport type { AnzuUser, BaseUser } from '@/shared/types/AnzuUser'\nimport type { IntegerId } from '@/shared/types/common'\nimport { UserSystemRefreshHookKey, type UserSystemRefreshHook } from '@/domains/anzuUser/composables/userSystemProbe'\nimport { OTHER_SYSTEMS_TAB } from '@/domains/anzuUser/utils/userTabs'\n\nconst props = withDefaults(\n defineProps<{\n userId: IntegerId\n /** Which tab carries the owning form, i.e. gets the slot. */\n owner: string\n /**\n * The tabs, in the order they are drawn, plus \"other systems\" appended by this component.\n *\n * A prop and not something derived from the descriptor array, because the list depends on the\n * route rather than on what the admin owns: admin-inhouse owns four systems and has two tabs,\n * since the system is part of the path.\n */\n ownedTabs: string[]\n /** Every system this admin can reach. The \"other systems\" tab lists the ones not in a tab. */\n descriptors: AnyUserSystemDescriptor[]\n /**\n * \"After a 401, refresh once and try again.\"\n *\n * The library cannot decide this for itself: the mechanism exists only in the apps, and each\n * one does it differently -- inhouse `refreshSession`, cms and contentHub their own\n * `refresh-token` call. Without it an expired token renders as \"no account in this system\",\n * which is the one confusion decision 16 forbids. Every panel this shell draws gets it.\n */\n refreshHook?: UserSystemRefreshHook | undefined\n readonly?: boolean\n /**\n * Whether the owning form holds edits that have not been saved.\n *\n * It drives two things. The dot on the owning tab, so the operator can see it from the other\n * tabs -- the Save button itself is visible everywhere, by decision, because a button that\n * disappeared would read as \"this is read-only\". And the guard below, which is the only thing\n * standing between unsaved work and the button in a panel that leaves the page: switching a tab\n * is not navigation, so nothing else ever asks.\n */\n unsavedChanges?: boolean\n /** Query key for the deep link. */\n tabQueryKey?: string\n }>(),\n {\n refreshHook: undefined,\n readonly: false,\n unsavedChanges: false,\n tabQueryKey: 'tab',\n }\n)\n\nconst emit = defineEmits<{\n /** After an account was created in another system, so a page can react if it wants to. */\n (e: 'created', descriptor: AnyUserSystemDescriptor): void\n}>()\n\nconst activeTab = defineModel<string>('activeTab', { required: false, default: '' })\n\nconst { t } = useI18n()\nconst route = useRoute()\nconst router = useRouter()\n\nconst bySystem = computed(() => new Map(props.descriptors.map((item) => [item.system, item])))\n\nconst tabs = computed(() => [...props.ownedTabs, OTHER_SYSTEMS_TAB])\n\nconst otherDescriptors = computed(() => props.descriptors.filter((item) => !props.ownedTabs.includes(item.system)))\n\nconst labelFor = (system: string) => bySystem.value.get(system)?.label ?? system\n\nconst isValidTab = (value: unknown): value is string => typeof value === 'string' && tabs.value.includes(value)\n\nonMounted(() => {\n const fromUrl = route.query[props.tabQueryKey]\n // An unknown tab -- a system dropped out of the configuration since the link was sent -- is\n // ignored without a word and the owning tab opens. An error here would help nobody.\n activeTab.value = isValidTab(fromUrl) ? fromUrl : props.owner\n})\n\nwatch(activeTab, (value) => {\n if (!isValidTab(value)) return\n // `replace`, not `push`: with `push` the back button would walk through the tabs instead of\n // leaving the page.\n void router.replace({ query: { ...route.query, [props.tabQueryKey]: value } })\n})\n\n/**\n * Registered here rather than in the page, because this is the component the leaving happens from:\n * an internal \"manage in X\" is a router link inside a panel, and `onBeforeRouteLeave` has to be\n * bound somewhere inside the route. An external one opens a new tab and leaves this page standing,\n * so it needs no guard at all.\n */\nconst unsavedSource = computed(() => props.unsavedChanges)\nconst { hasUnsavedChanges, dirtyLabels, promptOpen, resolvePrompt } = useUnsavedChangesGuard({\n sources: [unsavedSource],\n})\n\nconst otherSystems = ref<InstanceType<typeof AUserOtherSystemsTable> | null>(null)\nconst ownedPanels = ref<InstanceType<typeof AUserSystemPanel>[]>([])\n\n/**\n * Creating this person's account in another system.\n *\n * Handled here rather than by the page, because the panel that offers it is here and the whole\n * operation is the library's: read the owning system's record, copy the metadata, post it. The\n * page would only be passing it through.\n */\nconst writes = useUserCrossSystemWrites()\nconst { createAnzuUser } = useAnzuUserFactory()\nconst { showError, showRecordWas } = useAlerts()\n\n// Only when there is one: the panel's own `inject` default is `undefined`, and providing that\n// explicitly would say \"there is a hook\" to anything that merely checks for the key.\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (!isUndefined(props.refreshHook)) provide(UserSystemRefreshHookKey, props.refreshHook)\n\nconst ownerDescriptor = computed(() => bySystem.value.get(props.owner))\n/**\n * The owning system's record as the server holds it, not as the form does.\n *\n * Read when the panels are, so the owning tab costs nothing, and read again before each POST: a\n * switch flipped in the form and not saved must not be copied into another system, where in blog\n * and forum it would mean a working public account. That is the whole point of the fix commit this\n * rule comes from.\n */\nconst sourceUser = ref<AnzuUser | null>(null)\nconst creatingSystem = ref<string | null>(null)\n\nconst loadSource = async () => {\n const descriptor = ownerDescriptor.value\n if (isUndefined(descriptor)) return\n sourceUser.value = await writes.readSourceUser(descriptor, props.userId)\n}\n\n/** Copying a person into another system copies whether they are switched on. Roles stay empty. */\nconst createEnabled = computed(() => sourceUser.value?.enabled === true)\n\nconst onCreate = async (descriptor: AnyUserSystemDescriptor, metadata: BaseUser) => {\n const owner = ownerDescriptor.value\n if (isUndefined(owner)) return\n creatingSystem.value = descriptor.system\n try {\n const source = await writes.readSourceUser(owner, props.userId)\n if (isNull(source)) {\n showError(t('common.userSystem.create.sourceUnreadable', { system: labelFor(owner.system) }))\n return\n }\n // The dialog has already promised one of two sentences -- created ready to use, or created\n // switched off -- from the copy read when the panels were. If the server no longer says that,\n // the promise was wrong, and in blog and forum the difference is a working public account. The\n // commonest way to get here is that first read having failed, which leaves `sourceUser` null\n // and the dialog saying \"disabled\" about an account that is on. Nothing is written until the\n // corrected row has been confirmed again.\n if (source.enabled !== createEnabled.value) {\n sourceUser.value = source\n showError(t('common.userSystem.create.sourceChanged'))\n return\n }\n // The create right may have gone while the source was read; nothing is offered then, so nothing is said.\n if (!descriptorMayWrite(descriptor, 'create')) return\n // From the library factory, never assembled by hand: a body of base fields alone would have the\n // backend fill in `ROLE_USER`, leaving an account with a role nobody granted.\n //\n // The metadata is the dialog's, not the source's: the form was validated against the target's\n // profile and the operator may have filled in what the source leaves empty -- blog fills\n // `person` for nobody, and a system that requires it would get a record its own form refuses\n // to save. The id and `enabled` still come from the fresh read.\n const body = createAnzuUser(descriptor.system)\n body.id = source.id\n body.email = metadata.email\n body.person = cloneDeep(metadata.person)\n body.avatar = cloneDeep(metadata.avatar)\n body.enabled = source.enabled\n const result = await writes.createInSystem(descriptor, body)\n if (result.outcome !== BulkOutcome.Done) {\n // Silence here read as success: the row was re-probed, still said \"absent\", and nothing\n // explained why. The per-admin pages this replaces reported every write.\n showError(labelFor(descriptor.system) + ': ' + t('common.userSystem.bulk.outcome.' + result.outcome))\n return\n }\n showRecordWas('created')\n emit('created', descriptor)\n otherSystems.value?.refreshSystem(descriptor.system)\n ownedPanels.value.forEach((panel) => panel?.refresh())\n } finally {\n creatingSystem.value = null\n }\n}\n\n/**\n * Called by the page after the owning form saved.\n *\n * `VWindowItem` takes only `hasContent` from `useLazy` and hides the panel with `v-show`, so once a\n * panel is mounted it is never unmounted and never re-fetches on its own. Without this the panel\n * would keep showing what it read before the save -- and the create-in-another-system action,\n * which reads from it, would copy that stale snapshot.\n *\n * Deliberately not a refetch on every tab activation: that would turn cheap tab switching into\n * eight calls each time, which is the cost the pseudo-tab was dropped to avoid.\n */\nconst refresh = () => {\n void loadSource()\n otherSystems.value?.refresh()\n ownedPanels.value.forEach((panel) => panel?.refresh())\n}\n\n// Read alongside the panels, on the first activation of a tab that is not the owning one -- so the\n// owning tab still costs no foreign call at all.\nwatch(\n activeTab,\n (value) => {\n // `isValidTab` first: before the mount hook settles it, the model is an empty string, and\n // treating that as \"not the owning tab\" would fetch on the owning tab too -- the one call this\n // whole lazy arrangement exists to avoid.\n if (!isValidTab(value) || value === props.owner) return\n if (isNull(sourceUser.value)) void loadSource()\n },\n { immediate: true }\n)\n\ndefineExpose({ refresh })\n</script>\n\n<template>\n <div>\n <!--\n No tab navigates. Every one of them redraws the content, and what leaves the page is the\n Manage button inside a panel -- which is an anchor. `VTab` renders `role=\"tab\"` and could not\n carry a navigation semantically.\n -->\n <VTabs\n v-model=\"activeTab\"\n data-cy=\"user-tabs\"\n >\n <VTab\n v-for=\"tab in tabs\"\n :key=\"tab\"\n :value=\"tab\"\n :data-cy=\"`user-tab-${tab}`\"\n >\n {{ tab === OTHER_SYSTEMS_TAB ? t('common.userSystem.tab.otherSystems') : labelFor(tab) }}\n <!-- The owning tab says it holds unsaved work; the Save button itself is always visible. -->\n <VIcon\n v-if=\"tab === owner && hasUnsavedChanges\"\n class=\"ml-1\"\n size=\"x-small\"\n color=\"warning\"\n icon=\"mdi-circle\"\n data-cy=\"user-tab-unsaved\"\n />\n </VTab>\n </VTabs>\n <VWindow\n v-model=\"activeTab\"\n class=\"mt-4\"\n >\n <VWindowItem\n v-for=\"tab in ownedTabs\"\n :key=\"tab\"\n :value=\"tab\"\n >\n <!-- The owning system of the current route: the full form. -->\n <slot v-if=\"tab === owner\" />\n <!--\n Another system this admin owns, but whose route is not open: a probe with a summary and a\n Manage button, exactly like any other system. No tab takes the operator anywhere.\n -->\n <AUserSystemPanel\n v-else-if=\"!isUndefined(bySystem.get(tab))\"\n ref=\"ownedPanels\"\n :descriptor=\"bySystem.get(tab)!\"\n :user-id=\"userId\"\n :readonly=\"readonly\"\n :create-enabled=\"createEnabled\"\n :source=\"sourceUser\"\n :creating=\"creatingSystem === tab\"\n @create=\"onCreate\"\n />\n </VWindowItem>\n <VWindowItem :value=\"OTHER_SYSTEMS_TAB\">\n <!--\n Lazy by construction: `VWindowItem` renders its content on first activation, so opening a\n user costs no foreign calls at all.\n -->\n <AUserOtherSystemsTable\n ref=\"otherSystems\"\n :descriptors=\"otherDescriptors\"\n :user-id=\"userId\"\n :readonly=\"readonly\"\n :create-enabled=\"createEnabled\"\n :source=\"sourceUser\"\n :creating-system=\"creatingSystem\"\n @create=\"onCreate\"\n />\n </VWindowItem>\n </VWindow>\n <AUnsavedConfirmDialog\n v-model=\"promptOpen\"\n :dirty-labels=\"dirtyLabels\"\n @resolve=\"resolvePrompt\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AUserTabsShell.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","_component_VTabs","_withCtx","_Fragment","_renderList","_createBlock","_component_VTab","_createTextVNode","_toDisplayString","_unref","_component_VIcon","_createCommentVNode","_component_VWindow","_component_VWindowItem","_renderSlot","AUserSystemPanel","AUserOtherSystemsTable","AUnsavedConfirmDialog","_isRef","AUnsavedConfirmDialog_default","AUserSystemPanel_default","AUserOtherSystemsTable_default","AUserTabsShell_vue_vue_type_script_setup_true_lang_default","\"activeTab\"","\"activeTabModifiers\"","__expose","__emit","props","__props","emit","activeTab","useModel","useI18n","route","useRoute","router","useRouter","bySystem","computed","item","tabs","OTHER_SYSTEMS_TAB","otherDescriptors","labelFor","system","isValidTab","value","onMounted","fromUrl","watch","unsavedSource","useUnsavedChangesGuard","otherSystems","ref","ownedPanels","writes","useUserCrossSystemWrites","useAnzuUserFactory","useAlerts","isUndefined","provide","UserSystemRefreshHookKey","ownerDescriptor","sourceUser","creatingSystem","loadSource","descriptor","createEnabled","onCreate","owner","source","isNull","t","showError","descriptorMayWrite","body","createAnzuUser","metadata","cloneDeep","result","BulkOutcome","showRecordWas","panel","openBlock","createElementBlock","createVNode","VTabs","_cache","$event","withCtx","Fragment","renderList","createBlock","VTab","tab","createTextVNode","toDisplayString","unref","hasUnsavedChanges","VIcon","createCommentVNode","VWindow","VWindowItem","renderSlot","_ctx","promptOpen","isRef","dirtyLabels","resolvePrompt"],"sources":["../../../../src/domains/anzuUser/components/AUserTabsShell.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { computed, onMounted, provide, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useAlerts } from '@/domains/system/composables/alerts'\nimport { useAnzuUserFactory } from '@/domains/anzuUser/factory/AnzuUserFactory'\nimport { cloneDeep, isNull, isUndefined } from '@/shared/utils/common'\nimport { BulkOutcome } from '@/domains/anzuUser/store/userCrossSystemStore'\nimport { useUserCrossSystemWrites } from '@/domains/anzuUser/composables/userCrossSystemWrites'\nimport AUnsavedConfirmDialog from '@/domains/unsavedGuard/components/AUnsavedConfirmDialog.vue'\nimport { useUnsavedChangesGuard } from '@/domains/unsavedGuard/composables/useUnsavedChangesGuard'\nimport AUserOtherSystemsTable from '@/domains/anzuUser/components/AUserOtherSystemsTable.vue'\nimport AUserSystemPanel from '@/domains/anzuUser/components/AUserSystemPanel.vue'\nimport { type AnyUserSystemDescriptor, descriptorMayWrite } from '@/domains/anzuUser/composables/userSystemDescriptor'\nimport type { AnzuUser, BaseUser } from '@/shared/types/AnzuUser'\nimport type { IntegerId } from '@/shared/types/common'\nimport { UserSystemRefreshHookKey, type UserSystemRefreshHook } from '@/domains/anzuUser/composables/userSystemProbe'\nimport { OTHER_SYSTEMS_TAB } from '@/domains/anzuUser/utils/userTabs'\n\nconst props = withDefaults(\n defineProps<{\n userId: IntegerId\n /** Which tab carries the owning form, i.e. gets the slot. */\n owner: string\n /**\n * The tabs in draw order. This component appends \"other systems\".\n * A prop, not derived from descriptors, because it depends on the route. admin-inhouse\n * owns four systems but has two tabs, since the system is part of the path.\n */\n ownedTabs: string[]\n /** Every system this admin can reach. The \"other systems\" tab lists the ones not in a tab. */\n descriptors: AnyUserSystemDescriptor[]\n /**\n * After a 401, refresh once and retry.\n * Each app refreshes differently (inhouse `refreshSession`, cms and contentHub a\n * `refresh-token` call), so the library cannot do it. Without it an expired token shows as \"no\n * account in this system\", which decision 16 forbids. Every panel in this shell receives it.\n */\n refreshHook?: UserSystemRefreshHook | undefined\n readonly?: boolean\n /**\n * Whether the owning form has unsaved edits.\n * It drives the dot on the owning tab. The Save button stays visible\n * everywhere, because a hidden button would read as read-only.\n * It also drives the leave guard. Switching tabs is not navigation,\n * so nothing else asks before a panel button leaves the page.\n */\n unsavedChanges?: boolean\n tabQueryKey?: string\n }>(),\n {\n refreshHook: undefined,\n readonly: false,\n unsavedChanges: false,\n tabQueryKey: 'tab',\n }\n)\n\nconst emit = defineEmits<{\n /** After an account was created in another system, so a page can react if it wants to. */\n (e: 'created', descriptor: AnyUserSystemDescriptor): void\n}>()\n\nconst activeTab = defineModel<string>('activeTab', { required: false, default: '' })\n\nconst { t } = useI18n()\nconst route = useRoute()\nconst router = useRouter()\n\nconst bySystem = computed(() => new Map(props.descriptors.map((item) => [item.system, item])))\n\nconst tabs = computed(() => [...props.ownedTabs, OTHER_SYSTEMS_TAB])\n\nconst otherDescriptors = computed(() => props.descriptors.filter((item) => !props.ownedTabs.includes(item.system)))\n\nconst labelFor = (system: string) => bySystem.value.get(system)?.label ?? system\n\nconst isValidTab = (value: unknown): value is string => typeof value === 'string' && tabs.value.includes(value)\n\nonMounted(() => {\n const fromUrl = route.query[props.tabQueryKey]\n // An unknown tab, for example a system removed from the configuration\n // since the link was sent, is ignored silently and the owning tab opens.\n activeTab.value = isValidTab(fromUrl) ? fromUrl : props.owner\n})\n\nwatch(activeTab, (value) => {\n if (!isValidTab(value)) return\n // `replace`, not `push`: with `push` the back button would walk through the tabs instead of\n // leaving the page.\n void router.replace({ query: { ...route.query, [props.tabQueryKey]: value } })\n})\n\n/**\n * Registered here, not in the page, because an internal \"manage in X\" link inside a\n * panel leaves from here and `onBeforeRouteLeave` must be bound inside the route.\n * An external link opens a new tab and needs no guard.\n */\nconst unsavedSource = computed(() => props.unsavedChanges)\nconst { hasUnsavedChanges, dirtyLabels, promptOpen, resolvePrompt } = useUnsavedChangesGuard({\n sources: [unsavedSource],\n})\n\nconst otherSystems = ref<InstanceType<typeof AUserOtherSystemsTable> | null>(null)\nconst ownedPanels = ref<InstanceType<typeof AUserSystemPanel>[]>([])\n\n/**\n * Creating this person's account in another system.\n * Handled here because the panel offering it lives here and the\n * operation belongs to the library. The page would only pass it through.\n */\nconst writes = useUserCrossSystemWrites()\nconst { createAnzuUser } = useAnzuUserFactory()\nconst { showError, showRecordWas } = useAlerts()\n\n// Provide only when present. Providing `undefined` explicitly would signal a hook to code that only checks for the key.\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (!isUndefined(props.refreshHook)) provide(UserSystemRefreshHookKey, props.refreshHook)\n\nconst ownerDescriptor = computed(() => bySystem.value.get(props.owner))\n/**\n * The owning system's record as the server holds it, not as the form does.\n * Read together with the panels, so the owning tab costs nothing, and read again before each POST. An unsaved\n * switch in the form must not be copied, because in blog and forum it would mean a working public account.\n */\nconst sourceUser = ref<AnzuUser | null>(null)\nconst creatingSystem = ref<string | null>(null)\n\nconst loadSource = async () => {\n const descriptor = ownerDescriptor.value\n if (isUndefined(descriptor)) return\n sourceUser.value = await writes.readSourceUser(descriptor, props.userId)\n}\n\n/** Copying a person into another system copies whether they are switched on. Roles stay empty. */\nconst createEnabled = computed(() => sourceUser.value?.enabled === true)\n\nconst onCreate = async (descriptor: AnyUserSystemDescriptor, metadata: BaseUser) => {\n const owner = ownerDescriptor.value\n if (isUndefined(owner)) return\n creatingSystem.value = descriptor.system\n try {\n const source = await writes.readSourceUser(owner, props.userId)\n if (isNull(source)) {\n showError(t('common.userSystem.create.sourceUnreadable', { system: labelFor(owner.system) }))\n return\n }\n // The dialog already promised \"created ready to use\" or \"created switched off\" from the earlier read. If the\n // server now disagrees, the promise was wrong, and in blog and forum that means a working public account.\n // Usually the first read failed, leaving `sourceUser` null and the dialog saying \"disabled\"\n // for an enabled account. Nothing is written until the corrected row is confirmed again.\n if (source.enabled !== createEnabled.value) {\n sourceUser.value = source\n showError(t('common.userSystem.create.sourceChanged'))\n return\n }\n // The create right may have been lost while the source was read. Nothing is offered then, so nothing is reported.\n if (!descriptorMayWrite(descriptor, 'create')) return\n // Built by the library factory, never by hand. A body of base fields\n // alone makes the backend add `ROLE_USER`, a role nobody granted.\n // Metadata comes from the dialog, validated against the target's profile. The source may leave fields empty\n // (blog never fills `person`) that the target requires. The id and `enabled` come from the fresh read.\n const body = createAnzuUser(descriptor.system)\n body.id = source.id\n body.email = metadata.email\n body.person = cloneDeep(metadata.person)\n body.avatar = cloneDeep(metadata.avatar)\n body.enabled = source.enabled\n const result = await writes.createInSystem(descriptor, body)\n if (result.outcome !== BulkOutcome.Done) {\n // Without this message the failure looked like success: the\n // re-probed row still said \"absent\" with no explanation.\n showError(labelFor(descriptor.system) + ': ' + t('common.userSystem.bulk.outcome.' + result.outcome))\n return\n }\n showRecordWas('created')\n emit('created', descriptor)\n otherSystems.value?.refreshSystem(descriptor.system)\n ownedPanels.value.forEach((panel) => panel?.refresh())\n } finally {\n creatingSystem.value = null\n }\n}\n\n/**\n * Called by the page after the owning form saved.\n * `VWindowItem` hides panels with `v-show`, so a mounted panel never re-fetches by itself. Without\n * this it shows pre-save data, and create-in-another-system would copy that stale snapshot.\n * Not a refetch on every tab activation: that would cost eight calls per tab switch.\n */\nconst refresh = () => {\n void loadSource()\n otherSystems.value?.refresh()\n ownedPanels.value.forEach((panel) => panel?.refresh())\n}\n\n// Read on the first activation of a non-owning tab, so the owning tab makes no foreign call.\nwatch(\n activeTab,\n (value) => {\n // `isValidTab` first: before mount settles, the model is an empty string.\n // Treating it as a non-owning tab would fetch on the owning tab too.\n if (!isValidTab(value) || value === props.owner) return\n if (isNull(sourceUser.value)) void loadSource()\n },\n { immediate: true }\n)\n\ndefineExpose({ refresh })\n</script>\n\n<template>\n <div>\n <!--\n No tab navigates. Tabs only switch content, and leaving the page is done by the Manage\n anchor inside a panel. `VTab` renders `role=\"tab\"` and cannot carry navigation semantically.\n -->\n <VTabs\n v-model=\"activeTab\"\n data-cy=\"user-tabs\"\n >\n <VTab\n v-for=\"tab in tabs\"\n :key=\"tab\"\n :value=\"tab\"\n :data-cy=\"`user-tab-${tab}`\"\n >\n {{ tab === OTHER_SYSTEMS_TAB ? t('common.userSystem.tab.otherSystems') : labelFor(tab) }}\n <!-- The owning tab says it holds unsaved work; the Save button itself is always visible. -->\n <VIcon\n v-if=\"tab === owner && hasUnsavedChanges\"\n class=\"ml-1\"\n size=\"x-small\"\n color=\"warning\"\n icon=\"mdi-circle\"\n data-cy=\"user-tab-unsaved\"\n />\n </VTab>\n </VTabs>\n <VWindow\n v-model=\"activeTab\"\n class=\"mt-4\"\n >\n <VWindowItem\n v-for=\"tab in ownedTabs\"\n :key=\"tab\"\n :value=\"tab\"\n >\n <!-- The owning system of the current route: the full form. -->\n <slot v-if=\"tab === owner\" />\n <!--\n Another system this admin owns whose route is not open: a probe\n with a summary and a Manage button, like any other system.\n -->\n <AUserSystemPanel\n v-else-if=\"!isUndefined(bySystem.get(tab))\"\n ref=\"ownedPanels\"\n :descriptor=\"bySystem.get(tab)!\"\n :user-id=\"userId\"\n :readonly=\"readonly\"\n :create-enabled=\"createEnabled\"\n :source=\"sourceUser\"\n :creating=\"creatingSystem === tab\"\n @create=\"onCreate\"\n />\n </VWindowItem>\n <VWindowItem :value=\"OTHER_SYSTEMS_TAB\">\n <!-- `VWindowItem` renders content on first activation, so opening a user makes no foreign calls. -->\n <AUserOtherSystemsTable\n ref=\"otherSystems\"\n :descriptors=\"otherDescriptors\"\n :user-id=\"userId\"\n :readonly=\"readonly\"\n :create-enabled=\"createEnabled\"\n :source=\"sourceUser\"\n :creating-system=\"creatingSystem\"\n @create=\"onCreate\"\n />\n </VWindowItem>\n </VWindow>\n <AUnsavedConfirmDialog\n v-model=\"promptOpen\"\n :dirty-labels=\"dirtyLabels\"\n @resolve=\"resolvePrompt\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -9,11 +9,10 @@ export interface AnzuUserActionsParams {
|
|
|
9
9
|
system: string;
|
|
10
10
|
entity?: string;
|
|
11
11
|
/**
|
|
12
|
-
* i18n scope for
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* system fields as well passes its own pair, and keeps the base keys beside them.
|
|
12
|
+
* i18n scope for server-side validation errors, independent of which backend answered.
|
|
13
|
+
* `AnzuApiValidationError` builds `<system>.<entity>.model.<field>` keys, so this pair
|
|
14
|
+
* must name where the labels live. Defaults to `common` + `anzuUser`. An admin whose
|
|
15
|
+
* form adds system fields passes its own pair and keeps the base keys alongside.
|
|
17
16
|
*/
|
|
18
17
|
validationSystem?: string;
|
|
19
18
|
validationEntity?: string;
|
|
@@ -21,10 +20,7 @@ export interface AnzuUserActionsParams {
|
|
|
21
20
|
/** Vuelidate scope, when the page collects its fields under one of its own. */
|
|
22
21
|
validationScope?: string | symbol;
|
|
23
22
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Per instance, like every other actions composable here. The admins' versions kept their loading
|
|
26
|
-
* flags at module scope.
|
|
27
|
-
*/
|
|
23
|
+
/** Per instance, like the other actions composables. The admins' versions kept loading flags at module scope. */
|
|
28
24
|
export declare const useAnzuUserActions: (params: AnzuUserActionsParams) => {
|
|
29
25
|
isDirty: import('vue').ComputedRef<boolean>;
|
|
30
26
|
/** Takes the record as it stands as the new baseline; the page calls it after it seeds one. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anzuUserActions.js","names":["useVuelidate","fetchGeneration","useAnzuUserActions","ANZU_USER_ENTITY","ANZU_USER_ENDPOINT","params","useAlerts","useAnzuUserApi","executeList","abortList","useFetchAnzuUserList","anzuUserList","ref","loadingAnzuUserList","datatableHiddenColumns","listGeneration","fetchAnzuUserList","token","items","pagination","filterData","filterConfig","error","showErrorsDefault","cancelAnzuUserList","anzuUserOneStore","useAnzuUserOneStore","storeToRefs","pristine","snapshot","isDirty","computed","anzuUser","fetchAnzuUser","generation","isLatest","useFetchAnzuUser","res","execute","options","nextTick","system","v$","loadingCreateAnzuUser","createAnzuUser","showValidationError","useCreateAnzuUser","created","showRecordWas","loadingUpdateAnzuUser","id","isNull","isUndefined","AnzuFatalError","useUpdateAnzuUser","syncUserAndTimeTracking","args"],"sources":["../../../../src/domains/anzuUser/composables/anzuUserActions.ts"],"sourcesContent":["import { computed, nextTick, ref, type Ref } from 'vue'\nimport { storeToRefs } from 'pinia'\nimport useVuelidate from '@vuelidate/core'\nimport { useAlerts } from '@/domains/system/composables/alerts'\nimport { handleRecordLoadError } from '@/domains/system/composables/recordPage'\nimport type { AxiosClientFn } from '@/domains/api/utils/client'\nimport type { FilterConfig, FilterData } from '@/domains/filters/composables/filterFactory'\nimport type { Pagination } from '@/domains/api/composables/pagination'\nimport { ANZU_USER_ENDPOINT, ANZU_USER_ENTITY, useAnzuUserApi } from '@/domains/anzuUser/api/anzuUserApi'\nimport { useAnzuUserOneStore } from '@/domains/anzuUser/store/anzuUserStore'\nimport type { AnzuUser } from '@/shared/types/AnzuUser'\nimport type { IntegerId } from '@/shared/types/common'\nimport { AnzuFatalError } from '@/shared/error/AnzuFatalError'\nimport { isNull, isUndefined } from '@/shared/utils/common'\nimport { syncUserAndTimeTracking } from '@/shared/utils/userAndTimeTracking'\n\nexport interface AnzuUserActionsParams {\n client: AxiosClientFn\n system: string\n entity?: string\n /**\n * i18n scope for a server-side validation failure, which is a different question from which\n * backend answered. `AnzuApiValidationError` builds `<system>.<entity>.model.<field>` keys, so\n * the pair has to name the namespace the *labels* live under. It defaults to `common` +\n * `anzuUser`, which is where the shared form's own fields are; an admin whose form carries\n * system fields as well passes its own pair, and keeps the base keys beside them.\n */\n validationSystem?: string\n validationEntity?: string\n endPoint?: string\n /** Vuelidate scope, when the page collects its fields under one of its own. */\n validationScope?: string | symbol\n}\n\n// The record store is one for every page and every system, and a request is not aborted when its page\n// goes: only the latest fetch may write the record, or reset it on failure. A store reset (a page's\n// teardown, a create page's mount) counts as newer too.\nlet fetchGeneration = 0\n\n/**\n * Per instance, like every other actions composable here. The admins' versions kept their loading\n * flags at module scope.\n */\nexport const useAnzuUserActions = (params: AnzuUserActionsParams) => {\n const { client, system, entity = ANZU_USER_ENTITY, endPoint = ANZU_USER_ENDPOINT } = params\n\n const { showErrorsDefault, showRecordWas, showValidationError } = useAlerts()\n const { useFetchAnzuUserList, useFetchAnzuUser, useCreateAnzuUser, useUpdateAnzuUser } = useAnzuUserApi({\n client,\n system,\n entity,\n validationSystem: params.validationSystem,\n validationEntity: params.validationEntity,\n endPoint,\n })\n\n const { execute: executeList, abort: abortList } = useFetchAnzuUserList()\n\n const anzuUserList = ref<AnzuUser[]>([])\n const loadingAnzuUserList = ref(false)\n const datatableHiddenColumns = ref<Array<string>>([])\n\n let listGeneration = 0\n\n const fetchAnzuUserList = async (\n pagination: Ref<Pagination>,\n filterData: FilterData<any>,\n filterConfig: FilterConfig<any>\n ) => {\n const token = ++listGeneration\n loadingAnzuUserList.value = true\n try {\n const items = await executeList(pagination, filterData, filterConfig)\n if (token !== listGeneration) return\n anzuUserList.value = items\n } catch (error) {\n if (token !== listGeneration) return\n anzuUserList.value = []\n showErrorsDefault(error)\n } finally {\n if (token === listGeneration) loadingAnzuUserList.value = false\n }\n }\n\n const cancelAnzuUserList = () => {\n listGeneration++\n abortList()\n }\n\n const anzuUserOneStore = useAnzuUserOneStore()\n const { anzuUser, loadingAnzuUser } = storeToRefs(anzuUserOneStore)\n\n /**\n * What the server last said, so the page can tell whether anything has been edited.\n *\n * A page needs this for two things that look cosmetic and are not: the dot on the owning tab,\n * and the guard that asks before leaving. Switching a tab is not navigation -- the form stays\n * mounted and dirty -- so the moment the operator does leave is through a button inside a panel,\n * and by then nothing else remembers there was unsaved work.\n */\n const pristine = ref<string>('')\n const snapshot = () => {\n pristine.value = JSON.stringify(anzuUserOneStore.anzuUser)\n }\n\n const isDirty = computed(() => pristine.value !== '' && pristine.value !== JSON.stringify(anzuUser.value))\n\n /**\n * `true` once loaded, `false` when the page should leave (`handleRecordLoadError`), `undefined`\n * when a newer fetch took over or the request was stopped.\n */\n const fetchAnzuUser = async (id: IntegerId, options: { signal?: AbortSignal } = {}): Promise<boolean | undefined> => {\n const generation = ++fetchGeneration\n const isLatest = () => fetchGeneration === generation\n anzuUserOneStore.setLoadingAnzuUser(true)\n try {\n const { execute } = useFetchAnzuUser()\n const res = await execute({ urlParams: { id }, signal: options.signal })\n if (!isLatest()) return undefined\n anzuUserOneStore.setAnzuUser(res)\n // After the form has settled, not before it. The derived fields recompute in a watcher, and\n // a baseline taken ahead of that would make an account whose stored full name is empty read\n // as edited the instant it opens -- an unsaved dot and a leave prompt before anyone typed.\n await nextTick()\n snapshot()\n return true\n } catch (error) {\n // A newer fetch owns the record now, possibly another page's: leave it alone.\n if (!isLatest()) return undefined\n // Not the previous record: Save would PUT it back to its own id from a page opened for another.\n anzuUserOneStore.reset(system)\n pristine.value = ''\n return handleRecordLoadError(error) ? false : undefined\n } finally {\n if (isLatest()) anzuUserOneStore.setLoadingAnzuUser(false)\n }\n }\n\n // Collects whatever the form's children registered. With a scope it collects only that scope,\n // which is how an app keeps its own system fields in a separate one.\n const v$ = params.validationScope ? useVuelidate({}, {}, { $scope: params.validationScope }) : useVuelidate()\n\n const loadingCreateAnzuUser = ref(false)\n /**\n * The body is the store's record, which the library factory built: `roles: []` and\n * `enabled: false`. That matters -- a hand-assembled body of base fields would have the backend\n * fill in `ROLE_USER`, and the account would exist with a role nobody granted.\n */\n const createAnzuUser = async (): Promise<AnzuUser | null> => {\n try {\n loadingCreateAnzuUser.value = true\n v$.value.$touch()\n if (v$.value.$invalid) {\n showValidationError()\n return null\n }\n const { execute } = useCreateAnzuUser()\n const created = await execute({ body: anzuUserOneStore.anzuUser })\n showRecordWas('created')\n snapshot()\n return created\n } catch (error) {\n showErrorsDefault(error)\n return null\n } finally {\n loadingCreateAnzuUser.value = false\n }\n }\n\n const loadingUpdateAnzuUser = ref(false)\n /**\n * Sends the whole record the preceding GET returned, with only the edited fields changed.\n *\n * That is the write invariant, and it is not a style preference: an omitted field is destructive\n * rather than neutral. `UserDto` defaults `roles` to `[ROLE_USER]`, `enabled` to `true` and both\n * permission collections to empty, and the manager writes all four unconditionally -- so a body\n * carrying only the metadata resets roles, wipes grants, detaches groups and switches a disabled\n * account back on.\n */\n const updateAnzuUser = async (): Promise<boolean> => {\n try {\n loadingUpdateAnzuUser.value = true\n v$.value.$touch()\n if (v$.value.$invalid) {\n showValidationError()\n return false\n }\n const id = anzuUserOneStore.anzuUser.id\n if (isNull(id) || isUndefined(id)) {\n throw new AnzuFatalError(undefined, '[useAnzuUserActions] update called on a record with no id.')\n }\n const { execute } = useUpdateAnzuUser()\n const res = await execute({\n urlParams: { id },\n body: anzuUserOneStore.anzuUser,\n })\n // Before the snapshot: `isDirty` compares the whole record, so tracking written after it would\n // mark the form as unsaved.\n syncUserAndTimeTracking(anzuUserOneStore.anzuUser, res)\n showRecordWas('updated')\n snapshot()\n return true\n } catch (error) {\n showErrorsDefault(error)\n return false\n } finally {\n loadingUpdateAnzuUser.value = false\n }\n }\n\n return {\n isDirty,\n /** Takes the record as it stands as the new baseline; the page calls it after it seeds one. */\n markPristine: snapshot,\n anzuUserList,\n loadingAnzuUserList,\n datatableHiddenColumns,\n fetchAnzuUserList,\n cancelAnzuUserList,\n anzuUser,\n loadingAnzuUser,\n fetchAnzuUser,\n createAnzuUser,\n updateAnzuUser,\n loadingCreateAnzuUser,\n loadingUpdateAnzuUser,\n resetAnzuUserStore: (...args: Parameters<typeof anzuUserOneStore.reset>) => {\n fetchGeneration++\n anzuUserOneStore.reset(...args)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;AAqCA,IAAIC,IAAkB,GAMTC,KAAsB,MAAkC;CACnE,IAAM,EAAE,WAAQ,WAAQ,YAASC,GAAkB,cAAWC,MAAuBC,GAE/E,EAAE,sBAAmB,kBAAe,2BAAwBC,EAAU,GACtE,EAAE,yBAAsB,qBAAkB,sBAAmB,yBAAsBC,EAAe;EACtG;EACA;EACA;EACA,kBAAkBF,EAAO;EACzB,kBAAkBA,EAAO;EACzB;CACF,CAAC,GAEK,EAAE,SAASG,GAAa,OAAOC,MAAcC,EAAqB,GAElEC,IAAeC,EAAgB,CAAC,CAAC,GACjCC,IAAsBD,EAAI,EAAK,GAC/BE,IAAyBF,EAAmB,CAAC,CAAC,GAEhDG,IAAiB,GAEfC,IAAoB,OACxB,GACA,GACA,MACG;EACH,IAAMC,IAAQ,EAAEF;EAChB,EAAoB,QAAQ;EAC5B,IAAI;GACF,IAAMG,IAAQ,MAAMV,EAAYW,GAAYC,GAAYC,CAAY;GACpE,IAAIJ,MAAUF,GAAgB;GAC9B,EAAa,QAAQG;EACvB,SAASI,GAAO;GACd,IAAIL,MAAUF,GAAgB;GAE9B,AADA,EAAa,QAAQ,CAAC,GACtBQ,EAAkBD,CAAK;EACzB,UAAU;GACR,AAAIL,MAAUF,MAAgB,EAAoB,QAAQ;EAC5D;CACF,GAEMS,UAA2B;EAE/B,AADA,KACAf,EAAU;CACZ,GAEMgB,IAAmBC,EAAoB,GACvC,EAAE,aAAU,uBAAoBC,EAAYF,CAAgB,GAU5DG,IAAWhB,EAAY,EAAE,GACzBiB,UAAiB;EACrB,EAAS,QAAQ,KAAK,UAAUJ,EAAiB,QAAQ;CAC3D,GAEMK,IAAUC,QAAeH,EAAS,UAAU,MAAMA,EAAS,UAAU,KAAK,UAAUI,EAAS,KAAK,CAAC,GAMnGC,IAAgB,OAAO,GAAe,IAAoC,CAAC,MAAoC;EACnH,IAAMC,IAAa,EAAEjC,GACfkC,UAAiBlC,MAAoBiC;EAC3C,EAAiB,mBAAmB,EAAI;EACxC,IAAI;GACF,IAAM,EAAE,eAAYE,EAAiB,GAC/BC,IAAM,MAAMC,EAAQ;IAAE,WAAW,EAAE,MAAG;IAAG,QAAQC,EAAQ;GAAO,CAAC;GAQvE,OAPKJ,EAAS,KACdV,EAAiB,YAAYY,CAAG,GAIhC,MAAMG,EAAS,GACfX,EAAS,GACF,MAPU;EAQnB,SAASP,GAAO;GAMd,OAJKa,EAAS,KAEdV,EAAiB,MAAMgB,CAAM,GAC7B,EAAS,QAAQ,IACV,GAAsBnB,CAAK,KAAY,KAAA,KAJ7B;EAKnB,UAAU;GACR,AAAIa,EAAS,KAAGV,EAAiB,mBAAmB,EAAK;EAC3D;CACF,GAIMiB,IAAKrC,EAAO,kBAAkBL,EAAa,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQK,EAAO,gBAAgB,CAAC,IAAIL,EAAa,GAEtG2C,IAAwB/B,EAAI,EAAK,GAMjCgC,IAAiB,YAAsC;EAC3D,IAAI;GAGF,IAFA,EAAsB,QAAQ,IAC9BF,EAAG,MAAM,OAAO,GACZA,EAAG,MAAM,UAEX,OADAG,EAAoB,GACb;GAET,IAAM,EAAE,eAAYC,EAAkB,GAChCC,IAAU,MAAMT,EAAQ,EAAE,MAAMb,EAAiB,SAAS,CAAC;GAGjE,OAFAuB,EAAc,SAAS,GACvBnB,EAAS,GACFkB;EACT,SAASzB,GAAO;GAEd,OADAC,EAAkBD,CAAK,GAChB;EACT,UAAU;GACR,EAAsB,QAAQ;EAChC;CACF,GAEM2B,IAAwBrC,EAAI,EAAK;CAyCvC,OAAO;EACL;EAEA,cAAciB;EACd;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,4BA5CmD;GACnD,IAAI;IAGF,IAFA,EAAsB,QAAQ,IAC9Ba,EAAG,MAAM,OAAO,GACZA,EAAG,MAAM,UAEX,OADAG,EAAoB,GACb;IAET,IAAMK,IAAKzB,EAAiB,SAAS;IACrC,IAAI0B,EAAOD,CAAE,KAAKE,EAAYF,CAAE,GAC9B,MAAM,IAAIG,EAAe,KAAA,GAAW,4DAA4D;IAElG,IAAM,EAAE,eAAYC,EAAkB,GAChCjB,IAAM,MAAMC,EAAQ;KACxB,WAAW,EAAE,MAAG;KAChB,MAAMb,EAAiB;IACzB,CAAC;IAMD,OAHA8B,EAAwB9B,EAAiB,UAAUY,CAAG,GACtDW,EAAc,SAAS,GACvBnB,EAAS,GACF;GACT,SAASP,GAAO;IAEd,OADAC,EAAkBD,CAAK,GAChB;GACT,UAAU;IACR,EAAsB,QAAQ;GAChC;EACF;EAgBE;EACA;EACA,qBAAqB,GAAGkC,MAAoD;GAE1E,AADA,KACA/B,EAAiB,MAAM,GAAG+B,CAAI;EAChC;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"anzuUserActions.js","names":["useVuelidate","fetchGeneration","useAnzuUserActions","ANZU_USER_ENTITY","ANZU_USER_ENDPOINT","params","useAlerts","useAnzuUserApi","executeList","abortList","useFetchAnzuUserList","anzuUserList","ref","loadingAnzuUserList","datatableHiddenColumns","listGeneration","fetchAnzuUserList","token","items","pagination","filterData","filterConfig","error","showErrorsDefault","cancelAnzuUserList","anzuUserOneStore","useAnzuUserOneStore","storeToRefs","pristine","snapshot","isDirty","computed","anzuUser","fetchAnzuUser","generation","isLatest","useFetchAnzuUser","res","execute","options","nextTick","system","v$","loadingCreateAnzuUser","createAnzuUser","showValidationError","useCreateAnzuUser","created","showRecordWas","loadingUpdateAnzuUser","id","isNull","isUndefined","AnzuFatalError","useUpdateAnzuUser","syncUserAndTimeTracking","args"],"sources":["../../../../src/domains/anzuUser/composables/anzuUserActions.ts"],"sourcesContent":["import { computed, nextTick, ref, type Ref } from 'vue'\nimport { storeToRefs } from 'pinia'\nimport useVuelidate from '@vuelidate/core'\nimport { useAlerts } from '@/domains/system/composables/alerts'\nimport { handleRecordLoadError } from '@/domains/system/composables/recordPage'\nimport type { AxiosClientFn } from '@/domains/api/utils/client'\nimport type { FilterConfig, FilterData } from '@/domains/filters/composables/filterFactory'\nimport type { Pagination } from '@/domains/api/composables/pagination'\nimport { ANZU_USER_ENDPOINT, ANZU_USER_ENTITY, useAnzuUserApi } from '@/domains/anzuUser/api/anzuUserApi'\nimport { useAnzuUserOneStore } from '@/domains/anzuUser/store/anzuUserStore'\nimport type { AnzuUser } from '@/shared/types/AnzuUser'\nimport type { IntegerId } from '@/shared/types/common'\nimport { AnzuFatalError } from '@/shared/error/AnzuFatalError'\nimport { isNull, isUndefined } from '@/shared/utils/common'\nimport { syncUserAndTimeTracking } from '@/shared/utils/userAndTimeTracking'\n\nexport interface AnzuUserActionsParams {\n client: AxiosClientFn\n system: string\n entity?: string\n /**\n * i18n scope for server-side validation errors, independent of which backend answered.\n * `AnzuApiValidationError` builds `<system>.<entity>.model.<field>` keys, so this pair\n * must name where the labels live. Defaults to `common` + `anzuUser`. An admin whose\n * form adds system fields passes its own pair and keeps the base keys alongside.\n */\n validationSystem?: string\n validationEntity?: string\n endPoint?: string\n /** Vuelidate scope, when the page collects its fields under one of its own. */\n validationScope?: string | symbol\n}\n\n// The record store is shared by every page and system, and requests are not\n// aborted when a page goes. Only the latest fetch may write or reset the record.\n// A store reset (page teardown, create page mount) also counts as newer.\nlet fetchGeneration = 0\n\n/** Per instance, like the other actions composables. The admins' versions kept loading flags at module scope. */\nexport const useAnzuUserActions = (params: AnzuUserActionsParams) => {\n const { client, system, entity = ANZU_USER_ENTITY, endPoint = ANZU_USER_ENDPOINT } = params\n\n const { showErrorsDefault, showRecordWas, showValidationError } = useAlerts()\n const { useFetchAnzuUserList, useFetchAnzuUser, useCreateAnzuUser, useUpdateAnzuUser } = useAnzuUserApi({\n client,\n system,\n entity,\n validationSystem: params.validationSystem,\n validationEntity: params.validationEntity,\n endPoint,\n })\n\n const { execute: executeList, abort: abortList } = useFetchAnzuUserList()\n\n const anzuUserList = ref<AnzuUser[]>([])\n const loadingAnzuUserList = ref(false)\n const datatableHiddenColumns = ref<Array<string>>([])\n\n let listGeneration = 0\n\n const fetchAnzuUserList = async (\n pagination: Ref<Pagination>,\n filterData: FilterData<any>,\n filterConfig: FilterConfig<any>\n ) => {\n const token = ++listGeneration\n loadingAnzuUserList.value = true\n try {\n const items = await executeList(pagination, filterData, filterConfig)\n if (token !== listGeneration) return\n anzuUserList.value = items\n } catch (error) {\n if (token !== listGeneration) return\n anzuUserList.value = []\n showErrorsDefault(error)\n } finally {\n if (token === listGeneration) loadingAnzuUserList.value = false\n }\n }\n\n const cancelAnzuUserList = () => {\n listGeneration++\n abortList()\n }\n\n const anzuUserOneStore = useAnzuUserOneStore()\n const { anzuUser, loadingAnzuUser } = storeToRefs(anzuUserOneStore)\n\n /**\n * What the server last returned, used to detect edits.\n * It drives the dot on the owning tab and the leave guard. Switching tabs is not\n * navigation, so the form stays dirty and the actual leave happens through a panel button.\n */\n const pristine = ref<string>('')\n const snapshot = () => {\n pristine.value = JSON.stringify(anzuUserOneStore.anzuUser)\n }\n\n const isDirty = computed(() => pristine.value !== '' && pristine.value !== JSON.stringify(anzuUser.value))\n\n /**\n * `true` once loaded, `false` when the page should leave (`handleRecordLoadError`), `undefined`\n * when a newer fetch took over or the request was stopped.\n */\n const fetchAnzuUser = async (id: IntegerId, options: { signal?: AbortSignal } = {}): Promise<boolean | undefined> => {\n const generation = ++fetchGeneration\n const isLatest = () => fetchGeneration === generation\n anzuUserOneStore.setLoadingAnzuUser(true)\n try {\n const { execute } = useFetchAnzuUser()\n const res = await execute({ urlParams: { id }, signal: options.signal })\n if (!isLatest()) return undefined\n anzuUserOneStore.setAnzuUser(res)\n // Snapshot after the form settles. Derived fields recompute in a watcher, and an earlier\n // baseline would mark an account with an empty stored full name as edited on open.\n await nextTick()\n snapshot()\n return true\n } catch (error) {\n // A newer fetch owns the record now, possibly another page's: leave it alone.\n if (!isLatest()) return undefined\n // Not the previous record: Save would PUT it back to its own id from a page opened for another.\n anzuUserOneStore.reset(system)\n pristine.value = ''\n return handleRecordLoadError(error) ? false : undefined\n } finally {\n if (isLatest()) anzuUserOneStore.setLoadingAnzuUser(false)\n }\n }\n\n // Collects what the form's children registered. With a scope it collects\n // only that scope, which lets an app keep its system fields separate.\n const v$ = params.validationScope ? useVuelidate({}, {}, { $scope: params.validationScope }) : useVuelidate()\n\n const loadingCreateAnzuUser = ref(false)\n /**\n * The body is the store's record from the library factory, with `roles: []` and `enabled: false`.\n * A hand-assembled body would make the backend add `ROLE_USER`, a role nobody granted.\n */\n const createAnzuUser = async (): Promise<AnzuUser | null> => {\n try {\n loadingCreateAnzuUser.value = true\n v$.value.$touch()\n if (v$.value.$invalid) {\n showValidationError()\n return null\n }\n const { execute } = useCreateAnzuUser()\n const created = await execute({ body: anzuUserOneStore.anzuUser })\n showRecordWas('created')\n snapshot()\n return created\n } catch (error) {\n showErrorsDefault(error)\n return null\n } finally {\n loadingCreateAnzuUser.value = false\n }\n }\n\n const loadingUpdateAnzuUser = ref(false)\n /**\n * Sends the whole record from the preceding GET with only edited fields changed.\n * An omitted field is destructive. `UserDto` defaults `roles` to `[ROLE_USER]`, `enabled` to `true`\n * and both permission collections to empty, and the manager writes all four. A metadata-only body\n * resets roles, wipes grants, detaches groups and re-enables a disabled account.\n */\n const updateAnzuUser = async (): Promise<boolean> => {\n try {\n loadingUpdateAnzuUser.value = true\n v$.value.$touch()\n if (v$.value.$invalid) {\n showValidationError()\n return false\n }\n const id = anzuUserOneStore.anzuUser.id\n if (isNull(id) || isUndefined(id)) {\n throw new AnzuFatalError(undefined, '[useAnzuUserActions] update called on a record with no id.')\n }\n const { execute } = useUpdateAnzuUser()\n const res = await execute({\n urlParams: { id },\n body: anzuUserOneStore.anzuUser,\n })\n // Before the snapshot: `isDirty` compares the whole record, so tracking written after it would\n // mark the form as unsaved.\n syncUserAndTimeTracking(anzuUserOneStore.anzuUser, res)\n showRecordWas('updated')\n snapshot()\n return true\n } catch (error) {\n showErrorsDefault(error)\n return false\n } finally {\n loadingUpdateAnzuUser.value = false\n }\n }\n\n return {\n isDirty,\n /** Takes the record as it stands as the new baseline; the page calls it after it seeds one. */\n markPristine: snapshot,\n anzuUserList,\n loadingAnzuUserList,\n datatableHiddenColumns,\n fetchAnzuUserList,\n cancelAnzuUserList,\n anzuUser,\n loadingAnzuUser,\n fetchAnzuUser,\n createAnzuUser,\n updateAnzuUser,\n loadingCreateAnzuUser,\n loadingUpdateAnzuUser,\n resetAnzuUserStore: (...args: Parameters<typeof anzuUserOneStore.reset>) => {\n fetchGeneration++\n anzuUserOneStore.reset(...args)\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import { BaseUser } from '../../../shared/types/AnzuUser';
|
|
|
3
3
|
export interface UserMetadataValidationOptions {
|
|
4
4
|
/**
|
|
5
5
|
* The system's profile (`requiredMetadata` on its descriptor). `false` requires only the
|
|
6
|
-
* e-mail
|
|
7
|
-
* It applies
|
|
6
|
+
* e-mail. `true` also requires first, last and full name, avatar text and avatar colour.
|
|
7
|
+
* It applies equally to create and edit.
|
|
8
8
|
*/
|
|
9
9
|
required: MaybeRefOrGetter<boolean>;
|
|
10
10
|
/** Whether the id is a field at all. When it is, and this is a create, it is required. */
|
|
@@ -15,10 +15,8 @@ export interface UserMetadataValidationOptions {
|
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* The `BaseUserDto` rules, per profile.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* text 2-3). The backend requires only the e-mail; the front end is deliberately stricter, and
|
|
21
|
-
* `requiredMetadata` is what says by how much.
|
|
18
|
+
* Lengths follow backend constraints (`email` 256, first/last 120, full 242, avatar text 2-3). The
|
|
19
|
+
* backend requires only the e-mail. The front end is deliberately stricter, as set by `requiredMetadata`.
|
|
22
20
|
*/
|
|
23
21
|
export declare function useUserMetadataValidation(user: Ref<BaseUser>, options: UserMetadataValidationOptions): {
|
|
24
22
|
v$: Ref<import('@vuelidate/core').Validation<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anzuUserValidations.js","names":["useVuelidate","useUserMetadataValidation","useValidate","rules","computed","requiredWhenProfileSays","toValue","options","maxLength","minLength"],"sources":["../../../../src/domains/anzuUser/composables/anzuUserValidations.ts"],"sourcesContent":["import useVuelidate from '@vuelidate/core'\nimport { computed, toValue, type MaybeRefOrGetter, type Ref } from 'vue'\nimport { useValidate } from '@/shared/validators/vuelidate/useValidate'\nimport type { BaseUser } from '@/shared/types/AnzuUser'\n\nexport interface UserMetadataValidationOptions {\n /**\n * The system's profile (`requiredMetadata` on its descriptor). `false` requires only the\n * e-mail
|
|
1
|
+
{"version":3,"file":"anzuUserValidations.js","names":["useVuelidate","useUserMetadataValidation","useValidate","rules","computed","requiredWhenProfileSays","toValue","options","maxLength","minLength"],"sources":["../../../../src/domains/anzuUser/composables/anzuUserValidations.ts"],"sourcesContent":["import useVuelidate from '@vuelidate/core'\nimport { computed, toValue, type MaybeRefOrGetter, type Ref } from 'vue'\nimport { useValidate } from '@/shared/validators/vuelidate/useValidate'\nimport type { BaseUser } from '@/shared/types/AnzuUser'\n\nexport interface UserMetadataValidationOptions {\n /**\n * The system's profile (`requiredMetadata` on its descriptor). `false` requires only the\n * e-mail. `true` also requires first, last and full name, avatar text and avatar colour.\n * It applies equally to create and edit.\n */\n required: MaybeRefOrGetter<boolean>\n /** Whether the id is a field at all. When it is, and this is a create, it is required. */\n idInput: MaybeRefOrGetter<boolean>\n isEdit: MaybeRefOrGetter<boolean>\n /** Scope key, so an owning form can validate its own fields alongside the app's system fields. */\n scope?: string | symbol | false\n}\n\n/**\n * The `BaseUserDto` rules, per profile.\n * Lengths follow backend constraints (`email` 256, first/last 120, full 242, avatar text 2-3). The\n * backend requires only the e-mail. The front end is deliberately stricter, as set by `requiredMetadata`.\n */\nexport function useUserMetadataValidation(user: Ref<BaseUser>, options: UserMetadataValidationOptions) {\n const { email, hexColor, maxLength, minLength, required } = useValidate()\n\n const rules = computed(() => {\n // Read inside the computed, not at setup. The \"not found anywhere\" dialog switches the target\n // system under a mounted form, and a profile captured at mount would keep the first system's rules.\n const requiredWhenProfileSays = toValue(options.required) ? { required } : {}\n\n return {\n user: {\n // Required only on create where the id is typed. On edit it is a\n // displayed primary key, and in cms the backend resolves it from SSO.\n id: toValue(options.idInput) && !toValue(options.isEdit) ? { required } : {},\n email: {\n required,\n email,\n maxLength: maxLength(256),\n },\n person: {\n firstName: { ...requiredWhenProfileSays, minLength: minLength(2), maxLength: maxLength(120) },\n lastName: { ...requiredWhenProfileSays, minLength: minLength(2), maxLength: maxLength(120) },\n fullName: { ...requiredWhenProfileSays, minLength: minLength(3), maxLength: maxLength(242) },\n },\n avatar: {\n // Check the shape, not the length: `minLength(7)` accepts `#GGGGGG`, which the server rejects.\n // `hexColor` passes an empty value, so a profile without a required colour still saves.\n color: { ...requiredWhenProfileSays, hexColor },\n text: { ...requiredWhenProfileSays, minLength: minLength(2), maxLength: maxLength(3) },\n },\n },\n }\n })\n\n const v$ = useVuelidate(rules, { user }, options.scope === undefined ? undefined : { $scope: options.scope })\n\n return {\n v$,\n }\n}\n"],"mappings":";;;;AAwBA,SAAgBC,EAA0B,GAAqB,GAAwC;CACrG,IAAM,EAAE,UAAO,aAAU,cAAW,cAAW,gBAAaC,EAAY,GAElEC,IAAQC,QAAe;EAG3B,IAAMC,IAA0BC,EAAQC,EAAQ,QAAQ,IAAI,EAAE,YAAS,IAAI,CAAC;EAE5E,OAAO,EACL,MAAM;GAGJ,IAAID,EAAQC,EAAQ,OAAO,KAAK,CAACD,EAAQC,EAAQ,MAAM,IAAI,EAAE,YAAS,IAAI,CAAC;GAC3E,OAAO;IACL;IACA;IACA,WAAWC,EAAU,GAAG;GAC1B;GACA,QAAQ;IACN,WAAW;KAAE,GAAGH;KAAyB,WAAWI,EAAU,CAAC;KAAG,WAAWD,EAAU,GAAG;IAAE;IAC5F,UAAU;KAAE,GAAGH;KAAyB,WAAWI,EAAU,CAAC;KAAG,WAAWD,EAAU,GAAG;IAAE;IAC3F,UAAU;KAAE,GAAGH;KAAyB,WAAWI,EAAU,CAAC;KAAG,WAAWD,EAAU,GAAG;IAAE;GAC7F;GACA,QAAQ;IAGN,OAAO;KAAE,GAAGH;KAAyB;IAAS;IAC9C,MAAM;KAAE,GAAGA;KAAyB,WAAWI,EAAU,CAAC;KAAG,WAAWD,EAAU,CAAC;IAAE;GACvF;EACF,EACF;CACF,CAAC;CAID,OAAO,EACL,IAHSR,EAAaG,GAAO,EAAE,QAAK,GAAGI,EAAQ,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,QAAQA,EAAQ,MAAM,CAGzG,EACF;AACF"}
|
|
@@ -7,9 +7,9 @@ export interface CachedAnzuUsersParams {
|
|
|
7
7
|
endPoint?: string;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* Users of one backend, read from its `/adm/v1/anzu-user
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Users of one backend, read from its `/adm/v1/anzu-user`, for an admin without its own user cache for that backend.
|
|
11
|
+
* Returns the same names as the admins' `useCachedUsers()`, so
|
|
12
|
+
* it plugs into `createUserAndTimeTrackingFields` directly.
|
|
13
13
|
*/
|
|
14
14
|
export declare const useCachedAnzuUsers: (params: CachedAnzuUsersParams) => {
|
|
15
15
|
cachedUsers: import('vue').Ref<Map<number, import('../../cached/composables/defineCached').CachedItem<AnzuUserMinimal>>, Map<number, import('../../cached/composables/defineCached').CachedItem<AnzuUserMinimal>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cachedAnzuUsers.js","names":["registries","mapFullToMinimal","user","mapIdToMinimal","buildRegistry","useAnzuUserApi","params","defineCached","useFetchAnzuUserListByIds","ids","useCachedAnzuUsers","resolved","registry","cache","fetch","immediateFetch","add","addManual","addManualMinimal","has","get","isLoaded","clear"],"sources":["../../../../src/domains/anzuUser/composables/cachedAnzuUsers.ts"],"sourcesContent":["import { defineCached } from '@/domains/cached/composables/defineCached'\nimport type { AxiosClientFn } from '@/domains/api/utils/client'\nimport { ANZU_USER_ENDPOINT, ANZU_USER_ENTITY, useAnzuUserApi } from '@/domains/anzuUser/api/anzuUserApi'\nimport type { IntegerId } from '@/shared/types/common'\nimport type { AnzuUser, AnzuUserMinimal } from '@/shared/types/AnzuUser'\n\nexport interface CachedAnzuUsersParams {\n client: AxiosClientFn\n system: string\n entity?: string\n endPoint?: string\n}\n\ntype Registry = ReturnType<typeof buildRegistry>\n\n/**\n * One cache per system, not one shared
|
|
1
|
+
{"version":3,"file":"cachedAnzuUsers.js","names":["registries","mapFullToMinimal","user","mapIdToMinimal","buildRegistry","useAnzuUserApi","params","defineCached","useFetchAnzuUserListByIds","ids","useCachedAnzuUsers","resolved","registry","cache","fetch","immediateFetch","add","addManual","addManualMinimal","has","get","isLoaded","clear"],"sources":["../../../../src/domains/anzuUser/composables/cachedAnzuUsers.ts"],"sourcesContent":["import { defineCached } from '@/domains/cached/composables/defineCached'\nimport type { AxiosClientFn } from '@/domains/api/utils/client'\nimport { ANZU_USER_ENDPOINT, ANZU_USER_ENTITY, useAnzuUserApi } from '@/domains/anzuUser/api/anzuUserApi'\nimport type { IntegerId } from '@/shared/types/common'\nimport type { AnzuUser, AnzuUserMinimal } from '@/shared/types/AnzuUser'\n\nexport interface CachedAnzuUsersParams {\n client: AxiosClientFn\n system: string\n entity?: string\n endPoint?: string\n}\n\ntype Registry = ReturnType<typeof buildRegistry>\n\n/**\n * One cache per system, not one shared cache.\n * Each backend has its own user table. Ids agree across them, but a user may exist in only\n * one backend (sms-gateway system accounts). A shared table would draw such users as unknown.\n */\nconst registries = new Map<string, Registry>()\n\nconst mapFullToMinimal = (user: AnzuUser): AnzuUserMinimal => ({\n id: user.id ?? 0,\n email: user.email,\n person: user.person,\n avatar: user.avatar,\n})\n\nconst mapIdToMinimal = (id: IntegerId): AnzuUserMinimal => ({\n id,\n email: '',\n person: { firstName: '', lastName: '', fullName: '' },\n avatar: { color: '', text: '' },\n})\n\nconst buildRegistry = (params: Required<CachedAnzuUsersParams>) => {\n const { useFetchAnzuUserListByIds } = useAnzuUserApi(params)\n\n return defineCached<IntegerId, AnzuUser, AnzuUserMinimal>(\n mapFullToMinimal,\n mapIdToMinimal,\n (ids: IntegerId[]) => useFetchAnzuUserListByIds().execute(ids),\n 'id',\n 1000,\n // A user missing from the table stays missing. Otherwise another\n // backend's system user would be requested on every page that shows it.\n { retryNotFound: false }\n )\n}\n\n/**\n * Users of one backend, read from its `/adm/v1/anzu-user`, for an admin without its own user cache for that backend.\n * Returns the same names as the admins' `useCachedUsers()`, so\n * it plugs into `createUserAndTimeTrackingFields` directly.\n */\nexport const useCachedAnzuUsers = (params: CachedAnzuUsersParams) => {\n const resolved = {\n client: params.client,\n system: params.system,\n entity: params.entity ?? ANZU_USER_ENTITY,\n endPoint: params.endPoint ?? ANZU_USER_ENDPOINT,\n }\n\n let registry = registries.get(resolved.system)\n if (!registry) {\n registry = buildRegistry(resolved)\n registries.set(resolved.system, registry)\n }\n\n const { cache, fetch, immediateFetch, add, addManual, addManualMinimal, has, get, isLoaded, clear } = registry\n\n return {\n cachedUsers: cache,\n fetchCachedUsers: fetch,\n immediateFetchCachedUsers: immediateFetch,\n addToCachedUsers: add,\n addManualToCachedUsers: addManual,\n addManualMinimalToCachedUsers: addManualMinimal,\n hasCachedUser: has,\n getCachedUser: get,\n isLoadedCachedUser: isLoaded,\n clearCachedUsers: clear,\n }\n}\n\n/** Test seam. Registries are module state and would otherwise leak between cases. */\nexport const resetCachedAnzuUserRegistries = () => {\n registries.clear()\n}\n"],"mappings":";;;AAoBA,IAAMA,oBAAa,IAAI,IAAsB,GAEvCC,KAAoB,OAAqC;CAC7D,IAAIC,EAAK,MAAM;CACf,OAAOA,EAAK;CACZ,QAAQA,EAAK;CACb,QAAQA,EAAK;AACf,IAEMC,KAAkB,OAAoC;CAC1D;CACA,OAAO;CACP,QAAQ;EAAE,WAAW;EAAI,UAAU;EAAI,UAAU;CAAG;CACpD,QAAQ;EAAE,OAAO;EAAI,MAAM;CAAG;AAChC,IAEMC,KAAiB,MAA4C;CACjE,IAAM,EAAE,iCAA8BC,EAAeC,CAAM;CAE3D,OAAOC,EACLN,GACAE,IACC,MAAqBK,EAA0B,CAAC,CAAC,QAAQC,CAAG,GAC7D,MACA,KAGA,EAAE,eAAe,GAAM,CACzB;AACF,GAOaC,KAAsB,MAAkC;CACnE,IAAMC,IAAW;EACf,QAAQL,EAAO;EACf,QAAQA,EAAO;EACf,QAAQA,EAAO,UAAA;EACf,UAAUA,EAAO,YAAA;CACnB,GAEIM,IAAWZ,EAAW,IAAIW,EAAS,MAAM;CAC7C,AAAKC,MACH,IAAWR,EAAcO,CAAQ,GACjCX,EAAW,IAAIW,EAAS,QAAQC,CAAQ;CAG1C,IAAM,EAAE,UAAO,UAAO,mBAAgB,QAAK,cAAW,qBAAkB,QAAK,QAAK,aAAU,aAAUA;CAEtG,OAAO;EACL,aAAaC;EACb,kBAAkBC;EAClB,2BAA2BC;EAC3B,kBAAkBC;EAClB,wBAAwBC;EACxB,+BAA+BC;EAC/B,eAAeC;EACf,eAAeC;EACf,oBAAoBC;EACpB,kBAAkBC;CACpB;AACF"}
|
|
@@ -9,10 +9,8 @@ export interface CrossSystemSearchParams {
|
|
|
9
9
|
export declare const isEmailTerm: (term: string) => boolean;
|
|
10
10
|
/**
|
|
11
11
|
* The cross-system fan-out.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* probe's answer rather than by `<Acl>`, so there is nothing to load nine current users for. The
|
|
15
|
-
* budget is nine calls when searching by id, eighteen when searching by e-mail.
|
|
12
|
+
* No current-user endpoints are called, because row buttons depend on the
|
|
13
|
+
* probe's answer, not `<Acl>`. Budget: nine calls by id, eighteen by e-mail.
|
|
16
14
|
*/
|
|
17
15
|
export declare const useUserCrossSystemSearch: (params: CrossSystemSearchParams) => {
|
|
18
16
|
search: (term: string) => Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"userCrossSystemSearch.js","names":["EMAIL_PATTERN","isEmailTerm","term","useUserCrossSystemSearch","store","useUserCrossSystemStore","params","probes","descriptors","descriptor","useUserSystemProbe","generation","cancel","probe","runProbe","UserSystemLoad","id","token","searchById","CrossSystemPhase","lookupByEmail","useAnzuUserEmailLookupFilter","email","usePagination","SortOrder","useApiFetchList","execute","pagination","filterData","filterConfig","searchByEmail","found","ids","row","distinctIds","UserSystemPresence","UserSystemAccess","trimmed","item","system","computed","result","isAuthoritativelyAbsent"],"sources":["../../../../src/domains/anzuUser/composables/userCrossSystemSearch.ts"],"sourcesContent":["import { computed } from 'vue'\nimport { useApiFetchList } from '@/domains/api/composables/useApiFetchList'\nimport { usePagination } from '@/domains/api/composables/pagination'\nimport { SortOrder } from '@/domains/api/types/SortOrder'\nimport { useAnzuUserEmailLookupFilter } from '@/domains/anzuUser/filter/anzuUserFilter'\nimport {\n CrossSystemPhase,\n useUserCrossSystemStore,\n type UserSystemResult,\n} from '@/domains/anzuUser/store/userCrossSystemStore'\nimport type { AnyUserSystemDescriptor } from '@/domains/anzuUser/composables/userSystemDescriptor'\nimport { useUserSystemProbe, type UserSystemRefreshHook } from '@/domains/anzuUser/composables/userSystemProbe'\nimport {\n isAuthoritativelyAbsent,\n UserSystemAccess,\n UserSystemLoad,\n UserSystemPresence,\n} from '@/domains/anzuUser/utils/userSystemState'\nimport type { AnzuUser } from '@/shared/types/AnzuUser'\nimport type { IntegerId } from '@/shared/types/common'\n\nexport interface CrossSystemSearchParams {\n descriptors: AnyUserSystemDescriptor[]\n refreshHook?: UserSystemRefreshHook | undefined\n}\n\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+$/\n\nexport const isEmailTerm = (term: string): boolean => EMAIL_PATTERN.test(term.trim())\n\n/**\n * The cross-system fan-out.\n *\n * No calls to the current-user endpoints go out at all: the buttons in a row are decided by the\n * probe's answer rather than by `<Acl>`, so there is nothing to load nine current users for. The\n * budget is nine calls when searching by id, eighteen when searching by e-mail.\n */\nexport const useUserCrossSystemSearch = (params: CrossSystemSearchParams) => {\n const store = useUserCrossSystemStore()\n const { descriptors, refreshHook } = params\n\n // One probe instance per system, built once: each keeps its own abort token, and rebuilding them\n // per search would lose the ability to invalidate what is still in flight.\n const probes = new Map(\n descriptors.map((descriptor) => [descriptor.system, useUserSystemProbe({ descriptor, refreshHook })])\n )\n\n /**\n * Every search gets a number. A late answer from the previous one is dropped rather than written\n * over the results of the search the operator is looking at now.\n */\n let generation = 0\n\n const cancel = () => {\n generation++\n probes.forEach((probe) => probe.cancel())\n }\n\n const runProbe = async (descriptor: AnyUserSystemDescriptor, id: IntegerId, token: number) => {\n const probe = probes.get(descriptor.system)\n if (!probe) return\n store.patchAxes(descriptor.system, { ...probe.axes.value, load: UserSystemLoad.Loading })\n await probe.probe(id)\n if (token !== generation) return\n store.setResult(descriptor.system, { axes: probe.axes.value, user: probe.user.value })\n }\n\n /** Results are written as they arrive, never through `Promise.all`: one dead backend must not hold up the rest. */\n const searchById = async (id: IntegerId) => {\n const token = ++generation\n store.resetResults()\n store.resolvedId = id\n store.phase = CrossSystemPhase.VerifyingById\n await Promise.allSettled(descriptors.map((descriptor) => runProbe(descriptor, id, token)))\n if (token !== generation) return\n store.phase = CrossSystemPhase.Done\n }\n\n /** Exact match, `filter_eq[email]`, one row. `startsWith` would match a different person. */\n const lookupByEmail = async (descriptor: AnyUserSystemDescriptor, email: string): Promise<AnzuUser | null> => {\n if (!descriptor.isEnabled()) return null\n const { filterData, filterConfig } = useAnzuUserEmailLookupFilter()\n filterData.email = email\n // One row: an exact match either exists or does not, and asking for a page of them would only\n // cost the backend more.\n const { pagination } = usePagination('id', SortOrder.Desc, { rowsPerPage: 1 })\n\n const { execute } = useApiFetchList<AnzuUser>({\n client: descriptor.client,\n system: descriptor.system,\n entity: descriptor.entity,\n urlTemplate: descriptor.endpoints.list,\n })\n\n try {\n const rows = await execute(pagination, filterData, filterConfig)\n return rows[0] ?? null\n } catch {\n // The second round asks every system by id anyway, so a failure here is not a verdict about\n // that system -- it only means this round could not contribute an id.\n return null\n }\n }\n\n /**\n * Two rounds, and the first one must not lie while the second is still running.\n *\n * Between them a row is neither present nor absent: showing \"no account here\" in that window\n * would invite the operator to press Create for an account that does exist under another address.\n */\n const searchByEmail = async (email: string) => {\n const token = ++generation\n store.resetResults()\n store.phase = CrossSystemPhase.MatchingEmail\n\n const found = await Promise.all(\n descriptors.map(async (descriptor) => ({\n system: descriptor.system,\n user: await lookupByEmail(descriptor, email),\n }))\n )\n if (token !== generation) return\n\n const ids = new Map<string, IntegerId>()\n for (const row of found) {\n if (row.user?.id) ids.set(row.system, row.user.id)\n }\n\n const distinctIds = new Set(ids.values())\n if (distinctIds.size > 1) {\n // The same address under two identities. Bulk actions stop here rather than guessing.\n store.identityConflict = ids\n store.phase = CrossSystemPhase.Done\n for (const row of found) {\n if (!row.user) continue\n store.setResult(row.system, {\n axes: {\n load: UserSystemLoad.Loaded,\n presence: UserSystemPresence.Present,\n access: UserSystemAccess.Ok,\n enabled: row.user.enabled,\n },\n user: row.user,\n })\n }\n return\n }\n\n const id = distinctIds.values().next().value\n if (id === undefined) {\n // Nobody anywhere under this address. Every row is still unknown rather than absent: an\n // address search cannot prove absence, only an id search can.\n store.phase = CrossSystemPhase.Done\n return\n }\n\n await searchById(id)\n }\n\n /**\n * Runs the fan-out, and answers whether it ran at all.\n *\n * A term that is neither an address nor an id has to clear the screen rather than be ignored.\n * The rows left standing are live: their buttons and all three bulk actions write to\n * `resolvedId`, which is still the previous person, while the box above them now holds a name\n * that was never searched for. The plan expects this operator -- the one who knows only a\n * surname -- so the answer has to be an empty result, not the last one.\n */\n const search = async (term: string): Promise<boolean> => {\n const trimmed = term.trim()\n if (trimmed.length === 0) return false\n store.searchTerm = trimmed\n if (isEmailTerm(trimmed)) {\n await searchByEmail(trimmed)\n return true\n }\n const id = Number(trimmed)\n if (!Number.isInteger(id) || id <= 0) {\n cancel()\n store.resetResults()\n store.termRejected = true\n return false\n }\n await searchById(id)\n return true\n }\n\n /** Re-reads one system after a write, so the row stops showing what it showed before it. */\n const refreshSystem = async (system: string) => {\n const descriptor = descriptors.find((item) => item.system === system)\n const id = store.resolvedId\n if (!descriptor || id === null) return\n await runProbe(descriptor, id, generation)\n }\n\n const resultFor = (system: string): UserSystemResult | undefined => store.results.get(system)\n\n /**\n * Whether creating an account may be offered when nobody was found.\n *\n * Only when every relevant probe answered an authoritative 404. A 401, a 403 or a timeout means\n * the record could not be read, which is not the same as not existing -- and a duplicate identity\n * cannot be taken back.\n */\n const unresolvedSystems = computed(() =>\n descriptors\n .filter((descriptor) => descriptor.isEnabled())\n .filter((descriptor) => {\n const result = store.results.get(descriptor.system)\n return result === undefined || !isAuthoritativelyAbsent(result.axes)\n })\n .map((descriptor) => descriptor.system)\n )\n\n return {\n search,\n searchById,\n searchByEmail,\n refreshSystem,\n resultFor,\n unresolvedSystems,\n cancel,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"userCrossSystemSearch.js","names":["EMAIL_PATTERN","isEmailTerm","term","useUserCrossSystemSearch","store","useUserCrossSystemStore","params","probes","descriptors","descriptor","useUserSystemProbe","generation","cancel","probe","runProbe","UserSystemLoad","id","token","searchById","CrossSystemPhase","lookupByEmail","useAnzuUserEmailLookupFilter","email","usePagination","SortOrder","useApiFetchList","execute","pagination","filterData","filterConfig","searchByEmail","found","ids","row","distinctIds","UserSystemPresence","UserSystemAccess","trimmed","item","system","computed","result","isAuthoritativelyAbsent"],"sources":["../../../../src/domains/anzuUser/composables/userCrossSystemSearch.ts"],"sourcesContent":["import { computed } from 'vue'\nimport { useApiFetchList } from '@/domains/api/composables/useApiFetchList'\nimport { usePagination } from '@/domains/api/composables/pagination'\nimport { SortOrder } from '@/domains/api/types/SortOrder'\nimport { useAnzuUserEmailLookupFilter } from '@/domains/anzuUser/filter/anzuUserFilter'\nimport {\n CrossSystemPhase,\n useUserCrossSystemStore,\n type UserSystemResult,\n} from '@/domains/anzuUser/store/userCrossSystemStore'\nimport type { AnyUserSystemDescriptor } from '@/domains/anzuUser/composables/userSystemDescriptor'\nimport { useUserSystemProbe, type UserSystemRefreshHook } from '@/domains/anzuUser/composables/userSystemProbe'\nimport {\n isAuthoritativelyAbsent,\n UserSystemAccess,\n UserSystemLoad,\n UserSystemPresence,\n} from '@/domains/anzuUser/utils/userSystemState'\nimport type { AnzuUser } from '@/shared/types/AnzuUser'\nimport type { IntegerId } from '@/shared/types/common'\n\nexport interface CrossSystemSearchParams {\n descriptors: AnyUserSystemDescriptor[]\n refreshHook?: UserSystemRefreshHook | undefined\n}\n\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+$/\n\nexport const isEmailTerm = (term: string): boolean => EMAIL_PATTERN.test(term.trim())\n\n/**\n * The cross-system fan-out.\n * No current-user endpoints are called, because row buttons depend on the\n * probe's answer, not `<Acl>`. Budget: nine calls by id, eighteen by e-mail.\n */\nexport const useUserCrossSystemSearch = (params: CrossSystemSearchParams) => {\n const store = useUserCrossSystemStore()\n const { descriptors, refreshHook } = params\n\n // One probe per system, built once. Each keeps its own abort token, and\n // rebuilding per search would lose the ability to invalidate in-flight requests.\n const probes = new Map(\n descriptors.map((descriptor) => [descriptor.system, useUserSystemProbe({ descriptor, refreshHook })])\n )\n\n /**\n * Each search gets a number. A late answer from an older search\n * is dropped instead of overwriting the current results.\n */\n let generation = 0\n\n const cancel = () => {\n generation++\n probes.forEach((probe) => probe.cancel())\n }\n\n const runProbe = async (descriptor: AnyUserSystemDescriptor, id: IntegerId, token: number) => {\n const probe = probes.get(descriptor.system)\n if (!probe) return\n store.patchAxes(descriptor.system, { ...probe.axes.value, load: UserSystemLoad.Loading })\n await probe.probe(id)\n if (token !== generation) return\n store.setResult(descriptor.system, { axes: probe.axes.value, user: probe.user.value })\n }\n\n /** Results are written as they arrive, never through `Promise.all`: one dead backend must not hold up the rest. */\n const searchById = async (id: IntegerId) => {\n const token = ++generation\n store.resetResults()\n store.resolvedId = id\n store.phase = CrossSystemPhase.VerifyingById\n await Promise.allSettled(descriptors.map((descriptor) => runProbe(descriptor, id, token)))\n if (token !== generation) return\n store.phase = CrossSystemPhase.Done\n }\n\n /** Exact match, `filter_eq[email]`, one row. `startsWith` would match a different person. */\n const lookupByEmail = async (descriptor: AnyUserSystemDescriptor, email: string): Promise<AnzuUser | null> => {\n if (!descriptor.isEnabled()) return null\n const { filterData, filterConfig } = useAnzuUserEmailLookupFilter()\n filterData.email = email\n // One row is enough: an exact match either exists or does not.\n const { pagination } = usePagination('id', SortOrder.Desc, { rowsPerPage: 1 })\n\n const { execute } = useApiFetchList<AnzuUser>({\n client: descriptor.client,\n system: descriptor.system,\n entity: descriptor.entity,\n urlTemplate: descriptor.endpoints.list,\n })\n\n try {\n const rows = await execute(pagination, filterData, filterConfig)\n return rows[0] ?? null\n } catch {\n // The second round asks every system by id anyway.\n // A failure here only means this round found no id. It is not a verdict about the system.\n return null\n }\n }\n\n /**\n * Two rounds. Between them a row is neither present nor absent.\n * Showing \"no account here\" in that window would invite Create for an account that exists under another address.\n */\n const searchByEmail = async (email: string) => {\n const token = ++generation\n store.resetResults()\n store.phase = CrossSystemPhase.MatchingEmail\n\n const found = await Promise.all(\n descriptors.map(async (descriptor) => ({\n system: descriptor.system,\n user: await lookupByEmail(descriptor, email),\n }))\n )\n if (token !== generation) return\n\n const ids = new Map<string, IntegerId>()\n for (const row of found) {\n if (row.user?.id) ids.set(row.system, row.user.id)\n }\n\n const distinctIds = new Set(ids.values())\n if (distinctIds.size > 1) {\n // The same address under two identities. Bulk actions stop here instead of guessing.\n store.identityConflict = ids\n store.phase = CrossSystemPhase.Done\n for (const row of found) {\n if (!row.user) continue\n store.setResult(row.system, {\n axes: {\n load: UserSystemLoad.Loaded,\n presence: UserSystemPresence.Present,\n access: UserSystemAccess.Ok,\n enabled: row.user.enabled,\n },\n user: row.user,\n })\n }\n return\n }\n\n const id = distinctIds.values().next().value\n if (id === undefined) {\n // Rows stay unknown, not absent. An address search cannot prove absence, only an id search can.\n store.phase = CrossSystemPhase.Done\n return\n }\n\n await searchById(id)\n }\n\n /**\n * Runs the fan-out and returns whether it ran.\n * A term that is neither an address nor an id clears the results.\n * Stale rows stay live: their buttons and bulk actions write to `resolvedId`, the previous person.\n */\n const search = async (term: string): Promise<boolean> => {\n const trimmed = term.trim()\n if (trimmed.length === 0) return false\n store.searchTerm = trimmed\n if (isEmailTerm(trimmed)) {\n await searchByEmail(trimmed)\n return true\n }\n const id = Number(trimmed)\n if (!Number.isInteger(id) || id <= 0) {\n cancel()\n store.resetResults()\n store.termRejected = true\n return false\n }\n await searchById(id)\n return true\n }\n\n /** Re-reads one system after a write so the row shows the new state. */\n const refreshSystem = async (system: string) => {\n const descriptor = descriptors.find((item) => item.system === system)\n const id = store.resolvedId\n if (!descriptor || id === null) return\n await runProbe(descriptor, id, generation)\n }\n\n const resultFor = (system: string): UserSystemResult | undefined => store.results.get(system)\n\n /**\n * Create is offered only when every relevant probe answered an authoritative 404.\n * A 401, 403 or timeout means the record could not be read, not that it is missing.\n * A duplicate identity cannot be undone.\n */\n const unresolvedSystems = computed(() =>\n descriptors\n .filter((descriptor) => descriptor.isEnabled())\n .filter((descriptor) => {\n const result = store.results.get(descriptor.system)\n return result === undefined || !isAuthoritativelyAbsent(result.axes)\n })\n .map((descriptor) => descriptor.system)\n )\n\n return {\n search,\n searchById,\n searchByEmail,\n refreshSystem,\n resultFor,\n unresolvedSystems,\n cancel,\n }\n}\n"],"mappings":"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"}
|
|
@@ -5,24 +5,18 @@ import { AnzuUser, BaseUser } from '../../../shared/types/AnzuUser';
|
|
|
5
5
|
import { IntegerId } from '../../../shared/types/common';
|
|
6
6
|
export interface WriteResult {
|
|
7
7
|
outcome: BulkOutcomeType;
|
|
8
|
-
/**
|
|
8
|
+
/** The server's record after the write, when it returned one. */
|
|
9
9
|
user?: AnzuUser;
|
|
10
10
|
/**
|
|
11
|
-
* Fields whose stored value
|
|
12
|
-
*
|
|
13
|
-
* The write still goes through -- decision 24 says the operator's value wins -- but somebody
|
|
14
|
-
* edited the record in between, and the log line says so rather than letting it pass unnoticed.
|
|
11
|
+
* Fields whose stored value differed from both the target and what the search saw.
|
|
12
|
+
* The write still goes through (decision 24: the operator's value wins). The log reports the concurrent edit.
|
|
15
13
|
*/
|
|
16
14
|
concurrentFields?: UserMetadataField[];
|
|
17
15
|
detail?: string;
|
|
18
16
|
}
|
|
19
17
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* 422 and 400 are their own line and not a generic failure: a PUT validates the whole body, and an
|
|
23
|
-
* account carrying a colour or an e-mail that no longer passes validation will fail even on a plain
|
|
24
|
-
* "disable". With legacy data that is an ordinary outcome, and "could not be saved" would send
|
|
25
|
-
* somebody looking for a bug that is not there.
|
|
18
|
+
* 422 and 400 get their own outcome. A PUT validates the whole body.
|
|
19
|
+
* Legacy data that no longer validates fails even a plain disable. That is not a bug.
|
|
26
20
|
*/
|
|
27
21
|
export declare const classifyWriteStatus: (status: number | null) => BulkOutcomeType;
|
|
28
22
|
export declare const useUserCrossSystemWrites: () => {
|