overview-components 1.1.162 → 1.1.166

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 (252) hide show
  1. package/dist/assets/generated/locales/de.js +269 -0
  2. package/dist/assets/generated/locales/de.js.map +1 -0
  3. package/dist/assets/generated/locales/en.js +269 -0
  4. package/dist/assets/generated/locales/en.js.map +1 -0
  5. package/dist/assets/generated/locales/fr.js +269 -0
  6. package/dist/assets/generated/locales/fr.js.map +1 -0
  7. package/dist/assets/generated/locales/hr.js +269 -0
  8. package/dist/assets/generated/locales/hr.js.map +1 -0
  9. package/dist/assets/generated/locales/it.js +269 -0
  10. package/dist/assets/generated/locales/it.js.map +1 -0
  11. package/dist/assets/generated/locales/pl.js +269 -0
  12. package/dist/assets/generated/locales/pl.js.map +1 -0
  13. package/dist/assets/generated/locales/ro.js +269 -0
  14. package/dist/assets/generated/locales/ro.js.map +1 -0
  15. package/dist/assets/generated/locales/sk.js +269 -0
  16. package/dist/assets/generated/locales/sk.js.map +1 -0
  17. package/dist/assets/generated/locales/sr.js +269 -0
  18. package/dist/assets/generated/locales/sr.js.map +1 -0
  19. package/dist/assets/icons/iconGlyphs.js +691 -0
  20. package/dist/assets/icons/iconGlyphs.js.map +1 -0
  21. package/dist/assets/illustration/aichatbot-illustration.js +144 -0
  22. package/dist/assets/illustration/aichatbot-illustration.js.map +1 -0
  23. package/dist/assets/illustration/delete-illustration.js +88 -0
  24. package/dist/assets/illustration/delete-illustration.js.map +1 -0
  25. package/dist/assets/illustration/no-content.js +159 -0
  26. package/dist/assets/illustration/no-content.js.map +1 -0
  27. package/dist/assets/illustration/no-preview.js +125 -0
  28. package/dist/assets/illustration/no-preview.js.map +1 -0
  29. package/dist/assets/illustration/not-found.js +98 -0
  30. package/dist/assets/illustration/not-found.js.map +1 -0
  31. package/dist/assets/illustration/settings-illustration.js +168 -0
  32. package/dist/assets/illustration/settings-illustration.js.map +1 -0
  33. package/dist/components/components-settings/attachments-tab-settings.js +318 -0
  34. package/dist/components/components-settings/attachments-tab-settings.js.map +1 -0
  35. package/dist/components/components-settings/data-grid-settings.js +553 -0
  36. package/dist/components/components-settings/data-grid-settings.js.map +1 -0
  37. package/dist/components/components-settings/section-tab-settings.js +719 -0
  38. package/dist/components/components-settings/section-tab-settings.js.map +1 -0
  39. package/dist/components/components-settings/tabs-overview-settings.js +421 -0
  40. package/dist/components/components-settings/tabs-overview-settings.js.map +1 -0
  41. package/dist/components/index.js +30 -0
  42. package/dist/components/index.js.map +1 -0
  43. package/dist/components/lit-ai-filter-assistant.js +443 -0
  44. package/dist/components/lit-ai-filter-assistant.js.map +1 -0
  45. package/dist/components/lit-attachments-tab.js +2044 -0
  46. package/dist/components/lit-attachments-tab.js.map +1 -0
  47. package/dist/components/lit-badge.js +124 -0
  48. package/dist/components/lit-badge.js.map +1 -0
  49. package/dist/components/lit-case-variables-tab.d.ts +3 -0
  50. package/dist/components/lit-case-variables-tab.d.ts.map +1 -1
  51. package/dist/components/lit-case-variables-tab.js +3781 -0
  52. package/dist/components/lit-case-variables-tab.js.map +1 -0
  53. package/dist/components/lit-chart.js +727 -0
  54. package/dist/components/lit-chart.js.map +1 -0
  55. package/dist/components/lit-data-grid-tanstack.js +2550 -0
  56. package/dist/components/lit-data-grid-tanstack.js.map +1 -0
  57. package/dist/components/lit-filter-builder.js +701 -0
  58. package/dist/components/lit-filter-builder.js.map +1 -0
  59. package/dist/components/lit-filter-modal.js +349 -0
  60. package/dist/components/lit-filter-modal.js.map +1 -0
  61. package/dist/components/lit-multiselect-item.js +707 -0
  62. package/dist/components/lit-multiselect-item.js.map +1 -0
  63. package/dist/components/lit-section-tab.js +268 -0
  64. package/dist/components/lit-section-tab.js.map +1 -0
  65. package/dist/components/lit-tabs-overview.js +356 -0
  66. package/dist/components/lit-tabs-overview.js.map +1 -0
  67. package/dist/components/modals/lit-confirm-modal.js +121 -0
  68. package/dist/components/modals/lit-confirm-modal.js.map +1 -0
  69. package/dist/components/modals/lit-delete-modal.js +131 -0
  70. package/dist/components/modals/lit-delete-modal.js.map +1 -0
  71. package/dist/components/react-wrappers/ai-filter-assistant.js +9 -0
  72. package/dist/components/react-wrappers/ai-filter-assistant.js.map +1 -0
  73. package/dist/components/react-wrappers/attachments-tab.js +9 -0
  74. package/dist/components/react-wrappers/attachments-tab.js.map +1 -0
  75. package/dist/components/react-wrappers/badge.js +9 -0
  76. package/dist/components/react-wrappers/badge.js.map +1 -0
  77. package/dist/components/react-wrappers/button.js +9 -0
  78. package/dist/components/react-wrappers/button.js.map +1 -0
  79. package/dist/components/react-wrappers/calendar.js +9 -0
  80. package/dist/components/react-wrappers/calendar.js.map +1 -0
  81. package/dist/components/react-wrappers/case-variables-tab.js +9 -0
  82. package/dist/components/react-wrappers/case-variables-tab.js.map +1 -0
  83. package/dist/components/react-wrappers/chart.js +9 -0
  84. package/dist/components/react-wrappers/chart.js.map +1 -0
  85. package/dist/components/react-wrappers/data-grid-tanstack.js +9 -0
  86. package/dist/components/react-wrappers/data-grid-tanstack.js.map +1 -0
  87. package/dist/components/react-wrappers/filter-builder.js +12 -0
  88. package/dist/components/react-wrappers/filter-builder.js.map +1 -0
  89. package/dist/components/react-wrappers/filter-modal.js +9 -0
  90. package/dist/components/react-wrappers/filter-modal.js.map +1 -0
  91. package/dist/components/react-wrappers/index.js +27 -0
  92. package/dist/components/react-wrappers/index.js.map +1 -0
  93. package/dist/components/react-wrappers/progress-bar.js +9 -0
  94. package/dist/components/react-wrappers/progress-bar.js.map +1 -0
  95. package/dist/components/react-wrappers/section-tab.js +9 -0
  96. package/dist/components/react-wrappers/section-tab.js.map +1 -0
  97. package/dist/components/react-wrappers/tabs-overview.js +9 -0
  98. package/dist/components/react-wrappers/tabs-overview.js.map +1 -0
  99. package/dist/data/translations.js +2768 -0
  100. package/dist/data/translations.js.map +1 -0
  101. package/dist/index.d.ts +0 -1
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +7 -22487
  104. package/dist/index.js.map +1 -0
  105. package/dist/schemas/index.js +18 -0
  106. package/dist/schemas/index.js.map +1 -0
  107. package/dist/schemas/lit-attachments-tab-document.schema.js +39 -0
  108. package/dist/schemas/lit-attachments-tab-document.schema.js.map +1 -0
  109. package/dist/schemas/lit-attachments-tab-settings-value.schema.js +30 -0
  110. package/dist/schemas/lit-attachments-tab-settings-value.schema.js.map +1 -0
  111. package/dist/schemas/lit-attachments-tab.schema.js +68 -0
  112. package/dist/schemas/lit-attachments-tab.schema.js.map +1 -0
  113. package/dist/schemas/lit-case-variables-tab-cell.schema.d.ts +3 -0
  114. package/dist/schemas/lit-case-variables-tab-cell.schema.d.ts.map +1 -1
  115. package/dist/schemas/lit-case-variables-tab-cell.schema.js +226 -0
  116. package/dist/schemas/lit-case-variables-tab-cell.schema.js.map +1 -0
  117. package/dist/schemas/lit-case-variables-tab-rows.schema.d.ts +3 -0
  118. package/dist/schemas/lit-case-variables-tab-rows.schema.d.ts.map +1 -1
  119. package/dist/schemas/lit-case-variables-tab-rows.schema.js +6 -0
  120. package/dist/schemas/lit-case-variables-tab-rows.schema.js.map +1 -0
  121. package/dist/schemas/lit-case-variables-tab.schema.d.ts +6 -0
  122. package/dist/schemas/lit-case-variables-tab.schema.d.ts.map +1 -1
  123. package/dist/schemas/lit-case-variables-tab.schema.js +27 -0
  124. package/dist/schemas/lit-case-variables-tab.schema.js.map +1 -0
  125. package/dist/schemas/lit-data-grid-tanstack-column-array.schema.js +6 -0
  126. package/dist/schemas/lit-data-grid-tanstack-column-array.schema.js.map +1 -0
  127. package/dist/schemas/lit-data-grid-tanstack-column-custom-filter-array.schema.js +6 -0
  128. package/dist/schemas/lit-data-grid-tanstack-column-custom-filter-array.schema.js.map +1 -0
  129. package/dist/schemas/lit-data-grid-tanstack-column-custom-filter.schema.js +11 -0
  130. package/dist/schemas/lit-data-grid-tanstack-column-custom-filter.schema.js.map +1 -0
  131. package/dist/schemas/lit-data-grid-tanstack-column.schema.js +79 -0
  132. package/dist/schemas/lit-data-grid-tanstack-column.schema.js.map +1 -0
  133. package/dist/schemas/lit-data-grid-tanstack.schema.js +108 -0
  134. package/dist/schemas/lit-data-grid-tanstack.schema.js.map +1 -0
  135. package/dist/schemas/lit-filter-builder.schema.js +61 -0
  136. package/dist/schemas/lit-filter-builder.schema.js.map +1 -0
  137. package/dist/schemas/lit-section-tab-schema.js +37 -0
  138. package/dist/schemas/lit-section-tab-schema.js.map +1 -0
  139. package/dist/schemas/lit-tabs-overview-tab-array.schema.js +6 -0
  140. package/dist/schemas/lit-tabs-overview-tab-array.schema.js.map +1 -0
  141. package/dist/schemas/lit-tabs-overview-tab.schema.js +32 -0
  142. package/dist/schemas/lit-tabs-overview-tab.schema.js.map +1 -0
  143. package/dist/schemas/lit-tabs-overview.schema.js +29 -0
  144. package/dist/schemas/lit-tabs-overview.schema.js.map +1 -0
  145. package/dist/scripts/translate-locales.js +241 -0
  146. package/dist/scripts/translate-locales.js.map +1 -0
  147. package/dist/shared/filter-inputs.js +429 -0
  148. package/dist/shared/filter-inputs.js.map +1 -0
  149. package/dist/shared/index.js +40 -0
  150. package/dist/shared/index.js.map +1 -0
  151. package/dist/shared/lit-button.js +159 -0
  152. package/dist/shared/lit-button.js.map +1 -0
  153. package/dist/shared/lit-calendar.js +485 -0
  154. package/dist/shared/lit-calendar.js.map +1 -0
  155. package/dist/shared/lit-case-variables-tab-cell.d.ts +2 -0
  156. package/dist/shared/lit-case-variables-tab-cell.d.ts.map +1 -1
  157. package/dist/shared/lit-case-variables-tab-cell.js +235 -0
  158. package/dist/shared/lit-case-variables-tab-cell.js.map +1 -0
  159. package/dist/shared/lit-checkbox.js +184 -0
  160. package/dist/shared/lit-checkbox.js.map +1 -0
  161. package/dist/shared/lit-custom-popper.js +116 -0
  162. package/dist/shared/lit-custom-popper.js.map +1 -0
  163. package/dist/shared/lit-data-grid-action-buttons-popover.js +295 -0
  164. package/dist/shared/lit-data-grid-action-buttons-popover.js.map +1 -0
  165. package/dist/shared/lit-data-grid-density-popover.js +84 -0
  166. package/dist/shared/lit-data-grid-density-popover.js.map +1 -0
  167. package/dist/shared/lit-data-grid-export-popover.js +68 -0
  168. package/dist/shared/lit-data-grid-export-popover.js.map +1 -0
  169. package/dist/shared/lit-data-grid-operators-popover.js +114 -0
  170. package/dist/shared/lit-data-grid-operators-popover.js.map +1 -0
  171. package/dist/shared/lit-data-grid-row-actions.js +87 -0
  172. package/dist/shared/lit-data-grid-row-actions.js.map +1 -0
  173. package/dist/shared/lit-date-picker.js +608 -0
  174. package/dist/shared/lit-date-picker.js.map +1 -0
  175. package/dist/shared/lit-document-thumbnail.js +383 -0
  176. package/dist/shared/lit-document-thumbnail.js.map +1 -0
  177. package/dist/shared/lit-filter-input.js +115 -0
  178. package/dist/shared/lit-filter-input.js.map +1 -0
  179. package/dist/shared/lit-icon-button.js +165 -0
  180. package/dist/shared/lit-icon-button.js.map +1 -0
  181. package/dist/shared/lit-icon.js +337 -0
  182. package/dist/shared/lit-icon.js.map +1 -0
  183. package/dist/shared/lit-input.js +282 -0
  184. package/dist/shared/lit-input.js.map +1 -0
  185. package/dist/shared/lit-label.js +103 -0
  186. package/dist/shared/lit-label.js.map +1 -0
  187. package/dist/shared/lit-loader.js +68 -0
  188. package/dist/shared/lit-loader.js.map +1 -0
  189. package/dist/shared/lit-loading-bar.js +91 -0
  190. package/dist/shared/lit-loading-bar.js.map +1 -0
  191. package/dist/shared/lit-menu-item.js +98 -0
  192. package/dist/shared/lit-menu-item.js.map +1 -0
  193. package/dist/shared/lit-menu.js +29 -0
  194. package/dist/shared/lit-menu.js.map +1 -0
  195. package/dist/shared/lit-modal-body.js +24 -0
  196. package/dist/shared/lit-modal-body.js.map +1 -0
  197. package/dist/shared/lit-modal-footer.js +21 -0
  198. package/dist/shared/lit-modal-footer.js.map +1 -0
  199. package/dist/shared/lit-modal-header.js +34 -0
  200. package/dist/shared/lit-modal-header.js.map +1 -0
  201. package/dist/shared/lit-modal.js +168 -0
  202. package/dist/shared/lit-modal.js.map +1 -0
  203. package/dist/shared/lit-overflow-tooltip.js +114 -0
  204. package/dist/shared/lit-overflow-tooltip.js.map +1 -0
  205. package/dist/shared/lit-pill.js +87 -0
  206. package/dist/shared/lit-pill.js.map +1 -0
  207. package/dist/shared/lit-progress-bar.js +130 -0
  208. package/dist/shared/lit-progress-bar.js.map +1 -0
  209. package/dist/shared/lit-responsive-button.js +106 -0
  210. package/dist/shared/lit-responsive-button.js.map +1 -0
  211. package/dist/shared/lit-select-field.js +457 -0
  212. package/dist/shared/lit-select-field.js.map +1 -0
  213. package/dist/shared/lit-select.js +668 -0
  214. package/dist/shared/lit-select.js.map +1 -0
  215. package/dist/shared/lit-settings.js +76 -0
  216. package/dist/shared/lit-settings.js.map +1 -0
  217. package/dist/shared/lit-text-field.js +252 -0
  218. package/dist/shared/lit-text-field.js.map +1 -0
  219. package/dist/shared/lit-toggle.js +240 -0
  220. package/dist/shared/lit-toggle.js.map +1 -0
  221. package/dist/shared/lit-tooltip.js +165 -0
  222. package/dist/shared/lit-tooltip.js.map +1 -0
  223. package/dist/shared/simple-popper.js +285 -0
  224. package/dist/shared/simple-popper.js.map +1 -0
  225. package/dist/shared/simple-tooltip.js +249 -0
  226. package/dist/shared/simple-tooltip.js.map +1 -0
  227. package/dist/shared/styles/button-shared-styles.js +494 -0
  228. package/dist/shared/styles/button-shared-styles.js.map +1 -0
  229. package/dist/styles.js +169 -0
  230. package/dist/styles.js.map +1 -0
  231. package/dist/utils/custom-filters.js +42 -0
  232. package/dist/utils/custom-filters.js.map +1 -0
  233. package/dist/utils/date.js +21 -0
  234. package/dist/utils/date.js.map +1 -0
  235. package/dist/utils/file-type-utils.js +55 -0
  236. package/dist/utils/file-type-utils.js.map +1 -0
  237. package/dist/utils/formatNumber.js +62 -0
  238. package/dist/utils/formatNumber.js.map +1 -0
  239. package/dist/utils/getOperatorByType.js +70 -0
  240. package/dist/utils/getOperatorByType.js.map +1 -0
  241. package/dist/utils/getOverviewValue.js +175 -0
  242. package/dist/utils/getOverviewValue.js.map +1 -0
  243. package/dist/utils/localization.js +433 -0
  244. package/dist/utils/localization.js.map +1 -0
  245. package/dist/utils/pdf-thumbnail-generator.js +91 -0
  246. package/dist/utils/pdf-thumbnail-generator.js.map +1 -0
  247. package/dist/utils/utils.js +94 -0
  248. package/dist/utils/utils.js.map +1 -0
  249. package/package.json +21 -55
  250. package/README.md +0 -82
  251. package/dist/assets/illustration/index.d.ts +0 -7
  252. package/dist/assets/illustration/index.d.ts.map +0 -1
@@ -0,0 +1,3781 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement, html, css } from 'lit';
8
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
9
+ import { styleMap } from 'lit/directives/style-map.js';
10
+ import { property, state } from 'lit/decorators.js';
11
+ import Sortable from 'sortablejs';
12
+ import { repeat } from 'lit/directives/repeat.js';
13
+ import { Pane } from 'tweakpane';
14
+ // components
15
+ import '../shared/lit-icon.js';
16
+ import '../shared/lit-button.js';
17
+ import '../shared/lit-menu.js';
18
+ import '../shared/lit-menu-item.js';
19
+ import '../shared/lit-checkbox.js';
20
+ import '../shared/lit-input.js';
21
+ import '../shared/simple-popper.js';
22
+ import '../assets/illustration/not-found.js';
23
+ import { tooltip } from '../shared/simple-tooltip.js';
24
+ import '../shared/lit-tooltip.js';
25
+ import '../shared/lit-progress-bar.js';
26
+ import '../shared/lit-modal.js';
27
+ import '../shared/lit-modal-header.js';
28
+ import '../shared/lit-modal-body.js';
29
+ import '../shared/lit-modal-footer.js';
30
+ import '../shared/lit-select-field.js';
31
+ import '../shared/lit-select.js';
32
+ import '../shared/lit-label.js';
33
+ import '../shared/lit-icon-button.js';
34
+ import '../shared/lit-toggle.js';
35
+ import '../shared/lit-text-field.js';
36
+ import './lit-tabs-overview.js';
37
+ // utils
38
+ import { formatDate } from '../utils/date.js';
39
+ import { formatCurrency, formatDecimal } from '../utils/formatNumber.js';
40
+ import { setLocale, getLocale, LOCALE_LANGS } from '../utils/localization.js';
41
+ import { msg } from '@lit/localize';
42
+ import { isEqual } from 'lodash';
43
+ import { getOperatorsByColumnType, getDefaultOperator, } from '../utils/getOperatorByType.js';
44
+ export class LitCaseVariablesTab extends LitElement {
45
+ constructor() {
46
+ super(...arguments);
47
+ this.rows = [];
48
+ this.variables = [];
49
+ this.hideTabWhen = false;
50
+ this.userLang = 'cs';
51
+ this.allowedLang = ['cs'];
52
+ this.dateFormat = null;
53
+ this.isLoading = false;
54
+ this.enableSettings = false;
55
+ this.gridVariables = false;
56
+ this.onSettingsChanged = (rows) => { };
57
+ this.hostURL = '';
58
+ this.currentBreakpoint = this.getBreakpoint();
59
+ this.isOpen = false;
60
+ this.filterText = '';
61
+ this.isMobile = window.innerWidth <= 600;
62
+ this.expertModeModalOpen = false;
63
+ this.expertModeCell = null;
64
+ this.expertModeConfig = {
65
+ enabled: false,
66
+ leftType: 'column',
67
+ leftSource: '',
68
+ leftValue: '',
69
+ leftAggregation: 'sum',
70
+ operation: 'none',
71
+ rightType: 'variable',
72
+ rightSource: '',
73
+ rightValue: '',
74
+ rightAggregation: 'sum',
75
+ headerName: '',
76
+ headerNameMutations: {},
77
+ pmEnabled: false,
78
+ pmLeftType: 'column',
79
+ pmLeftSource: '',
80
+ pmLeftValue: '',
81
+ pmLeftAggregation: 'sum',
82
+ pmOperation: 'none',
83
+ pmRightType: 'variable',
84
+ pmRightSource: '',
85
+ pmRightValue: '',
86
+ pmRightAggregation: 'sum',
87
+ };
88
+ this._resolvedExpertValues = new Map();
89
+ this._resizeListener = this.handleResize.bind(this);
90
+ this.sortableInstances = [];
91
+ this.settingsPanes = new Map();
92
+ this.operatorInputs = new Map(); // Track conditional formatting operator inputs
93
+ this.conditionValueInputs = new Map(); // Track conditional formatting value inputs
94
+ this.hideOperatorInputs = new Map(); // Track hide condition operator inputs
95
+ this.hideValueInputs = new Map(); // Track hide condition value inputs
96
+ this.sortableGroupId = `group-${Math.random().toString(36).substring(2, 9)}`;
97
+ this.activeSettingsCell = null;
98
+ this.settingsPopperOpen = false;
99
+ this.conditionSubFolders = new Map();
100
+ this.language = 'cs';
101
+ this.BREAKPOINTS = ['xs', 'sm', 'md', 'lg', 'xl'];
102
+ this.closeSettingsPopper = () => {
103
+ // Clean up any existing tweakpanes before closing
104
+ this.destroySettingsPanes();
105
+ this.settingsPopperOpen = false;
106
+ this.activeSettingsCell = null;
107
+ };
108
+ this.handleSettingsChanged = (newRows) => {
109
+ this.onSettingsChanged?.(newRows);
110
+ };
111
+ this.addCustomEmptyCell = () => {
112
+ // Generate a unique field name for the custom cell
113
+ const customCellCount = this.rows.filter((cell) => cell.field.startsWith('custom_cell_')).length;
114
+ const fieldName = `custom_cell_${customCellCount + 1}`;
115
+ // Create a new empty custom cell (without tooltip, headerName, or value)
116
+ const newCell = {
117
+ field: fieldName,
118
+ type: 'string',
119
+ size: { xs: 4, sm: 2, md: 1, lg: 1, xl: 1 },
120
+ };
121
+ const newRows = [...this.rows, newCell];
122
+ this.rows = newRows;
123
+ this.handleSettingsChanged(newRows);
124
+ // Automatically open settings for the new cell to allow user to customize it
125
+ setTimeout(() => {
126
+ this.toggleSettingsPane(newCell);
127
+ }, 100);
128
+ };
129
+ this.getHeaderActions = (cell) => {
130
+ return html `<div class="header-buttons">
131
+ ${this.enableSettings
132
+ ? html `
133
+ <div style="position: relative;">
134
+ <lit-icon
135
+ icon="cog"
136
+ size="1rem"
137
+ style="cursor: pointer"
138
+ @click=${() => this.toggleSettingsPane(cell)}
139
+ id="settings-trigger-${cell.field}"
140
+ ></lit-icon>
141
+
142
+ ${this.activeSettingsCell?.field === cell.field
143
+ ? html `
144
+ <simple-popper
145
+ .showing=${this.settingsPopperOpen}
146
+ .placement=${'bottom'}
147
+ .manualOpening=${true}
148
+ .maxWidthAsTarget=${false}
149
+ .onClose=${this.closeSettingsPopper}
150
+ >
151
+ ${this.renderSettingsContent()}
152
+ </simple-popper>
153
+ `
154
+ : ''}
155
+ </div>
156
+
157
+ <div class="drag-handle">
158
+ <lit-icon icon="hamburger" size="1rem"></lit-icon>
159
+ </div>
160
+ `
161
+ : null}
162
+ </div>`;
163
+ };
164
+ this.getHeaderLabel = (cell) => {
165
+ const tooltipText = cell?.[`tooltip_${(this.userLang)}`] || cell?.tooltip;
166
+ return html ` <div
167
+ style="${cell?.headerStyle ? styleMap(cell?.headerStyle) : ''}"
168
+ class="process-data-heading"
169
+ >
170
+ ${cell?.[`headerName_${(this.userLang)}`] ||
171
+ cell?.headerName ||
172
+ ''}
173
+ ${tooltipText
174
+ ? html `
175
+ <lit-icon
176
+ ${tooltip(tooltipText, 'right', 100)}
177
+ size="12px"
178
+ icon="informative"
179
+ ></lit-icon>
180
+ `
181
+ : ''}
182
+ </div>`;
183
+ };
184
+ this.getHeader = (cell) => {
185
+ return html ` <div class="header-cell">
186
+ ${this.getHeaderLabel(cell)} ${this.getHeaderActions(cell)}
187
+ </div>`;
188
+ };
189
+ this.handleButtonClick = (cell) => {
190
+ // First try the original buttonFn if it exists and is a function
191
+ if (cell.buttonFn && typeof cell.buttonFn === 'function') {
192
+ cell.buttonFn();
193
+ return;
194
+ }
195
+ const url = this.getLinkUrl(cell);
196
+ if (!url)
197
+ return;
198
+ const openInNewTab = cell.openInNewTab !== false;
199
+ if (!openInNewTab && cell.linkType === 'dynamic') {
200
+ this.dispatchDynamicLinkEvent(cell, url);
201
+ return;
202
+ }
203
+ if (openInNewTab) {
204
+ window.open(url, '_blank');
205
+ }
206
+ else {
207
+ window.location.href = url;
208
+ }
209
+ };
210
+ this.getCellButton = (cell) => {
211
+ return html `
212
+ <div style="display: flex; justify-content: space-between">
213
+ <lit-button
214
+ style="flex-grow: 1; margin-right: 0.5rem"
215
+ .fullWidth="${cell.buttonFullWidth}"
216
+ variant="${cell.buttonVariant || 'contained'}"
217
+ color="${cell.buttonColor || 'primary'}"
218
+ label="${cell?.headerName}"
219
+ @click=${() => this.handleButtonClick(cell)}
220
+ ></lit-button>
221
+ ${this.getHeaderActions(cell)}
222
+ </div>
223
+ `;
224
+ };
225
+ this.getCellLink = (cell) => {
226
+ const linkUrl = this.getLinkUrl(cell);
227
+ const displayText = cell?.value || linkUrl || '';
228
+ const openInNewTab = cell.openInNewTab !== false;
229
+ const dispatchEvent = !openInNewTab && cell.linkType === 'dynamic';
230
+ const onClick = dispatchEvent
231
+ ? (e) => {
232
+ e.preventDefault();
233
+ this.dispatchDynamicLinkEvent(cell, linkUrl);
234
+ }
235
+ : undefined;
236
+ return html `<div>${this.getHeader(cell)}</div>
237
+ <a
238
+ class="link"
239
+ href=${linkUrl}
240
+ target=${openInNewTab ? '_blank' : '_self'}
241
+ rel=${openInNewTab ? 'noopener noreferrer' : ''}
242
+ @click=${onClick}
243
+ >${displayText}
244
+ </a> `;
245
+ };
246
+ this.getCellValue = (cell) => {
247
+ const langValue = cell?.[`value_${(this.userLang)}`];
248
+ const rawValue = (langValue !== null && langValue !== undefined && langValue !== '') ? langValue : (cell?.value ?? '');
249
+ const value = this.formatDisplayValue(rawValue);
250
+ return html `<div>${this.getHeader(cell)}</div>
251
+ <div
252
+ style="${styleMap(this.computeValueStyles(cell))}"
253
+ class="process-data-value"
254
+ >
255
+ ${unsafeHTML(value)}
256
+ </div> `;
257
+ };
258
+ this.getCellDate = (cell) => {
259
+ return html `<div>${this.getHeader(cell)}</div>
260
+ <div
261
+ style="${styleMap(this.computeValueStyles(cell))}"
262
+ class="process-data-value"
263
+ >
264
+ ${cell?.value
265
+ ? formatDate(cell.value, this.getLocaleLang(), !!this.dateFormat, this.dateFormat)
266
+ : ''}
267
+ </div> `;
268
+ };
269
+ this.getCellCurrency = (cell) => {
270
+ const resolvedCurrency = this.resolveCurrencyType(cell);
271
+ return html `<div>${this.getHeader(cell)}</div>
272
+ <div
273
+ style="${styleMap(this.computeValueStyles(cell))}"
274
+ class="process-data-value"
275
+ >
276
+ ${cell?.value != null
277
+ ? formatCurrency(cell.value, {
278
+ locale: this.getLocaleLang(),
279
+ currency: resolvedCurrency,
280
+ numberOfDecimal: typeof cell.numberOfDecimal === 'number' ? cell.numberOfDecimal : 2,
281
+ })
282
+ : ''}
283
+ </div> `;
284
+ };
285
+ this.getCellNumber = (cell) => {
286
+ return html `<div>${this.getHeader(cell)}</div>
287
+ <div
288
+ style="${styleMap(this.computeValueStyles(cell))}"
289
+ class="process-data-value"
290
+ >
291
+ ${cell?.value != null
292
+ ? formatDecimal(cell.value, {
293
+ locale: this.getLocaleLang(),
294
+ numberOfDecimal: typeof cell.numberOfDecimal === 'number'
295
+ ? cell.numberOfDecimal
296
+ : undefined,
297
+ })
298
+ : ''}
299
+ </div> `;
300
+ };
301
+ this.getCellProgress = (cell) => {
302
+ const numericValue = this.parseProgressValue(cell?.value);
303
+ const progressMax = this.resolveProgressMax(cell);
304
+ const percentage = progressMax > 0 ? (numericValue / progressMax) * 100 : 0;
305
+ const progressColor = this.computeProgressColor(cell);
306
+ return html `<div>${this.getHeader(cell)}</div>
307
+ <div
308
+ style="${styleMap(this.computeValueStyles(cell))}"
309
+ class="process-data-value"
310
+ >
311
+ <lit-progress-bar
312
+ .progress="${percentage}"
313
+ .color="${progressColor}"
314
+ label=""
315
+ style="width: 100%;"
316
+ ></lit-progress-bar>
317
+ </div> `;
318
+ };
319
+ this.getCellCheckbox = (cell) => {
320
+ const checked = this.parseBooleanValue(cell?.value);
321
+ return html `<div>${this.getHeader(cell)}</div>
322
+ <div class="process-data-value">
323
+ <lit-checkbox
324
+ .checked=${checked}
325
+ .disabled=${true}
326
+ ></lit-checkbox>
327
+ </div> `;
328
+ };
329
+ this.getInlineCellValue = (cell) => {
330
+ const langVal = cell?.[`value_${(this.userLang)}`];
331
+ let rawValue = (langVal !== null && langVal !== undefined && langVal !== '') ? langVal : (cell?.value ?? '');
332
+ let value = this.formatDisplayValue(rawValue);
333
+ // Format value based on cell.type
334
+ switch (cell.type) {
335
+ case 'currency':
336
+ value = cell?.value != null
337
+ ? formatCurrency(cell.value, {
338
+ locale: this.getLocaleLang(),
339
+ currency: this.resolveCurrencyType(cell),
340
+ numberOfDecimal: typeof cell.numberOfDecimal === 'number' ? cell.numberOfDecimal : 2,
341
+ })
342
+ : '';
343
+ break;
344
+ case 'number':
345
+ value = cell?.value != null
346
+ ? formatDecimal(cell.value, {
347
+ locale: this.getLocaleLang(),
348
+ numberOfDecimal: typeof cell.numberOfDecimal === 'number'
349
+ ? cell.numberOfDecimal
350
+ : undefined,
351
+ })
352
+ : '';
353
+ break;
354
+ case 'date':
355
+ value = cell?.value
356
+ ? formatDate(cell.value, this.getLocaleLang(), !!this.dateFormat, this.dateFormat)
357
+ : '';
358
+ break;
359
+ case 'progress':
360
+ // For progress, show percentage value based on progressMax variable
361
+ const progressNumeric = this.parseProgressValue(cell?.value);
362
+ const progressMaxVal = this.resolveProgressMax(cell);
363
+ const progressPercent = progressMaxVal > 0 ? (progressNumeric / progressMaxVal) * 100 : 0;
364
+ value = `${parseFloat(progressPercent.toFixed(2))}%`;
365
+ break;
366
+ case 'checkbox':
367
+ value = this.parseBooleanValue(cell?.value) ? msg('Ano') : msg('Ne');
368
+ break;
369
+ default:
370
+ value = this.formatDisplayValue(rawValue);
371
+ }
372
+ return html `
373
+ <div style="display: flex;align-items: center; justify-content: end; gap: 0.5rem;">
374
+ <div
375
+ style="${styleMap({
376
+ ...this.computeCellStyles(cell),
377
+ width: 'fit-content',
378
+ display: 'flex',
379
+ alignItems: 'center',
380
+ justifyContent: 'end',
381
+ gap: '0.5rem',
382
+ padding: '0.375rem',
383
+ })}"
384
+ >
385
+ <div
386
+ style="display: flex;align-items: center; justify-content: end; gap: 0.5rem; flex-direction: row"
387
+ >
388
+ <div>${this.getHeaderLabel(cell)}</div>
389
+ <div
390
+ style="${styleMap(this.computeValueStyles(cell))}"
391
+ class="process-data-value"
392
+ >
393
+ ${value}
394
+ </div>
395
+ <div>${this.getHeaderActions(cell)}</div>
396
+ </div>
397
+ </div>
398
+ </div>
399
+ `;
400
+ };
401
+ }
402
+ normalizeConditions(formatting) {
403
+ if (!formatting)
404
+ return [];
405
+ // Backward compat: single object → wrap in array
406
+ const arr = Array.isArray(formatting) ? formatting : [formatting];
407
+ // Ensure every condition property has a concrete type (tweakpane throws
408
+ // "No matching controller" when a bound value is undefined/null/unsupported)
409
+ const defaults = {
410
+ enabled: true,
411
+ variable: '',
412
+ operator: '',
413
+ value: '',
414
+ cellVariant: 'default',
415
+ valueVariant: 'default',
416
+ progressColor: 'primary',
417
+ };
418
+ return arr.map((c) => ({
419
+ ...defaults,
420
+ ...c,
421
+ // Force value to string — it may arrive as number, array, object, null
422
+ value: c.value != null ? String(c.value) : '',
423
+ enabled: typeof c.enabled === 'boolean' ? c.enabled : true,
424
+ }));
425
+ }
426
+ createDefaultCondition(cell) {
427
+ return {
428
+ enabled: true,
429
+ variable: cell.field,
430
+ operator: this.getDefaultOperatorForCell(cell),
431
+ value: '',
432
+ cellVariant: 'default',
433
+ valueVariant: 'default',
434
+ progressColor: 'primary',
435
+ };
436
+ }
437
+ rebuildConditionFolders(parentFolder, config, cell) {
438
+ // Dispose old sub-folders for this cell
439
+ const key = cell.field;
440
+ const oldFolders = this.conditionSubFolders.get(key) || [];
441
+ for (const f of oldFolders) {
442
+ try {
443
+ f.dispose();
444
+ }
445
+ catch (_e) { /* already disposed */ }
446
+ }
447
+ this.conditionSubFolders.set(key, []);
448
+ // Clean up tracked inputs for this cell's conditions
449
+ for (const [k] of this.operatorInputs) {
450
+ if (k.startsWith(`${key}_condition_`)) {
451
+ this.operatorInputs.delete(k);
452
+ }
453
+ }
454
+ for (const [k] of this.conditionValueInputs) {
455
+ if (k.startsWith(`${key}_condition_`)) {
456
+ this.conditionValueInputs.delete(k);
457
+ }
458
+ }
459
+ const conditions = config.conditions;
460
+ const folders = [];
461
+ conditions.forEach((conditionObj, idx) => {
462
+ const subFolder = parentFolder.addFolder({
463
+ title: `${msg('Podmínka')} ${idx + 1}`,
464
+ expanded: idx === conditions.length - 1,
465
+ });
466
+ folders.push(subFolder);
467
+ this.buildSingleConditionFolder(subFolder, conditionObj, config, cell, idx);
468
+ // Delete condition button
469
+ const deleteBtn = subFolder.addButton({ title: msg('Smazat podmínku') });
470
+ deleteBtn.on('click', () => {
471
+ this.removeConditionFromCell(cell, idx);
472
+ config.conditions = this.normalizeConditions(this.rows.find((c) => c.field === cell.field)?.conditionalFormatting);
473
+ this.rebuildConditionFolders(parentFolder, config, cell);
474
+ });
475
+ });
476
+ this.conditionSubFolders.set(key, folders);
477
+ }
478
+ buildSingleConditionFolder(folder, conditionObj, _config, cell, conditionIndex) {
479
+ // Guard: ensure all bound properties have concrete types for tweakpane
480
+ if (typeof conditionObj.enabled !== 'boolean')
481
+ conditionObj.enabled = true;
482
+ if (typeof conditionObj.variable !== 'string')
483
+ conditionObj.variable = cell.field || '';
484
+ if (typeof conditionObj.operator !== 'string')
485
+ conditionObj.operator = '';
486
+ if (conditionObj.value == null || typeof conditionObj.value !== 'string')
487
+ conditionObj.value = conditionObj.value != null ? String(conditionObj.value) : '';
488
+ if (typeof conditionObj.cellVariant !== 'string')
489
+ conditionObj.cellVariant = 'default';
490
+ if (typeof conditionObj.valueVariant !== 'string')
491
+ conditionObj.valueVariant = 'default';
492
+ if (typeof conditionObj.progressColor !== 'string')
493
+ conditionObj.progressColor = 'primary';
494
+ // Enable toggle
495
+ const enabledInput = folder.addBinding(conditionObj, 'enabled', {
496
+ label: msg('Povolit'),
497
+ });
498
+ enabledInput.on('change', (ev) => {
499
+ this.setConditionalFormatting(cell, conditionIndex, 'enabled', ev.value);
500
+ });
501
+ // Variable selector
502
+ const variableOptions = this.getAllAvailableVariables();
503
+ if (variableOptions.length > 0) {
504
+ if (!conditionObj.variable) {
505
+ conditionObj.variable = cell.field;
506
+ this.setConditionalFormatting(cell, conditionIndex, 'variable', cell.field);
507
+ }
508
+ const variableInput = folder.addBinding(conditionObj, 'variable', {
509
+ view: 'list',
510
+ label: msg('Proměnná'),
511
+ options: variableOptions,
512
+ });
513
+ variableInput.on('change', (ev) => {
514
+ this.setConditionalFormatting(cell, conditionIndex, 'variable', ev.value);
515
+ this.updateConditionalFormattingOperators(folder, conditionObj, cell, conditionIndex, ev.value);
516
+ });
517
+ }
518
+ // Operator
519
+ const variableType = this.getVariableTypeByField(conditionObj.variable);
520
+ const tempCell = { ...cell, field: conditionObj.variable, type: variableType };
521
+ const operatorOptions = this.getOperatorOptionsForCell(tempCell);
522
+ const operatorInput = folder.addBinding(conditionObj, 'operator', {
523
+ view: 'list',
524
+ label: msg('Operátor'),
525
+ options: operatorOptions,
526
+ });
527
+ operatorInput.on('change', (ev) => {
528
+ this.setConditionalFormatting(cell, conditionIndex, 'operator', ev.value);
529
+ });
530
+ const operatorKey = `${cell.field}_condition_${conditionIndex}_operator`;
531
+ this.operatorInputs.set(operatorKey, operatorInput);
532
+ // Value input
533
+ this.addConditionalFormattingValueInput(folder, conditionObj, cell, conditionIndex, conditionObj.variable);
534
+ // Cell Variant
535
+ const cellVariantOptions = [
536
+ { text: msg('Výchozí'), value: 'default' },
537
+ { text: msg('Primární'), value: 'primary' },
538
+ { text: msg('Úspěch'), value: 'success' },
539
+ { text: msg('Varování'), value: 'warning' },
540
+ { text: msg('Chyba'), value: 'error' },
541
+ { text: msg('Informace'), value: 'info' },
542
+ ];
543
+ const cellVariantInput = folder.addBinding(conditionObj, 'cellVariant', {
544
+ view: 'list',
545
+ label: msg('Styl buňky'),
546
+ options: cellVariantOptions,
547
+ });
548
+ cellVariantInput.on('change', (ev) => {
549
+ this.setConditionalFormatting(cell, conditionIndex, 'cellVariant', ev.value);
550
+ });
551
+ this.colorizeVariantSelect(cellVariantInput, cellVariantOptions, conditionObj, 'cellVariant');
552
+ // Value Variant
553
+ const valueVariantOptions = [
554
+ { text: msg('Výchozí'), value: 'default' },
555
+ { text: msg('Primární'), value: 'primary' },
556
+ { text: msg('Úspěch'), value: 'success' },
557
+ { text: msg('Varování'), value: 'warning' },
558
+ { text: msg('Chyba'), value: 'error' },
559
+ { text: msg('Informace'), value: 'info' },
560
+ ];
561
+ const valueVariantInput = folder.addBinding(conditionObj, 'valueVariant', {
562
+ view: 'list',
563
+ label: msg('Barva hodnoty'),
564
+ options: valueVariantOptions,
565
+ });
566
+ valueVariantInput.on('change', (ev) => {
567
+ this.setConditionalFormatting(cell, conditionIndex, 'valueVariant', ev.value);
568
+ });
569
+ this.colorizeVariantSelect(valueVariantInput, valueVariantOptions, conditionObj, 'valueVariant');
570
+ // Progress Color (only for progress type)
571
+ if (cell.type === 'progress') {
572
+ const progressColorOptions = [
573
+ { text: msg('Primární'), value: 'primary' },
574
+ { text: msg('Úspěch'), value: 'success' },
575
+ { text: msg('Varování'), value: 'warning' },
576
+ { text: msg('Chyba'), value: 'error' },
577
+ { text: msg('Informace'), value: 'info' },
578
+ ];
579
+ const progressColorInput = folder.addBinding(conditionObj, 'progressColor', {
580
+ view: 'list',
581
+ label: msg('Barva Progressu'),
582
+ options: progressColorOptions,
583
+ });
584
+ progressColorInput.on('change', (ev) => {
585
+ this.setConditionalFormatting(cell, conditionIndex, 'progressColor', ev.value);
586
+ });
587
+ this.colorizeVariantSelect(progressColorInput, progressColorOptions, conditionObj, 'progressColor');
588
+ }
589
+ }
590
+ createCellSettingsConfig(cell) {
591
+ // If cell type is 'select' or 'multiselect', set cellType to 'string' for settings display
592
+ let cellType = cell.type || 'string';
593
+ if (cellType === 'select' || cellType === 'multiselect') {
594
+ cellType = 'string';
595
+ }
596
+ return {
597
+ size: cell.size?.lg ?? 1,
598
+ mobileSize: cell.size?.xs ?? 4,
599
+ cellVariant: cell.cellVariant || 'default',
600
+ cellCustomStyles: cell.cellCustomStyles || false,
601
+ valueVariant: cell.valueVariant || 'default',
602
+ valueCustomStyles: cell.valueCustomStyles || false,
603
+ fontWeight: cell.valueStyle?.fontWeight === 'bold',
604
+ cellType,
605
+ // Cell content properties
606
+ headerName: cell.headerName || '',
607
+ cellValue: cell.value || '',
608
+ // Cell type specific properties
609
+ href: cell.href || '',
610
+ openInNewTab: cell.openInNewTab !== false,
611
+ linkType: cell.linkType || 'custom',
612
+ dynamicLink: cell.dynamicLink || '',
613
+ numberOfDecimal: cell.numberOfDecimal ?? 2,
614
+ progressColor: cell.progressColor || 'primary',
615
+ progressMax: cell.progressMax ?? 100,
616
+ buttonVariant: cell.buttonVariant || 'contained',
617
+ buttonColor: cell.buttonColor || 'primary',
618
+ buttonFullWidth: cell.buttonFullWidth ?? false,
619
+ currencyType: cell.currencyType || 'CZK',
620
+ customCSS: JSON.stringify(cell.cellStyle || {}),
621
+ // Conditional formatting - array of conditions (backward compat: wrap single object)
622
+ conditions: this.normalizeConditions(cell.conditionalFormatting),
623
+ // Conditional hide cell settings
624
+ hideConditionEnabled: !!cell.hideCondition?.enabled,
625
+ hideConditionVariable: cell.hideCondition?.variable ?? '',
626
+ hideConditionOperator: cell.hideCondition?.operator ?? '',
627
+ hideConditionValue: cell.hideCondition?.value ?? '',
628
+ };
629
+ }
630
+ getOperatorOptionsForCell(cell) {
631
+ // Map Cell type to FieldType for operators
632
+ let variableType = 'string'; // default type
633
+ if (cell.type) {
634
+ switch (cell.type) {
635
+ case 'select':
636
+ case 'checkbox':
637
+ variableType = 'select';
638
+ break;
639
+ case 'multiselect':
640
+ variableType = 'multiselect';
641
+ break;
642
+ case 'number':
643
+ case 'currency':
644
+ case 'progress':
645
+ variableType = 'number';
646
+ break;
647
+ case 'date':
648
+ variableType = 'date';
649
+ break;
650
+ case 'string':
651
+ case 'button':
652
+ case 'link':
653
+ default:
654
+ variableType = 'string';
655
+ break;
656
+ }
657
+ }
658
+ return getOperatorsByColumnType(variableType).map((op) => ({
659
+ text: op.label,
660
+ value: op.value,
661
+ }));
662
+ }
663
+ getDefaultOperatorForCell(cell) {
664
+ let variableType = 'string'; // default type
665
+ // Map Cell type to FieldType for operators
666
+ if (cell.type) {
667
+ switch (cell.type) {
668
+ case 'select':
669
+ case 'checkbox':
670
+ variableType = 'select';
671
+ break;
672
+ case 'multiselect':
673
+ variableType = 'multiselect';
674
+ break;
675
+ case 'number':
676
+ case 'currency':
677
+ case 'progress':
678
+ variableType = 'number';
679
+ break;
680
+ case 'date':
681
+ variableType = 'date';
682
+ break;
683
+ case 'string':
684
+ case 'button':
685
+ case 'link':
686
+ default:
687
+ variableType = 'string';
688
+ break;
689
+ }
690
+ }
691
+ return getDefaultOperator(variableType);
692
+ }
693
+ getVariableTypeByField(fieldName) {
694
+ // First check variables array
695
+ const cellInVariables = this.variables.find((variable) => variable.field === fieldName);
696
+ if (cellInVariables?.type) {
697
+ return cellInVariables.type;
698
+ }
699
+ // Then check in rows array
700
+ const cellInRows = this.rows.find((cell) => cell.field === fieldName);
701
+ if (cellInRows?.type) {
702
+ return cellInRows.type;
703
+ }
704
+ // Default to string if not found
705
+ return 'string';
706
+ }
707
+ getValueOptionsByField(fieldName) {
708
+ // Firs check in variables array
709
+ const cellInVariables = this.variables.find((variable) => variable.field === fieldName);
710
+ if (cellInVariables?.valueOptions) {
711
+ return cellInVariables.valueOptions;
712
+ }
713
+ // Than check in rows
714
+ const cellInRows = this.rows.find((cell) => cell.field === fieldName);
715
+ if (cellInRows?.valueOptions) {
716
+ return cellInRows.valueOptions;
717
+ }
718
+ return undefined;
719
+ }
720
+ updateConditionalFormattingOperators(folder, conditionObj, cell, conditionIndex, variableName) {
721
+ const variableType = this.getVariableTypeByField(variableName);
722
+ const tempCell = { ...cell, field: variableName, type: variableType };
723
+ const newOperatorOptions = this.getOperatorOptionsForCell(tempCell);
724
+ const operatorKey = `${cell.field}_condition_${conditionIndex}_operator`;
725
+ const existingOperatorInput = this.operatorInputs.get(operatorKey);
726
+ let insertIndex = -1;
727
+ if (existingOperatorInput) {
728
+ try {
729
+ insertIndex = folder.children.indexOf(existingOperatorInput);
730
+ existingOperatorInput.dispose();
731
+ this.operatorInputs.delete(operatorKey);
732
+ }
733
+ catch (error) {
734
+ console.warn('Could not dispose existing operator binding:', error);
735
+ }
736
+ }
737
+ const defaultOperator = this.getDefaultOperatorForCell(tempCell);
738
+ conditionObj.operator = defaultOperator;
739
+ this.setConditionalFormatting(cell, conditionIndex, 'operator', defaultOperator);
740
+ const operatorInput = folder.addBinding(conditionObj, 'operator', {
741
+ view: 'list',
742
+ label: msg('Operátor'),
743
+ options: newOperatorOptions,
744
+ index: insertIndex >= 0 ? insertIndex : undefined,
745
+ });
746
+ operatorInput.on('change', (ev) => {
747
+ this.setConditionalFormatting(cell, conditionIndex, 'operator', ev.value);
748
+ });
749
+ this.operatorInputs.set(operatorKey, operatorInput);
750
+ this.addConditionalFormattingValueInput(folder, conditionObj, cell, conditionIndex, variableName);
751
+ }
752
+ updateHideConditionOperators(folder, config, cell, variableName) {
753
+ // Get the type of the selected variable to ensure correct operators
754
+ const variableType = this.getVariableTypeByField(variableName);
755
+ // Create a temporary cell object with the new variable and its type
756
+ const tempCell = { ...cell, field: variableName, type: variableType };
757
+ const newOperatorOptions = this.getOperatorOptionsForCell(tempCell);
758
+ // Find existing operator binding and its position
759
+ const operatorKey = `${cell.field}_hide_operator`;
760
+ const existingOperatorInput = this.hideOperatorInputs.get(operatorKey);
761
+ let insertIndex = -1;
762
+ if (existingOperatorInput) {
763
+ try {
764
+ // Find the index of the existing operator input
765
+ insertIndex = folder.children.indexOf(existingOperatorInput);
766
+ existingOperatorInput.dispose();
767
+ this.hideOperatorInputs.delete(operatorKey);
768
+ }
769
+ catch (error) {
770
+ console.warn('Could not dispose existing hide operator binding:', error);
771
+ }
772
+ }
773
+ // Reset operator to default for new variable type
774
+ const defaultOperator = this.getDefaultOperatorForCell(tempCell);
775
+ config.hideConditionOperator = defaultOperator;
776
+ this.setHideCondition(cell, 'operator', defaultOperator);
777
+ // Add new operator binding with updated options
778
+ const hideOperatorInput = folder.addBinding(config, 'hideConditionOperator', {
779
+ view: 'list',
780
+ label: msg('Operátor'),
781
+ options: newOperatorOptions,
782
+ index: insertIndex >= 0 ? insertIndex : undefined, // Insert at same position if possible
783
+ });
784
+ hideOperatorInput.on('change', (ev) => {
785
+ this.setHideCondition(cell, 'operator', ev.value);
786
+ });
787
+ // Store the new operator input for future disposal
788
+ this.hideOperatorInputs.set(operatorKey, hideOperatorInput);
789
+ // Update the value input to match the new variable type
790
+ this.addHideConditionValueInput(folder, config, cell, variableName);
791
+ }
792
+ addHideConditionValueInput(folder, config, cell, variableName) {
793
+ // Find and dispose existing value input if it exists
794
+ const valueKey = `${cell.field}_hide_value`;
795
+ const existingValueInput = this.hideValueInputs.get(valueKey);
796
+ let insertIndex = -1;
797
+ if (existingValueInput) {
798
+ try {
799
+ // Find the index of the existing value input
800
+ insertIndex = folder.children.indexOf(existingValueInput);
801
+ existingValueInput.dispose();
802
+ this.hideValueInputs.delete(valueKey);
803
+ }
804
+ catch (error) {
805
+ console.warn('Could not dispose existing hide value binding:', error);
806
+ }
807
+ }
808
+ // Get the type and valueOptions of the selected variable
809
+ const variableType = this.getVariableTypeByField(variableName);
810
+ const valueOptions = this.getValueOptionsByField(variableName);
811
+ let hideValueInput;
812
+ // If variable is type 'select' or 'multiselect' and has valueOptions, create a dropdown
813
+ if ((variableType === 'select' || variableType === 'multiselect') &&
814
+ valueOptions &&
815
+ valueOptions.length > 0) {
816
+ // Convert valueOptions from {label, value} to {text, value} for Tweakpane
817
+ const tweakpaneOptions = valueOptions.map((opt) => ({
818
+ text: opt.label,
819
+ value: opt.value,
820
+ }));
821
+ hideValueInput = folder.addBinding(config, 'hideConditionValue', {
822
+ view: 'list',
823
+ label: msg('Hodnota'),
824
+ options: tweakpaneOptions,
825
+ index: insertIndex >= 0 ? insertIndex : undefined,
826
+ });
827
+ }
828
+ else {
829
+ // Otherwise, create a text input
830
+ hideValueInput = folder.addBinding(config, 'hideConditionValue', {
831
+ label: msg('Hodnota'),
832
+ index: insertIndex >= 0 ? insertIndex : undefined,
833
+ });
834
+ }
835
+ hideValueInput.on('change', (ev) => {
836
+ this.setHideCondition(cell, 'value', ev.value);
837
+ });
838
+ // Store the new value input for future disposal
839
+ this.hideValueInputs.set(valueKey, hideValueInput);
840
+ }
841
+ addConditionalFormattingValueInput(folder, conditionObj, cell, conditionIndex, variableName) {
842
+ const valueKey = `${cell.field}_condition_${conditionIndex}_value`;
843
+ const existingValueInput = this.conditionValueInputs.get(valueKey);
844
+ let insertIndex = -1;
845
+ if (existingValueInput) {
846
+ try {
847
+ insertIndex = folder.children.indexOf(existingValueInput);
848
+ existingValueInput.dispose();
849
+ this.conditionValueInputs.delete(valueKey);
850
+ }
851
+ catch (error) {
852
+ console.warn('Could not dispose existing condition value binding:', error);
853
+ }
854
+ }
855
+ const variableType = this.getVariableTypeByField(variableName);
856
+ const valueOptions = this.getValueOptionsByField(variableName);
857
+ // Ensure value is a string before binding (tweakpane requires a concrete type)
858
+ if (conditionObj.value == null || typeof conditionObj.value !== 'string') {
859
+ conditionObj.value = conditionObj.value != null ? String(conditionObj.value) : '';
860
+ }
861
+ let conditionValueInput;
862
+ if ((variableType === 'select' || variableType === 'multiselect') &&
863
+ valueOptions &&
864
+ valueOptions.length > 0) {
865
+ const tweakpaneOptions = valueOptions.map((opt) => ({
866
+ text: opt.label,
867
+ value: opt.value,
868
+ }));
869
+ conditionValueInput = folder.addBinding(conditionObj, 'value', {
870
+ view: 'list',
871
+ label: msg('Hodnota'),
872
+ options: tweakpaneOptions,
873
+ index: insertIndex >= 0 ? insertIndex : undefined,
874
+ });
875
+ }
876
+ else {
877
+ conditionValueInput = folder.addBinding(conditionObj, 'value', {
878
+ label: msg('Hodnota'),
879
+ index: insertIndex >= 0 ? insertIndex : undefined,
880
+ });
881
+ }
882
+ conditionValueInput.on('change', (ev) => {
883
+ this.setConditionalFormatting(cell, conditionIndex, 'value', ev.value);
884
+ });
885
+ this.conditionValueInputs.set(valueKey, conditionValueInput);
886
+ }
887
+ getBreakpoint() {
888
+ const width = window.innerWidth;
889
+ if (width >= 1920)
890
+ return 'xl';
891
+ if (width >= 1280)
892
+ return 'lg';
893
+ if (width >= 960)
894
+ return 'md';
895
+ if (width >= 600)
896
+ return 'sm';
897
+ return 'xs';
898
+ }
899
+ // Function to handle resize events
900
+ handleResize() {
901
+ const newBreakpoint = this.getBreakpoint();
902
+ if (newBreakpoint !== this.currentBreakpoint) {
903
+ this.currentBreakpoint = newBreakpoint; // Update property
904
+ }
905
+ this.isMobile = window.innerWidth <= 600;
906
+ }
907
+ connectedCallback() {
908
+ super.connectedCallback();
909
+ window.addEventListener('resize', this._resizeListener); // Add listener
910
+ this.isMobile = window.innerWidth <= 600;
911
+ if (!this.dateFormat) {
912
+ const userSettings = localStorage.getItem('userSettings');
913
+ const storedFormat = userSettings
914
+ ? JSON.parse(userSettings)?.state?.dateFormat
915
+ : undefined;
916
+ this.dateFormat = storedFormat;
917
+ }
918
+ }
919
+ disconnectedCallback() {
920
+ this.destroySortables();
921
+ this.destroySettingsPanes();
922
+ window.removeEventListener('resize', this._resizeListener); // Remove listener
923
+ super.disconnectedCallback();
924
+ }
925
+ firstUpdated() {
926
+ if (this.enableSettings) {
927
+ this.initSortable();
928
+ }
929
+ }
930
+ setFontWeight(cell) {
931
+ this.rows = this.rows.map((c) => {
932
+ if (c.field === cell.field) {
933
+ const isBold = c.valueStyle?.fontWeight === 'bold';
934
+ return {
935
+ ...c,
936
+ valueCustomStyles: true,
937
+ valueVariant: 'default',
938
+ valueStyle: {
939
+ ...(c.valueStyle || {}),
940
+ fontWeight: isBold ? '500' : 'bold',
941
+ },
942
+ };
943
+ }
944
+ return c;
945
+ });
946
+ this.handleSettingsChanged(this.rows);
947
+ }
948
+ getAllAvailableVariables() {
949
+ const variables = [];
950
+ // Add variables from current rows (including all cells)
951
+ this.rows.forEach((cell) => {
952
+ variables.push({
953
+ text: `${cell.headerName || cell.field} (${cell.field})`,
954
+ value: cell.field,
955
+ });
956
+ });
957
+ // Add variables from variables array (that are not in current rows)
958
+ const existingFields = this.rows.map((cell) => cell.field);
959
+ this.variables.forEach((variable) => {
960
+ if (!existingFields.includes(variable.field)) {
961
+ const name = variable.headerName || variable.field;
962
+ variables.push({
963
+ text: `${name} (${variable.field})`,
964
+ value: variable.field,
965
+ });
966
+ }
967
+ });
968
+ return variables.sort((a, b) => a.text.localeCompare(b.text));
969
+ }
970
+ setConditionalFormatting(cell, conditionIndex, property, value) {
971
+ this.rows = this.rows.map((c) => {
972
+ if (c.field === cell.field) {
973
+ const updatedCell = { ...c };
974
+ // Normalize to array
975
+ const conditions = this.normalizeConditions(updatedCell.conditionalFormatting).map((cond) => ({ ...cond }));
976
+ // Ensure index exists
977
+ if (!conditions[conditionIndex]) {
978
+ conditions[conditionIndex] = this.createDefaultCondition(cell);
979
+ }
980
+ conditions[conditionIndex][property] = value;
981
+ updatedCell.conditionalFormatting = conditions;
982
+ return updatedCell;
983
+ }
984
+ return c;
985
+ });
986
+ this.handleSettingsChanged(this.rows);
987
+ }
988
+ addConditionToCell(cell) {
989
+ this.rows = this.rows.map((c) => {
990
+ if (c.field === cell.field) {
991
+ const updatedCell = { ...c };
992
+ const conditions = this.normalizeConditions(updatedCell.conditionalFormatting).map((cond) => ({ ...cond }));
993
+ conditions.push(this.createDefaultCondition(cell));
994
+ updatedCell.conditionalFormatting = conditions;
995
+ return updatedCell;
996
+ }
997
+ return c;
998
+ });
999
+ this.handleSettingsChanged(this.rows);
1000
+ }
1001
+ removeConditionFromCell(cell, conditionIndex) {
1002
+ this.rows = this.rows.map((c) => {
1003
+ if (c.field === cell.field) {
1004
+ const updatedCell = { ...c };
1005
+ const conditions = this.normalizeConditions(updatedCell.conditionalFormatting).map((cond) => ({ ...cond }));
1006
+ conditions.splice(conditionIndex, 1);
1007
+ updatedCell.conditionalFormatting = conditions;
1008
+ return updatedCell;
1009
+ }
1010
+ return c;
1011
+ });
1012
+ this.handleSettingsChanged(this.rows);
1013
+ }
1014
+ setCellStyle(style, cell) {
1015
+ this.rows = this.rows.map((c) => {
1016
+ if (c.field === cell.field) {
1017
+ return { ...c, cellStyle: style };
1018
+ }
1019
+ return c;
1020
+ });
1021
+ this.handleSettingsChanged(this.rows);
1022
+ }
1023
+ setCellVariant(variant, cell) {
1024
+ this.rows = this.rows.map((c) => {
1025
+ if (c.field === cell.field) {
1026
+ const updatedCell = { ...c, cellVariant: variant };
1027
+ // If setting a semantic variant, disable custom styles
1028
+ if (variant !== 'default') {
1029
+ updatedCell.cellCustomStyles = false;
1030
+ }
1031
+ return updatedCell;
1032
+ }
1033
+ return c;
1034
+ });
1035
+ this.handleSettingsChanged(this.rows);
1036
+ }
1037
+ setValueVariant(variant, cell) {
1038
+ this.rows = this.rows.map((c) => {
1039
+ if (c.field === cell.field) {
1040
+ const updatedCell = { ...c, valueVariant: variant };
1041
+ // If setting a semantic variant, disable custom styles
1042
+ if (variant !== 'default') {
1043
+ updatedCell.valueCustomStyles = false;
1044
+ }
1045
+ return updatedCell;
1046
+ }
1047
+ return c;
1048
+ });
1049
+ this.handleSettingsChanged(this.rows);
1050
+ }
1051
+ enableCellCustomStyles(cell) {
1052
+ this.rows = this.rows.map((c) => {
1053
+ if (c.field === cell.field) {
1054
+ return {
1055
+ ...c,
1056
+ cellCustomStyles: true,
1057
+ cellVariant: 'default',
1058
+ };
1059
+ }
1060
+ return c;
1061
+ });
1062
+ this.handleSettingsChanged(this.rows);
1063
+ }
1064
+ enableValueCustomStyles(cell) {
1065
+ this.rows = this.rows.map((c) => {
1066
+ if (c.field === cell.field) {
1067
+ return {
1068
+ ...c,
1069
+ valueCustomStyles: true,
1070
+ valueVariant: 'default',
1071
+ };
1072
+ }
1073
+ return c;
1074
+ });
1075
+ this.handleSettingsChanged(this.rows);
1076
+ }
1077
+ destroySortables() {
1078
+ this.sortableInstances.forEach((instance) => {
1079
+ instance.destroy();
1080
+ });
1081
+ this.sortableInstances = [];
1082
+ }
1083
+ destroySettingsPanes() {
1084
+ this.settingsPanes.forEach((pane, field) => {
1085
+ try {
1086
+ if (pane) {
1087
+ pane.dispose();
1088
+ }
1089
+ }
1090
+ catch (error) {
1091
+ // Silently catch disposal errors (usually means already disposed)
1092
+ if (error.type !== 'alreadydisposed') {
1093
+ console.error(`Error disposing pane for ${field}:`, error);
1094
+ }
1095
+ }
1096
+ });
1097
+ this.settingsPanes.clear();
1098
+ // Remove any floating tooltip containers (legacy cleanup)
1099
+ document.querySelectorAll('.tweakpane-floating-tooltip').forEach((el) => {
1100
+ el.remove();
1101
+ });
1102
+ // Clean up any leftover tweakpane containers in document
1103
+ document.querySelectorAll('[id^="tweakpane-"]').forEach((el) => {
1104
+ const parentContainer = el.closest('.tweakpane-container');
1105
+ if (parentContainer) {
1106
+ parentContainer.remove();
1107
+ }
1108
+ });
1109
+ }
1110
+ toggleSettingsPane(cell) {
1111
+ // If clicking the same cell, toggle the popper
1112
+ if (this.activeSettingsCell?.field === cell.field) {
1113
+ this.settingsPopperOpen = !this.settingsPopperOpen;
1114
+ if (!this.settingsPopperOpen) {
1115
+ this.activeSettingsCell = null;
1116
+ }
1117
+ }
1118
+ else {
1119
+ // Different cell, show popper for this cell
1120
+ this.activeSettingsCell = cell;
1121
+ this.settingsPopperOpen = true;
1122
+ }
1123
+ }
1124
+ getVariantColor(variant) {
1125
+ const entry = LitCaseVariablesTab.VARIANT_CSS_VARS[variant];
1126
+ if (!entry)
1127
+ return '#9ca3af';
1128
+ const styles = getComputedStyle(this);
1129
+ return styles.getPropertyValue(entry.var).trim() || entry.fallback;
1130
+ }
1131
+ colorizeVariantSelect(binding, options, config, configKey) {
1132
+ const el = binding.element;
1133
+ if (!el)
1134
+ return;
1135
+ const selectEl = el.querySelector('select');
1136
+ if (!selectEl)
1137
+ return;
1138
+ // Hide the native select
1139
+ const valueContainer = el.querySelector('.tp-lblv_v');
1140
+ if (!valueContainer)
1141
+ return;
1142
+ selectEl.style.display = 'none';
1143
+ // Also hide the dropdown arrow
1144
+ const arrow = valueContainer.querySelector('.tp-lstv_m');
1145
+ if (arrow)
1146
+ arrow.style.display = 'none';
1147
+ // Create swatches container
1148
+ const swatchContainer = document.createElement('div');
1149
+ swatchContainer.style.cssText = 'display:flex;gap:4px;flex-wrap:wrap;align-items:center;';
1150
+ const borderVarMap = {
1151
+ default: 'var(--text-secondary, #9ca3af)',
1152
+ primary: 'var(--color-primary-main, #76b703)',
1153
+ secondary: 'var(--color-secondary-main, #6b7280)',
1154
+ success: 'var(--color-success-main, #22c55e)',
1155
+ warning: 'var(--color-warning-main, #f59e0b)',
1156
+ error: 'var(--color-error-main, #ef4444)',
1157
+ info: 'var(--color-info-main, #3b82f6)',
1158
+ custom: 'var(--color-primary-main, #8b5cf6)',
1159
+ ai: 'var(--color-primary-main, #a855f7)',
1160
+ };
1161
+ options.forEach((opt) => {
1162
+ const color = this.getVariantColor(opt.value);
1163
+ const borderColor = borderVarMap[opt.value] || 'var(--text-secondary, #9ca3af)';
1164
+ const isCustom = opt.value === 'custom';
1165
+ // Wrapper for positioning the tooltip
1166
+ const wrapper = document.createElement('div');
1167
+ wrapper.style.cssText = 'position:relative;display:inline-flex;';
1168
+ const swatch = document.createElement('div');
1169
+ swatch.dataset.value = opt.value;
1170
+ if (isCustom) {
1171
+ swatch.style.cssText = `
1172
+ width:16px;height:16px;border-radius:50%;cursor:pointer;
1173
+ background:conic-gradient(#ef4444,#f59e0b,#22c55e,#3b82f6,#8b5cf6,#ef4444);
1174
+ border:2px dashed var(--text-secondary, #9ca3af);transition:box-shadow .15s;flex-shrink:0;
1175
+ `;
1176
+ }
1177
+ else {
1178
+ swatch.style.cssText = `
1179
+ width:16px;height:16px;border-radius:50%;background:${color};cursor:pointer;
1180
+ border:2px solid ${borderColor};transition:box-shadow .15s;flex-shrink:0;
1181
+ `;
1182
+ }
1183
+ // Tooltip using SimpleTooltip component
1184
+ const tip = document.createElement('simple-tooltip');
1185
+ tip.textContent = opt.text;
1186
+ tip.placement = 'top';
1187
+ tip.offset = 6;
1188
+ tip.openDelayMs = 200;
1189
+ tip.target = swatch;
1190
+ wrapper.appendChild(tip);
1191
+ if (config[configKey] === opt.value) {
1192
+ swatch.style.boxShadow = `0 0 0 2px #fff, 0 0 0 4px ${borderColor}`;
1193
+ }
1194
+ swatch.addEventListener('click', () => {
1195
+ config[configKey] = opt.value;
1196
+ binding.refresh();
1197
+ swatchContainer.querySelectorAll('[data-value]').forEach((s) => {
1198
+ s.style.boxShadow = 'none';
1199
+ });
1200
+ swatch.style.boxShadow = `0 0 0 2px #fff, 0 0 0 4px ${borderColor}`;
1201
+ });
1202
+ wrapper.appendChild(swatch);
1203
+ swatchContainer.appendChild(wrapper);
1204
+ });
1205
+ valueContainer.appendChild(swatchContainer);
1206
+ }
1207
+ // Sanitize field name for use in CSS selectors
1208
+ sanitizeFieldName(field) {
1209
+ return field.replace(/[^a-zA-Z0-9-_]/g, '-');
1210
+ }
1211
+ renderSettingsContent() {
1212
+ if (!this.activeSettingsCell)
1213
+ return null;
1214
+ const cell = this.activeSettingsCell;
1215
+ return html `
1216
+ <div class="tweakpane-container" @click=${(e) => e.stopPropagation()}>
1217
+ <div id="tweakpane-${this.sanitizeFieldName(cell.field)}"></div>
1218
+ </div>
1219
+ `;
1220
+ }
1221
+ updated(changedProperties) {
1222
+ super.updated(changedProperties);
1223
+ if (changedProperties.has('userLang')) {
1224
+ const localeLang = this.getLocaleLang();
1225
+ if (getLocale() !== localeLang) {
1226
+ setLocale(localeLang).then(() => this.requestUpdate());
1227
+ }
1228
+ }
1229
+ // Initialize tweakpane when activeSettingsCell changes and popper is open
1230
+ if (changedProperties.has('activeSettingsCell') ||
1231
+ changedProperties.has('settingsPopperOpen')) {
1232
+ if (this.activeSettingsCell && this.settingsPopperOpen) {
1233
+ // Use requestAnimationFrame + small delay to ensure DOM is ready (container is in shadowRoot)
1234
+ requestAnimationFrame(() => {
1235
+ this.initializeTweakpane(this.activeSettingsCell, 0);
1236
+ });
1237
+ }
1238
+ }
1239
+ }
1240
+ initializeTweakpaneWithRetry(cell, attempt = 1) {
1241
+ // Clean up any existing pane for this cell first
1242
+ const existingPane = this.settingsPanes.get(cell.field);
1243
+ if (existingPane) {
1244
+ try {
1245
+ existingPane.dispose();
1246
+ }
1247
+ catch (error) {
1248
+ // Silently catch disposal errors (usually means already disposed)
1249
+ if (error.type !== 'alreadydisposed') {
1250
+ console.error(`Error disposing existing pane for ${cell.field}:`, error);
1251
+ }
1252
+ }
1253
+ this.settingsPanes.delete(cell.field);
1254
+ }
1255
+ // Increased retries and delay for slower PCs
1256
+ const maxAttempts = 20;
1257
+ const retryDelay = 100; // 100ms per retry = 2000ms total
1258
+ const selector = `#tweakpane-${this.sanitizeFieldName(cell.field)}`;
1259
+ const container = document.querySelector(selector) || this.shadowRoot?.querySelector(selector);
1260
+ if (container) {
1261
+ this.initializeTweakpane(cell, 0);
1262
+ }
1263
+ else if (attempt < maxAttempts) {
1264
+ setTimeout(() => {
1265
+ // Check if we're still supposed to be showing this cell
1266
+ if (this.activeSettingsCell?.field === cell.field && this.settingsPopperOpen) {
1267
+ this.initializeTweakpaneWithRetry(cell, attempt + 1);
1268
+ }
1269
+ }, retryDelay);
1270
+ }
1271
+ else {
1272
+ console.warn(`Failed to find tweakpane container for ${cell.field} after ${maxAttempts} attempts (${maxAttempts * retryDelay}ms)`);
1273
+ }
1274
+ }
1275
+ initializeTweakpane(cell, retryCount = 0) {
1276
+ // Get the container from shadow DOM (always available in fixed overlay)
1277
+ const selector = `#tweakpane-${this.sanitizeFieldName(cell.field)}`;
1278
+ const container = document.querySelector(selector) || this.shadowRoot?.querySelector(selector);
1279
+ if (!container) {
1280
+ // Increased retries for slower PCs
1281
+ const maxRetries = 5;
1282
+ const retryDelay = 150;
1283
+ if (retryCount < maxRetries) {
1284
+ console.warn(`Tweakpane container not found, retrying... (${retryCount + 1}/${maxRetries})`);
1285
+ setTimeout(() => {
1286
+ this.initializeTweakpane(cell, retryCount + 1);
1287
+ }, retryDelay);
1288
+ return;
1289
+ }
1290
+ else {
1291
+ console.error(`Tweakpane container not found: #tweakpane-${this.sanitizeFieldName(cell.field)}`);
1292
+ return;
1293
+ }
1294
+ }
1295
+ // Clear any existing pane for this cell
1296
+ const existingPane = this.settingsPanes.get(cell.field);
1297
+ if (existingPane) {
1298
+ try {
1299
+ existingPane.dispose();
1300
+ }
1301
+ catch (error) {
1302
+ // Silently catch disposal errors (usually means already disposed)
1303
+ if (error.type !== 'alreadydisposed') {
1304
+ console.error(`Error disposing existing pane for ${cell.field}:`, error);
1305
+ }
1306
+ }
1307
+ this.settingsPanes.delete(cell.field);
1308
+ }
1309
+ // Create Tweakpane in the container
1310
+ const pane = new Pane({
1311
+ container: container,
1312
+ title: `${cell.headerName || cell.field}`,
1313
+ });
1314
+ // Apply app theme CSS variables to Tweakpane
1315
+ const styles = getComputedStyle(this);
1316
+ const bgPaper = styles.getPropertyValue('--background-paper').trim() || '#fff';
1317
+ const bgDefault = styles.getPropertyValue('--background-default').trim() || '#fff';
1318
+ const textPrimary = styles.getPropertyValue('--text-primary').trim() || '#111827';
1319
+ const textSecondary = styles.getPropertyValue('--text-secondary').trim() || '#5d6371';
1320
+ const colorDivider = styles.getPropertyValue('--color-divider').trim() || '#e5e7eb';
1321
+ const containerEl = container;
1322
+ containerEl.style.setProperty('--tp-base-background-color', bgPaper);
1323
+ containerEl.style.setProperty('--tp-base-shadow-color', 'rgba(0,0,0,0)');
1324
+ containerEl.style.setProperty('--tp-button-background-color', bgDefault);
1325
+ containerEl.style.setProperty('--tp-button-foreground-color', textPrimary);
1326
+ containerEl.style.setProperty('--tp-container-background-color', colorDivider);
1327
+ containerEl.style.setProperty('--tp-container-background-color-hover', colorDivider);
1328
+ containerEl.style.setProperty('--tp-container-foreground-color', textPrimary);
1329
+ containerEl.style.setProperty('--tp-input-background-color', bgDefault);
1330
+ containerEl.style.setProperty('--tp-input-foreground-color', textPrimary);
1331
+ containerEl.style.setProperty('--tp-label-foreground-color', textSecondary);
1332
+ containerEl.style.setProperty('--tp-monitor-background-color', colorDivider);
1333
+ containerEl.style.setProperty('--tp-monitor-foreground-color', textSecondary);
1334
+ containerEl.style.setProperty('--tp-groove-foreground-color', colorDivider);
1335
+ const config = this.createCellSettingsConfig(cell);
1336
+ // Add size controls for desktop and mobile (only if not in grid variables mode)
1337
+ if (!this.gridVariables) {
1338
+ // Desktop size input
1339
+ const desktopSizeInput = pane.addBinding(config, 'size', {
1340
+ view: 'list',
1341
+ label: msg('Velikost desktop'),
1342
+ options: [
1343
+ { text: msg('Skrytý'), value: 0 },
1344
+ { text: msg('1 sloupec'), value: 1 },
1345
+ { text: msg('2 sloupce'), value: 2 },
1346
+ { text: msg('3 sloupce'), value: 3 },
1347
+ { text: msg('4 sloupce'), value: 4 },
1348
+ ],
1349
+ });
1350
+ desktopSizeInput.on('change', (ev) => {
1351
+ this.setCellSize(ev.value, cell, 'lg');
1352
+ });
1353
+ // Mobile size input
1354
+ const mobileSizeInput = pane.addBinding(config, 'mobileSize', {
1355
+ view: 'list',
1356
+ label: msg('Velikost mobil'),
1357
+ options: [
1358
+ { text: msg('Skrytý'), value: 0 },
1359
+ { text: msg('1 sloupec'), value: 1 },
1360
+ { text: msg('2 sloupce'), value: 2 },
1361
+ { text: msg('3 sloupce'), value: 3 },
1362
+ { text: msg('4 sloupce'), value: 4 },
1363
+ ],
1364
+ });
1365
+ mobileSizeInput.on('change', (ev) => {
1366
+ this.setCellSize(ev.value, cell, 'xs');
1367
+ });
1368
+ }
1369
+ // Add cell type control - at the top
1370
+ const cellTypeInput = pane.addBinding(config, 'cellType', {
1371
+ view: 'list',
1372
+ label: msg('Typ buňky'),
1373
+ options: [
1374
+ { text: msg('Text'), value: 'string' },
1375
+ { text: msg('Tlačítko'), value: 'button' },
1376
+ { text: msg('Odkaz'), value: 'link' },
1377
+ { text: msg('Datum'), value: 'date' },
1378
+ { text: msg('Měna'), value: 'currency' },
1379
+ { text: msg('Progress'), value: 'progress' },
1380
+ { text: msg('Číslo'), value: 'number' },
1381
+ { text: msg('Checkbox'), value: 'checkbox' },
1382
+ ],
1383
+ });
1384
+ cellTypeInput.on('change', (ev) => {
1385
+ this.setCellType(cell, ev.value);
1386
+ });
1387
+ // Add header name and value controls (only for custom cells)
1388
+ const isCustomCell = cell.field.startsWith('custom_cell_');
1389
+ if (isCustomCell) {
1390
+ const headerNameInput = pane.addBinding(config, 'headerName', {
1391
+ label: msg('Název buňky'),
1392
+ });
1393
+ headerNameInput.on('change', (ev) => {
1394
+ this.setCellHeaderName(cell, ev.value);
1395
+ });
1396
+ // Add cell value control for custom cells
1397
+ const cellValueInput = pane.addBinding(config, 'cellValue', {
1398
+ label: msg('Hodnota buňky'),
1399
+ multiline: cell.type === 'string',
1400
+ });
1401
+ cellValueInput.on('change', (ev) => {
1402
+ this.setCellValue(cell, ev.value);
1403
+ });
1404
+ }
1405
+ // Add cell variant control - common for all types
1406
+ const cellVariantOptions = [
1407
+ { text: msg('Výchozí'), value: 'default' },
1408
+ { text: msg('Primární'), value: 'primary' },
1409
+ { text: msg('Úspěch'), value: 'success' },
1410
+ { text: msg('Varování'), value: 'warning' },
1411
+ { text: msg('Chyba'), value: 'error' },
1412
+ { text: msg('Informace'), value: 'info' },
1413
+ { text: msg('Vlastní'), value: 'custom' },
1414
+ ];
1415
+ const cellVariantInput = pane.addBinding(config, 'cellVariant', {
1416
+ view: 'list',
1417
+ label: msg('Styl buňky'),
1418
+ options: cellVariantOptions,
1419
+ });
1420
+ // Add CSS input for custom styles (always present but controlled by visibility)
1421
+ const cssInput = pane.addBinding(config, 'customCSS', {
1422
+ label: msg('CSS buňky'),
1423
+ multiline: true,
1424
+ rows: 4,
1425
+ });
1426
+ cssInput.on('change', (ev) => {
1427
+ try {
1428
+ const cssObject = JSON.parse(ev.value || '{}');
1429
+ this.setCellStyle(cssObject, cell);
1430
+ }
1431
+ catch (error) {
1432
+ console.error('Invalid JSON for custom CSS:', error);
1433
+ }
1434
+ });
1435
+ const showCssInput = () => {
1436
+ if (cssInput.element) {
1437
+ cssInput.element.style.display = '';
1438
+ }
1439
+ };
1440
+ const hideCssInput = () => {
1441
+ if (cssInput.element) {
1442
+ cssInput.element.style.display = 'none';
1443
+ }
1444
+ };
1445
+ // Set initial visibility based on whether custom style is selected
1446
+ if (config.cellCustomStyles) {
1447
+ showCssInput();
1448
+ }
1449
+ else {
1450
+ hideCssInput();
1451
+ }
1452
+ cellVariantInput.on('change', (ev) => {
1453
+ if (ev.value === 'custom') {
1454
+ this.enableCellCustomStyles(cell);
1455
+ showCssInput();
1456
+ }
1457
+ else {
1458
+ this.setCellVariant(ev.value, cell);
1459
+ hideCssInput();
1460
+ }
1461
+ });
1462
+ this.colorizeVariantSelect(cellVariantInput, cellVariantOptions, config, 'cellVariant');
1463
+ // Add cell type-specific controls
1464
+ this.addCellTypeSpecificControls(pane, config, cell);
1465
+ // Add conditional formatting section
1466
+ const conditionFolder = pane.addFolder({
1467
+ title: msg('Podmíněné formátování buněk'),
1468
+ expanded: false,
1469
+ });
1470
+ // "Add Condition" button
1471
+ const addConditionBtn = conditionFolder.addButton({ title: `+ ${msg('Přidat podmínku')}` });
1472
+ addConditionBtn.on('click', () => {
1473
+ this.addConditionToCell(cell);
1474
+ // Rebuild conditions UI
1475
+ config.conditions = this.normalizeConditions(this.rows.find((c) => c.field === cell.field)?.conditionalFormatting);
1476
+ this.rebuildConditionFolders(conditionFolder, config, cell);
1477
+ });
1478
+ // Build initial condition sub-folders
1479
+ this.rebuildConditionFolders(conditionFolder, config, cell);
1480
+ // Add conditional hide section
1481
+ const hideFolder = pane.addFolder({
1482
+ title: msg('Podmíněné skrytí buněk'),
1483
+ expanded: false,
1484
+ });
1485
+ // Enable/disable conditional hide
1486
+ const hideConditionEnabledInput = hideFolder.addBinding(config, 'hideConditionEnabled', {
1487
+ label: msg('Povolit podmínky skrytí'),
1488
+ });
1489
+ hideConditionEnabledInput.on('change', (ev) => {
1490
+ this.setHideCondition(cell, 'enabled', ev.value);
1491
+ });
1492
+ // Variable selector for hide condition
1493
+ const hideVariableOptions = this.getAllAvailableVariables();
1494
+ if (hideVariableOptions.length > 0) {
1495
+ // Set default variable to current cell's field if not already set
1496
+ if (!config.hideConditionVariable) {
1497
+ config.hideConditionVariable = cell.field;
1498
+ this.setHideCondition(cell, 'variable', cell.field);
1499
+ }
1500
+ const hideConditionVariableInput = hideFolder.addBinding(config, 'hideConditionVariable', {
1501
+ view: 'list',
1502
+ label: msg('Proměnná'),
1503
+ options: hideVariableOptions,
1504
+ });
1505
+ hideConditionVariableInput.on('change', (ev) => {
1506
+ this.setHideCondition(cell, 'variable', ev.value);
1507
+ // Update operators when variable changes
1508
+ this.updateHideConditionOperators(hideFolder, config, cell, ev.value);
1509
+ });
1510
+ }
1511
+ // Hide condition operator - use operators based on cell type
1512
+ // Get the actual cell/variable to determine correct operators
1513
+ const hideVariableType = this.getVariableTypeByField(config.hideConditionVariable);
1514
+ const tempHideCell = {
1515
+ ...cell,
1516
+ field: config.hideConditionVariable,
1517
+ type: hideVariableType,
1518
+ };
1519
+ const hideOperatorOptions = this.getOperatorOptionsForCell(tempHideCell);
1520
+ const hideOperatorInput = hideFolder.addBinding(config, 'hideConditionOperator', {
1521
+ view: 'list',
1522
+ label: msg('Operátor'),
1523
+ options: hideOperatorOptions,
1524
+ });
1525
+ hideOperatorInput.on('change', (ev) => {
1526
+ this.setHideCondition(cell, 'operator', ev.value);
1527
+ });
1528
+ // Store the operator input for future disposal
1529
+ const hideOperatorKey = `${cell.field}_hide_operator`;
1530
+ this.hideOperatorInputs.set(hideOperatorKey, hideOperatorInput);
1531
+ // Hide condition value - dynamic input based on variable type
1532
+ this.addHideConditionValueInput(hideFolder, config, cell, config.hideConditionVariable);
1533
+ // Expert mode button
1534
+ const expertBtn = pane.addButton({ title: msg('Expertní mód') });
1535
+ expertBtn.on('click', () => {
1536
+ this.openExpertModeModal(cell);
1537
+ });
1538
+ // Add delete button
1539
+ const deleteBtn = pane.addButton({ title: msg('Smazat buňku') });
1540
+ deleteBtn.on('click', () => {
1541
+ this.removeCellFromRows(cell.field);
1542
+ this.closeSettingsPopper();
1543
+ });
1544
+ this.settingsPanes.set(cell.field, pane);
1545
+ return pane;
1546
+ }
1547
+ addCellTypeSpecificControls(pane, config, cell) {
1548
+ const cellType = cell.type || 'string';
1549
+ // Create a tab for the current cell type only
1550
+ const tabTitle = this.getCellTypeTabTitle(cellType);
1551
+ if (tabTitle) {
1552
+ const tab = pane.addTab({
1553
+ pages: [{ title: tabTitle }],
1554
+ });
1555
+ const tabPage = tab.pages[0];
1556
+ // Add controls based on cell type
1557
+ switch (cellType) {
1558
+ case 'link':
1559
+ this.addLinkControls(tabPage, config, cell);
1560
+ break;
1561
+ case 'number':
1562
+ this.addNumberControls(tabPage, config, cell);
1563
+ break;
1564
+ case 'progress':
1565
+ this.addProgressControls(tabPage, config, cell);
1566
+ break;
1567
+ case 'button':
1568
+ this.addButtonControls(tabPage, config, cell);
1569
+ break;
1570
+ case 'currency':
1571
+ this.addCurrencyControls(tabPage, config, cell);
1572
+ break;
1573
+ case 'date':
1574
+ this.addDateControls(tabPage, config, cell);
1575
+ break;
1576
+ case 'checkbox':
1577
+ // Checkbox has no additional type-specific controls
1578
+ break;
1579
+ default:
1580
+ this.addStringControls(tabPage, config, cell);
1581
+ break;
1582
+ }
1583
+ }
1584
+ }
1585
+ getCellTypeTabTitle(cellType) {
1586
+ const typeTitles = {
1587
+ string: msg('Nastavení textu'),
1588
+ link: msg('Nastavení odkazu'),
1589
+ number: msg('Nastavení čísla'),
1590
+ button: msg('Nastavení tlačítka'),
1591
+ currency: msg('Nastavení měny'),
1592
+ date: msg('Nastavení data'),
1593
+ progress: msg('Nastavení postupu'),
1594
+ checkbox: msg('Nastavení checkboxu'),
1595
+ };
1596
+ return typeTitles[cellType] || msg('Nastavení buňky');
1597
+ }
1598
+ addStringControls(pane, config, cell) {
1599
+ // Value Bold
1600
+ const fontInput = pane.addBinding(config, 'fontWeight', {
1601
+ label: msg('Tučná hodnota'),
1602
+ });
1603
+ fontInput.on('change', () => {
1604
+ this.setFontWeight(cell);
1605
+ });
1606
+ // Value Variant
1607
+ const valueVariantOptions = [
1608
+ { text: msg('Výchozí'), value: 'default' },
1609
+ { text: msg('Primární'), value: 'primary' },
1610
+ { text: msg('Úspěch'), value: 'success' },
1611
+ { text: msg('Varování'), value: 'warning' },
1612
+ { text: msg('Chyba'), value: 'error' },
1613
+ { text: msg('Informace'), value: 'info' },
1614
+ ];
1615
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1616
+ view: 'list',
1617
+ label: 'Value Color',
1618
+ options: valueVariantOptions,
1619
+ });
1620
+ valueVariantInput.on('change', (ev) => {
1621
+ if (ev.value === 'custom') {
1622
+ this.enableValueCustomStyles(cell);
1623
+ }
1624
+ else {
1625
+ this.setValueVariant(ev.value, cell);
1626
+ }
1627
+ });
1628
+ this.colorizeVariantSelect(valueVariantInput, valueVariantOptions, config, 'valueVariant');
1629
+ }
1630
+ addLinkControls(pane, config, cell) {
1631
+ // Link Type selector
1632
+ const linkTypeInput = pane.addBinding(config, 'linkType', {
1633
+ view: 'list',
1634
+ label: msg('Typ odkazu'),
1635
+ options: [
1636
+ { text: msg('Vlastní URL'), value: 'custom' },
1637
+ { text: msg('Dynamický odkaz'), value: 'dynamic' },
1638
+ ],
1639
+ });
1640
+ linkTypeInput.on('change', (ev) => {
1641
+ this.setLinkType(cell, ev.value);
1642
+ });
1643
+ // Custom URL input (shown when linkType is 'custom')
1644
+ const hrefInput = pane.addBinding(config, 'href', {
1645
+ label: msg('Vlastní URL'),
1646
+ });
1647
+ hrefInput.on('change', (ev) => {
1648
+ this.setHref(cell, ev.value);
1649
+ });
1650
+ // Open in new tab
1651
+ const openInNewTabInput = pane.addBinding(config, 'openInNewTab', {
1652
+ label: msg('Otevřít v nové záložce'),
1653
+ });
1654
+ openInNewTabInput.on('change', (ev) => {
1655
+ this.setOpenInNewTab(cell, ev.value);
1656
+ });
1657
+ }
1658
+ addNumberControls(pane, config, cell) {
1659
+ // Value Bold
1660
+ const fontInput = pane.addBinding(config, 'fontWeight', {
1661
+ label: msg('Hodnota tučně'),
1662
+ });
1663
+ fontInput.on('change', () => {
1664
+ this.setFontWeight(cell);
1665
+ });
1666
+ // Value Variant
1667
+ const valueVariantOptions = [
1668
+ { text: msg('Výchozí'), value: 'default' },
1669
+ { text: msg('Primární'), value: 'primary' },
1670
+ { text: msg('Úspěch'), value: 'success' },
1671
+ { text: msg('Varování'), value: 'warning' },
1672
+ { text: msg('Chyba'), value: 'error' },
1673
+ { text: msg('Informace'), value: 'info' },
1674
+ ];
1675
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1676
+ view: 'list',
1677
+ label: 'Value Color',
1678
+ options: valueVariantOptions,
1679
+ });
1680
+ valueVariantInput.on('change', (ev) => {
1681
+ if (ev.value === 'custom') {
1682
+ this.enableValueCustomStyles(cell);
1683
+ }
1684
+ else {
1685
+ this.setValueVariant(ev.value, cell);
1686
+ }
1687
+ });
1688
+ this.colorizeVariantSelect(valueVariantInput, valueVariantOptions, config, 'valueVariant');
1689
+ }
1690
+ addButtonControls(pane, config, cell) {
1691
+ // Button Variant
1692
+ const variantInput = pane.addBinding(config, 'buttonVariant', {
1693
+ view: 'list',
1694
+ label: msg('Varianta tlačítka'),
1695
+ options: [
1696
+ { text: msg('Vyplněné'), value: 'contained' },
1697
+ { text: msg('Ohraničené'), value: 'outlined' },
1698
+ { text: msg('Textové'), value: 'text' },
1699
+ { text: msg('Čárkované'), value: 'dashed' },
1700
+ ],
1701
+ });
1702
+ variantInput.on('change', (ev) => {
1703
+ this.setButtonVariant(cell, ev.value);
1704
+ });
1705
+ // Button Color
1706
+ const buttonColorOptions = [
1707
+ { text: msg('Primární'), value: 'primary' },
1708
+ { text: msg('Druhé'), value: 'secondary' },
1709
+ { text: msg('Chyba'), value: 'error' },
1710
+ { text: msg('Varování'), value: 'warning' },
1711
+ { text: msg('AI'), value: 'ai' },
1712
+ ];
1713
+ const colorInput = pane.addBinding(config, 'buttonColor', {
1714
+ view: 'list',
1715
+ label: msg('Barva tlačítka'),
1716
+ options: buttonColorOptions,
1717
+ });
1718
+ colorInput.on('change', (ev) => {
1719
+ this.setButtonColor(cell, ev.value);
1720
+ });
1721
+ this.colorizeVariantSelect(colorInput, buttonColorOptions, config, 'buttonColor');
1722
+ // Button Full Width
1723
+ const fullWidthInput = pane.addBinding(config, 'buttonFullWidth', {
1724
+ label: msg('Tlačítko na celou šířku'),
1725
+ });
1726
+ fullWidthInput.on('change', (ev) => {
1727
+ this.setButtonFullWidth(cell, ev.value);
1728
+ });
1729
+ // Add link configuration for buttons (same as links)
1730
+ // Link Type selector
1731
+ const linkTypeInput = pane.addBinding(config, 'linkType', {
1732
+ view: 'list',
1733
+ label: msg('Typ odkazu'),
1734
+ options: [
1735
+ { text: msg('Vlastní URL'), value: 'custom' },
1736
+ { text: msg('Dynamický odkaz'), value: 'dynamic' },
1737
+ ],
1738
+ });
1739
+ linkTypeInput.on('change', (ev) => {
1740
+ this.setLinkType(cell, ev.value);
1741
+ });
1742
+ // Custom URL input (shown when linkType is 'custom')
1743
+ const hrefInput = pane.addBinding(config, 'href', {
1744
+ label: msg('Vlastní URL'),
1745
+ });
1746
+ hrefInput.on('change', (ev) => {
1747
+ this.setHref(cell, ev.value);
1748
+ });
1749
+ // Open in new tab
1750
+ const openInNewTabInput = pane.addBinding(config, 'openInNewTab', {
1751
+ label: msg('Otevřít v nové záložce'),
1752
+ });
1753
+ openInNewTabInput.on('change', (ev) => {
1754
+ this.setOpenInNewTab(cell, ev.value);
1755
+ });
1756
+ }
1757
+ addCurrencyControls(pane, config, cell) {
1758
+ // Value Bold
1759
+ const fontInput = pane.addBinding(config, 'fontWeight', {
1760
+ label: msg('Tučná hodnota'),
1761
+ });
1762
+ fontInput.on('change', () => {
1763
+ this.setFontWeight(cell);
1764
+ });
1765
+ // Value Variant
1766
+ const valueVariantOptions = [
1767
+ { text: msg('Výchozí'), value: 'default' },
1768
+ { text: msg('Primární'), value: 'primary' },
1769
+ { text: msg('Úspěch'), value: 'success' },
1770
+ { text: msg('Varování'), value: 'warning' },
1771
+ { text: msg('Chyba'), value: 'error' },
1772
+ { text: msg('Informace'), value: 'info' },
1773
+ { text: msg('Vlastní'), value: 'custom' },
1774
+ ];
1775
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1776
+ view: 'list',
1777
+ label: 'Value Color',
1778
+ options: valueVariantOptions,
1779
+ });
1780
+ valueVariantInput.on('change', (ev) => {
1781
+ if (ev.value === 'custom') {
1782
+ this.enableValueCustomStyles(cell);
1783
+ }
1784
+ else {
1785
+ this.setValueVariant(ev.value, cell);
1786
+ }
1787
+ });
1788
+ this.colorizeVariantSelect(valueVariantInput, valueVariantOptions, config, 'valueVariant');
1789
+ // Number of Decimals
1790
+ const decimalInput = pane.addBinding(config, 'numberOfDecimal', {
1791
+ label: msg('Počet desetinných míst'),
1792
+ min: 0,
1793
+ max: 10,
1794
+ step: 1,
1795
+ });
1796
+ decimalInput.on('change', (ev) => {
1797
+ this.setNumberOfDecimal(cell, ev.value);
1798
+ });
1799
+ // Currency Type
1800
+ const currencyOptions = [
1801
+ { text: 'CZK', value: 'CZK' },
1802
+ { text: 'EUR', value: 'EUR' },
1803
+ { text: 'USD', value: 'USD' },
1804
+ { text: 'GBP', value: 'GBP' },
1805
+ { text: 'CHF', value: 'CHF' },
1806
+ { text: 'PLN', value: 'PLN' },
1807
+ { text: 'HUF', value: 'HUF' },
1808
+ { text: 'JPY', value: 'JPY' },
1809
+ { text: 'AUD', value: 'AUD' },
1810
+ { text: 'CAD', value: 'CAD' },
1811
+ { text: 'NOK', value: 'NOK' },
1812
+ { text: 'SEK', value: 'SEK' },
1813
+ { text: 'DKK', value: 'DKK' },
1814
+ { text: 'CNY', value: 'CNY' },
1815
+ { text: 'RUB', value: 'RUB' },
1816
+ ];
1817
+ // Add variables as currency source options
1818
+ const variableOptions = this.getAllAvailableVariables();
1819
+ variableOptions.forEach((v) => {
1820
+ currencyOptions.push({
1821
+ text: `${v.text}`,
1822
+ value: `var:${v.value}`,
1823
+ });
1824
+ });
1825
+ const currencyInput = pane.addBinding(config, 'currencyType', {
1826
+ view: 'list',
1827
+ label: msg('Typ měny'),
1828
+ options: currencyOptions,
1829
+ });
1830
+ currencyInput.on('change', (ev) => {
1831
+ this.setCurrencyType(cell, ev.value);
1832
+ });
1833
+ }
1834
+ addDateControls(pane, config, cell) {
1835
+ // Value Bold
1836
+ const fontInput = pane.addBinding(config, 'fontWeight', {
1837
+ label: msg('Tučná hodnota'),
1838
+ });
1839
+ fontInput.on('change', () => {
1840
+ this.setFontWeight(cell);
1841
+ });
1842
+ // Value Variant
1843
+ const valueVariantOptions = [
1844
+ { text: msg('Výchozí'), value: 'default' },
1845
+ { text: msg('Primární'), value: 'primary' },
1846
+ { text: msg('Úspěch'), value: 'success' },
1847
+ { text: msg('Varování'), value: 'warning' },
1848
+ { text: msg('Chyba'), value: 'error' },
1849
+ { text: msg('Informace'), value: 'info' },
1850
+ ];
1851
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1852
+ view: 'list',
1853
+ label: 'Value Color',
1854
+ options: valueVariantOptions,
1855
+ });
1856
+ valueVariantInput.on('change', (ev) => {
1857
+ if (ev.value === 'custom') {
1858
+ this.enableValueCustomStyles(cell);
1859
+ }
1860
+ else {
1861
+ this.setValueVariant(ev.value, cell);
1862
+ }
1863
+ });
1864
+ this.colorizeVariantSelect(valueVariantInput, valueVariantOptions, config, 'valueVariant');
1865
+ }
1866
+ addProgressControls(pane, config, cell) {
1867
+ // Progress Max — numeric value for 100%
1868
+ const progressMaxInput = pane.addBinding(config, 'progressMax', {
1869
+ label: msg('Hodnota 100%'),
1870
+ min: 1,
1871
+ step: 1,
1872
+ });
1873
+ progressMaxInput.on('change', (ev) => {
1874
+ this.setProgressMax(cell, ev.value);
1875
+ });
1876
+ // Progress Color
1877
+ const progressColorOptions = [
1878
+ { text: msg('Primární'), value: 'primary' },
1879
+ { text: msg('Úspěch'), value: 'success' },
1880
+ { text: msg('Varování'), value: 'warning' },
1881
+ { text: msg('Chyba'), value: 'error' },
1882
+ { text: msg('Informace'), value: 'info' },
1883
+ ];
1884
+ const progressColorInput = pane.addBinding(config, 'progressColor', {
1885
+ view: 'list',
1886
+ label: msg('Barva postupu'),
1887
+ options: progressColorOptions,
1888
+ });
1889
+ progressColorInput.on('change', (ev) => {
1890
+ this.setProgressColor(cell, ev.value);
1891
+ });
1892
+ this.colorizeVariantSelect(progressColorInput, progressColorOptions, config, 'progressColor');
1893
+ // Value Variant (for progress text color if needed)
1894
+ const valueVariantOptions = [
1895
+ { text: msg('Výchozí'), value: 'default' },
1896
+ { text: msg('Primární'), value: 'primary' },
1897
+ { text: msg('Úspěch'), value: 'success' },
1898
+ { text: msg('Varování'), value: 'warning' },
1899
+ { text: msg('Chyba'), value: 'error' },
1900
+ { text: msg('Informace'), value: 'info' },
1901
+ ];
1902
+ const valueVariantInput = pane.addBinding(config, 'valueVariant', {
1903
+ view: 'list',
1904
+ label: 'Value Color',
1905
+ options: valueVariantOptions,
1906
+ });
1907
+ valueVariantInput.on('change', (ev) => {
1908
+ if (ev.value === 'custom') {
1909
+ this.enableValueCustomStyles(cell);
1910
+ }
1911
+ else {
1912
+ this.setValueVariant(ev.value, cell);
1913
+ }
1914
+ });
1915
+ this.colorizeVariantSelect(valueVariantInput, valueVariantOptions, config, 'valueVariant');
1916
+ }
1917
+ getVariableValue(fieldName) {
1918
+ // First check in variables array for a matching field
1919
+ if (this.variables && Array.isArray(this.variables)) {
1920
+ const variableObj = this.variables.find((variable) => variable.field === fieldName);
1921
+ if (variableObj) {
1922
+ return variableObj.value;
1923
+ }
1924
+ }
1925
+ // Then check in current rows
1926
+ const rowCell = this.rows.find((cell) => cell.field === fieldName);
1927
+ if (rowCell) {
1928
+ return rowCell.value;
1929
+ }
1930
+ // Finally check in variables array
1931
+ const variableItem = this.variables.find((variable) => variable.field === fieldName);
1932
+ if (variableItem) {
1933
+ return variableItem.value;
1934
+ }
1935
+ return '';
1936
+ }
1937
+ evaluateCondition(variableField, conditionValue, operator) {
1938
+ // Get the value of the selected variable
1939
+ const variableValue = this.getVariableValue(variableField);
1940
+ // For isEmpty/isNotEmpty operators, check the raw value first
1941
+ if (operator === 'isEmpty') {
1942
+ return (variableValue === null ||
1943
+ variableValue === undefined ||
1944
+ variableValue === '' ||
1945
+ (typeof variableValue === 'string' && variableValue.trim() === ''));
1946
+ }
1947
+ if (operator === 'isNotEmpty') {
1948
+ return !(variableValue === null ||
1949
+ variableValue === undefined ||
1950
+ variableValue === '' ||
1951
+ (typeof variableValue === 'string' && variableValue.trim() === ''));
1952
+ }
1953
+ // Determine field type for proper comparison
1954
+ const fieldCell = this.rows.find((cell) => cell.field === variableField);
1955
+ // Determine field type for proper comparison
1956
+ let fieldType = 'string';
1957
+ if (fieldCell) {
1958
+ // Use cell.type directly for field type determination
1959
+ switch (fieldCell.type) {
1960
+ case 'number':
1961
+ case 'progress':
1962
+ case 'currency':
1963
+ fieldType = 'number';
1964
+ break;
1965
+ case 'date':
1966
+ fieldType = 'date';
1967
+ break;
1968
+ case 'select':
1969
+ case 'checkbox':
1970
+ fieldType = 'select';
1971
+ break;
1972
+ case 'multiselect':
1973
+ fieldType = 'multiselect';
1974
+ break;
1975
+ case 'string':
1976
+ case 'button':
1977
+ case 'link':
1978
+ default:
1979
+ fieldType = 'string';
1980
+ break;
1981
+ }
1982
+ }
1983
+ const variableStr = String(variableValue || '').toLowerCase();
1984
+ const conditionStr = String(conditionValue || '').toLowerCase();
1985
+ const variableNum = parseFloat(variableValue);
1986
+ const conditionNum = parseFloat(conditionValue);
1987
+ // For date fields, parse dates for comparison
1988
+ let variableDate = null;
1989
+ let conditionDate = null;
1990
+ if (fieldType === 'date') {
1991
+ variableDate = variableValue ? new Date(variableValue) : null;
1992
+ conditionDate = conditionValue ? new Date(conditionValue) : null;
1993
+ }
1994
+ switch (operator) {
1995
+ case '=':
1996
+ // Use numeric comparison for number/currency/progress types
1997
+ if (fieldType === 'number' /* ||
1998
+ fieldType === 'currency' ||
1999
+ fieldType === 'progress' */) {
2000
+ return (!isNaN(variableNum) && !isNaN(conditionNum) && variableNum === conditionNum);
2001
+ }
2002
+ else if (fieldType === 'date') {
2003
+ if (!variableDate || !conditionDate)
2004
+ return false;
2005
+ return variableDate.getTime() === conditionDate.getTime();
2006
+ }
2007
+ else {
2008
+ return variableStr === conditionStr;
2009
+ }
2010
+ case '!=':
2011
+ // Use numeric comparison for number/currency/progress types
2012
+ if (fieldType === 'number' /* ||
2013
+ fieldType === 'currency' ||
2014
+ fieldType === 'progress' */) {
2015
+ return (!isNaN(variableNum) && !isNaN(conditionNum) && variableNum !== conditionNum);
2016
+ }
2017
+ else if (fieldType === 'date') {
2018
+ if (!variableDate || !conditionDate)
2019
+ return true;
2020
+ return variableDate.getTime() !== conditionDate.getTime();
2021
+ }
2022
+ else {
2023
+ return variableStr !== conditionStr;
2024
+ }
2025
+ case '>':
2026
+ if (fieldType === 'date') {
2027
+ if (!variableDate || !conditionDate)
2028
+ return false;
2029
+ return variableDate.getTime() > conditionDate.getTime();
2030
+ }
2031
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum > conditionNum;
2032
+ case '>=':
2033
+ if (fieldType === 'date') {
2034
+ if (!variableDate || !conditionDate)
2035
+ return false;
2036
+ return variableDate.getTime() >= conditionDate.getTime();
2037
+ }
2038
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum >= conditionNum;
2039
+ case '<':
2040
+ if (fieldType === 'date') {
2041
+ if (!variableDate || !conditionDate)
2042
+ return false;
2043
+ return variableDate.getTime() < conditionDate.getTime();
2044
+ }
2045
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum < conditionNum;
2046
+ case '<=':
2047
+ if (fieldType === 'date') {
2048
+ if (!variableDate || !conditionDate)
2049
+ return false;
2050
+ return variableDate.getTime() <= conditionDate.getTime();
2051
+ }
2052
+ return !isNaN(variableNum) && !isNaN(conditionNum) && variableNum <= conditionNum;
2053
+ case 'contains':
2054
+ return variableStr.includes(conditionStr);
2055
+ case 'doesNotContain':
2056
+ return !variableStr.includes(conditionStr);
2057
+ case 'startsWith':
2058
+ return variableStr.startsWith(conditionStr);
2059
+ case 'endsWith':
2060
+ return variableStr.endsWith(conditionStr);
2061
+ case 'is':
2062
+ // "is" operator - for select type fields only
2063
+ // Use exact value matching (case-sensitive)
2064
+ return String(variableValue) === String(conditionValue);
2065
+ case 'not':
2066
+ // "not" operator (is not) - for select type fields only
2067
+ // Use exact value matching (case-sensitive)
2068
+ return String(variableValue) !== String(conditionValue);
2069
+ case 'in':
2070
+ // "in" operator - for multiselect fields
2071
+ // variableValue is an array, check if conditionValue is in that array
2072
+ if (Array.isArray(variableValue)) {
2073
+ return variableValue.includes(conditionValue);
2074
+ }
2075
+ // Fallback: check if variableValue is in conditionValue list
2076
+ if (Array.isArray(conditionValue)) {
2077
+ return conditionValue.includes(variableValue);
2078
+ }
2079
+ else {
2080
+ // Parse comma-separated string
2081
+ const values = String(conditionValue)
2082
+ .split(',')
2083
+ .map((v) => v.trim());
2084
+ return values.includes(String(variableValue));
2085
+ }
2086
+ case 'nin':
2087
+ // "nin" operator (not in) - for multiselect fields
2088
+ // variableValue is an array, check if conditionValue is not in that array
2089
+ if (Array.isArray(variableValue)) {
2090
+ return !variableValue.includes(conditionValue);
2091
+ }
2092
+ // Fallback: check if variableValue is not in conditionValue list
2093
+ if (Array.isArray(conditionValue)) {
2094
+ return !conditionValue.includes(variableValue);
2095
+ }
2096
+ else {
2097
+ // Parse comma-separated string
2098
+ const values = String(conditionValue)
2099
+ .split(',')
2100
+ .map((v) => v.trim());
2101
+ return !values.includes(String(variableValue));
2102
+ }
2103
+ case 'isAnyOfValue':
2104
+ // "isAnyOfValue" operator - checks if variableValue matches any of the comma-separated values
2105
+ if (!conditionValue)
2106
+ return false;
2107
+ // If variableValue is an array (for multiselect), check if any element matches any condition value
2108
+ if (Array.isArray(variableValue)) {
2109
+ const conditionValues = String(conditionValue)
2110
+ .split(',')
2111
+ .map((v) => v.trim().toLowerCase());
2112
+ return variableValue.some((val) => conditionValues.includes(String(val).toLowerCase()));
2113
+ }
2114
+ // For single values, check if variableValue matches any of the condition values
2115
+ const values = String(conditionValue)
2116
+ .split(',')
2117
+ .map((v) => v.trim().toLowerCase());
2118
+ return values.includes(variableStr);
2119
+ default:
2120
+ return false;
2121
+ }
2122
+ }
2123
+ computeCellStyles(cell) {
2124
+ // Priority order:
2125
+ // 1. Conditional formatting (highest)
2126
+ // 2. Custom cellStyle (if cellCustomStyles = true)
2127
+ // 3. Semantic cellVariant
2128
+ // 4. Default styles (lowest)
2129
+ let styles = {};
2130
+ // 4. Default styles (base)
2131
+ // (none for now, could add default cell styling here)
2132
+ // 3. Semantic cellVariant
2133
+ if (cell.cellVariant && cell.cellVariant !== 'default') {
2134
+ const variantStyle = this.getCellVariantStyle(cell.cellVariant);
2135
+ styles = { ...styles, ...variantStyle };
2136
+ }
2137
+ // 2. Custom cellStyle (if explicitly enabled)
2138
+ if (cell.cellCustomStyles && cell.cellStyle) {
2139
+ styles = { ...styles, ...cell.cellStyle };
2140
+ }
2141
+ // 1. Conditional formatting cell variant (highest priority, first match wins)
2142
+ const conditions = this.normalizeConditions(cell.conditionalFormatting);
2143
+ for (const condition of conditions) {
2144
+ if (condition?.enabled && condition?.variable) {
2145
+ const conditionMet = this.evaluateCondition(condition.variable, condition.value, condition.operator);
2146
+ if (conditionMet &&
2147
+ condition.cellVariant &&
2148
+ condition.cellVariant !== 'default') {
2149
+ const conditionalCellStyle = this.getCellVariantStyle(condition.cellVariant);
2150
+ styles = { ...styles, ...conditionalCellStyle };
2151
+ break;
2152
+ }
2153
+ }
2154
+ }
2155
+ return styles;
2156
+ }
2157
+ getCellVariantStyle(variant) {
2158
+ const variantMap = {
2159
+ primary: {
2160
+ backgroundColor: 'var(--color-primary-light)',
2161
+ borderRadius: '8px',
2162
+ border: '1px solid var(--color-primary-dark)',
2163
+ },
2164
+ success: {
2165
+ backgroundColor: 'var(--color-success-light)',
2166
+ borderRadius: '8px',
2167
+ border: '1px solid var(--color-success-dark)',
2168
+ },
2169
+ warning: {
2170
+ backgroundColor: 'var(--color-warning-light)',
2171
+ borderRadius: '8px',
2172
+ border: '1px solid var(--color-warning-dark)',
2173
+ },
2174
+ error: {
2175
+ backgroundColor: 'var(--color-error-light)',
2176
+ borderRadius: '8px',
2177
+ border: '1px solid var(--color-error-dark)',
2178
+ },
2179
+ info: {
2180
+ backgroundColor: 'var(--color-info-light)',
2181
+ borderRadius: '8px',
2182
+ border: '1px solid var(--color-info-dark)',
2183
+ },
2184
+ };
2185
+ return variantMap[variant] || {};
2186
+ }
2187
+ computeValueStyles(cell) {
2188
+ // Priority order:
2189
+ // 1. Conditional formatting value variant (highest)
2190
+ // 2. Custom valueStyle (if valueCustomStyles = true)
2191
+ // 3. Semantic valueVariant + Independent fontWeight
2192
+ // 4. Default styles (lowest)
2193
+ let styles = {};
2194
+ // 4. Default styles (base)
2195
+ // (none for now, could add default value styling here)
2196
+ // 3. Semantic valueVariant
2197
+ if (cell.valueVariant && cell.valueVariant !== 'default') {
2198
+ const variantStyle = this.getValueVariantStyle(cell.valueVariant);
2199
+ styles = { ...styles, ...variantStyle };
2200
+ }
2201
+ // 3b. Independent fontWeight (works alongside variants)
2202
+ if (cell.fontWeight && cell.fontWeight !== 'normal') {
2203
+ styles = { ...styles, fontWeight: cell.fontWeight };
2204
+ }
2205
+ // 2. Custom valueStyle (if explicitly enabled)
2206
+ if (cell.valueCustomStyles && cell.valueStyle) {
2207
+ styles = { ...styles, ...cell.valueStyle };
2208
+ }
2209
+ // 1. Conditional formatting value variant (highest priority, first match wins)
2210
+ const conditions = this.normalizeConditions(cell.conditionalFormatting);
2211
+ for (const condition of conditions) {
2212
+ if (condition?.enabled && condition?.variable) {
2213
+ const conditionMet = this.evaluateCondition(condition.variable, condition.value, condition.operator);
2214
+ if (conditionMet &&
2215
+ condition.valueVariant &&
2216
+ condition.valueVariant !== 'default') {
2217
+ const conditionalValueStyle = this.getValueVariantStyle(condition.valueVariant);
2218
+ styles = { ...styles, ...conditionalValueStyle };
2219
+ break;
2220
+ }
2221
+ }
2222
+ }
2223
+ return styles;
2224
+ }
2225
+ // Helper method to convert progress value (string or number) to numeric value
2226
+ parseProgressValue(value) {
2227
+ if (typeof value === 'number') {
2228
+ return value;
2229
+ }
2230
+ else if (typeof value === 'string') {
2231
+ const parsed = parseFloat(value);
2232
+ return !isNaN(parsed) ? parsed : 0;
2233
+ }
2234
+ return 0;
2235
+ }
2236
+ computeProgressColor(cell) {
2237
+ // Priority order:
2238
+ // 1. Conditional formatting progressColor (highest)
2239
+ // 2. Cell progressColor property
2240
+ // 3. Default 'primary' color (lowest)
2241
+ let progressColor = cell.progressColor || 'primary';
2242
+ // 1. Conditional formatting progressColor (highest priority, first match wins)
2243
+ const conditions = this.normalizeConditions(cell.conditionalFormatting);
2244
+ for (const condition of conditions) {
2245
+ if (condition?.enabled && condition?.variable) {
2246
+ const conditionMet = this.evaluateCondition(condition.variable, condition.value, condition.operator);
2247
+ if (conditionMet && condition.progressColor) {
2248
+ progressColor = condition.progressColor;
2249
+ break;
2250
+ }
2251
+ }
2252
+ }
2253
+ return progressColor;
2254
+ }
2255
+ getValueVariantStyle(variant) {
2256
+ const variantMap = {
2257
+ primary: {
2258
+ color: 'var(--color-primary-main)',
2259
+ fontWeight: '500',
2260
+ },
2261
+ success: {
2262
+ color: 'var(--color-success-main)',
2263
+ fontWeight: '500',
2264
+ },
2265
+ warning: {
2266
+ color: 'var(--color-warning-main)',
2267
+ fontWeight: '500',
2268
+ },
2269
+ error: {
2270
+ color: 'var(--color-error-main)',
2271
+ fontWeight: '500',
2272
+ },
2273
+ info: {
2274
+ color: 'var(--color-info-main)',
2275
+ fontWeight: '500',
2276
+ },
2277
+ };
2278
+ return variantMap[variant] || {};
2279
+ }
2280
+ shouldHideCell(cell) {
2281
+ const hideCondition = cell.hideCondition;
2282
+ if (!hideCondition?.enabled || !hideCondition?.variable || this.enableSettings) {
2283
+ return false;
2284
+ }
2285
+ return this.evaluateCondition(hideCondition.variable, hideCondition.value, hideCondition.operator);
2286
+ }
2287
+ initSortable() {
2288
+ this.updateComplete.then(() => {
2289
+ const containers = this.shadowRoot?.querySelectorAll('.grid-container');
2290
+ if (!containers?.length)
2291
+ return;
2292
+ containers.forEach((container) => {
2293
+ let originalNodes = [];
2294
+ const sortableInstance = Sortable.create(container, {
2295
+ group: this.tabId || this.sortableGroupId,
2296
+ animation: 150,
2297
+ handle: '.drag-handle',
2298
+ ghostClass: 'sortable-ghost',
2299
+ chosenClass: 'sortable-chosen',
2300
+ dragClass: 'sortable-drag',
2301
+ sort: true,
2302
+ onStart: (evt) => {
2303
+ originalNodes = Array.from(evt.from.childNodes);
2304
+ },
2305
+ onEnd: (evt) => {
2306
+ evt.from.innerHTML = '';
2307
+ originalNodes.forEach((node) => evt.from.appendChild(node));
2308
+ const { oldIndex, newIndex } = evt;
2309
+ if (oldIndex == null || newIndex == null || oldIndex === newIndex)
2310
+ return;
2311
+ const updated = [...this.rows];
2312
+ const [movedItem] = updated.splice(oldIndex, 1);
2313
+ updated.splice(newIndex, 0, movedItem);
2314
+ this.rows = updated;
2315
+ this.handleSettingsChanged?.(updated);
2316
+ },
2317
+ });
2318
+ this.sortableInstances.push(sortableInstance);
2319
+ });
2320
+ });
2321
+ }
2322
+ getLocaleLang() {
2323
+ if (this.userLang && LOCALE_LANGS.has(this.userLang)) {
2324
+ return this.userLang;
2325
+ }
2326
+ return 'cs';
2327
+ }
2328
+ setCellSize(size, cell, breakpoint = 'lg') {
2329
+ this.rows = this.rows.map((c) => {
2330
+ if (c.field === cell.field) {
2331
+ const updatedCell = { ...c };
2332
+ if (!updatedCell.size) {
2333
+ updatedCell.size = {};
2334
+ }
2335
+ if (breakpoint === 'xs') {
2336
+ updatedCell.size.xs = size;
2337
+ updatedCell.size.sm = size;
2338
+ }
2339
+ else if (breakpoint === 'lg') {
2340
+ updatedCell.size.md = size;
2341
+ updatedCell.size.lg = size;
2342
+ updatedCell.size.xl = size;
2343
+ }
2344
+ else {
2345
+ updatedCell.size[breakpoint] = size;
2346
+ }
2347
+ return updatedCell;
2348
+ }
2349
+ return c;
2350
+ });
2351
+ this.handleSettingsChanged(this.rows);
2352
+ }
2353
+ setCellType(cell, type) {
2354
+ this.rows = this.rows.map((c) => {
2355
+ if (c.field === cell.field) {
2356
+ return { ...c, type };
2357
+ }
2358
+ return c;
2359
+ });
2360
+ this.handleSettingsChanged(this.rows);
2361
+ // Simply close the settings popper when cell type changes
2362
+ // User can reopen to see the new type-specific controls
2363
+ //this.closeSettingsPopper();
2364
+ }
2365
+ setHideCondition(cell, property, value) {
2366
+ // Update the cell in the rows array
2367
+ this.rows = this.rows.map((c) => {
2368
+ if (c.field === cell.field) {
2369
+ const updatedCell = { ...c };
2370
+ // Initialize hide condition if not exists
2371
+ if (!updatedCell.hideCondition) {
2372
+ updatedCell.hideCondition = {
2373
+ // Set default operator when creating new hide condition
2374
+ operator: this.getDefaultOperatorForCell(cell),
2375
+ };
2376
+ }
2377
+ else {
2378
+ // Create a copy of hideCondition to avoid mutating the original
2379
+ updatedCell.hideCondition = { ...updatedCell.hideCondition };
2380
+ }
2381
+ // Set the property
2382
+ updatedCell.hideCondition[property] = value;
2383
+ return updatedCell;
2384
+ }
2385
+ return c;
2386
+ });
2387
+ this.handleSettingsChanged(this.rows);
2388
+ }
2389
+ setHref(cell, href) {
2390
+ this.rows = this.rows.map((c) => {
2391
+ if (c.field === cell.field) {
2392
+ return { ...c, href };
2393
+ }
2394
+ return c;
2395
+ });
2396
+ this.handleSettingsChanged(this.rows);
2397
+ }
2398
+ setOpenInNewTab(cell, openInNewTab) {
2399
+ this.rows = this.rows.map((c) => {
2400
+ if (c.field === cell.field) {
2401
+ return { ...c, openInNewTab };
2402
+ }
2403
+ return c;
2404
+ });
2405
+ this.handleSettingsChanged(this.rows);
2406
+ }
2407
+ setLinkType(cell, linkType) {
2408
+ this.rows = this.rows.map((c) => {
2409
+ if (c.field === cell.field) {
2410
+ const updatedCell = { ...c, linkType: linkType };
2411
+ // Clear other link properties when switching types
2412
+ {
2413
+ updatedCell.href = '';
2414
+ }
2415
+ return updatedCell;
2416
+ }
2417
+ return c;
2418
+ });
2419
+ this.handleSettingsChanged(this.rows);
2420
+ }
2421
+ setNumberOfDecimal(cell, numberOfDecimal) {
2422
+ this.rows = this.rows.map((c) => {
2423
+ if (c.field === cell.field) {
2424
+ return { ...c, numberOfDecimal };
2425
+ }
2426
+ return c;
2427
+ });
2428
+ this.handleSettingsChanged(this.rows);
2429
+ }
2430
+ setButtonVariant(cell, variant) {
2431
+ this.rows = this.rows.map((c) => {
2432
+ if (c.field === cell.field) {
2433
+ return { ...c, buttonVariant: variant };
2434
+ }
2435
+ return c;
2436
+ });
2437
+ this.handleSettingsChanged(this.rows);
2438
+ }
2439
+ setButtonColor(cell, color) {
2440
+ this.rows = this.rows.map((c) => {
2441
+ if (c.field === cell.field) {
2442
+ return { ...c, buttonColor: color };
2443
+ }
2444
+ return c;
2445
+ });
2446
+ this.handleSettingsChanged(this.rows);
2447
+ }
2448
+ setButtonFullWidth(cell, fullWidth) {
2449
+ this.rows = this.rows.map((c) => {
2450
+ if (c.field === cell.field) {
2451
+ return { ...c, buttonFullWidth: fullWidth };
2452
+ }
2453
+ return c;
2454
+ });
2455
+ this.handleSettingsChanged(this.rows);
2456
+ }
2457
+ setCurrencyType(cell, currencyType) {
2458
+ this.rows = this.rows.map((c) => {
2459
+ if (c.field === cell.field) {
2460
+ return { ...c, currencyType };
2461
+ }
2462
+ return c;
2463
+ });
2464
+ this.handleSettingsChanged(this.rows);
2465
+ }
2466
+ setProgressMax(cell, progressMax) {
2467
+ this.rows = this.rows.map((c) => {
2468
+ if (c.field === cell.field) {
2469
+ return { ...c, progressMax };
2470
+ }
2471
+ return c;
2472
+ });
2473
+ this.handleSettingsChanged(this.rows);
2474
+ }
2475
+ setProgressColor(cell, progressColor) {
2476
+ this.rows = this.rows.map((c) => {
2477
+ if (c.field === cell.field) {
2478
+ return { ...c, progressColor };
2479
+ }
2480
+ return c;
2481
+ });
2482
+ this.handleSettingsChanged(this.rows);
2483
+ }
2484
+ setCellHeaderName(cell, headerName) {
2485
+ this.rows = this.rows.map((c) => {
2486
+ if (c.field === cell.field) {
2487
+ return { ...c, headerName };
2488
+ }
2489
+ return c;
2490
+ });
2491
+ this.handleSettingsChanged(this.rows);
2492
+ }
2493
+ setCellValue(cell, value) {
2494
+ // Update the cell in the rows array
2495
+ this.rows = this.rows.map((c) => {
2496
+ if (c.field === cell.field) {
2497
+ return { ...c, value };
2498
+ }
2499
+ return c;
2500
+ });
2501
+ this.handleSettingsChanged(this.rows);
2502
+ }
2503
+ removeCellFromRows(field) {
2504
+ this.destroySortables();
2505
+ const updatedRows = this.rows.filter((c) => c.field !== field);
2506
+ this.rows = [];
2507
+ this.updateComplete.then(() => {
2508
+ this.rows = [...updatedRows];
2509
+ this.initSortable();
2510
+ this.handleSettingsChanged(this.rows);
2511
+ });
2512
+ }
2513
+ closePopover() {
2514
+ this.isOpen = false;
2515
+ }
2516
+ toggleCustomPopover() {
2517
+ this.isOpen = !this.isOpen;
2518
+ if (this.isOpen) {
2519
+ this.updateComplete.then(() => {
2520
+ setTimeout(() => {
2521
+ const input = this.shadowRoot?.querySelector('#variable-filter-input') ||
2522
+ document.querySelector('#variable-filter-input');
2523
+ input?.focus();
2524
+ }, 100);
2525
+ });
2526
+ }
2527
+ }
2528
+ get existingFields() {
2529
+ return this.rows.flat().map((cell) => cell.field);
2530
+ }
2531
+ toggleRowCell(key) {
2532
+ const exists = this.rows.some((cell) => cell.field === key);
2533
+ if (exists) {
2534
+ this.removeCellFromRows(key);
2535
+ }
2536
+ else {
2537
+ const raw = this.variables.find((variable) => variable.field === key);
2538
+ if (!raw)
2539
+ return;
2540
+ const newCell = {
2541
+ field: key,
2542
+ type: raw.type,
2543
+ headerName: raw.headerName,
2544
+ value: raw.value,
2545
+ size: { xs: 4, sm: 2, md: 1, lg: 1, xl: 1 },
2546
+ tooltip: raw.tooltip,
2547
+ };
2548
+ const newRows = [...this.rows];
2549
+ newRows.push(newCell);
2550
+ this.rows = newRows;
2551
+ this.handleSettingsChanged(newRows);
2552
+ }
2553
+ }
2554
+ dispatchDynamicLinkEvent(cell, url) {
2555
+ this.dispatchEvent(new CustomEvent('dynamic-link-click', {
2556
+ detail: { cell, url, href: cell.href || '' },
2557
+ bubbles: true,
2558
+ composed: true,
2559
+ }));
2560
+ }
2561
+ replaceDynamicVariables(template) {
2562
+ return template.replace(/\{([^}]+)\}/g, (_match, variableName) => {
2563
+ const name = variableName.trim();
2564
+ const variableValue = this.getVariableValue(name);
2565
+ if (variableValue === undefined || variableValue === null || variableValue === '') {
2566
+ console.warn(`[lit-case-variables-tab] Dynamic link variable "{${name}}" resolved to empty.`);
2567
+ return '';
2568
+ }
2569
+ return String(variableValue);
2570
+ });
2571
+ }
2572
+ collapseEmptyPathSegments(url) {
2573
+ const schemeMatch = url.match(/^([a-z][a-z0-9+.-]*:\/\/)(.*)$/i);
2574
+ const scheme = schemeMatch ? schemeMatch[1] : '';
2575
+ const rest = schemeMatch ? schemeMatch[2] : url;
2576
+ const [pathAndAuthority, query = ''] = rest.split('?');
2577
+ const collapsedPath = pathAndAuthority.replace(/\/{2,}/g, '/').replace(/\/+$/g, '');
2578
+ return scheme + collapsedPath + (query ? `?${query}` : '');
2579
+ }
2580
+ getLinkUrl(cell) {
2581
+ const href = cell.href || '';
2582
+ const resolved = href.includes('{') ? this.replaceDynamicVariables(href) : href;
2583
+ const raw = cell.linkType === 'dynamic' ? `${this.hostURL}/${resolved}` : resolved;
2584
+ return this.collapseEmptyPathSegments(raw);
2585
+ }
2586
+ formatDisplayValue(rawValue) {
2587
+ if (rawValue === null || rawValue === undefined)
2588
+ return '';
2589
+ if (typeof rawValue === 'string') {
2590
+ // Handle string representations of arrays, e.g. "[Finance, Legal, HR]"
2591
+ if (rawValue.startsWith('[') && rawValue.endsWith(']')) {
2592
+ const inner = rawValue.slice(1, -1).trim();
2593
+ if (inner.length > 0) {
2594
+ return inner.split(',').map((s) => s.trim()).filter((s) => s !== '').join(', ');
2595
+ }
2596
+ return '';
2597
+ }
2598
+ return rawValue;
2599
+ }
2600
+ if (Array.isArray(rawValue)) {
2601
+ return rawValue
2602
+ .map((v) => this.formatDisplayValue(v))
2603
+ .filter((v) => v !== '')
2604
+ .join(', ');
2605
+ }
2606
+ if (typeof rawValue === 'object') {
2607
+ const entries = Object.entries(rawValue)
2608
+ .map(([key, v]) => {
2609
+ const val = this.formatDisplayValue(v);
2610
+ return val ? `${key}: ${val}` : '';
2611
+ })
2612
+ .filter((entry) => entry !== '');
2613
+ return entries.length > 0 ? entries.join(' | ') : '';
2614
+ }
2615
+ return String(rawValue);
2616
+ }
2617
+ getAllDataGridRefs() {
2618
+ if (this.dataGridRefs?.length)
2619
+ return this.dataGridRefs;
2620
+ if (this.dataGridRef)
2621
+ return [{ id: '_default', label: 'DataGrid', ref: this.dataGridRef }];
2622
+ return [];
2623
+ }
2624
+ hasAnyDataGridRef() {
2625
+ return this.getAllDataGridRefs().length > 0;
2626
+ }
2627
+ getDataGridBySource(source) {
2628
+ const refs = this.getAllDataGridRefs();
2629
+ if (!source) {
2630
+ return refs.length === 1 ? refs[0].ref : null;
2631
+ }
2632
+ const entry = refs.find((r) => r.id === source);
2633
+ return entry?.ref || null;
2634
+ }
2635
+ resolveExpertOperand(type, value, source, aggregation = 'sum') {
2636
+ if (!value)
2637
+ return null;
2638
+ if (type === 'column') {
2639
+ const grid = this.getDataGridBySource(source || '');
2640
+ if (!grid)
2641
+ return null;
2642
+ const rows = grid.row || [];
2643
+ const values = rows.map((row) => parseFloat(row[value])).filter((v) => !isNaN(v));
2644
+ if (values.length === 0)
2645
+ return 0;
2646
+ switch (aggregation) {
2647
+ case 'sum':
2648
+ return values.reduce((acc, v) => acc + v, 0);
2649
+ case 'avg':
2650
+ return values.reduce((acc, v) => acc + v, 0) / values.length;
2651
+ case 'min':
2652
+ return Math.min(...values);
2653
+ case 'max':
2654
+ return Math.max(...values);
2655
+ case 'count':
2656
+ return values.length;
2657
+ default:
2658
+ return values.reduce((acc, v) => acc + v, 0);
2659
+ }
2660
+ }
2661
+ // type === 'variable'
2662
+ // Use pre-computed expert value if available, otherwise fall back to raw value
2663
+ if (this._resolvedExpertValues.has(value)) {
2664
+ return this._resolvedExpertValues.get(value);
2665
+ }
2666
+ const variable = [...this.rows, ...this.variables].find((v) => v.field === value);
2667
+ if (!variable)
2668
+ return null;
2669
+ const parsed = parseFloat(String(variable.value || 0));
2670
+ return isNaN(parsed) ? 0 : parsed;
2671
+ }
2672
+ computeExpertValue(cell) {
2673
+ const config = cell.expertMode;
2674
+ if (!config?.enabled)
2675
+ return null;
2676
+ const leftType = config.leftType || 'column';
2677
+ const rightType = config.rightType || 'variable';
2678
+ const left = this.resolveExpertOperand(leftType, config.leftValue || config.sourceColumn || '', config.leftSource, config.leftAggregation || 'sum');
2679
+ if (left === null)
2680
+ return null;
2681
+ if (config.operation === 'none')
2682
+ return left;
2683
+ const rightValue = config.rightValue || config.variableField || '';
2684
+ if (!rightValue)
2685
+ return left;
2686
+ const right = this.resolveExpertOperand(rightType, rightValue, config.rightSource, config.rightAggregation || 'sum');
2687
+ if (right === null)
2688
+ return left;
2689
+ switch (config.operation) {
2690
+ case '+':
2691
+ return left + right;
2692
+ case '-':
2693
+ return left - right;
2694
+ case '*':
2695
+ return left * right;
2696
+ case '/':
2697
+ return right !== 0 ? left / right : null;
2698
+ default:
2699
+ return left;
2700
+ }
2701
+ }
2702
+ precomputeExpertValues() {
2703
+ this._resolvedExpertValues.clear();
2704
+ const maxPasses = 3;
2705
+ for (let pass = 0; pass < maxPasses; pass++) {
2706
+ let changed = false;
2707
+ for (const cell of this.rows) {
2708
+ const expertValue = this.computeExpertValue(cell);
2709
+ if (expertValue !== null) {
2710
+ const prev = this._resolvedExpertValues.get(cell.field);
2711
+ if (prev !== expertValue) {
2712
+ this._resolvedExpertValues.set(cell.field, expertValue);
2713
+ changed = true;
2714
+ }
2715
+ }
2716
+ }
2717
+ if (!changed)
2718
+ break;
2719
+ }
2720
+ }
2721
+ getCellWithExpertValue(cell) {
2722
+ const expertValue = this._resolvedExpertValues.get(cell.field);
2723
+ if (expertValue !== undefined) {
2724
+ return { ...cell, value: expertValue };
2725
+ }
2726
+ return cell;
2727
+ }
2728
+ openExpertModeModal(cell) {
2729
+ this.closeSettingsPopper();
2730
+ this.expertModeCell = cell;
2731
+ const existing = cell.expertMode;
2732
+ const defaultSource = this.getAllDataGridRefs().length === 1 ? this.getAllDataGridRefs()[0].id : '';
2733
+ // Load headerName mutations from cell
2734
+ const mutations = {};
2735
+ const supportedLangs = ['cs', 'en', 'de', 'sk', 'pl', 'hu', 'fr', 'it', 'es', 'sr'];
2736
+ supportedLangs.forEach((lang) => {
2737
+ const val = cell[`headerName_${lang}`];
2738
+ if (val)
2739
+ mutations[lang] = val;
2740
+ });
2741
+ this.expertModeConfig = {
2742
+ enabled: existing?.enabled || false,
2743
+ leftType: existing?.leftType || 'column',
2744
+ leftSource: existing?.leftSource || defaultSource,
2745
+ leftValue: existing?.leftValue || existing?.sourceColumn || '',
2746
+ leftAggregation: existing?.leftAggregation || 'sum',
2747
+ operation: existing?.operation || 'none',
2748
+ rightType: existing?.rightType || 'variable',
2749
+ rightSource: existing?.rightSource || defaultSource,
2750
+ rightValue: existing?.rightValue || existing?.variableField || '',
2751
+ rightAggregation: existing?.rightAggregation || 'sum',
2752
+ headerName: cell.headerName || '',
2753
+ headerNameMutations: mutations,
2754
+ pmEnabled: existing?.pmEnabled || false,
2755
+ pmLeftType: existing?.pmLeftType || 'column',
2756
+ pmLeftSource: existing?.pmLeftSource || defaultSource,
2757
+ pmLeftValue: existing?.pmLeftValue || '',
2758
+ pmLeftAggregation: existing?.pmLeftAggregation || 'sum',
2759
+ pmOperation: existing?.pmOperation || 'none',
2760
+ pmRightType: existing?.pmRightType || 'variable',
2761
+ pmRightSource: existing?.pmRightSource || defaultSource,
2762
+ pmRightValue: existing?.pmRightValue || '',
2763
+ pmRightAggregation: existing?.pmRightAggregation || 'sum',
2764
+ };
2765
+ this.expertModeModalOpen = true;
2766
+ }
2767
+ saveExpertMode() {
2768
+ if (!this.expertModeCell)
2769
+ return;
2770
+ this.rows = this.rows.map((c) => {
2771
+ if (c.field === this.expertModeCell.field) {
2772
+ const { headerName, headerNameMutations, ...expertModeData } = this.expertModeConfig;
2773
+ const updated = {
2774
+ ...c,
2775
+ expertMode: expertModeData,
2776
+ headerName: headerName,
2777
+ };
2778
+ // Write language mutations
2779
+ Object.entries(headerNameMutations).forEach(([lang, val]) => {
2780
+ updated[`headerName_${lang}`] = val;
2781
+ });
2782
+ // Remove empty mutations
2783
+ const supportedLangs = ['cs', 'en', 'de', 'sk', 'pl', 'hu', 'fr', 'it', 'es', 'sr'];
2784
+ supportedLangs.forEach((lang) => {
2785
+ if (!headerNameMutations[lang]) {
2786
+ delete updated[`headerName_${lang}`];
2787
+ }
2788
+ });
2789
+ return updated;
2790
+ }
2791
+ return c;
2792
+ });
2793
+ this.handleSettingsChanged(this.rows);
2794
+ this.expertModeModalOpen = false;
2795
+ this.expertModeCell = null;
2796
+ }
2797
+ getGridColumnOptions(source) {
2798
+ const grid = this.getDataGridBySource(source || '');
2799
+ if (!grid?.columns)
2800
+ return [];
2801
+ return grid.columns
2802
+ .filter((col) => {
2803
+ const type = col.type;
2804
+ return type === 'number' || type === 'currency' || type === 'range' || type === 'numberRange';
2805
+ })
2806
+ .map((col) => ({
2807
+ label: col.headerName || col.field,
2808
+ value: col.field,
2809
+ }));
2810
+ }
2811
+ getGridSourceOptions() {
2812
+ return this.getAllDataGridRefs().map((entry) => ({
2813
+ label: entry.label,
2814
+ value: entry.id,
2815
+ }));
2816
+ }
2817
+ getExpertVariableOptions() {
2818
+ const numericTypes = ['currency', 'number'];
2819
+ const variables = [];
2820
+ this.rows.forEach((cell) => {
2821
+ if (cell.type && numericTypes.includes(cell.type)) {
2822
+ variables.push({
2823
+ label: cell.headerName || cell.field,
2824
+ value: cell.field,
2825
+ });
2826
+ }
2827
+ });
2828
+ const existingFields = this.rows.map((cell) => cell.field);
2829
+ this.variables.forEach((variable) => {
2830
+ if (!existingFields.includes(variable.field) && variable.type && numericTypes.includes(variable.type)) {
2831
+ variables.push({
2832
+ label: variable.headerName || variable.field,
2833
+ value: variable.field,
2834
+ });
2835
+ }
2836
+ });
2837
+ return variables.sort((a, b) => a.label.localeCompare(b.label));
2838
+ }
2839
+ getExpertModePreviewValue() {
2840
+ if (!this.expertModeConfig.enabled || !this.expertModeConfig.leftValue) {
2841
+ return '-';
2842
+ }
2843
+ const tempCell = { field: '__preview__', expertMode: { ...this.expertModeConfig } };
2844
+ const value = this.computeExpertValue(tempCell);
2845
+ if (value === null)
2846
+ return 'N/A';
2847
+ return formatDecimal(value, { locale: this.getLocaleLang(), numberOfDecimal: 2 }) || String(value);
2848
+ }
2849
+ computeProgressMaxExpertValue(config) {
2850
+ if (!config?.pmEnabled)
2851
+ return null;
2852
+ const leftType = config.pmLeftType || 'column';
2853
+ const rightType = config.pmRightType || 'variable';
2854
+ const left = this.resolveExpertOperand(leftType, config.pmLeftValue || '', config.pmLeftSource, config.pmLeftAggregation || 'sum');
2855
+ if (left === null)
2856
+ return null;
2857
+ if (config.pmOperation === 'none')
2858
+ return left;
2859
+ const rightValue = config.pmRightValue || '';
2860
+ if (!rightValue)
2861
+ return left;
2862
+ const right = this.resolveExpertOperand(rightType, rightValue, config.pmRightSource, config.pmRightAggregation || 'sum');
2863
+ if (right === null)
2864
+ return left;
2865
+ switch (config.pmOperation) {
2866
+ case '+': return left + right;
2867
+ case '-': return left - right;
2868
+ case '*': return left * right;
2869
+ case '/': return right !== 0 ? left / right : null;
2870
+ default: return left;
2871
+ }
2872
+ }
2873
+ getProgressMaxPreviewValue() {
2874
+ if (!this.expertModeConfig.pmEnabled || !this.expertModeConfig.pmLeftValue) {
2875
+ return '-';
2876
+ }
2877
+ const value = this.computeProgressMaxExpertValue(this.expertModeConfig);
2878
+ if (value === null)
2879
+ return 'N/A';
2880
+ return formatDecimal(value, { locale: this.getLocaleLang(), numberOfDecimal: 2 }) || String(value);
2881
+ }
2882
+ getExpertOperandLabel(type, value, source, aggregation = 'sum') {
2883
+ if (!value)
2884
+ return '?';
2885
+ if (type === 'column') {
2886
+ const refs = this.getAllDataGridRefs();
2887
+ const sourceLabel = refs.length > 1
2888
+ ? refs.find((r) => r.id === source)?.label || ''
2889
+ : '';
2890
+ const aggLabel = (aggregation || 'sum').toUpperCase();
2891
+ return sourceLabel ? `${aggLabel}(${sourceLabel}.${value})` : `${aggLabel}(${value})`;
2892
+ }
2893
+ const variable = [...this.rows, ...this.variables].find((v) => v.field === value);
2894
+ return variable?.headerName || value;
2895
+ }
2896
+ renderExpertOperandSelector(side, label, tooltipText, prefix = '') {
2897
+ const pre = prefix || '';
2898
+ const typeKey = (pre + (side === 'left' ? 'LeftType' : 'RightType'));
2899
+ const sourceKey = (pre + (side === 'left' ? 'LeftSource' : 'RightSource'));
2900
+ const valueKey = (pre + (side === 'left' ? 'LeftValue' : 'RightValue'));
2901
+ const aggregationKey = (pre + (side === 'left' ? 'LeftAggregation' : 'RightAggregation'));
2902
+ const enabledKey = (pre ? pre + 'Enabled' : 'enabled');
2903
+ // For non-prefixed keys (default), use original camelCase: leftType, rightType, etc.
2904
+ const typeKeyFinal = pre ? typeKey : (side === 'left' ? 'leftType' : 'rightType');
2905
+ const sourceKeyFinal = pre ? sourceKey : (side === 'left' ? 'leftSource' : 'rightSource');
2906
+ const valueKeyFinal = pre ? valueKey : (side === 'left' ? 'leftValue' : 'rightValue');
2907
+ const aggregationKeyFinal = pre ? aggregationKey : (side === 'left' ? 'leftAggregation' : 'rightAggregation');
2908
+ const currentType = this.expertModeConfig[typeKeyFinal];
2909
+ const currentSource = this.expertModeConfig[sourceKeyFinal];
2910
+ const currentValue = this.expertModeConfig[valueKeyFinal];
2911
+ const currentAggregation = this.expertModeConfig[aggregationKeyFinal];
2912
+ const isEnabled = !!this.expertModeConfig[enabledKey];
2913
+ const typeOptions = [
2914
+ { label: msg('Tabulka'), value: 'column' },
2915
+ { label: msg('Proměnná'), value: 'variable' },
2916
+ ];
2917
+ const aggregationOptions = [
2918
+ { label: 'SUM', value: 'sum' },
2919
+ { label: 'AVG', value: 'avg' },
2920
+ { label: 'MIN', value: 'min' },
2921
+ { label: 'MAX', value: 'max' },
2922
+ { label: 'COUNT', value: 'count' },
2923
+ ];
2924
+ const gridSourceOptions = this.getGridSourceOptions();
2925
+ const showSourceSelector = currentType === 'column' && gridSourceOptions.length >= 1;
2926
+ const valueOptions = currentType === 'column'
2927
+ ? this.getGridColumnOptions(currentSource)
2928
+ : this.getExpertVariableOptions();
2929
+ return html `
2930
+ <div style="flex: 1; display: flex; flex-direction: column; gap: 4px;">
2931
+ <lit-label .label="${label}" .tooltip="${tooltipText}"></lit-label>
2932
+ <div style="display: flex; flex-direction: column; gap: 4px;">
2933
+ <lit-select
2934
+ .options=${typeOptions}
2935
+ .value=${currentType}
2936
+ .placeholder=${msg('Vyberte typ')}
2937
+ .disabled=${!isEnabled}
2938
+ .onChange=${(value) => {
2939
+ const val = (Array.isArray(value) ? value[0] : value);
2940
+ this.expertModeConfig = {
2941
+ ...this.expertModeConfig,
2942
+ [typeKeyFinal]: val || 'column',
2943
+ [valueKeyFinal]: '',
2944
+ };
2945
+ this.requestUpdate();
2946
+ }}
2947
+ ></lit-select>
2948
+ ${currentType === 'column' && gridSourceOptions.length === 0
2949
+ ? html `
2950
+ <div style="
2951
+ display: flex;
2952
+ align-items: center;
2953
+ gap: 0.375rem;
2954
+ padding: 0.5rem 0.75rem;
2955
+ background: var(--color-info-light, #e0f2fe);
2956
+ color: var(--color-info-dark, #0369a1);
2957
+ border-radius: var(--border-radius-small, 8px);
2958
+ font-size: 0.75rem;
2959
+ font-weight: 500;
2960
+ ">
2961
+ <lit-icon name="info" size="16"></lit-icon>
2962
+ ${msg('Pro výpočet z tabulky je nutné přidat tabulku.')}
2963
+ </div>
2964
+ `
2965
+ : html `
2966
+ ${showSourceSelector
2967
+ ? html `
2968
+ <lit-select
2969
+ .options=${gridSourceOptions}
2970
+ .value=${currentSource}
2971
+ .placeholder=${msg('Vyberte tabulku')}
2972
+ .disabled=${!isEnabled}
2973
+ .onChange=${(value) => {
2974
+ const val = Array.isArray(value) ? value[0] : value;
2975
+ this.expertModeConfig = {
2976
+ ...this.expertModeConfig,
2977
+ [sourceKeyFinal]: val || '',
2978
+ [valueKeyFinal]: '',
2979
+ };
2980
+ this.requestUpdate();
2981
+ }}
2982
+ ></lit-select>
2983
+ `
2984
+ : ''}
2985
+ <lit-select
2986
+ .options=${valueOptions}
2987
+ .value=${currentValue}
2988
+ .placeholder=${currentType === 'column' ? msg('Vyberte sloupec') : msg('Vyberte proměnnou')}
2989
+ .disabled=${!isEnabled}
2990
+ .onChange=${(value) => {
2991
+ const val = Array.isArray(value) ? value[0] : value;
2992
+ this.expertModeConfig = {
2993
+ ...this.expertModeConfig,
2994
+ [valueKeyFinal]: val || '',
2995
+ };
2996
+ this.requestUpdate();
2997
+ }}
2998
+ ></lit-select>
2999
+ ${currentType === 'column'
3000
+ ? html `
3001
+ <lit-select
3002
+ .options=${aggregationOptions}
3003
+ .value=${currentAggregation}
3004
+ .placeholder=${msg('Vyberte agregaci')}
3005
+ .disabled=${!isEnabled}
3006
+ .onChange=${(value) => {
3007
+ const val = Array.isArray(value) ? value[0] : value;
3008
+ this.expertModeConfig = {
3009
+ ...this.expertModeConfig,
3010
+ [aggregationKeyFinal]: val || 'sum',
3011
+ };
3012
+ this.requestUpdate();
3013
+ }}
3014
+ ></lit-select>
3015
+ `
3016
+ : ''}
3017
+ `}
3018
+ </div>
3019
+ </div>
3020
+ `;
3021
+ }
3022
+ renderExpertModeModal() {
3023
+ const operationOptions = [
3024
+ { label: msg('Žádná'), value: 'none' },
3025
+ { label: '+ (' + msg('Sčítání') + ')', value: '+' },
3026
+ { label: '- (' + msg('Odčítání') + ')', value: '-' },
3027
+ { label: '× (' + msg('Násobení') + ')', value: '*' },
3028
+ { label: '÷ (' + msg('Dělení') + ')', value: '/' },
3029
+ ];
3030
+ const isNoOperation = this.expertModeConfig.operation === 'none';
3031
+ const closeModal = () => {
3032
+ this.expertModeModalOpen = false;
3033
+ this.expertModeCell = null;
3034
+ };
3035
+ return html `
3036
+ <lit-modal
3037
+ .open=${this.expertModeModalOpen}
3038
+ .onClose=${closeModal}
3039
+ .closeOnOutsideClick=${false}
3040
+ style="min-width: 60vw;"
3041
+ >
3042
+ <lit-modal-header
3043
+ style="display: flex; align-items: center; justify-content: space-between; color: var(--text-secondary, #777);"
3044
+ >
3045
+ ${msg('Expertní mód')} - ${this.expertModeCell?.headerName || this.expertModeCell?.field || ''}
3046
+ <lit-icon-button
3047
+ .icon="${'close'}"
3048
+ variant="text"
3049
+ color="secondary"
3050
+ size="${'small'}"
3051
+ @click=${closeModal}
3052
+ ></lit-icon-button>
3053
+ </lit-modal-header>
3054
+ <lit-modal-body>
3055
+ <div style="height: 400px;">
3056
+ <lit-tabs-overview
3057
+ .tabs=${[
3058
+ ...(this.expertModeCell?.type === 'progress'
3059
+ ? [{ id: 'progressMax', label: { default: msg('Hodnota 100%') }, icon: 'accomplish' }]
3060
+ : []),
3061
+ ...(this.expertModeCell?.type === 'number' || this.expertModeCell?.type === 'currency' || this.expertModeCell?.type === 'progress'
3062
+ ? [{ id: 'calculation', label: { default: msg('Výpočet') }, icon: 'calculator' }]
3063
+ : []),
3064
+ ...(this.expertModeCell?.field.startsWith('custom_cell_')
3065
+ ? [{ id: 'header', label: { default: msg('Název buňky') }, icon: 'lang' }]
3066
+ : []),
3067
+ ]}
3068
+ .userLang=${this.userLang}
3069
+ >
3070
+ <!-- Tab: Výpočet (Calculation) -->
3071
+ <div slot="calculation" style="display: flex; flex-direction: column; gap: 1rem;">
3072
+ <lit-toggle
3073
+ .label="${msg('Povolit expertní výpočet')}"
3074
+ .tooltip="${msg('Vypočítá hodnotu na základě vybraných sloupců/proměnných a zvolené matematické operace.')}"
3075
+ .checked=${this.expertModeConfig.enabled}
3076
+ @change=${(e) => {
3077
+ this.expertModeConfig = {
3078
+ ...this.expertModeConfig,
3079
+ enabled: e.detail,
3080
+ };
3081
+ }}
3082
+ ></lit-toggle>
3083
+
3084
+ ${this.expertModeConfig.enabled ? html `
3085
+ <div style="display: flex; flex-direction: row; gap: 1rem; align-items: flex-start;">
3086
+ ${this.renderExpertOperandSelector('left', msg('Levý operand'), msg('Vyberte typ a hodnotu levého operandu. Sloupec vypočítá agregaci (SUM, AVG, MIN, MAX, COUNT) všech hodnot, proměnná použije hodnotu vybrané buňky.'))}
3087
+
3088
+ <div style="flex: 0 0 auto; display: flex; flex-direction: column; gap: 4px; min-width: 120px;">
3089
+ <lit-label .label="${msg('Operace')}" .tooltip="${msg('Matematická operace mezi levým a pravým operandem. Zvolte Žádná pro zobrazení pouze levého operandu.')}"></lit-label>
3090
+ <lit-select
3091
+ .options=${operationOptions}
3092
+ .value=${this.expertModeConfig.operation}
3093
+ .placeholder=${msg('Vyberte operaci')}
3094
+ .onChange=${(value) => {
3095
+ const val = Array.isArray(value) ? value[0] : value;
3096
+ this.expertModeConfig = {
3097
+ ...this.expertModeConfig,
3098
+ operation: val || '+',
3099
+ };
3100
+ this.requestUpdate();
3101
+ }}
3102
+ ></lit-select>
3103
+ </div>
3104
+
3105
+ ${!isNoOperation ? this.renderExpertOperandSelector('right', msg('Pravý operand'), msg('Vyberte typ a hodnotu pravého operandu. Sloupec vypočítá agregaci (SUM, AVG, MIN, MAX, COUNT) všech hodnot, proměnná použije hodnotu vybrané buňky.')) : ''}
3106
+ </div>
3107
+
3108
+ <div
3109
+ style="
3110
+ padding: 0.75rem;
3111
+ background: var(--background-default, #f5f5f5);
3112
+ border-radius: var(--border-radius-small, 8px);
3113
+ font-size: 0.8125rem;
3114
+ color: var(--text-secondary, #5d6371);
3115
+ "
3116
+ >
3117
+ <div style="font-weight: 600; margin-bottom: 0.25rem;">${msg('Náhled výpočtu')}</div>
3118
+ <div>
3119
+ ${this.getExpertOperandLabel(this.expertModeConfig.leftType, this.expertModeConfig.leftValue, this.expertModeConfig.leftSource, this.expertModeConfig.leftAggregation)}
3120
+ ${this.expertModeConfig.operation !== 'none'
3121
+ ? html `${this.expertModeConfig.operation} ${this.getExpertOperandLabel(this.expertModeConfig.rightType, this.expertModeConfig.rightValue, this.expertModeConfig.rightSource, this.expertModeConfig.rightAggregation)}`
3122
+ : ''}
3123
+ = <strong style="color: var(--text-primary, #111827);">${this.getExpertModePreviewValue()}</strong>
3124
+ </div>
3125
+ </div>
3126
+ ` : ''}
3127
+ </div>
3128
+
3129
+ <!-- Tab: Hodnota 100% (Progress Max) -->
3130
+ ${this.expertModeCell?.type === 'progress' ? html `
3131
+ <div slot="progressMax" style="display: flex; flex-direction: column; gap: 1rem;">
3132
+ <lit-toggle
3133
+ .label="${msg('Vypočítat hodnotu 100%')}"
3134
+ .tooltip="${msg('Vypočítá hodnotu pro 100% na základě vybraných sloupců/proměnných a zvolené matematické operace.')}"
3135
+ .checked=${this.expertModeConfig.pmEnabled}
3136
+ @change=${(e) => {
3137
+ this.expertModeConfig = {
3138
+ ...this.expertModeConfig,
3139
+ pmEnabled: e.detail,
3140
+ };
3141
+ }}
3142
+ ></lit-toggle>
3143
+
3144
+ ${this.expertModeConfig.pmEnabled ? html `
3145
+ <div style="display: flex; flex-direction: row; gap: 1rem; align-items: flex-start;">
3146
+ ${this.renderExpertOperandSelector('left', msg('Levý operand'), msg('Vyberte typ a hodnotu levého operandu pro výpočet hodnoty 100%.'), 'pm')}
3147
+
3148
+ <div style="flex: 0 0 auto; display: flex; flex-direction: column; gap: 4px; min-width: 120px;">
3149
+ <lit-label .label="${msg('Operace')}" .tooltip="${msg('Matematická operace mezi levým a pravým operandem.')}"></lit-label>
3150
+ <lit-select
3151
+ .options=${operationOptions}
3152
+ .value=${this.expertModeConfig.pmOperation}
3153
+ .placeholder=${msg('Vyberte operaci')}
3154
+ .onChange=${(value) => {
3155
+ const val = Array.isArray(value) ? value[0] : value;
3156
+ this.expertModeConfig = {
3157
+ ...this.expertModeConfig,
3158
+ pmOperation: val || 'none',
3159
+ };
3160
+ this.requestUpdate();
3161
+ }}
3162
+ ></lit-select>
3163
+ </div>
3164
+
3165
+ ${this.expertModeConfig.pmOperation !== 'none' ? this.renderExpertOperandSelector('right', msg('Pravý operand'), msg('Vyberte typ a hodnotu pravého operandu pro výpočet hodnoty 100%.'), 'pm') : ''}
3166
+ </div>
3167
+
3168
+ <div
3169
+ style="
3170
+ padding: 0.75rem;
3171
+ background: var(--background-default, #f5f5f5);
3172
+ border-radius: var(--border-radius-small, 8px);
3173
+ font-size: 0.8125rem;
3174
+ color: var(--text-secondary, #5d6371);
3175
+ "
3176
+ >
3177
+ <div style="font-weight: 600; margin-bottom: 0.25rem;">${msg('Náhled hodnoty 100%')}</div>
3178
+ <div>
3179
+ ${this.getExpertOperandLabel(this.expertModeConfig.pmLeftType, this.expertModeConfig.pmLeftValue, this.expertModeConfig.pmLeftSource, this.expertModeConfig.pmLeftAggregation)}
3180
+ ${this.expertModeConfig.pmOperation !== 'none'
3181
+ ? html `${this.expertModeConfig.pmOperation} ${this.getExpertOperandLabel(this.expertModeConfig.pmRightType, this.expertModeConfig.pmRightValue, this.expertModeConfig.pmRightSource, this.expertModeConfig.pmRightAggregation)}`
3182
+ : ''}
3183
+ = <strong style="color: var(--text-primary, #111827);">${this.getProgressMaxPreviewValue()}</strong>
3184
+ </div>
3185
+ </div>
3186
+ ` : ''}
3187
+ </div>
3188
+ ` : ''}
3189
+
3190
+ <!-- Tab: Název buňky (Header) -->
3191
+ <div slot="header" style="display: flex; flex-direction: column; gap: 1rem;">
3192
+ <lit-label
3193
+ .label="${msg('Název buňky')}"
3194
+ .tooltip="${msg('Název buňky zobrazený v záhlaví. Můžete nastavit překlad pro různé jazyky.')}"
3195
+ ></lit-label>
3196
+ <div style="display: flex; flex-direction: column; gap: 0.5rem;">
3197
+ <lit-text-field
3198
+ .label="${msg('Výchozí název')}"
3199
+ .value=${this.expertModeConfig.headerName}
3200
+ @onChange=${(e) => {
3201
+ this.expertModeConfig = {
3202
+ ...this.expertModeConfig,
3203
+ headerName: e.detail,
3204
+ };
3205
+ }}
3206
+ ></lit-text-field>
3207
+
3208
+ ${(this.allowedLang || []).map((lang) => html `
3209
+ <lit-text-field
3210
+ .label="${msg('Název')} ${lang.toUpperCase()}"
3211
+ .placeholder="${msg('Zadejte název')} ${lang.toUpperCase()}"
3212
+ .value=${this.expertModeConfig.headerNameMutations[lang] || ''}
3213
+ @onChange=${(e) => {
3214
+ this.expertModeConfig = {
3215
+ ...this.expertModeConfig,
3216
+ headerNameMutations: {
3217
+ ...this.expertModeConfig.headerNameMutations,
3218
+ [lang]: e.detail,
3219
+ },
3220
+ };
3221
+ }}
3222
+ ></lit-text-field>
3223
+ `)}
3224
+ </div>
3225
+ </div>
3226
+ </lit-tabs-overview>
3227
+ </div>
3228
+ </lit-modal-body>
3229
+ <lit-modal-footer
3230
+ style="display: flex; flex-direction: row; gap: 0.5rem; justify-content: center;"
3231
+ >
3232
+ <lit-button
3233
+ .label="${msg('Uložit')}"
3234
+ .icon="check"
3235
+ .size="medium"
3236
+ @click=${() => this.saveExpertMode()}
3237
+ ></lit-button>
3238
+ <lit-button
3239
+ color="secondary"
3240
+ .label="${msg('Zrušit')}"
3241
+ variant="text"
3242
+ .icon="close"
3243
+ .size="medium"
3244
+ @click=${closeModal}
3245
+ ></lit-button>
3246
+ </lit-modal-footer>
3247
+ </lit-modal>
3248
+ `;
3249
+ }
3250
+ resolveCurrencyType(cell) {
3251
+ const currencyType = cell.currencyType || 'CZK';
3252
+ if (currencyType.startsWith('var:')) {
3253
+ const variableField = currencyType.substring(4);
3254
+ const variable = this.variables.find((v) => v.field === variableField)
3255
+ || this.rows.find((c) => c.field === variableField);
3256
+ const resolved = String(variable?.value || '').toUpperCase();
3257
+ if (LitCaseVariablesTab.SUPPORTED_CURRENCIES.includes(resolved)) {
3258
+ return resolved;
3259
+ }
3260
+ return 'CZK';
3261
+ }
3262
+ return currencyType;
3263
+ }
3264
+ resolveProgressMax(cell) {
3265
+ // 1. If expert mode progressMax computation is enabled, use it
3266
+ const config = cell.expertMode;
3267
+ if (config?.pmEnabled) {
3268
+ const computed = this.computeProgressMaxExpertValue(config);
3269
+ if (computed !== null && computed > 0)
3270
+ return computed;
3271
+ }
3272
+ // 2. Otherwise use static progressMax from tweakpane
3273
+ const staticMax = cell.progressMax;
3274
+ if (typeof staticMax === 'number' && staticMax > 0)
3275
+ return staticMax;
3276
+ return 100;
3277
+ }
3278
+ parseBooleanValue(value) {
3279
+ if (typeof value === 'boolean')
3280
+ return value;
3281
+ if (typeof value === 'string') {
3282
+ const lower = value.toLowerCase().trim();
3283
+ return lower === 'true' || lower === '1' || lower === 'yes' || lower === 'ano';
3284
+ }
3285
+ if (typeof value === 'number')
3286
+ return value !== 0;
3287
+ return !!value;
3288
+ }
3289
+ render() {
3290
+ if (this.hideTabWhen)
3291
+ return null;
3292
+ this.precomputeExpertValues();
3293
+ const filteredKeys = this.variables
3294
+ .map((variable) => variable.field)
3295
+ .filter((key) => {
3296
+ const item = this.variables.find((variable) => variable.field === key);
3297
+ const headerName = item?.headerName || '';
3298
+ return (key.toLowerCase().includes(this.filterText) ||
3299
+ headerName.toLowerCase().includes(this.filterText));
3300
+ });
3301
+ return html `
3302
+ ${this.enableSettings
3303
+ ? html `
3304
+ <div
3305
+ style="display: flex; gap: 0.5rem; justify-content: right; margin-bottom: 1rem; flex-wrap: wrap;"
3306
+ >
3307
+ <lit-button
3308
+ color="secondary"
3309
+ variant="${'dashed'}"
3310
+ label="${msg('Přiřadit vlastní buňku')}"
3311
+ icon="add"
3312
+ .fullWidth=${this.isMobile}
3313
+ @click="${this.addCustomEmptyCell}"
3314
+ class="add-variable-button"
3315
+ ></lit-button>
3316
+ <lit-button
3317
+ color="secondary"
3318
+ variant="${'dashed'}"
3319
+ label="${msg('Přiřadit proměnnou')}"
3320
+ icon="add"
3321
+ .fullWidth=${this.isMobile}
3322
+ @click="${this.toggleCustomPopover}"
3323
+ class="add-variable-button"
3324
+ ></lit-button>
3325
+
3326
+ <simple-popper
3327
+ .showing=${this.isOpen}
3328
+ .placement=${'bottom-end'}
3329
+ .manualOpening=${true}
3330
+ .maxWidthAsTarget=${false}
3331
+ .minWidth=${'400px'}
3332
+ .minHeight=${'300px'}
3333
+ .onClose=${() => this.closePopover()}
3334
+ >
3335
+ <div
3336
+ class="popper-input"
3337
+ style="position: sticky; top: 0; z-index: 1;"
3338
+ >
3339
+ <lit-input
3340
+ id="variable-filter-input"
3341
+ .value=${this.filterText}
3342
+ .onInput=${(value) => {
3343
+ this.filterText = value?.toLowerCase?.() || '';
3344
+ }}
3345
+ .onClear=${() => {
3346
+ this.filterText = '';
3347
+ }}
3348
+ placeholder="${msg('Zadejte název proměnné')}"
3349
+ .size=${'small'}
3350
+ ></lit-input>
3351
+ </div>
3352
+ <lit-menu tabindex="0">
3353
+ ${this.variables
3354
+ .map((variable) => variable.field)
3355
+ .filter((key) => {
3356
+ const item = this.variables.find((variable) => variable.field === key);
3357
+ const headerName = item?.headerName || '';
3358
+ return (key.toLowerCase().includes(this.filterText) ||
3359
+ headerName.toLowerCase().includes(this.filterText));
3360
+ })
3361
+ .sort((a, b) => {
3362
+ const aIsUnderscore = a.startsWith('_');
3363
+ const bIsUnderscore = b.startsWith('_');
3364
+ if (aIsUnderscore && !bIsUnderscore)
3365
+ return 1;
3366
+ if (!aIsUnderscore && bIsUnderscore)
3367
+ return -1;
3368
+ const aItem = this.variables.find((v) => v.field === a);
3369
+ const bItem = this.variables.find((v) => v.field === b);
3370
+ const aName = aItem?.headerName || a;
3371
+ const bName = bItem?.headerName || b;
3372
+ return aName.localeCompare(bName, this.getLocaleLang());
3373
+ })
3374
+ .map((key) => html `
3375
+ <lit-menu-item
3376
+ .onClick=${() => this.toggleRowCell(key)}
3377
+ .isActive=${this.existingFields.includes(key)}
3378
+ >
3379
+ <span class="menu-item--multiple">
3380
+ <lit-checkbox
3381
+ class="cursor"
3382
+ .checked=${this.existingFields.includes(key)}
3383
+ ></lit-checkbox>
3384
+ ${this.variables.find((variable) => variable.field === key)?.headerName || key}
3385
+ (${key})
3386
+ </span>
3387
+ </lit-menu-item>
3388
+ `)}
3389
+ </lit-menu>
3390
+
3391
+ ${isEqual(filteredKeys.length, 0)
3392
+ ? html `
3393
+ <div
3394
+ style="display: flex;flex-direction: column; align-items: center; justify-content: center; height: 15.625rem;"
3395
+ >
3396
+ <div style="max-height: 7.125rem; max-width: 7.125rem">
3397
+ <not-found></not-found>
3398
+ </div>
3399
+ ${msg('Nenalezeno')}
3400
+ </div>
3401
+ `
3402
+ : null}
3403
+ </simple-popper>
3404
+ </div>
3405
+ `
3406
+ : ''}
3407
+ ${this.isLoading
3408
+ ? html `<lit-loader></lit-loader>`
3409
+ : this.gridVariables
3410
+ ? html ` <div class="grid-container">
3411
+ ${repeat(this.rows, (cell, index) => cell.field, (cell) => {
3412
+ const resolvedCell = this.getCellWithExpertValue(cell);
3413
+ const classes = `cell--span4`;
3414
+ return html `
3415
+ <div class="${classes}" data-field="${cell.field}">
3416
+ ${this.getInlineCellValue(resolvedCell)}
3417
+ </div>
3418
+ `;
3419
+ })}
3420
+ </div>`
3421
+ : html `
3422
+ <div class="grid-container">
3423
+ ${repeat(this.rows, (cell, index) => cell.field, (cell) => {
3424
+ const resolvedCell = this.getCellWithExpertValue(cell);
3425
+ const bpIndex = this.BREAKPOINTS.indexOf(this.currentBreakpoint);
3426
+ const spanSize = this.gridVariables
3427
+ ? 4
3428
+ : (this.BREAKPOINTS.slice(0, bpIndex + 1)
3429
+ .reverse()
3430
+ .map((bp) => cell.size?.[bp])
3431
+ .find((s) => s !== undefined) ?? 2);
3432
+ const classes = `cell--span${spanSize} cell ${this.shouldHideCell(cell) ? 'hidden-cell' : ''}`;
3433
+ return html `
3434
+ <div
3435
+ class="${classes}"
3436
+ style="${styleMap(this.computeCellStyles(cell))}"
3437
+ data-field="${cell.field}"
3438
+ >
3439
+ ${resolvedCell?.type === 'button'
3440
+ ? this.getCellButton(resolvedCell)
3441
+ : resolvedCell.type === 'link'
3442
+ ? this.getCellLink(resolvedCell)
3443
+ : resolvedCell.type === 'progress'
3444
+ ? this.getCellProgress(resolvedCell)
3445
+ : resolvedCell.type === 'currency'
3446
+ ? this.getCellCurrency(resolvedCell)
3447
+ : resolvedCell.type === 'date'
3448
+ ? this.getCellDate(resolvedCell)
3449
+ : resolvedCell.type === 'number'
3450
+ ? this.getCellNumber(resolvedCell)
3451
+ : resolvedCell.type === 'checkbox'
3452
+ ? this.getCellCheckbox(resolvedCell)
3453
+ : this.getCellValue(resolvedCell)}
3454
+ </div>
3455
+ `;
3456
+ })}
3457
+ </div>
3458
+ `}
3459
+ ${this.settingsPopperOpen && this.activeSettingsCell
3460
+ ? html `
3461
+ <div class="tweakpane-overlay" @click=${this.closeSettingsPopper}>
3462
+ <div class="tweakpane-panel" @click=${(e) => e.stopPropagation()}>
3463
+ ${this.renderSettingsContent()}
3464
+ </div>
3465
+ </div>
3466
+ `
3467
+ : ''}
3468
+ ${this.renderExpertModeModal()}
3469
+ `;
3470
+ }
3471
+ }
3472
+ LitCaseVariablesTab.VARIANT_CSS_VARS = {
3473
+ default: { var: '--background-paper', fallback: '#9ca3af' },
3474
+ primary: { var: '--color-primary-light', fallback: '#76b703' },
3475
+ secondary: { var: '--color-secondary-light', fallback: '#6b7280' },
3476
+ success: { var: '--color-success-light', fallback: '#22c55e' },
3477
+ warning: { var: '--color-warning-light', fallback: '#f59e0b' },
3478
+ error: { var: '--color-error-light', fallback: '#ef4444' },
3479
+ info: { var: '--color-info-light', fallback: '#3b82f6' },
3480
+ custom: { var: '--color-primary-light', fallback: '#8b5cf6' },
3481
+ ai: { var: '--color-primary-light', fallback: '#a855f7' },
3482
+ };
3483
+ LitCaseVariablesTab.styles = [
3484
+ // styles,
3485
+ css `
3486
+ :host {
3487
+ font-family: 'Inter', sans-serif;
3488
+ }
3489
+
3490
+ .header-cell {
3491
+ min-height: 1.25rem;
3492
+ display: flex;
3493
+ justify-content: space-between;
3494
+ align-items: center;
3495
+ }
3496
+
3497
+ .drag-handle {
3498
+ cursor: grab;
3499
+ opacity: 0.6;
3500
+ transition: opacity 0.2s;
3501
+ }
3502
+
3503
+ .drag-handle:hover {
3504
+ opacity: 1;
3505
+ }
3506
+
3507
+ .grid-container {
3508
+ display: grid;
3509
+ justify-content: start;
3510
+ align-items: start;
3511
+ gap: 0.5rem;
3512
+ border: 1px dashed transparent;
3513
+ border-radius: var(--border-radius-small, 8px);
3514
+ transition: border-color 0.2s;
3515
+ }
3516
+
3517
+ .grid-container.sortable-drag-over {
3518
+ border-color: var(--color-primary-main, #76b703);
3519
+ }
3520
+
3521
+ .process-data-heading {
3522
+ font-size: 0.75rem;
3523
+ color: var(--text-secondary, #5d6371);
3524
+ font-weight: 400 !important;
3525
+ display: flex;
3526
+ gap: 5px;
3527
+ align-items: center;
3528
+ }
3529
+
3530
+ .process-data-value {
3531
+ min-height: 1.25rem;
3532
+ font-size: 0.8125rem;
3533
+ color: var(--text-primary, #111827);
3534
+ margin: 0;
3535
+ font-weight: 500;
3536
+ display: flex;
3537
+ align-items: center;
3538
+ }
3539
+
3540
+ .status {
3541
+ color: var(--color-primary-main, #76b703);
3542
+ }
3543
+
3544
+ .link {
3545
+ font-size: 0.8125rem;
3546
+ text-decoration: none;
3547
+ color: var(--text-primary, #111827);
3548
+ border-bottom: 0.0625rem solid var(--color-primary-main, #76b703);
3549
+ }
3550
+
3551
+ .cell {
3552
+ padding: 0.375rem;
3553
+ border-radius: var(--border-radius-small, 8px);
3554
+ border: 1px solid transparent;
3555
+ transition: all 0.2s;
3556
+ min-height: 2.625rem;
3557
+ }
3558
+
3559
+ .cell.one-column {
3560
+ min-height: 0 !important;
3561
+ }
3562
+
3563
+ .cell.sortable-ghost {
3564
+ opacity: 0.5;
3565
+ border-color: var(--color-primary-main, #76b703);
3566
+ }
3567
+
3568
+ .cell.sortable-chosen {
3569
+ transform: scale(1.02);
3570
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
3571
+ }
3572
+
3573
+ .link:hover {
3574
+ color: var(--color-primary-main, #76b703);
3575
+ }
3576
+
3577
+ .settings-buttons {
3578
+ display: flex;
3579
+ align-items: center;
3580
+ }
3581
+
3582
+ .header-buttons {
3583
+ display: flex;
3584
+ gap: 0.5rem;
3585
+ color: var(--text-secondary, #777);
3586
+ }
3587
+
3588
+ .size-button {
3589
+ margin-right: 0.5rem;
3590
+ cursor: pointer;
3591
+ }
3592
+
3593
+ .size-button--active {
3594
+ text-decoration: underline;
3595
+ font-weight: bold;
3596
+ }
3597
+
3598
+ .popper-input {
3599
+ margin-bottom: 0.5rem;
3600
+ background-color: var(--background-paper, #fff);
3601
+ z-index: 1;
3602
+ }
3603
+
3604
+ .cell-background {
3605
+ width: 14px;
3606
+ height: 14px;
3607
+ border-radius: 4px;
3608
+ border: 1px solid #ccc;
3609
+ cursor: pointer;
3610
+ margin-right: 0.5rem;
3611
+ }
3612
+
3613
+ .bold-toggle {
3614
+ cursor: pointer;
3615
+ }
3616
+
3617
+ .bold-toggle--active {
3618
+ text-decoration: underline;
3619
+ font-weight: bold;
3620
+ }
3621
+
3622
+ .color-label {
3623
+ margin: 0.5rem 0 0.25rem 0;
3624
+ }
3625
+
3626
+ .cell-background--active {
3627
+ border-bottom: 1px solid white;
3628
+ margin-top: 1px;
3629
+ margin-right: 0.5rem;
3630
+ }
3631
+
3632
+ .add-variable-button {
3633
+ display: inline-block;
3634
+ }
3635
+
3636
+ @media (max-width: 600px) {
3637
+ .add-variable-button {
3638
+ display: block;
3639
+ width: 100%;
3640
+ }
3641
+ }
3642
+
3643
+ .cell--span0 {
3644
+ display: none;
3645
+ }
3646
+ .cell--span1 {
3647
+ grid-column: span 1 / span 1;
3648
+ }
3649
+ .cell--span2 {
3650
+ grid-column: span 2 / span 2;
3651
+ }
3652
+ .cell--span3 {
3653
+ grid-column: span 3 / span 3;
3654
+ }
3655
+ .cell--span4 {
3656
+ grid-column: span 4 / span 4;
3657
+ }
3658
+
3659
+ /* Responzívne nastavenie počtu stĺpcov */
3660
+ @media (min-width: 0px) {
3661
+ .grid-container {
3662
+ grid-template-columns: repeat(4, minmax(0, 1fr)); /* xs */
3663
+ }
3664
+ }
3665
+
3666
+ @media (min-width: var(--breakpoint-sm, 600px)) {
3667
+ .grid-container {
3668
+ grid-template-columns: repeat(4, minmax(0, 1fr)); /* sm */
3669
+ }
3670
+ }
3671
+
3672
+ @media (min-width: var(--breakpoint-md, 960px)) {
3673
+ .grid-container {
3674
+ grid-template-columns: repeat(4, minmax(0, 1fr)); /* md */
3675
+ }
3676
+ }
3677
+
3678
+ @media (min-width: var(--breakpoint-lg, 1280px)) {
3679
+ .grid-container {
3680
+ grid-template-columns: repeat(4, minmax(0, 1fr)); /* lg */
3681
+ }
3682
+ }
3683
+
3684
+ @media (min-width: var(--breakpoint-xl, 1536px)) {
3685
+ .grid-container {
3686
+ grid-template-columns: repeat(4, minmax(0, 1fr));
3687
+ }
3688
+ }
3689
+
3690
+ .hidden-cell {
3691
+ display: none;
3692
+ }
3693
+
3694
+ .tweakpane-container {
3695
+ min-width: 250px;
3696
+ max-width: 300px;
3697
+ }
3698
+
3699
+ /* Basic Tweakpane in tooltip styling - applying to document to bypass shadow DOM */
3700
+ :host([data-tweakpane-loaded]) {
3701
+ display: block;
3702
+ }
3703
+ `,
3704
+ ];
3705
+ LitCaseVariablesTab.SUPPORTED_CURRENCIES = [
3706
+ 'CZK', 'EUR', 'USD', 'GBP', 'CHF', 'PLN', 'HUF',
3707
+ 'JPY', 'AUD', 'CAD', 'NOK', 'SEK', 'DKK', 'CNY', 'RUB',
3708
+ ];
3709
+ __decorate([
3710
+ property({ type: Array })
3711
+ ], LitCaseVariablesTab.prototype, "rows", void 0);
3712
+ __decorate([
3713
+ property({ type: Array })
3714
+ ], LitCaseVariablesTab.prototype, "variables", void 0);
3715
+ __decorate([
3716
+ property({ type: Boolean })
3717
+ ], LitCaseVariablesTab.prototype, "hideTabWhen", void 0);
3718
+ __decorate([
3719
+ property({ type: String })
3720
+ ], LitCaseVariablesTab.prototype, "userLang", void 0);
3721
+ __decorate([
3722
+ property({ type: Array })
3723
+ ], LitCaseVariablesTab.prototype, "allowedLang", void 0);
3724
+ __decorate([
3725
+ property({ type: String })
3726
+ ], LitCaseVariablesTab.prototype, "dateFormat", void 0);
3727
+ __decorate([
3728
+ property({ type: Boolean })
3729
+ ], LitCaseVariablesTab.prototype, "isLoading", void 0);
3730
+ __decorate([
3731
+ property({ type: Boolean })
3732
+ ], LitCaseVariablesTab.prototype, "enableSettings", void 0);
3733
+ __decorate([
3734
+ property({ type: String })
3735
+ ], LitCaseVariablesTab.prototype, "tabId", void 0);
3736
+ __decorate([
3737
+ property({ type: Boolean })
3738
+ ], LitCaseVariablesTab.prototype, "gridVariables", void 0);
3739
+ __decorate([
3740
+ property({ type: Function })
3741
+ ], LitCaseVariablesTab.prototype, "onSettingsChanged", void 0);
3742
+ __decorate([
3743
+ property({ type: String })
3744
+ ], LitCaseVariablesTab.prototype, "hostURL", void 0);
3745
+ __decorate([
3746
+ property({ attribute: false })
3747
+ ], LitCaseVariablesTab.prototype, "dataGridRef", void 0);
3748
+ __decorate([
3749
+ property({ attribute: false })
3750
+ ], LitCaseVariablesTab.prototype, "dataGridRefs", void 0);
3751
+ __decorate([
3752
+ state()
3753
+ ], LitCaseVariablesTab.prototype, "currentBreakpoint", void 0);
3754
+ __decorate([
3755
+ state()
3756
+ ], LitCaseVariablesTab.prototype, "isOpen", void 0);
3757
+ __decorate([
3758
+ state()
3759
+ ], LitCaseVariablesTab.prototype, "filterText", void 0);
3760
+ __decorate([
3761
+ state()
3762
+ ], LitCaseVariablesTab.prototype, "isMobile", void 0);
3763
+ __decorate([
3764
+ state()
3765
+ ], LitCaseVariablesTab.prototype, "expertModeModalOpen", void 0);
3766
+ __decorate([
3767
+ state()
3768
+ ], LitCaseVariablesTab.prototype, "expertModeCell", void 0);
3769
+ __decorate([
3770
+ state()
3771
+ ], LitCaseVariablesTab.prototype, "expertModeConfig", void 0);
3772
+ __decorate([
3773
+ state()
3774
+ ], LitCaseVariablesTab.prototype, "activeSettingsCell", void 0);
3775
+ __decorate([
3776
+ state()
3777
+ ], LitCaseVariablesTab.prototype, "settingsPopperOpen", void 0);
3778
+ if (!window.customElements.get('lit-case-variables-tab')) {
3779
+ window.customElements.define('lit-case-variables-tab', LitCaseVariablesTab);
3780
+ }
3781
+ //# sourceMappingURL=lit-case-variables-tab.js.map