overview-components 1.1.162 → 1.1.165

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