@ngbplatform/ui 1.3.0

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.
Files changed (217) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +44 -0
  3. package/package.json +61 -0
  4. package/public/favicon.svg +6 -0
  5. package/public/silent-check-sso.html +8 -0
  6. package/src/assets/ngb_logo.svg +17 -0
  7. package/src/assets/ngb_logo_color.svg +17 -0
  8. package/src/index.ts +1023 -0
  9. package/src/ngb/README.md +27 -0
  10. package/src/ngb/accounting/NgbAccountingPeriodClosingPage.vue +1157 -0
  11. package/src/ngb/accounting/NgbChartOfAccountEditor.vue +590 -0
  12. package/src/ngb/accounting/NgbChartOfAccountsPage.vue +420 -0
  13. package/src/ngb/accounting/NgbGeneralJournalEntryEditPage.vue +796 -0
  14. package/src/ngb/accounting/NgbGeneralJournalEntryLinesEditor.vue +454 -0
  15. package/src/ngb/accounting/NgbGeneralJournalEntryListPage.vue +186 -0
  16. package/src/ngb/accounting/api.ts +79 -0
  17. package/src/ngb/accounting/generalJournalEntry.ts +127 -0
  18. package/src/ngb/accounting/generalJournalEntryApi.ts +112 -0
  19. package/src/ngb/accounting/generalJournalEntryTypes.ts +155 -0
  20. package/src/ngb/accounting/navigation.ts +83 -0
  21. package/src/ngb/accounting/periodClosing.ts +75 -0
  22. package/src/ngb/accounting/periodClosingApi.ts +60 -0
  23. package/src/ngb/accounting/periodClosingTypes.ts +73 -0
  24. package/src/ngb/accounting/types.ts +57 -0
  25. package/src/ngb/api/audit.ts +23 -0
  26. package/src/ngb/api/catalogs.ts +50 -0
  27. package/src/ngb/api/contracts.ts +285 -0
  28. package/src/ngb/api/documents.ts +170 -0
  29. package/src/ngb/api/http.ts +446 -0
  30. package/src/ngb/api/lookups.ts +14 -0
  31. package/src/ngb/api/types.ts +6 -0
  32. package/src/ngb/auth/index.ts +13 -0
  33. package/src/ngb/auth/keycloak.ts +374 -0
  34. package/src/ngb/auth/router.ts +35 -0
  35. package/src/ngb/auth/types.ts +12 -0
  36. package/src/ngb/auth/useAuthStore.ts +209 -0
  37. package/src/ngb/command-palette/NgbCommandPaletteDialog.vue +342 -0
  38. package/src/ngb/command-palette/NgbCommandPaletteEmptyState.vue +55 -0
  39. package/src/ngb/command-palette/NgbCommandPaletteFooterHints.vue +29 -0
  40. package/src/ngb/command-palette/api.ts +10 -0
  41. package/src/ngb/command-palette/config.ts +16 -0
  42. package/src/ngb/command-palette/presentation.ts +85 -0
  43. package/src/ngb/command-palette/search.ts +130 -0
  44. package/src/ngb/command-palette/staticItems.ts +243 -0
  45. package/src/ngb/command-palette/storage.ts +45 -0
  46. package/src/ngb/command-palette/store.ts +716 -0
  47. package/src/ngb/command-palette/types.ts +120 -0
  48. package/src/ngb/command-palette/useCommandPaletteHotkeys.ts +27 -0
  49. package/src/ngb/command-palette/useCommandPalettePageContext.ts +18 -0
  50. package/src/ngb/components/NgbConfirmDialog.vue +63 -0
  51. package/src/ngb/components/NgbDialog.vue +44 -0
  52. package/src/ngb/components/NgbDrawer.vue +156 -0
  53. package/src/ngb/components/NgbHeaderActionCluster.vue +140 -0
  54. package/src/ngb/components/NgbModalShell.vue +99 -0
  55. package/src/ngb/components/NgbToolbar.vue +14 -0
  56. package/src/ngb/components/forms/NgbFormLayout.vue +13 -0
  57. package/src/ngb/components/forms/NgbFormRow.vue +21 -0
  58. package/src/ngb/components/forms/NgbFormSection.vue +16 -0
  59. package/src/ngb/components/forms/NgbValidationSummary.vue +18 -0
  60. package/src/ngb/components/navigation/NgbNavigationTree.vue +68 -0
  61. package/src/ngb/components/navigation/NgbTreeNode.vue +94 -0
  62. package/src/ngb/components/register/NgbColumnChooser.vue +101 -0
  63. package/src/ngb/components/register/NgbRegisterGrid.vue +473 -0
  64. package/src/ngb/components/register/registerTypes.ts +51 -0
  65. package/src/ngb/components/register/useRegisterColumnResize.ts +99 -0
  66. package/src/ngb/components/register/useRegisterColumnState.ts +220 -0
  67. package/src/ngb/components/register/useRegisterRows.ts +209 -0
  68. package/src/ngb/components/register/useRegisterViewport.ts +56 -0
  69. package/src/ngb/editor/NgbDocumentEffectsPage.vue +512 -0
  70. package/src/ngb/editor/NgbDocumentFlowPage.vue +409 -0
  71. package/src/ngb/editor/NgbDocumentPrintPage.vue +712 -0
  72. package/src/ngb/editor/NgbEditorDiscardDialog.vue +40 -0
  73. package/src/ngb/editor/NgbEntityAuditSidebar.vue +288 -0
  74. package/src/ngb/editor/NgbEntityEditor.vue +250 -0
  75. package/src/ngb/editor/NgbEntityEditorDrawerActions.vue +88 -0
  76. package/src/ngb/editor/NgbEntityEditorHeader.vue +114 -0
  77. package/src/ngb/editor/catalogNavigation.ts +13 -0
  78. package/src/ngb/editor/config.ts +252 -0
  79. package/src/ngb/editor/documentCopyDraft.ts +245 -0
  80. package/src/ngb/editor/documentEffects.ts +43 -0
  81. package/src/ngb/editor/documentEffectsDateFormatting.ts +18 -0
  82. package/src/ngb/editor/documentNavigation.ts +115 -0
  83. package/src/ngb/editor/documentStatus.ts +45 -0
  84. package/src/ngb/editor/entityEditorErrors.ts +162 -0
  85. package/src/ngb/editor/entityEditorPersistence.ts +241 -0
  86. package/src/ngb/editor/extensions.ts +40 -0
  87. package/src/ngb/editor/types.ts +295 -0
  88. package/src/ngb/editor/useConfiguredEntityEditorDocumentActions.ts +183 -0
  89. package/src/ngb/editor/useDocumentEditorDrawerState.ts +152 -0
  90. package/src/ngb/editor/useEditorDrawerState.ts +88 -0
  91. package/src/ngb/editor/useEntityEditorBusinessContext.ts +97 -0
  92. package/src/ngb/editor/useEntityEditorCapabilities.ts +190 -0
  93. package/src/ngb/editor/useEntityEditorCommandPalette.ts +154 -0
  94. package/src/ngb/editor/useEntityEditorCommitHandlers.ts +102 -0
  95. package/src/ngb/editor/useEntityEditorHeaderActions.ts +253 -0
  96. package/src/ngb/editor/useEntityEditorLeaveGuard.ts +66 -0
  97. package/src/ngb/editor/useEntityEditorNavigationActions.ts +235 -0
  98. package/src/ngb/editor/useEntityEditorOutputs.ts +59 -0
  99. package/src/ngb/editor/useEntityEditorPageActions.ts +57 -0
  100. package/src/ngb/editor/useRouteQueryEditorDrawer.ts +173 -0
  101. package/src/ngb/env/runtimeConfig.ts +25 -0
  102. package/src/ngb/lookup/config.ts +42 -0
  103. package/src/ngb/lookup/defaultConfig.ts +136 -0
  104. package/src/ngb/lookup/navigation.ts +76 -0
  105. package/src/ngb/lookup/prefetch.ts +40 -0
  106. package/src/ngb/lookup/store.ts +261 -0
  107. package/src/ngb/metadata/NgbDocumentListFiltersDrawer.vue +78 -0
  108. package/src/ngb/metadata/NgbDocumentPeriodFilter.vue +53 -0
  109. package/src/ngb/metadata/NgbEntityForm.vue +84 -0
  110. package/src/ngb/metadata/NgbEntityFormFieldsBlock.vue +110 -0
  111. package/src/ngb/metadata/NgbEntityListPageHeader.vue +80 -0
  112. package/src/ngb/metadata/NgbFilterFieldControl.vue +104 -0
  113. package/src/ngb/metadata/NgbMetadataCatalogEditPage.vue +42 -0
  114. package/src/ngb/metadata/NgbMetadataCatalogListPage.vue +269 -0
  115. package/src/ngb/metadata/NgbMetadataDocumentEditPage.vue +68 -0
  116. package/src/ngb/metadata/NgbMetadataDocumentListPage.vue +353 -0
  117. package/src/ngb/metadata/NgbMetadataFieldRenderer.vue +124 -0
  118. package/src/ngb/metadata/NgbMetadataLookupControl.vue +92 -0
  119. package/src/ngb/metadata/NgbRecycleBinFilter.vue +53 -0
  120. package/src/ngb/metadata/NgbRegisterPageLayout.vue +143 -0
  121. package/src/ngb/metadata/config.ts +28 -0
  122. package/src/ngb/metadata/dataTypes.ts +27 -0
  123. package/src/ngb/metadata/entityForm.ts +114 -0
  124. package/src/ngb/metadata/entityModel.ts +34 -0
  125. package/src/ngb/metadata/entityValueFormatting.ts +83 -0
  126. package/src/ngb/metadata/fieldRendererState.ts +84 -0
  127. package/src/ngb/metadata/filtering.ts +153 -0
  128. package/src/ngb/metadata/lookup.ts +25 -0
  129. package/src/ngb/metadata/monthPagedListQuery.ts +108 -0
  130. package/src/ngb/metadata/normalization.ts +100 -0
  131. package/src/ngb/metadata/referenceHydration.ts +99 -0
  132. package/src/ngb/metadata/register.ts +135 -0
  133. package/src/ngb/metadata/routePages.ts +86 -0
  134. package/src/ngb/metadata/store.ts +35 -0
  135. package/src/ngb/metadata/types.ts +276 -0
  136. package/src/ngb/metadata/useMetadataListFilters.ts +306 -0
  137. package/src/ngb/metadata/useMetadataRegisterPageData.ts +246 -0
  138. package/src/ngb/metadata/useValidationFocus.ts +49 -0
  139. package/src/ngb/primitives/NgbBadge.vue +31 -0
  140. package/src/ngb/primitives/NgbButton.vue +53 -0
  141. package/src/ngb/primitives/NgbCheckbox.vue +33 -0
  142. package/src/ngb/primitives/NgbDatePicker.vue +141 -0
  143. package/src/ngb/primitives/NgbIcon.vue +545 -0
  144. package/src/ngb/primitives/NgbInput.vue +57 -0
  145. package/src/ngb/primitives/NgbLookup.vue +264 -0
  146. package/src/ngb/primitives/NgbMonthPicker.vue +132 -0
  147. package/src/ngb/primitives/NgbMultiSelect.vue +179 -0
  148. package/src/ngb/primitives/NgbPeriodPicker.vue +125 -0
  149. package/src/ngb/primitives/NgbPickerNavButton.vue +31 -0
  150. package/src/ngb/primitives/NgbPickerPopover.vue +79 -0
  151. package/src/ngb/primitives/NgbRadioGroup.vue +53 -0
  152. package/src/ngb/primitives/NgbSelect.vue +108 -0
  153. package/src/ngb/primitives/NgbStatusIcon.vue +63 -0
  154. package/src/ngb/primitives/NgbSwitch.vue +42 -0
  155. package/src/ngb/primitives/NgbTabs.vue +116 -0
  156. package/src/ngb/primitives/NgbToastHost.vue +49 -0
  157. package/src/ngb/primitives/NgbTooltip.vue +27 -0
  158. package/src/ngb/primitives/iconNames.ts +83 -0
  159. package/src/ngb/primitives/toast.ts +66 -0
  160. package/src/ngb/primitives/useAsyncComboboxQuery.ts +85 -0
  161. package/src/ngb/primitives/useFloatingDropdownPosition.ts +129 -0
  162. package/src/ngb/reporting/NgbReportComposerCollectionSection.vue +106 -0
  163. package/src/ngb/reporting/NgbReportComposerPanel.vue +1187 -0
  164. package/src/ngb/reporting/NgbReportDateRangeFilter.vue +54 -0
  165. package/src/ngb/reporting/NgbReportPage.vue +1124 -0
  166. package/src/ngb/reporting/NgbReportSheet.vue +467 -0
  167. package/src/ngb/reporting/api.ts +35 -0
  168. package/src/ngb/reporting/composer.ts +904 -0
  169. package/src/ngb/reporting/config.ts +120 -0
  170. package/src/ngb/reporting/defaultConfig.ts +15 -0
  171. package/src/ngb/reporting/lookupFilters.ts +43 -0
  172. package/src/ngb/reporting/navigation.ts +181 -0
  173. package/src/ngb/reporting/pageHelpers.ts +73 -0
  174. package/src/ngb/reporting/pageSession.ts +92 -0
  175. package/src/ngb/reporting/paging.ts +66 -0
  176. package/src/ngb/reporting/types.ts +333 -0
  177. package/src/ngb/router/backNavigation.ts +122 -0
  178. package/src/ngb/router/queryParams.ts +129 -0
  179. package/src/ngb/router/queryState.ts +121 -0
  180. package/src/ngb/router/routeAliases.ts +66 -0
  181. package/src/ngb/router/routeParams.ts +15 -0
  182. package/src/ngb/router/shareLink.ts +39 -0
  183. package/src/ngb/security/NgbAccessAuditPanel.vue +32 -0
  184. package/src/ngb/security/NgbAccessDeniedState.vue +27 -0
  185. package/src/ngb/security/NgbEffectiveAccessPanel.vue +60 -0
  186. package/src/ngb/security/NgbPermissionMatrix.vue +160 -0
  187. package/src/ngb/security/NgbRoleEditorPage.vue +319 -0
  188. package/src/ngb/security/NgbRolesPage.vue +125 -0
  189. package/src/ngb/security/NgbUserEditorPage.vue +615 -0
  190. package/src/ngb/security/NgbUsersPage.vue +125 -0
  191. package/src/ngb/security/api.ts +91 -0
  192. package/src/ngb/security/audit.ts +21 -0
  193. package/src/ngb/security/permissions.ts +65 -0
  194. package/src/ngb/security/types.ts +157 -0
  195. package/src/ngb/security/useAccessStore.ts +69 -0
  196. package/src/ngb/site/NgbDashboardAsOfToolbar.vue +100 -0
  197. package/src/ngb/site/NgbDashboardStatusBanner.vue +91 -0
  198. package/src/ngb/site/NgbLogo.vue +44 -0
  199. package/src/ngb/site/NgbPageHeader.vue +49 -0
  200. package/src/ngb/site/NgbSiteShell.vue +286 -0
  201. package/src/ngb/site/NgbSiteSidebar.vue +270 -0
  202. package/src/ngb/site/NgbTopBar.vue +425 -0
  203. package/src/ngb/site/NgbTrendChart.vue +224 -0
  204. package/src/ngb/site/dashboardData.ts +324 -0
  205. package/src/ngb/site/mainMenuStore.ts +49 -0
  206. package/src/ngb/site/types.ts +31 -0
  207. package/src/ngb/site/useDashboardPageState.ts +98 -0
  208. package/src/ngb/site/useTheme.ts +95 -0
  209. package/src/ngb/utils/clone.ts +43 -0
  210. package/src/ngb/utils/dateValues.ts +107 -0
  211. package/src/ngb/utils/errorMessage.ts +14 -0
  212. package/src/ngb/utils/guid.ts +21 -0
  213. package/src/ngb/utils/stableValue.ts +21 -0
  214. package/src/ngb/utils/storage.ts +135 -0
  215. package/src/styles/tailwind.css +165 -0
  216. package/src/vite/publicAssets.ts +104 -0
  217. package/vite-public-assets.js +68 -0
@@ -0,0 +1,420 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref, watch } from 'vue'
3
+ import { useRoute, useRouter } from 'vue-router'
4
+
5
+ import NgbRegisterGrid from '../components/register/NgbRegisterGrid.vue'
6
+ import NgbEditorDiscardDialog from '../editor/NgbEditorDiscardDialog.vue'
7
+ import { useEntityEditorCommitHandlers } from '../editor/useEntityEditorCommitHandlers'
8
+ import NgbEntityEditorDrawerActions from '../editor/NgbEntityEditorDrawerActions.vue'
9
+ import { useEditorDrawerState } from '../editor/useEditorDrawerState'
10
+ import { useRouteQueryEditorDrawer } from '../editor/useRouteQueryEditorDrawer'
11
+ import NgbRegisterPageLayout from '../metadata/NgbRegisterPageLayout.vue'
12
+ import NgbRecycleBinFilter from '../metadata/NgbRecycleBinFilter.vue'
13
+ import NgbIcon from '../primitives/NgbIcon.vue'
14
+ import { navigateBack } from '../router/backNavigation'
15
+ import {
16
+ normalizeSingleQueryValue,
17
+ normalizeTrashMode,
18
+ pushCleanRouteQuery,
19
+ replaceCleanRouteQuery,
20
+ type QueryTrashMode,
21
+ } from '../router/queryParams'
22
+ import { toErrorMessage } from '../utils/errorMessage'
23
+ import { getChartOfAccountsMetadata, getChartOfAccountsPage } from './api'
24
+ import NgbChartOfAccountEditor from './NgbChartOfAccountEditor.vue'
25
+ import type {
26
+ ChartOfAccountsAccountDto,
27
+ ChartOfAccountsMetadataDto,
28
+ ChartOfAccountsPageDto,
29
+ ChartOfAccountEditorShellState,
30
+ } from './types'
31
+
32
+ type ChartOfAccountEditorHandle = {
33
+ save: () => Promise<void>
34
+ copyShareLink: () => Promise<boolean>
35
+ openAuditLog: () => void
36
+ closeAuditLog: () => void
37
+ toggleMarkForDeletion: () => void
38
+ }
39
+
40
+ const DEFAULT_EDITOR_SHELL: ChartOfAccountEditorShellState = {
41
+ hideHeader: false,
42
+ flushBody: false,
43
+ }
44
+
45
+ const props = withDefaults(defineProps<{
46
+ title?: string
47
+ backTarget?: string | null
48
+ storageKey?: string | null
49
+ routeBasePath?: string | null
50
+ }>(), {
51
+ title: 'Chart of Accounts',
52
+ backTarget: '/',
53
+ storageKey: null,
54
+ routeBasePath: null,
55
+ })
56
+
57
+ const route = useRoute()
58
+ const router = useRouter()
59
+
60
+ watch(
61
+ () => [route.query.id, route.query.accountId, route.query.panel],
62
+ ([idValue, legacyAccountId, panelValue]) => {
63
+ const legacyId = normalizeSingleQueryValue(legacyAccountId)
64
+ if (!legacyId) return
65
+
66
+ const id = normalizeSingleQueryValue(idValue)
67
+ if (id) {
68
+ void replaceCleanRouteQuery(route, router, { accountId: undefined })
69
+ return
70
+ }
71
+
72
+ const panel = normalizeSingleQueryValue(panelValue)
73
+ void replaceCleanRouteQuery(route, router, {
74
+ id: legacyId,
75
+ accountId: undefined,
76
+ panel: panel || 'edit',
77
+ })
78
+ },
79
+ { immediate: true },
80
+ )
81
+
82
+ const resolvedBackTarget = computed(() => String(props.backTarget ?? '').trim() || '/')
83
+ const resolvedRouteBasePath = computed(() => String(props.routeBasePath ?? '').trim() || route.path)
84
+ const resolvedStorageKey = computed(() => String(props.storageKey ?? '').trim() || `ngb:accounting:chart-of-accounts:${resolvedRouteBasePath.value}`)
85
+ const canBack = computed(() => route.path !== resolvedBackTarget.value)
86
+ const offset = computed(() => Number(route.query.offset ?? 0) || 0)
87
+ const limit = computed(() => Number(route.query.limit ?? 50) || 50)
88
+
89
+ const trashMode = computed<QueryTrashMode>({
90
+ get: () => normalizeTrashMode(route.query.trash),
91
+ set: (value) => {
92
+ void replaceCleanRouteQuery(route, router, {
93
+ trash: value,
94
+ offset: 0,
95
+ })
96
+ },
97
+ })
98
+
99
+ const loading = ref(false)
100
+ const error = ref<string | null>(null)
101
+ const page = ref<ChartOfAccountsPageDto | null>(null)
102
+ const metadata = ref<ChartOfAccountsMetadataDto | null>(null)
103
+ let loadSequence = 0
104
+
105
+ const columns = computed(() => [
106
+ { key: 'code', title: 'Code', width: 120, align: 'left' as const, sortable: true },
107
+ { key: 'name', title: 'Name', align: 'left' as const, sortable: true },
108
+ { key: 'accountType', title: 'Type', width: 140, align: 'left' as const, sortable: true },
109
+ { key: 'cashFlowRole', title: 'Cash Flow', width: 180, align: 'left' as const, sortable: true },
110
+ {
111
+ key: 'isActive',
112
+ title: 'Active',
113
+ width: 90,
114
+ align: 'center' as const,
115
+ sortable: true,
116
+ format: (value: unknown) => (value ? 'Yes' : 'No'),
117
+ },
118
+ ])
119
+
120
+ const cashFlowRoleLabelByValue = computed(() => {
121
+ const entries = (metadata.value?.cashFlowRoleOptions ?? []).map((option) => [option.value, option.label] as const)
122
+ return new Map(entries)
123
+ })
124
+
125
+ const rows = computed(() => {
126
+ const items = page.value?.items ?? []
127
+ return items.map((account: ChartOfAccountsAccountDto) => ({
128
+ key: account.accountId,
129
+ __status: (account.isDeleted || account.isMarkedForDeletion) ? 'marked' : (account.isActive ? 'active' : 'saved'),
130
+ isDeleted: account.isDeleted,
131
+ isMarkedForDeletion: account.isMarkedForDeletion,
132
+ code: account.code,
133
+ name: account.name,
134
+ accountType: account.accountType,
135
+ cashFlowRole: cashFlowRoleLabelByValue.value.get(account.cashFlowRole ?? '') ?? '',
136
+ isActive: account.isActive,
137
+ }))
138
+ })
139
+
140
+ const coaGridKey = computed(() => [
141
+ trashMode.value,
142
+ String(offset.value),
143
+ String(limit.value),
144
+ String(page.value?.items?.length ?? 0),
145
+ ].join('|'))
146
+
147
+ async function ensureMetadataLoaded(): Promise<void> {
148
+ if (metadata.value) return
149
+ metadata.value = await getChartOfAccountsMetadata()
150
+ }
151
+
152
+ async function load(): Promise<boolean> {
153
+ const seq = ++loadSequence
154
+ loading.value = true
155
+ error.value = null
156
+
157
+ try {
158
+ await ensureMetadataLoaded()
159
+
160
+ const mode = trashMode.value
161
+ const includeDeleted = mode !== 'active'
162
+ const onlyDeleted = mode === 'deleted' ? true : null
163
+
164
+ const nextPage = await getChartOfAccountsPage({
165
+ offset: offset.value,
166
+ limit: limit.value,
167
+ search: null,
168
+ onlyActive: null,
169
+ includeDeleted,
170
+ onlyDeleted,
171
+ })
172
+ if (seq !== loadSequence) return false
173
+
174
+ page.value = nextPage
175
+
176
+ return true
177
+ } catch (cause) {
178
+ if (seq !== loadSequence) return false
179
+ error.value = toErrorMessage(cause, 'Failed to load the chart of accounts.')
180
+ return false
181
+ } finally {
182
+ if (seq === loadSequence) loading.value = false
183
+ }
184
+ }
185
+
186
+ watch(
187
+ () => [route.query.offset, route.query.limit, route.query.trash],
188
+ () => {
189
+ void load()
190
+ },
191
+ { immediate: true },
192
+ )
193
+
194
+ function nextPage() {
195
+ void pushCleanRouteQuery(route, router, { offset: offset.value + limit.value })
196
+ }
197
+
198
+ function prevPage() {
199
+ void pushCleanRouteQuery(route, router, { offset: Math.max(0, offset.value - limit.value) })
200
+ }
201
+
202
+ const editorRef = ref<ChartOfAccountEditorHandle | null>(null)
203
+ const editorShell = ref<ChartOfAccountEditorShellState>({ ...DEFAULT_EDITOR_SHELL })
204
+ const {
205
+ drawerTitle,
206
+ drawerSubtitle,
207
+ editorFlags,
208
+ discardOpen,
209
+ handleEditorFlags,
210
+ handleEditorState,
211
+ resetDrawerHeading,
212
+ requestDiscard,
213
+ discardConfirm,
214
+ discardCancel,
215
+ beforeCloseDrawer,
216
+ } = useEditorDrawerState()
217
+
218
+ function resetEditorShell() {
219
+ editorShell.value = { ...DEFAULT_EDITOR_SHELL }
220
+ }
221
+
222
+ function handleEditorShell(next: ChartOfAccountEditorShellState) {
223
+ editorShell.value = { ...next }
224
+ }
225
+
226
+ async function beforeRouteDrawerClose(): Promise<boolean> {
227
+ if (editorShell.value.hideHeader) {
228
+ editorRef.value?.closeAuditLog()
229
+ return false
230
+ }
231
+
232
+ if (!editorFlags.value.isDirty) return true
233
+ return await requestDiscard()
234
+ }
235
+
236
+ const {
237
+ panelMode,
238
+ currentId,
239
+ isPanelOpen,
240
+ openCreateDrawer: openRouteCreateDrawer,
241
+ openEditDrawer: openRouteEditDrawer,
242
+ closeDrawer: closeRouteDrawer,
243
+ } = useRouteQueryEditorDrawer({
244
+ route,
245
+ router,
246
+ idImpliesEdit: true,
247
+ clearKeys: ['accountId'],
248
+ onBeforeOpen: async (_next, current) => {
249
+ if (editorShell.value.hideHeader) editorRef.value?.closeAuditLog()
250
+ if (current.mode === null || !editorFlags.value.isDirty) return true
251
+ return await requestDiscard()
252
+ },
253
+ onBeforeClose: async () => await beforeRouteDrawerClose(),
254
+ })
255
+
256
+ async function openCreateDrawer() {
257
+ await openRouteCreateDrawer({
258
+ onCommit: () => {
259
+ resetDrawerHeading()
260
+ resetEditorShell()
261
+ },
262
+ })
263
+ }
264
+
265
+ async function openEditDrawer(id: string) {
266
+ await openRouteEditDrawer(id, {
267
+ onCommit: () => {
268
+ resetDrawerHeading()
269
+ resetEditorShell()
270
+ },
271
+ })
272
+ }
273
+
274
+ function closeDrawer() {
275
+ void closeRouteDrawer({
276
+ onCommit: () => {
277
+ resetEditorShell()
278
+ },
279
+ })
280
+ }
281
+
282
+ const {
283
+ handleCreated,
284
+ handleSaved,
285
+ handleChanged,
286
+ } = useEntityEditorCommitHandlers({
287
+ reload: load,
288
+ closeDrawer,
289
+ closeOnCreated: ({ reloadSucceeded }) => reloadSucceeded,
290
+ onCreated: async ({ id, reloadSucceeded }) => {
291
+ if (reloadSucceeded) return
292
+
293
+ resetEditorShell()
294
+ resetDrawerHeading()
295
+ void replaceCleanRouteQuery(route, router, {
296
+ panel: 'edit',
297
+ id,
298
+ accountId: undefined,
299
+ })
300
+ },
301
+ })
302
+
303
+ async function beforeCloseChartOfAccountsDrawer(): Promise<boolean> {
304
+ if (editorShell.value.hideHeader) return await beforeRouteDrawerClose()
305
+ return await beforeCloseDrawer()
306
+ }
307
+
308
+ function handleDrawerAction(action: string) {
309
+ switch (action) {
310
+ case 'share':
311
+ void editorRef.value?.copyShareLink()
312
+ return
313
+ case 'audit':
314
+ editorRef.value?.openAuditLog()
315
+ return
316
+ case 'mark':
317
+ editorRef.value?.toggleMarkForDeletion()
318
+ return
319
+ case 'save':
320
+ void editorRef.value?.save()
321
+ }
322
+ }
323
+ </script>
324
+
325
+ <template>
326
+ <NgbRegisterPageLayout
327
+ :title="title"
328
+ :can-back="canBack"
329
+ :items-count="page ? page.items.length : null"
330
+ :total="page?.total ?? null"
331
+ :loading="loading"
332
+ :error="error"
333
+ :show-filter="false"
334
+ :disable-prev="offset === 0"
335
+ :disable-next="(page?.items?.length ?? 0) < limit"
336
+ :disable-create="loading"
337
+ :columns="columns"
338
+ :rows="rows"
339
+ :storage-key="resolvedStorageKey"
340
+ :drawer-open="isPanelOpen"
341
+ :drawer-title="drawerTitle || (panelMode === 'new' ? 'New account' : 'Account')"
342
+ :drawer-subtitle="drawerSubtitle"
343
+ :drawer-hide-header="editorShell.hideHeader"
344
+ :drawer-flush-body="editorShell.flushBody"
345
+ :before-close="beforeCloseChartOfAccountsDrawer"
346
+ @back="navigateBack(router, route, resolvedBackTarget)"
347
+ @refresh="load"
348
+ @create="openCreateDrawer"
349
+ @prev="prevPage"
350
+ @next="nextPage"
351
+ @rowActivate="openEditDrawer"
352
+ @update:drawerOpen="(value) => (!value ? closeDrawer() : null)"
353
+ >
354
+ <template #filters>
355
+ <NgbRecycleBinFilter v-model="trashMode" :disabled="loading" />
356
+ </template>
357
+
358
+ <template #grid>
359
+ <NgbRegisterGrid
360
+ class="flex-1 min-h-0"
361
+ :key="coaGridKey"
362
+ fill-height
363
+ :show-panel="false"
364
+ :columns="columns"
365
+ :rows="rows"
366
+ :group-by="['accountType']"
367
+ :default-expanded="true"
368
+ :storage-key="resolvedStorageKey"
369
+ :show-status-column="true"
370
+ :show-group-counts="true"
371
+ :show-group-toggle-icons="true"
372
+ :show-totals="false"
373
+ activate-on-row-click
374
+ @rowActivate="(id) => openEditDrawer(String(id))"
375
+ >
376
+ <template #statusHeader="{ hasGroups, allGroupsExpanded, toggleAllGroups }">
377
+ <button
378
+ v-if="hasGroups"
379
+ class="flex items-center justify-center rounded-[var(--ngb-radius)] border-0 bg-transparent p-0 text-ngb-muted hover:text-ngb-text ngb-focus"
380
+ :title="allGroupsExpanded ? 'Collapse all' : 'Expand all'"
381
+ @click.stop="toggleAllGroups()"
382
+ >
383
+ <NgbIcon :name="allGroupsExpanded ? 'minus' : 'plus'" :size="14" />
384
+ </button>
385
+ </template>
386
+ </NgbRegisterGrid>
387
+ </template>
388
+
389
+ <template #drawerActions>
390
+ <NgbEntityEditorDrawerActions
391
+ :flags="editorFlags"
392
+ restore-title="Restore"
393
+ @action="handleDrawerAction"
394
+ />
395
+ </template>
396
+
397
+ <template #drawerContent>
398
+ <NgbChartOfAccountEditor
399
+ ref="editorRef"
400
+ v-if="isPanelOpen"
401
+ :id="currentId"
402
+ :metadata="metadata"
403
+ :route-base-path="resolvedRouteBasePath"
404
+ @state="handleEditorState"
405
+ @flags="handleEditorFlags"
406
+ @shell="handleEditorShell"
407
+ @created="handleCreated"
408
+ @saved="handleSaved"
409
+ @changed="handleChanged"
410
+ @close="closeDrawer"
411
+ />
412
+ </template>
413
+ </NgbRegisterPageLayout>
414
+
415
+ <NgbEditorDiscardDialog
416
+ :open="discardOpen"
417
+ @cancel="discardCancel"
418
+ @confirm="discardConfirm"
419
+ />
420
+ </template>