@sdcorejs/angular 20.1.5 → 20.2.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 (208) hide show
  1. package/README.md +12 -4
  2. package/assets/scss/core/menu.scss +18 -0
  3. package/assets/scss/core/utilities/_misc.scss +15 -0
  4. package/assets/scss/sd-core.scss +1 -0
  5. package/components/anchor/index.d.ts +3 -1
  6. package/components/badge/index.d.ts +1 -0
  7. package/components/ckeditor-styles/index.d.ts +1 -1
  8. package/components/form-generic/index.d.ts +44 -33
  9. package/components/import-excel/index.d.ts +1 -0
  10. package/components/index.d.ts +6 -1
  11. package/components/mini-editor/index.d.ts +1 -1
  12. package/components/modal/index.d.ts +3 -2
  13. package/components/modal-resizable/index.d.ts +92 -0
  14. package/components/org-chart/index.d.ts +6 -0
  15. package/components/preview/index.d.ts +1 -0
  16. package/components/query-bar/index.d.ts +55 -17
  17. package/components/query-builder/index.d.ts +150 -98
  18. package/components/section/index.d.ts +3 -0
  19. package/components/tab-router/index.d.ts +19 -19
  20. package/components/table/index.d.ts +252 -110
  21. package/components/tree/index.d.ts +48 -30
  22. package/components/upload-file/index.d.ts +6 -3
  23. package/configurations/index.d.ts +1 -2
  24. package/fesm2022/sdcorejs-angular-components-anchor.mjs +37 -13
  25. package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
  26. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +2 -2
  27. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
  28. package/fesm2022/sdcorejs-angular-components-badge.mjs +15 -2
  29. package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
  30. package/fesm2022/sdcorejs-angular-components-button.mjs +2 -2
  31. package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
  32. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs +1 -1
  33. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -1
  34. package/fesm2022/sdcorejs-angular-components-code-editor.mjs +3 -3
  35. package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -1
  36. package/fesm2022/sdcorejs-angular-components-data-state.mjs +3 -3
  37. package/fesm2022/sdcorejs-angular-components-data-state.mjs.map +1 -1
  38. package/fesm2022/sdcorejs-angular-components-editor.mjs +2 -2
  39. package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
  40. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +324 -192
  41. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  42. package/fesm2022/sdcorejs-angular-components-history.mjs +4 -4
  43. package/fesm2022/sdcorejs-angular-components-history.mjs.map +1 -1
  44. package/fesm2022/sdcorejs-angular-components-import-excel.mjs +13 -5
  45. package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
  46. package/fesm2022/sdcorejs-angular-components-inform.mjs +3 -3
  47. package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
  48. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +164 -8
  49. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
  50. package/fesm2022/sdcorejs-angular-components-modal.mjs +30 -18
  51. package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
  52. package/fesm2022/sdcorejs-angular-components-org-chart.mjs +60 -13
  53. package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
  54. package/fesm2022/sdcorejs-angular-components-preview.mjs +58 -19
  55. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  56. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +192 -30
  57. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  58. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +187 -127
  59. package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
  60. package/fesm2022/sdcorejs-angular-components-section.mjs +16 -2
  61. package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
  62. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +83 -24
  63. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  64. package/fesm2022/sdcorejs-angular-components-splitter.mjs +57 -21
  65. package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
  66. package/fesm2022/sdcorejs-angular-components-stepper.mjs +2 -2
  67. package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
  68. package/fesm2022/sdcorejs-angular-components-tab-router.mjs +68 -20
  69. package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-components-tab.mjs +3 -2
  71. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  72. package/fesm2022/sdcorejs-angular-components-table.mjs +557 -255
  73. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  74. package/fesm2022/sdcorejs-angular-components-tree.mjs +80 -17
  75. package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
  76. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +48 -13
  77. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-components.mjs +6 -1
  79. package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-configurations.mjs.map +1 -1
  81. package/fesm2022/sdcorejs-angular-directives.mjs +45 -8
  82. package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
  83. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +40 -29
  84. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  85. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +5 -5
  86. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  87. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +67 -50
  88. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  89. package/fesm2022/sdcorejs-angular-forms-chip.mjs +57 -43
  90. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  91. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +234 -64
  92. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  93. package/fesm2022/sdcorejs-angular-forms-date.mjs +209 -42
  94. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  95. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +131 -27
  96. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  97. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs +40 -16
  98. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs.map +1 -1
  99. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +16 -5
  100. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  101. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +24 -9
  102. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  103. package/fesm2022/sdcorejs-angular-forms-input.mjs +58 -10
  104. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  105. package/fesm2022/sdcorejs-angular-forms-models.mjs +279 -6
  106. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  107. package/fesm2022/sdcorejs-angular-forms-radio.mjs +4 -4
  108. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  109. package/fesm2022/sdcorejs-angular-forms-select.mjs +136 -38
  110. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  111. package/fesm2022/sdcorejs-angular-forms-switch.mjs +18 -3
  112. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  113. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +51 -62
  114. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  115. package/fesm2022/sdcorejs-angular-forms-time-range.mjs +57 -12
  116. package/fesm2022/sdcorejs-angular-forms-time-range.mjs.map +1 -1
  117. package/fesm2022/sdcorejs-angular-forms-time.mjs +16 -5
  118. package/fesm2022/sdcorejs-angular-forms-time.mjs.map +1 -1
  119. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs +100 -9
  120. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs.map +1 -1
  121. package/fesm2022/sdcorejs-angular-forms.mjs +91 -46
  122. package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -1
  123. package/fesm2022/sdcorejs-angular-handlers.mjs +18 -3
  124. package/fesm2022/sdcorejs-angular-handlers.mjs.map +1 -1
  125. package/fesm2022/sdcorejs-angular-i18n.mjs +510 -68
  126. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  127. package/fesm2022/sdcorejs-angular-interceptors.mjs +87 -29
  128. package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
  129. package/fesm2022/sdcorejs-angular-modules-auth.mjs +25 -15
  130. package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -1
  131. package/fesm2022/sdcorejs-angular-modules-icon.mjs +2 -2
  132. package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -1
  133. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +32 -3
  134. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
  135. package/fesm2022/sdcorejs-angular-modules-layout.mjs +441 -135
  136. package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
  137. package/fesm2022/sdcorejs-angular-modules-permission.mjs +177 -40
  138. package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -1
  139. package/fesm2022/sdcorejs-angular-pipes.mjs +62 -28
  140. package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
  141. package/fesm2022/sdcorejs-angular-services-api.mjs +123 -13
  142. package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
  143. package/fesm2022/sdcorejs-angular-services-cache.mjs +53 -3
  144. package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
  145. package/fesm2022/sdcorejs-angular-services-confirm.mjs +25 -73
  146. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  147. package/fesm2022/sdcorejs-angular-services-excel.mjs +12 -10
  148. package/fesm2022/sdcorejs-angular-services-excel.mjs.map +1 -1
  149. package/fesm2022/sdcorejs-angular-services-loading.mjs +75 -84
  150. package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -1
  151. package/fesm2022/sdcorejs-angular-services-notify.mjs +46 -5
  152. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  153. package/fesm2022/sdcorejs-angular-services-storage.mjs +4 -0
  154. package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
  155. package/fesm2022/sdcorejs-angular-services.mjs +0 -1
  156. package/fesm2022/sdcorejs-angular-services.mjs.map +1 -1
  157. package/fesm2022/sdcorejs-angular-utilities-extensions.mjs +225 -80
  158. package/fesm2022/sdcorejs-angular-utilities-extensions.mjs.map +1 -1
  159. package/fesm2022/sdcorejs-angular-utilities-models.mjs +1 -63
  160. package/fesm2022/sdcorejs-angular-utilities-models.mjs.map +1 -1
  161. package/fesm2022/sdcorejs-angular.mjs +17 -10
  162. package/fesm2022/sdcorejs-angular.mjs.map +1 -1
  163. package/forms/autocomplete/index.d.ts +5 -2
  164. package/forms/chip-calendar/index.d.ts +10 -0
  165. package/forms/date/index.d.ts +21 -3
  166. package/forms/date-range/index.d.ts +14 -2
  167. package/forms/datetime/index.d.ts +13 -2
  168. package/forms/entity-picker/index.d.ts +9 -3
  169. package/forms/index.d.ts +22 -13
  170. package/forms/input/index.d.ts +3 -0
  171. package/forms/input-color/index.d.ts +4 -0
  172. package/forms/input-number/index.d.ts +3 -0
  173. package/forms/models/index.d.ts +146 -5
  174. package/forms/select/index.d.ts +27 -4
  175. package/forms/switch/index.d.ts +7 -1
  176. package/forms/textarea/index.d.ts +5 -3
  177. package/forms/time-range/index.d.ts +22 -1
  178. package/forms/tree-select/index.d.ts +36 -5
  179. package/i18n/index.d.ts +99 -16
  180. package/index.d.ts +11 -2
  181. package/interceptors/index.d.ts +13 -3
  182. package/modules/auth/index.d.ts +1 -1
  183. package/modules/keycloak/index.d.ts +1 -0
  184. package/modules/layout/index.d.ts +103 -28
  185. package/modules/permission/index.d.ts +66 -4
  186. package/package.json +40 -25
  187. package/pipes/index.d.ts +27 -5
  188. package/services/api/index.d.ts +21 -1
  189. package/services/cache/index.d.ts +11 -1
  190. package/services/index.d.ts +0 -1
  191. package/services/notify/index.d.ts +1 -1
  192. package/utilities/extensions/index.d.ts +83 -61
  193. package/utilities/models/index.d.ts +2 -76
  194. package/components/base/index.d.ts +0 -11
  195. package/components/document-builder/index.d.ts +0 -252
  196. package/fesm2022/sdcorejs-angular-components-base.mjs +0 -23
  197. package/fesm2022/sdcorejs-angular-components-base.mjs.map +0 -1
  198. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +0 -5038
  199. package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +0 -1
  200. package/fesm2022/sdcorejs-angular-models.mjs +0 -6
  201. package/fesm2022/sdcorejs-angular-models.mjs.map +0 -1
  202. package/fesm2022/sdcorejs-angular-services-docx.mjs +0 -291
  203. package/fesm2022/sdcorejs-angular-services-docx.mjs.map +0 -1
  204. package/fesm2022/sdcorejs-angular-services-license.mjs +0 -97
  205. package/fesm2022/sdcorejs-angular-services-license.mjs.map +0 -1
  206. package/models/index.d.ts +0 -2
  207. package/services/docx/index.d.ts +0 -27
  208. package/services/license/index.d.ts +0 -12
package/i18n/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { Language } from '@sdcorejs/angular/models';
2
- export { Language, SUPPORTED_LANGUAGES } from '@sdcorejs/angular/models';
1
+ import { Language } from '@sdcorejs/utils/models';
3
2
  import * as i0 from '@angular/core';
4
3
  import { Signal, PipeTransform } from '@angular/core';
5
4
 
@@ -85,9 +84,6 @@ declare const EN_MESSAGES: {
85
84
  readonly 'core.interceptor.no-internet.restored': "Connection restored.";
86
85
  readonly 'core.excel.cannot-read-file': "Could not read file content";
87
86
  readonly 'core.excel.no-sheet': "Excel file has no data sheet";
88
- readonly 'core.docx.invalid-format': "Invalid format. Please select a template in DOC or DOCX format";
89
- readonly 'core.docx.size-exceeded': "Template file size exceeds the supported limit. Please try again";
90
- readonly 'core.docx.convert-error': "An error occurred while converting the DOCX file";
91
87
  readonly 'core.notify.type.success': "Success";
92
88
  readonly 'core.notify.type.info': "Information";
93
89
  readonly 'core.notify.type.warning': "Warning";
@@ -184,7 +180,6 @@ declare const EN_MESSAGES: {
184
180
  readonly 'core.form.time-range.step': "Times must align to a {step}-minute interval";
185
181
  readonly 'core.form.time-range.from': "From";
186
182
  readonly 'core.form.time-range.to': "To";
187
- readonly 'core.form.time-range.clear': "Clear time range";
188
183
  readonly 'core.form.time-spinner.hour': "Hour";
189
184
  readonly 'core.form.time-spinner.minute': "Minute";
190
185
  readonly 'core.form.time-spinner.second': "Second";
@@ -203,6 +198,7 @@ declare const EN_MESSAGES: {
203
198
  readonly 'core.form.checkbox.checked': "Yes";
204
199
  readonly 'core.form.checkbox.unchecked': "No";
205
200
  readonly 'core.form.select.required': "Please enter information";
201
+ readonly 'core.form.select.selectAll': "All";
206
202
  readonly 'core.form.textarea.required': "Please enter information";
207
203
  readonly 'core.form.textarea.maxlength': "Maximum characters: {max}";
208
204
  readonly 'core.form.textarea.invalid-pattern': "Invalid format";
@@ -216,12 +212,6 @@ declare const EN_MESSAGES: {
216
212
  readonly 'core.component.editor.image.max-width': "Image width {width}px exceeds the limit of {max}px";
217
213
  readonly 'core.component.editor.image.max-height': "Image height {height}px exceeds the limit of {max}px";
218
214
  readonly 'core.component.editor.image.max-per-selection': "You can select at most {max} images per selection";
219
- readonly 'core.component.document-builder.page-number.current': "Current page number";
220
- readonly 'core.component.document-builder.page-number.total': "Total pages";
221
- readonly 'core.component.document-builder.ck-comment.label': "Comment";
222
- readonly 'core.component.document-builder.ck-comment.text-too-long': "Text too long ({length} characters). Maximum {max} characters.";
223
- readonly 'core.component.document-builder.variable.not-allowed': "Adding variable to the text is not allowed";
224
- readonly 'core.component.document-builder.variable.invalid-data': "Invalid variable data";
225
215
  readonly 'core.component.form-builder.field-key': "Field key";
226
216
  readonly 'core.component.form-builder.display': "Display";
227
217
  readonly 'core.component.form-builder.general': "General";
@@ -235,6 +225,7 @@ declare const EN_MESSAGES: {
235
225
  readonly 'core.component.form-builder.required-when': "Required when";
236
226
  readonly 'core.component.form-builder.confirm': "Confirm";
237
227
  readonly 'core.component.form-builder.delete': "Delete";
228
+ readonly 'core.component.form-builder.select-item': "Select to edit";
238
229
  readonly 'core.component.form-builder.save': "Save";
239
230
  readonly 'core.component.form-builder.hint': "Hint";
240
231
  readonly 'core.component.form-builder.parameter': "Parameters";
@@ -306,9 +297,13 @@ declare const EN_MESSAGES: {
306
297
  readonly 'core.component.form-builder.display-label': "Display label";
307
298
  readonly 'core.component.form-builder.attribute': "Attribute";
308
299
  readonly 'core.component.form-builder.add-variable': "Add variable";
300
+ readonly 'core.component.form-builder.no-variable': "No variables yet. Add one to use it in condition expressions.";
301
+ readonly 'core.component.form-builder.no-validation': "No validations yet. Add one to show a warning or an error on a condition.";
309
302
  readonly 'core.component.form-builder.add-new': "Add new";
310
303
  readonly 'core.component.form-builder.detail': "Details";
311
304
  readonly 'core.component.form-builder.create-update': "Create/update";
305
+ readonly 'core.component.form-builder.update-row': "Update row";
306
+ readonly 'core.component.form-builder.add-row': "Add row";
312
307
  readonly 'core.component.form-builder.default': "Default";
313
308
  readonly 'core.component.form-builder.show-more': "Show more";
314
309
  readonly 'core.component.form-builder.show-less': "Show less";
@@ -465,6 +460,8 @@ declare const EN_MESSAGES: {
465
460
  readonly 'core.component.table.choose-filter-hint': "Please choose a filter to start";
466
461
  readonly 'core.component.table.no-data': "No data";
467
462
  readonly 'core.component.table.export-excel': "Export Excel";
463
+ readonly 'core.component.table.exporting': "Exporting...{percent}%";
464
+ readonly 'core.component.table.export': "Export";
468
465
  readonly 'core.component.table.export-csv': "Export CSV";
469
466
  readonly 'core.component.table.showing': "Showing:";
470
467
  readonly 'core.component.table.paginator.first-page': "First page";
@@ -475,6 +472,8 @@ declare const EN_MESSAGES: {
475
472
  readonly 'core.component.table.error-occurred': "An error occurred";
476
473
  readonly 'core.component.table.not-an-array': "Data is not an array";
477
474
  readonly 'core.component.table.config.confirm-reset': "Confirm reset all settings to defaults";
475
+ readonly 'core.component.table.config.drag-hint': "Drag the ⠿ handle to reorder columns";
476
+ readonly 'core.component.table.config.drag-handle': "Drag to reorder column";
478
477
  readonly 'core.component.table.popup-export.select-columns': "Please select columns to export";
479
478
  readonly 'core.component.table.selector-action.default-msg': "items selected";
480
479
  readonly 'core.component.tab-router.too-many-tabs': "You have opened too many tabs.";
@@ -503,6 +502,13 @@ declare const EN_MESSAGES: {
503
502
  readonly 'core.module.layout.user.notification': "Notifications";
504
503
  readonly 'core.module.layout.sidebar.search': "Search";
505
504
  readonly 'core.module.layout.sidebar.toggle': "Toggle sidebar";
505
+ readonly 'core.module.layout.sidebar.menu-groups': "Menu groups";
506
+ readonly 'core.module.layout.sidebar.close-menu': "Close menu";
507
+ readonly 'core.module.layout.sidebar.search-in-group': "Search this group";
508
+ readonly 'core.module.layout.sidebar.primary-nav': "Primary navigation";
509
+ readonly 'core.module.layout.sidebar.more-menu': "More menus";
510
+ readonly 'core.module.layout.sidebar.more': "More";
511
+ readonly 'core.module.layout.sidebar.search-in-menu': "Search menus";
506
512
  readonly 'core.module.layout.greeting.hello': "Hello, {name}";
507
513
  readonly 'core.module.layout.weekday.0': "Sunday";
508
514
  readonly 'core.module.layout.weekday.1': "Monday";
@@ -519,6 +525,8 @@ declare const EN_MESSAGES: {
519
525
  readonly 'core.module.layout.not-found.message': "The page you're looking for doesn't exist or has been removed. Please check the URL or go back to the home page to continue.";
520
526
  readonly 'core.module.layout.not-found.back': "Go back";
521
527
  readonly 'core.module.layout.home.tab-name': "Home";
528
+ readonly 'core.module.layout.not-found.tab-name': "Page Not Found";
529
+ readonly 'core.module.layout.forbidden.tab-name': "Access Denied";
522
530
  readonly 'core.module.layout.home.feature.data': "Data";
523
531
  readonly 'core.module.layout.home.feature.reports': "Reports";
524
532
  readonly 'core.module.layout.home.feature.users': "Users";
@@ -527,6 +535,81 @@ declare const EN_MESSAGES: {
527
535
  readonly 'core.module.layout.home.feature.integration': "Integration";
528
536
  readonly 'core.module.layout.mock.user.full-name': "Demo User";
529
537
  readonly 'core.module.generic.generic-select.detail-link': "details";
538
+ readonly 'core.component.query-bar.search-placeholder': "Search...";
539
+ readonly 'core.component.query-bar.no-fields': "No fields configured";
540
+ readonly 'core.component.query-bar.add-filter': "Add filter";
541
+ readonly 'core.component.query-bar.clear-all': "Clear all ({count})";
542
+ readonly 'core.component.query-bar.search': "Search";
543
+ readonly 'core.component.query-bar.logic-operator': "Logic operator";
544
+ readonly 'core.component.query-bar.boolean.true': "Yes";
545
+ readonly 'core.component.query-bar.boolean.false': "No";
546
+ readonly 'core.component.query-bar.placeholder.value': "value";
547
+ readonly 'core.component.query-bar.placeholder.text': "type…";
548
+ readonly 'core.component.query-bar.placeholder.from-number': "From";
549
+ readonly 'core.component.query-bar.placeholder.to-number': "To";
550
+ readonly 'core.component.query-bar.placeholder.from-text': "from…";
551
+ readonly 'core.component.query-bar.placeholder.to-text': "to…";
552
+ readonly 'core.component.query-bar.swap-field': "Swap field";
553
+ readonly 'core.component.query-bar.placeholder.select-value': "Select value";
554
+ readonly 'core.component.query-bar.placeholder.enter-value': "Enter value";
555
+ readonly 'core.component.query-bar.loading-values': "Loading...";
556
+ readonly 'core.component.query-bar.field-empty': "No fields configured yet.";
557
+ readonly 'core.component.query-bar.saved-filters.tooltip': "Saved filters";
558
+ readonly 'core.component.query-bar.saved-filters.tooltip-disabled': "Requires [savedFiltersKey] to enable";
559
+ readonly 'core.component.query-bar.saved-filters.delete': "Delete filter";
560
+ readonly 'core.component.query-bar.saved-filters.empty': "No saved filters yet.";
561
+ readonly 'core.component.query-bar.saved-filters.save': "Save current filter";
562
+ readonly 'core.component.query-bar.saved-filters.name-label': "Filter name";
563
+ readonly 'core.component.query-builder.date-mode.absolute': "Specific date";
564
+ readonly 'core.component.query-builder.date-mode.now': "Today";
565
+ readonly 'core.component.query-builder.date-mode.relative': "Relative";
566
+ readonly 'core.component.query-builder.value-source.literal': "Enter a value";
567
+ readonly 'core.component.query-builder.value-source.field': "Compare with field";
568
+ readonly 'core.component.query-builder.relative.hour-previous': "hours ago";
569
+ readonly 'core.component.query-builder.relative.hour-next': "hours from now";
570
+ readonly 'core.component.query-builder.relative.day-previous': "days ago";
571
+ readonly 'core.component.query-builder.relative.day-next': "days from now";
572
+ readonly 'core.component.query-builder.relative.week-previous': "weeks ago";
573
+ readonly 'core.component.query-builder.relative.week-next': "weeks from now";
574
+ readonly 'core.component.query-builder.relative.month-previous': "months ago";
575
+ readonly 'core.component.query-builder.relative.month-next': "months from now";
576
+ readonly 'core.component.query-builder.relative.format': "{amount} {phrase}";
577
+ readonly 'core.component.query-builder.add': "Add";
578
+ readonly 'core.component.query-builder.add-node': "Add a condition or group";
579
+ readonly 'core.component.query-builder.condition': "Condition";
580
+ readonly 'core.component.query-builder.group': "Group";
581
+ readonly 'core.component.query-builder.remove-group': "Remove group";
582
+ readonly 'core.component.query-builder.remove-condition': "Remove condition";
583
+ readonly 'core.component.query-builder.empty': "No conditions yet";
584
+ readonly 'core.component.query-builder.select-field': "Select field";
585
+ readonly 'core.component.query-builder.value': "Value";
586
+ readonly 'core.component.query-builder.from': "From";
587
+ readonly 'core.component.query-builder.to': "To";
588
+ readonly 'core.component.query-builder.boolean.true': "Yes";
589
+ readonly 'core.component.query-builder.boolean.false': "No";
590
+ readonly 'core.component.tree.selected-count': "{count} item(s) selected";
591
+ readonly 'core.component.tree.expand': "Expand tree item";
592
+ readonly 'core.component.tree.collapse': "Collapse tree item";
593
+ readonly 'core.component.tree.retry-item': "Retry loading tree item";
594
+ readonly 'core.component.tree.load-error': "Unable to load tree data";
595
+ readonly 'core.directive.hover-copy.copied': "Copied";
596
+ readonly 'core.module.layout.sidebar.pinned': "Pinned";
597
+ readonly 'core.module.layout.sidebar.recent': "Recent";
598
+ readonly 'core.module.layout.sidebar.all-menu': "All menus";
599
+ readonly 'core.module.layout.menu.pin': "Pin {title}";
600
+ readonly 'core.module.layout.menu.unpin': "Unpin {title}";
601
+ readonly 'core.form.date.open-picker': "Open calendar";
602
+ readonly 'core.form.datetime.open-picker': "Open calendar";
603
+ readonly 'core.form.date-range.open-picker': "Open calendar";
604
+ readonly 'core.form.date-range.clear': "Clear date range";
605
+ readonly 'core.form.select.search': "Search";
606
+ readonly 'core.component.table.loading': "Loading table data";
607
+ readonly 'core.component.upload-file.loading': "Uploading file";
608
+ readonly 'core.component.import-excel.loading': "Loading data";
609
+ readonly 'core.component.upload-file.remove': "Remove file";
610
+ readonly 'core.component.upload-file.zoom': "Zoom image";
611
+ readonly 'core.component.upload-file.view-all': "View all images";
612
+ readonly 'core.component.form-builder.canvas': "Form design canvas";
530
613
  };
531
614
 
532
615
  type I18nKey = keyof typeof EN_MESSAGES;
@@ -571,12 +654,12 @@ declare class I18nService {
571
654
  static ɵprov: i0.ɵɵInjectableDeclaration<I18nService>;
572
655
  }
573
656
 
574
- declare class TranslatePipe implements PipeTransform {
657
+ declare class SdTranslatePipe implements PipeTransform {
575
658
  #private;
576
659
  transform(key: string, params?: I18nParams): string;
577
- static ɵfac: i0.ɵɵFactoryDeclaration<TranslatePipe, never>;
578
- static ɵpipe: i0.ɵɵPipeDeclaration<TranslatePipe, "translate", true>;
660
+ static ɵfac: i0.ɵɵFactoryDeclaration<SdTranslatePipe, never>;
661
+ static ɵpipe: i0.ɵɵPipeDeclaration<SdTranslatePipe, "sdTranslate", true>;
579
662
  }
580
663
 
581
- export { I18N_MESSAGES, I18N_STORAGE_KEY, I18nService, TranslatePipe };
664
+ export { I18N_MESSAGES, I18N_STORAGE_KEY, I18nService, SdTranslatePipe };
582
665
  export type { CustomLanguageProvider, I18nCatalog, I18nKey, I18nParams };
package/index.d.ts CHANGED
@@ -1,2 +1,11 @@
1
-
2
- export { };
1
+ export * from '@sdcorejs/angular/configurations';
2
+ export * from '@sdcorejs/angular/i18n';
3
+ export * from '@sdcorejs/angular/utilities';
4
+ export * from '@sdcorejs/angular/pipes';
5
+ export * from '@sdcorejs/angular/directives';
6
+ export * from '@sdcorejs/angular/services';
7
+ export * from '@sdcorejs/angular/interceptors';
8
+ export * from '@sdcorejs/angular/handlers';
9
+ export * from '@sdcorejs/angular/components';
10
+ export * from '@sdcorejs/angular/forms';
11
+ export * from '@sdcorejs/angular/modules';
@@ -1,11 +1,21 @@
1
1
  import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
2
- import { Observable } from 'rxjs';
3
2
  import * as i0 from '@angular/core';
3
+ import { InjectionToken } from '@angular/core';
4
+ import { Observable } from 'rxjs';
4
5
 
6
+ /**
7
+ * URL dùng để dò kết nối khi một request trả về status 0.
8
+ *
9
+ * why: bản cũ hard-code `https://jsonplaceholder.typicode.com/todos/1`, không override được. Mọi
10
+ * app tiêu dùng thư viện đều ping một bên thứ ba lạ mỗi 3 giây khi mất mạng, và vì probe đi qua
11
+ * NGUYÊN chuỗi interceptor của app nên bất kỳ interceptor nào gắn header auth vô điều kiện đều
12
+ * rò token ra ngoài origin. Mặc định giờ là một đường dẫn same-origin; app đổi bằng cách provide
13
+ * lại token này (nên trỏ tới endpoint tĩnh, rẻ, không cần auth).
14
+ */
15
+ declare const SD_NO_INTERNET_PROBE_URL: InjectionToken<string>;
5
16
  declare class SdNoInternetInterceptor implements HttpInterceptor {
6
17
  #private;
7
18
  private snackBar;
8
- private injector;
9
19
  /** Inserted by Angular inject() migration for backwards compatibility */
10
20
  constructor(...args: unknown[]);
11
21
  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>>;
@@ -23,4 +33,4 @@ declare class SdUnauthorizedInterceptor implements HttpInterceptor {
23
33
  static ɵprov: i0.ɵɵInjectableDeclaration<SdUnauthorizedInterceptor>;
24
34
  }
25
35
 
26
- export { SdNoInternetInterceptor, SdUnauthorizedInterceptor };
36
+ export { SD_NO_INTERNET_PROBE_URL, SdNoInternetInterceptor, SdUnauthorizedInterceptor };
@@ -5,7 +5,7 @@ import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from
5
5
  import { MaybeAsync } from '@sdcorejs/utils/models';
6
6
  import { Observable } from 'rxjs';
7
7
 
8
- interface SdAuthInfo<T = any> {
8
+ interface SdAuthInfo<T = unknown> {
9
9
  id?: string;
10
10
  username?: string;
11
11
  firstName?: string;
@@ -40,6 +40,7 @@ interface ISdKeycloakConfiguration {
40
40
  declare const SD_KEYCLOAK_CONFIGURATION: InjectionToken<ISdKeycloakConfiguration>;
41
41
 
42
42
  declare class SdKeycloakService {
43
+ #private;
43
44
  keycloak: Keycloak;
44
45
  config: SdKeycloakTenantConfig;
45
46
  init(config: SdKeycloakTenantConfig): Promise<boolean>;
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { Signal, InjectionToken, PipeTransform } from '@angular/core';
2
+ import { InjectionToken, Signal, PipeTransform } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
4
  import * as i1 from '@angular/router';
5
5
  import { Params } from '@angular/router';
@@ -57,15 +57,59 @@ interface SdLayoutChildrenMenu {
57
57
  tooltipTitle?: string;
58
58
  }
59
59
 
60
+ /**
61
+ * Namespace áp cho toàn bộ state layout được persist — hằng chuỗi, hoặc hàm resolve lại mỗi lần đọc
62
+ * (dùng cho danh tính chỉ biết được SAU khi đăng nhập, ví dụ id user hoặc tenant).
63
+ */
64
+ type SdLayoutStorageNamespace = string | (() => string | null | undefined);
65
+ /**
66
+ * Namespace do consumer cung cấp cho toàn bộ state layout được persist (thường là id user hoặc tenant).
67
+ *
68
+ * why: các key dưới đây là UUID CỐ ĐỊNH, không gắn với ai cả. Trên máy dùng chung, user A đăng xuất
69
+ * rồi user B đăng nhập thì `pinnedMenuKeys` / `recentMenuKeys` / `lastActiveMenuGroupId` của A vẫn
70
+ * còn nguyên trong localStorage và B nhìn thấy đúng những module A đã ghim và vừa truy cập. Cấp
71
+ * namespace theo user/tenant sẽ tách hẳn không gian lưu trữ.
72
+ *
73
+ * ⚠️ `SdLayoutStorageService` là singleton `providedIn: 'root'`, thường được khởi tạo TRƯỚC khi biết
74
+ * người dùng là ai. Vì vậy hãy cấp một **hàm** — nó được gọi lại ở mỗi lần truy cập handle, nên khi
75
+ * danh tính đến (hoặc đổi) thì cả bảy handle tự dựng lại trên namespace mới:
76
+ *
77
+ * ```ts
78
+ * providers: [
79
+ * {
80
+ * provide: SD_LAYOUT_STORAGE_NAMESPACE,
81
+ * useFactory: () => {
82
+ * const auth = inject(SdAuthService);
83
+ * return () => auth.getAuthInfo?.()?.id;
84
+ * },
85
+ * },
86
+ * ];
87
+ * ```
88
+ *
89
+ * Đây là biện pháp bổ sung chứ không thay thế `SdLayoutStorageService.clear()` lúc signout.
90
+ */
91
+ declare const SD_LAYOUT_STORAGE_NAMESPACE: InjectionToken<SdLayoutStorageNamespace>;
60
92
  declare class SdLayoutStorageService {
61
93
  #private;
62
- readonly isShowSidebar: SdStorage<boolean>;
63
- readonly menuLockStatus: SdStorage<boolean>;
64
- readonly lastActiveMenuGroupId: SdStorage<string>;
65
- readonly pinnedMenuGroup: SdStorage<SdLayoutChildrenMenu>;
66
- readonly pinnedMenuKeys: SdStorage<string[]>;
67
- readonly recentMenuKeys: SdStorage<string[]>;
68
- readonly versionStates: SdStorage<Record<string, SdLayoutVersionState>>;
94
+ get isShowSidebar(): SdStorage<boolean>;
95
+ get menuLockStatus(): SdStorage<boolean>;
96
+ get lastActiveMenuGroupId(): SdStorage<string>;
97
+ get pinnedMenuGroup(): SdStorage<SdLayoutChildrenMenu>;
98
+ get pinnedMenuKeys(): SdStorage<string[]>;
99
+ get recentMenuKeys(): SdStorage<string[]>;
100
+ get versionStates(): SdStorage<Record<string, SdLayoutVersionState>>;
101
+ /**
102
+ * Xoá toàn bộ state layout đã persist.
103
+ *
104
+ * **Consumer PHẢI gọi hàm này trong luồng signout, TRƯỚC khi danh tính bị xoá.** Nếu không,
105
+ * pinned/recent/last-active của user vừa đăng xuất sẽ còn lại trên trình duyệt và hiện ra cho người
106
+ * đăng nhập kế tiếp — rò rỉ tên module nội bộ mà người đó có thể không có quyền thấy.
107
+ *
108
+ * why: khi đã cấu hình `SD_LAYOUT_STORAGE_NAMESPACE` theo user, namespace được resolve NGAY LÚC GỌI.
109
+ * Gọi `clear()` sau khi auth info về `undefined` sẽ xoá nhầm partition không-namespace, còn dữ liệu
110
+ * của user vừa thoát thì vẫn nguyên.
111
+ */
112
+ clear(): void;
69
113
  readPinnedMenuKeys(menus: SdLayoutMenu[]): string[];
70
114
  writePinnedMenuKeys(keys: string[]): void;
71
115
  readRecentMenuKeys(menus: SdLayoutMenu[], maximum?: number): string[];
@@ -251,10 +295,30 @@ declare function selectPrimaryMenuGroups(menus: SdLayoutMenu[], requestedIds: st
251
295
  declare function resolveMenuKeys(menus: SdLayoutMenu[], keys: string[]): (SdLayoutRootMenu | SdLayoutChildrenMenu)[];
252
296
  declare function flattenMenuLeaves(menus: SdLayoutMenu[]): SdLayoutRootMenu[];
253
297
 
298
+ /**
299
+ * Bật fallback demo của `SdLayoutService` khi KHÔNG provide `SD_LAYOUT_CONFIGURATION`.
300
+ *
301
+ * why: fallback cũ chạy ngầm sau mỗi `console.warn`, nên một app cấu hình thiếu vẫn ship được UI có
302
+ * user "demo@example.com" đang đăng nhập cùng nút signout không làm gì — người dùng cuối tin là đã
303
+ * đăng nhập thật. Giờ mặc định là throw; ai thực sự cần demo/playground phải khai báo ý định:
304
+ *
305
+ * ```ts
306
+ * providers: [{ provide: SD_LAYOUT_DEMO_FALLBACK, useValue: true }]
307
+ * ```
308
+ *
309
+ * Cờ nằm ở token riêng chứ không phải field của `ISdLayoutConfiguration`, vì nó phải đọc được ĐÚNG
310
+ * lúc `SD_LAYOUT_CONFIGURATION` vắng mặt — khi đó không có object configuration nào để đọc field.
311
+ */
312
+ declare const SD_LAYOUT_DEMO_FALLBACK: InjectionToken<boolean>;
254
313
  declare class SdLayoutService {
255
314
  #private;
256
315
  userInfo: _angular_core.WritableSignal<SdLayoutUserInfo | undefined>;
257
316
  sidebar: _angular_core.WritableSignal<ISdSidebarConfiguration | undefined>;
317
+ /**
318
+ * Route "về trang chủ" của consumer, lấy từ `ISdLayoutConfiguration.homeUrl`.
319
+ * why: các trang lỗi (forbidden / not-found) cần một đích điều hướng thật thay vì reload chính nó.
320
+ */
321
+ readonly homeUrl: string;
258
322
  constructor();
259
323
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdLayoutService, never>;
260
324
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<SdLayoutService>;
@@ -285,7 +349,7 @@ declare class SdLayoutComponent {
285
349
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdLayoutComponent, "sd-layout", never, { "menusInput": { "alias": "menus"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
286
350
  }
287
351
 
288
- declare class SidebarMobileV1Component {
352
+ declare class SdSidebarMobileV1 {
289
353
  #private;
290
354
  menus: _angular_core.InputSignal<SdLayoutMenu[]>;
291
355
  userInfo: _angular_core.InputSignal<SdLayoutUserInfo>;
@@ -300,11 +364,11 @@ declare class SidebarMobileV1Component {
300
364
  onExpandSideBar: () => void;
301
365
  onMouseleaveSideBar: () => void;
302
366
  onTitleMenuGroupChanged: (title: string | undefined) => void;
303
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<SidebarMobileV1Component, never>;
304
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarMobileV1Component, "sidebar-mobile-v1", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
367
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSidebarMobileV1, never>;
368
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSidebarMobileV1, "sd-sidebar-mobile-v1", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
305
369
  }
306
370
 
307
- declare class SidebarMobileOverlayComponent {
371
+ declare class SdSidebarMobileOverlay {
308
372
  #private;
309
373
  isShowSidebar: _angular_core.InputSignal<boolean>;
310
374
  menus: _angular_core.InputSignal<SdLayoutMenu[]>;
@@ -332,8 +396,8 @@ declare class SidebarMobileOverlayComponent {
332
396
  getQueryParams(menu: SdLayoutMenu): Params;
333
397
  onUserMenuOpened: () => void;
334
398
  onUserMenuClosed: () => void;
335
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<SidebarMobileOverlayComponent, never>;
336
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarMobileOverlayComponent, "sd-sidebar-mobile-overlay", never, { "isShowSidebar": { "alias": "isShowSidebar"; "required": false; "isSignal": true; }; "menus": { "alias": "menus"; "required": true; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, { "showSideBar": "showSideBar"; "expandSideBar": "expandSideBar"; "popupUserMenuOpened": "popupUserMenuOpened"; "popupUserMenuClosed": "popupUserMenuClosed"; "titleMenuGroupChanged": "titleMenuGroupChanged"; }, never, never, true, never>;
399
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSidebarMobileOverlay, never>;
400
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSidebarMobileOverlay, "sd-sidebar-mobile-overlay", never, { "isShowSidebar": { "alias": "isShowSidebar"; "required": false; "isSignal": true; }; "menus": { "alias": "menus"; "required": true; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, { "showSideBar": "showSideBar"; "expandSideBar": "expandSideBar"; "popupUserMenuOpened": "popupUserMenuOpened"; "popupUserMenuClosed": "popupUserMenuClosed"; "titleMenuGroupChanged": "titleMenuGroupChanged"; }, never, never, true, never>;
337
401
  }
338
402
 
339
403
  interface SdLayoutMenuTreeNode {
@@ -346,6 +410,8 @@ interface SdLayoutMenuTreeNode {
346
410
  isActive: boolean;
347
411
  isPinned: boolean;
348
412
  isPinVisible: boolean;
413
+ /** Accessible name of the pin toggle — already i18n-resolved with the menu title interpolated. */
414
+ pinLabel: string;
349
415
  }
350
416
  declare class SdLayoutMenuTreeComponent {
351
417
  #private;
@@ -416,7 +482,7 @@ interface SidebarV2RailItem {
416
482
  key: string;
417
483
  title: string;
418
484
  }
419
- declare class SidebarV2Component {
485
+ declare class SdSidebarV2 {
420
486
  #private;
421
487
  menus: _angular_core.InputSignal<SdLayoutMenu[]>;
422
488
  userInfo: _angular_core.InputSignal<SdLayoutUserInfo>;
@@ -440,11 +506,11 @@ declare class SidebarV2Component {
440
506
  closeFromNavigation(): void;
441
507
  onNavigate(menu: SdLayoutMenu): void;
442
508
  onTogglePinned(menu: SdLayoutMenu): void;
443
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<SidebarV2Component, never>;
444
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarV2Component, "sidebar-v2", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
509
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSidebarV2, never>;
510
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSidebarV2, "sd-sidebar-v2", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
445
511
  }
446
512
 
447
- declare class SidebarMobileV2Component {
513
+ declare class SdSidebarMobileV2 {
448
514
  #private;
449
515
  menus: _angular_core.InputSignal<SdLayoutMenu[]>;
450
516
  userInfo: _angular_core.InputSignal<SdLayoutUserInfo>;
@@ -465,11 +531,11 @@ declare class SidebarMobileV2Component {
465
531
  onSheetKeydown(event: KeyboardEvent): void;
466
532
  onNavigate(menu: SdLayoutMenu): void;
467
533
  onTogglePinned(menu: SdLayoutMenu): void;
468
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<SidebarMobileV2Component, never>;
469
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarMobileV2Component, "sidebar-mobile-v2", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
534
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSidebarMobileV2, never>;
535
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSidebarMobileV2, "sd-sidebar-mobile-v2", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
470
536
  }
471
537
 
472
- declare class SidebarV3Component {
538
+ declare class SdSidebarV3 {
473
539
  #private;
474
540
  menus: _angular_core.InputSignal<SdLayoutMenu[]>;
475
541
  userInfo: _angular_core.InputSignal<SdLayoutUserInfo>;
@@ -492,11 +558,11 @@ declare class SidebarV3Component {
492
558
  activateCollapsedMenu(menu: SdLayoutMenu): void;
493
559
  navigateMenu(menu: SdLayoutMenu): void;
494
560
  onTogglePinned(menu: SdLayoutMenu): void;
495
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<SidebarV3Component, never>;
496
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarV3Component, "sidebar-v3", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
561
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSidebarV3, never>;
562
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSidebarV3, "sd-sidebar-v3", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
497
563
  }
498
564
 
499
- declare class SidebarMobileV3Component {
565
+ declare class SdSidebarMobileV3 {
500
566
  #private;
501
567
  private readonly trigger;
502
568
  menus: _angular_core.InputSignal<SdLayoutMenu[]>;
@@ -518,10 +584,19 @@ declare class SidebarMobileV3Component {
518
584
  onDrawerKeydown(event: KeyboardEvent): void;
519
585
  navigateMenu(menu: SdLayoutMenu): void;
520
586
  onTogglePinned(menu: SdLayoutMenu): void;
521
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<SidebarMobileV3Component, never>;
522
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SidebarMobileV3Component, "sidebar-mobile-v3", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
587
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSidebarMobileV3, never>;
588
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSidebarMobileV3, "sd-sidebar-mobile-v3", never, { "menus": { "alias": "menus"; "required": false; "isSignal": true; }; "userInfo": { "alias": "userInfo"; "required": true; "isSignal": true; }; "sidebar": { "alias": "sidebar"; "required": true; "isSignal": true; }; }, {}, never, ["*"], true, never>;
523
589
  }
524
590
 
591
+ /**
592
+ * Resolve a translated tab name for `@SdTabComponent`.
593
+ *
594
+ * WHY not I18nService: the decorator runs at module-evaluation time, before
595
+ * Angular's DI exists, so the service cannot be injected. We read the language
596
+ * the app persisted and look the key up in the static catalog instead.
597
+ */
598
+ declare function resolveTabName(key: string): string;
599
+
525
600
  declare class MenuPipe implements PipeTransform {
526
601
  #private;
527
602
  private permissionService;
@@ -556,5 +631,5 @@ declare class SdLayoutModule {
556
631
  static ɵinj: _angular_core.ɵɵInjectorDeclaration<SdLayoutModule>;
557
632
  }
558
633
 
559
- export { DEFAULT_LAYOUT_MOBILE_BREAKPOINT, ForbiddenModule, HighlightSearchPipe, HomeModule, MenuFocusPipe, MenuPipe, NotFoundModule, SD_LAYOUT_CONFIGURATION, SD_LAYOUT_VIEWPORT, SdLayoutComponent, SdLayoutMenuTreeComponent, SdLayoutModule, SdLayoutNavigationStateService, SdLayoutResponsiveService, SdLayoutService, SdLayoutStorageService, SdLayoutUserMenuComponent, SdPageComponent, SidebarMobileOverlayComponent, SidebarMobileV1Component, SidebarMobileV2Component, SidebarMobileV3Component, SidebarV2Component, SidebarV3Component, flattenMenuLeaves, getMenuStableKey, normalizeLayoutMobileBreakpoint, normalizeSidebarConfiguration, resolveMenuKeys, resolveSidebarV2Interaction, resolveSidebarV3Recent, searchMenuLeaves, selectPrimaryMenuGroups };
560
- export type { ISdLayoutConfiguration, ISdSidebarConfiguration, Menus, ResolvedSidebarRecentConfiguration, SdLayoutAccountAction, SdLayoutChildrenMenu, SdLayoutMenu, SdLayoutNotificationConfiguration, SdLayoutRootMenu, SdLayoutUserInfo, SdLayoutUserRole, SdLayoutVersionState, SdLayoutViewport, SidebarConfigurationBase, SidebarConfigurationV1, SidebarConfigurationV2, SidebarConfigurationV3 };
634
+ export { DEFAULT_LAYOUT_MOBILE_BREAKPOINT, ForbiddenModule, HighlightSearchPipe, HomeModule, MenuFocusPipe, MenuPipe, NotFoundModule, SD_LAYOUT_CONFIGURATION, SD_LAYOUT_DEMO_FALLBACK, SD_LAYOUT_STORAGE_NAMESPACE, SD_LAYOUT_VIEWPORT, SdLayoutComponent, SdLayoutMenuTreeComponent, SdLayoutModule, SdLayoutNavigationStateService, SdLayoutResponsiveService, SdLayoutService, SdLayoutStorageService, SdLayoutUserMenuComponent, SdPageComponent, SdSidebarMobileOverlay, SdSidebarMobileV1, SdSidebarMobileV2, SdSidebarMobileV3, SdSidebarV2, SdSidebarV3, flattenMenuLeaves, getMenuStableKey, normalizeLayoutMobileBreakpoint, normalizeSidebarConfiguration, resolveMenuKeys, resolveSidebarV2Interaction, resolveSidebarV3Recent, resolveTabName, searchMenuLeaves, selectPrimaryMenuGroups };
635
+ export type { ISdLayoutConfiguration, ISdSidebarConfiguration, Menus, ResolvedSidebarRecentConfiguration, SdLayoutAccountAction, SdLayoutChildrenMenu, SdLayoutMenu, SdLayoutNotificationConfiguration, SdLayoutRootMenu, SdLayoutStorageNamespace, SdLayoutUserInfo, SdLayoutUserRole, SdLayoutVersionState, SdLayoutViewport, SidebarConfigurationBase, SidebarConfigurationV1, SidebarConfigurationV2, SidebarConfigurationV3 };
@@ -49,6 +49,17 @@ interface ISdPermissionConfiguration {
49
49
  * Hỗ trợ trả về đồng bộ, Promise hoặc Observable.
50
50
  */
51
51
  getToken?: () => MaybeAsync<string | undefined | null>;
52
+ /**
53
+ * Cho phép mirror danh sách mã quyền của key này xuống `sessionStorage` để sống qua reload.
54
+ *
55
+ * ⚠️ Mặc định `false` — danh sách quyền CHỈ nằm trong bộ nhớ.
56
+ *
57
+ * Bật cờ này nghĩa là chấp nhận: mọi script chạy trên cùng origin đều ĐỌC và GHI được danh sách đó.
58
+ * Cache KHÔNG phải một ranh giới phân quyền — nó chỉ tiết kiệm một lần gọi API khi reload; backend
59
+ * vẫn phải kiểm tra quyền cho từng request. Khi bật, nhớ gọi `SdPermissionService.reset()` lúc
60
+ * signout để xoá cả bản mirror.
61
+ */
62
+ persistCache?: boolean;
52
63
  }
53
64
  /**
54
65
  * InjectionToken cho cấu hình permission.
@@ -65,13 +76,64 @@ interface ISdPermissionConfiguration {
65
76
  */
66
77
  declare const SD_PERMISSION_CONFIGURATION: InjectionToken<ISdPermissionConfiguration | ISdPermissionConfiguration[]>;
67
78
 
79
+ /**
80
+ * Opt-out TƯỜNG MINH: "chỗ này cố ý không yêu cầu quyền nào".
81
+ *
82
+ * Dùng cho `route.data.permission`, `[sdPermission]` hoặc `hasPermission(...)` khi một route/phần tử
83
+ * thật sự công khai. Mọi giá trị rỗng khác (`undefined`, `null`, `''`, `[]`) đều bị coi là CẤU HÌNH
84
+ * THIẾU và bị từ chối — xem `SdPermissionService.hasPermission`.
85
+ */
86
+ declare const SD_PERMISSION_PUBLIC = "__SD_PERMISSION_PUBLIC__";
87
+ /** Kiểu đầu vào cho `hasPermission` / `[sdPermission]`. */
88
+ type SdPermissionInput = string | string[] | null | undefined;
68
89
  declare class SdPermissionService {
69
90
  #private;
70
91
  constructor();
71
92
  loadPermissions: (key?: string) => Promise<string[]>;
72
93
  loadAllPermissions: () => Promise<void>;
73
- hasPermission: (permission: string | string[], key?: string) => boolean;
94
+ /**
95
+ * Xoá TOÀN BỘ quyền đã nạp (mọi key) — cả map trong bộ nhớ, cờ "đã nạp" lẫn bản mirror
96
+ * `sessionStorage` của các key bật `persistCache`.
97
+ *
98
+ * ⚠️ BẮT BUỘC gọi khi signout. Service là singleton `providedIn: 'root'`, nên trong một SPA
99
+ * signout → signin (không reload trang) mà không reset thì `loadPermissions()` sẽ short-circuit
100
+ * theo key đã cache và user MỚI thừa hưởng nguyên bộ quyền của user CŨ.
101
+ *
102
+ * ```ts
103
+ * auth.signout$?.subscribe(() => permissionService.reset());
104
+ * ```
105
+ */
106
+ reset: () => void;
107
+ /**
108
+ * Xoá quyền đã nạp của MỘT key (mặc định là key portal `undefined`), buộc lần
109
+ * `loadPermissions(key)` kế tiếp gọi lại loader. Dùng khi chỉ một profile/tenant đổi quyền;
110
+ * signout thì dùng {@link reset}.
111
+ */
112
+ invalidate: (key?: string) => void;
113
+ /**
114
+ * Kiểm tra quyền (OR cho mảng).
115
+ *
116
+ * ⚠️ BREAKING: đầu vào rỗng (`undefined` / `null` / `''` / `[]`) giờ trả `false`.
117
+ * Muốn "không yêu cầu quyền" thì phải nói ra bằng {@link SD_PERMISSION_PUBLIC}.
118
+ */
119
+ hasPermission: (permission: SdPermissionInput, key?: string) => boolean;
74
120
  getToken: (key?: string) => Promise<string | null | undefined>;
121
+ /**
122
+ * Giải mã phần payload của JWT hiện tại và trả về claim **CHƯA ĐƯỢC XÁC THỰC**.
123
+ *
124
+ * ⚠️ KHÔNG kiểm chữ ký, KHÔNG kiểm `exp`/`nbf`/`aud`/`iss`. Đây thuần tuý là base64url-decode: bất
125
+ * kỳ ai cũng tự tạo được một token có claim tuỳ ý và hàm này sẽ vui vẻ trả về. Vì vậy kết quả CHỈ
126
+ * dùng cho mục đích hiển thị (tên, avatar, tenant đang chọn…) và TUYỆT ĐỐI không được dùng để ra
127
+ * quyết định phân quyền — quyền phải do backend xác thực chữ ký rồi trả về.
128
+ *
129
+ * Trả `null` khi không có token hoặc payload hỏng.
130
+ */
131
+ readUnverifiedTokenClaims: <T>(key?: string) => Promise<T | null>;
132
+ /**
133
+ * @deprecated Tên `decodeToken` gợi ý một thao tác đã được kiểm chứng, trong khi thực tế payload
134
+ * hoàn toàn KHÔNG được xác thực. Dùng {@link readUnverifiedTokenClaims} — alias này chỉ còn để
135
+ * consumer cũ không vỡ và sẽ bị gỡ ở release sau.
136
+ */
75
137
  decodeToken: <T>(key?: string) => Promise<T | null>;
76
138
  static ɵfac: i0.ɵɵFactoryDeclaration<SdPermissionService, never>;
77
139
  static ɵprov: i0.ɵɵInjectableDeclaration<SdPermissionService>;
@@ -79,7 +141,7 @@ declare class SdPermissionService {
79
141
 
80
142
  declare class SdPermissionDirective {
81
143
  #private;
82
- readonly sdPermission: i0.InputSignal<string | string[] | null | undefined>;
144
+ readonly sdPermission: i0.InputSignal<SdPermissionInput>;
83
145
  readonly sdPermissionKey: i0.InputSignal<string | undefined>;
84
146
  constructor();
85
147
  static ɵfac: i0.ɵɵFactoryDeclaration<SdPermissionDirective, never>;
@@ -96,5 +158,5 @@ declare class SdPermissionGuard implements CanActivate, CanActivateChild {
96
158
  static ɵprov: i0.ɵɵInjectableDeclaration<SdPermissionGuard>;
97
159
  }
98
160
 
99
- export { SD_PERMISSION_CONFIGURATION, SdPermissionDirective, SdPermissionGuard, SdPermissionService };
100
- export type { ISdPermissionConfiguration };
161
+ export { SD_PERMISSION_CONFIGURATION, SD_PERMISSION_PUBLIC, SdPermissionDirective, SdPermissionGuard, SdPermissionService };
162
+ export type { ISdPermissionConfiguration, SdPermissionInput };