@eturnity/eturnity_reusable_components 9.13.4 → 9.13.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es3.js CHANGED
@@ -26,6 +26,8 @@ const theme = (() => {
26
26
  red2: "#de5959",
27
27
  red3: "#FFCCCC",
28
28
  red4: "#FF9A9A",
29
+ red6: "#FFEBEB",
30
+ red5: "#CC4545",
29
31
  pureRed: "#ff0000",
30
32
  darkRed: "#d00000",
31
33
  cornellRed: "#a52019",
@@ -67,6 +69,8 @@ const theme = (() => {
67
69
  purple4: "#D0D6F5",
68
70
  purple5: "#533181",
69
71
  purple6: "#6F20DC",
72
+ purple7: "#F5EEFF",
73
+ purple8: "#B17BFA",
70
74
  orange: "#ffc338",
71
75
  disabled: "#dfe1e1",
72
76
  transparentWhite2: "#ffffff32",
@@ -212,35 +216,9 @@ const theme = (() => {
212
216
  900: "#6E8E9Efa"
213
217
  }
214
218
  };
215
- const chartGradients = {
216
- simple: {
217
- from: semanticColors.purple[500],
218
- to: semanticColors.purple[400]
219
- },
220
- stacked: [{
221
- from: "#F5EDFF",
222
- to: "#DEC5FF"
223
- }, {
224
- from: "#CAA2FF",
225
- to: "#F2E8FF"
226
- }, {
227
- from: "#B987FC",
228
- to: "#904AEF"
229
- }, {
230
- from: "#8B40F2",
231
- to: "#4A1394"
232
- }, {
233
- from: "#6A05F2",
234
- to: "#4905A5"
235
- }, {
236
- from: "#5402C3",
237
- to: "#2B0362"
238
- }]
239
- };
240
219
  return {
241
220
  colors,
242
221
  semanticColors,
243
- chartGradients,
244
222
  fonts: {
245
223
  mainFont: '"Figtree", sans-serif'
246
224
  },
@@ -468,29 +446,27 @@ const theme = (() => {
468
446
  backgroundColor: semanticColors.grey[300],
469
447
  borderColor: ""
470
448
  }
471
- }
472
- },
473
- protag: {
474
- main: {
449
+ },
450
+ tertiary: {
475
451
  default: {
476
- backgroundColor: semanticColors.yellow[300],
452
+ backgroundColor: "transparent",
477
453
  textColor: semanticColors.teal[800],
478
- borderColor: "transparent"
454
+ borderColor: semanticColors.teal[100]
479
455
  },
480
456
  hover: {
481
- backgroundColor: semanticColors.yellow[300],
457
+ backgroundColor: semanticColors.grey[200],
482
458
  textColor: semanticColors.teal[800],
483
- borderColor: ""
459
+ borderColor: semanticColors.teal[100]
484
460
  },
485
461
  active: {
486
- backgroundColor: semanticColors.yellow[300],
462
+ backgroundColor: semanticColors.grey[400],
487
463
  textColor: semanticColors.teal[800],
488
- borderColor: ""
464
+ borderColor: semanticColors.teal[100]
489
465
  },
490
466
  disabled: {
491
- backgroundColor: semanticColors.yellow[300],
492
- textColor: semanticColors.teal[400],
493
- borderColor: ""
467
+ textColor: semanticColors.grey[600],
468
+ backgroundColor: semanticColors.grey[500],
469
+ borderColor: semanticColors.grey[800]
494
470
  }
495
471
  }
496
472
  },
@@ -517,6 +493,54 @@ const theme = (() => {
517
493
  borderColor: ""
518
494
  }
519
495
  }
496
+ },
497
+ protag: {
498
+ main: {
499
+ default: {
500
+ backgroundColor: semanticColors.yellow[200],
501
+ textColor: semanticColors.teal[800],
502
+ borderColor: ""
503
+ },
504
+ hover: {
505
+ backgroundColor: semanticColors.yellow[200],
506
+ textColor: semanticColors.teal[800],
507
+ borderColor: ""
508
+ },
509
+ active: {
510
+ backgroundColor: semanticColors.yellow[200],
511
+ textColor: semanticColors.teal[800],
512
+ borderColor: ""
513
+ },
514
+ disabled: {
515
+ backgroundColor: semanticColors.yellow[200],
516
+ textColor: semanticColors.teal[400],
517
+ borderColor: ""
518
+ }
519
+ }
520
+ },
521
+ freeTrialTag: {
522
+ main: {
523
+ default: {
524
+ backgroundColor: semanticColors.blue[200],
525
+ textColor: semanticColors.teal[800],
526
+ borderColor: ""
527
+ },
528
+ hover: {
529
+ backgroundColor: semanticColors.blue[200],
530
+ textColor: semanticColors.teal[800],
531
+ borderColor: ""
532
+ },
533
+ active: {
534
+ backgroundColor: semanticColors.blue[200],
535
+ textColor: semanticColors.teal[800],
536
+ borderColor: ""
537
+ },
538
+ disabled: {
539
+ backgroundColor: semanticColors.blue[200],
540
+ textColor: semanticColors.teal[400],
541
+ borderColor: ""
542
+ }
543
+ }
520
544
  }
521
545
  },
522
546
  dark: {
@@ -759,9 +783,9 @@ const theme = (() => {
759
783
  iconWidth: "26px"
760
784
  },
761
785
  tiny: {
762
- padding: "2px 5px",
763
- fontSize: "8px",
764
- iconWidth: "18px"
786
+ padding: "3px 5px",
787
+ fontSize: "11px",
788
+ iconWidth: "14px"
765
789
  }
766
790
  }
767
791
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "9.13.4",
3
+ "version": "9.13.6",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -1,3 +1,3 @@
1
- <svg width="10" height="18" viewBox="0 0 10 18" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" clip-rule="evenodd" d="M9.36652 9.33445C9.4832 9.20595 9.39203 9 9.21845 9H6.16767L8.29896 0.785289C8.35143 0.583073 8.09775 0.44595 7.95731 0.60061L0.633784 8.66555C0.517096 8.79405 0.608271 9 0.781847 9H3.83263L1.70134 17.2147C1.64887 17.4169 1.90255 17.5541 2.04299 17.3994L9.36652 9.33445Z" fill="#263238"/>
1
+ <svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M8.5125 0.999636C9.0643 1.00006 9.51229 1.44779 9.5125 1.99964V4.44104C9.56257 4.43332 9.61457 4.42835 9.6668 4.42835H11.8973C12.449 4.4288 12.8971 4.87652 12.8973 5.42835V11.9996C12.8971 12.5515 12.4491 12.9992 11.8973 12.9996H8.6668V12.986C8.61656 12.9938 8.56492 12.9996 8.5125 12.9996H6.28203L6.1795 12.9948C6.16229 12.993 6.14468 12.9896 6.12774 12.9869V12.9996H2.89727L2.79473 12.9948C2.29064 12.9434 1.89733 12.5173 1.89727 11.9996V11.3092C2.25984 11.3343 2.61386 11.2265 2.89727 11.0153V11.9996H5.12774V7.99964H4.18633L4.51934 6.99964H5.12774C5.18011 6.99968 5.23184 7.00454 5.28203 7.01233V1.99964C5.28223 1.48213 5.67549 1.05584 6.1795 1.00452L6.28203 0.999636H8.5125ZM6.28203 11.9996H8.5125V1.99964H6.28203V11.9996ZM9.6668 11.9996H11.8973V5.42835H9.6668V11.9996ZM1.5252 0.656862C1.61252 0.394909 1.89606 0.253171 2.15801 0.340456C2.41998 0.42778 2.56174 0.711297 2.47442 0.973268L1.19414 4.81507H3.22246C3.70002 4.81516 4.03723 5.28288 3.88653 5.73596L2.47442 9.97327C2.38695 10.235 2.10346 10.377 1.84161 10.2897C1.57979 10.2024 1.43813 9.91871 1.5252 9.65686L2.80547 5.81507H0.777152C0.299817 5.81486 -0.0372931 5.34708 0.11309 4.89417L1.5252 0.656862Z" fill="black"/>
3
3
  </svg>
@@ -1,3 +1,3 @@
1
- <svg fill="none" height="15" viewbox="12 12 16 15" width="16" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M25.6 16.15H23.5V14.75C23.5 13.973 22.877 13.35 22.1 13.35H17.9C17.123 13.35 16.5 13.973 16.5 14.75V16.15H14.4C13.623 16.15 13 16.773 13 17.55V25.25C13 26.027 13.623 26.65 14.4 26.65H25.6C26.377 26.65 27 26.027 27 25.25V17.55C27 16.773 26.377 16.15 25.6 16.15ZM17.9 14.75H22.1V16.15H17.9V14.75ZM25.6 21.75H14.4V17.55H16.5H17.9H22.1H23.5H25.6V21.75Z" fill="#263238"></path>
1
+ <svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M8 0C9.10457 3.22133e-08 10 0.895431 10 2V3H12.5L12.6533 3.00781C13.4097 3.08461 14 3.72334 14 4.5V11.5C14 12.2767 13.4097 12.9154 12.6533 12.9922L12.5 13H1.5C0.723336 13 0.0846097 12.4097 0.0078125 11.6533L0 11.5V4.5C0 3.67157 0.671573 3 1.5 3H4V2C4 0.895431 4.89543 3.22128e-08 6 0H8ZM1.5 4C1.22386 4 1 4.22386 1 4.5V11.5C1 11.7761 1.22386 12 1.5 12H12.5C12.7761 12 13 11.7761 13 11.5V4.5C13 4.22386 12.7761 4 12.5 4H1.5ZM6 1C5.44772 1 5 1.44772 5 2V3H9V2C9 1.44772 8.55228 1 8 1H6Z" fill="black"/>
3
3
  </svg>
@@ -26,6 +26,8 @@ const theme = (() => {
26
26
  red2: '#de5959',
27
27
  red3: '#FFCCCC',
28
28
  red4: '#FF9A9A',
29
+ red6: '#FFEBEB',
30
+ red5: '#CC4545',
29
31
  pureRed: '#ff0000',
30
32
  darkRed: '#d00000',
31
33
  cornellRed: '#a52019',
@@ -66,6 +68,8 @@ const theme = (() => {
66
68
  purple4: '#D0D6F5',
67
69
  purple5: '#533181',
68
70
  purple6: '#6F20DC',
71
+ purple7: '#F5EEFF',
72
+ purple8: '#B17BFA',
69
73
  orange: '#ffc338',
70
74
  disabled: '#dfe1e1',
71
75
  transparentWhite2: '#ffffff32',
@@ -213,25 +217,9 @@ const theme = (() => {
213
217
  },
214
218
  }
215
219
 
216
- const chartGradients = {
217
- simple: {
218
- from: semanticColors.purple[500],
219
- to: semanticColors.purple[400],
220
- },
221
- stacked: [
222
- { from: '#F5EDFF', to: '#DEC5FF' },
223
- { from: '#CAA2FF', to: '#F2E8FF' },
224
- { from: '#B987FC', to: '#904AEF' },
225
- { from: '#8B40F2', to: '#4A1394' },
226
- { from: '#6A05F2', to: '#4905A5' },
227
- { from: '#5402C3', to: '#2B0362' },
228
- ],
229
- }
230
-
231
220
  return {
232
221
  colors,
233
222
  semanticColors,
234
- chartGradients,
235
223
  fonts: {
236
224
  mainFont: '"Figtree", sans-serif',
237
225
  },
@@ -460,28 +448,26 @@ const theme = (() => {
460
448
  borderColor: '',
461
449
  },
462
450
  },
463
- },
464
- protag: {
465
- main: {
451
+ tertiary: {
466
452
  default: {
467
- backgroundColor: semanticColors.yellow[300],
453
+ backgroundColor: 'transparent',
468
454
  textColor: semanticColors.teal[800],
469
- borderColor: 'transparent',
455
+ borderColor: semanticColors.teal[100],
470
456
  },
471
457
  hover: {
472
- backgroundColor: semanticColors.yellow[300],
458
+ backgroundColor: semanticColors.grey[200],
473
459
  textColor: semanticColors.teal[800],
474
- borderColor: '',
460
+ borderColor: semanticColors.teal[100],
475
461
  },
476
462
  active: {
477
- backgroundColor: semanticColors.yellow[300],
463
+ backgroundColor: semanticColors.grey[400],
478
464
  textColor: semanticColors.teal[800],
479
- borderColor: '',
465
+ borderColor: semanticColors.teal[100],
480
466
  },
481
467
  disabled: {
482
- backgroundColor: semanticColors.yellow[300],
483
- textColor: semanticColors.teal[400],
484
- borderColor: '',
468
+ textColor: semanticColors.grey[600],
469
+ backgroundColor: semanticColors.grey[500],
470
+ borderColor: semanticColors.grey[800],
485
471
  },
486
472
  },
487
473
  },
@@ -509,6 +495,54 @@ const theme = (() => {
509
495
  },
510
496
  },
511
497
  },
498
+ protag: {
499
+ main: {
500
+ default: {
501
+ backgroundColor: semanticColors.yellow[200],
502
+ textColor: semanticColors.teal[800],
503
+ borderColor: '',
504
+ },
505
+ hover: {
506
+ backgroundColor: semanticColors.yellow[200],
507
+ textColor: semanticColors.teal[800],
508
+ borderColor: '',
509
+ },
510
+ active: {
511
+ backgroundColor: semanticColors.yellow[200],
512
+ textColor: semanticColors.teal[800],
513
+ borderColor: '',
514
+ },
515
+ disabled: {
516
+ backgroundColor: semanticColors.yellow[200],
517
+ textColor: semanticColors.teal[400],
518
+ borderColor: '',
519
+ },
520
+ },
521
+ },
522
+ freeTrialTag: {
523
+ main: {
524
+ default: {
525
+ backgroundColor: semanticColors.blue[200],
526
+ textColor: semanticColors.teal[800],
527
+ borderColor: '',
528
+ },
529
+ hover: {
530
+ backgroundColor: semanticColors.blue[200],
531
+ textColor: semanticColors.teal[800],
532
+ borderColor: '',
533
+ },
534
+ active: {
535
+ backgroundColor: semanticColors.blue[200],
536
+ textColor: semanticColors.teal[800],
537
+ borderColor: '',
538
+ },
539
+ disabled: {
540
+ backgroundColor: semanticColors.blue[200],
541
+ textColor: semanticColors.teal[400],
542
+ borderColor: '',
543
+ },
544
+ },
545
+ },
512
546
  },
513
547
  dark: {
514
548
  // theme
@@ -750,9 +784,9 @@ const theme = (() => {
750
784
  iconWidth: '26px',
751
785
  },
752
786
  tiny: {
753
- padding: '2px 5px',
754
- fontSize: '8px',
755
- iconWidth: '18px',
787
+ padding: '3px 5px',
788
+ fontSize: '11px',
789
+ iconWidth: '14px',
756
790
  },
757
791
  },
758
792
  },
@@ -1,35 +1,6 @@
1
1
  <template>
2
2
  <ContainerWrapper @click="$emit('on-container-click')">
3
3
  <UpperContainer v-if="filterViews && filterViews.length">
4
- <ViewContainer :max-width="activeView.length">
5
- <SelectComponent
6
- align-items="vertical"
7
- :data-id="componentName + '_filter_view_select'"
8
- :data-qa-id="componentName + '_filter_view_select'"
9
- font-size="13px"
10
- :label="$gettext('active_filter')"
11
- select-height="36px"
12
- select-width="100%"
13
- @click.stop
14
- >
15
- <template #selector>
16
- <OptionTitle>
17
- {{ activeView }}
18
- </OptionTitle>
19
- </template>
20
- <template #dropdown>
21
- <Option
22
- v-for="(item, idx) in filterViews"
23
- :key="idx + '_view'"
24
- :value="item.name"
25
- @click="$emit('on-view-select', item)"
26
- >
27
- {{ item.name }}
28
- <DeleteIcon @click.stop="$emit('on-view-delete', item)" />
29
- </Option>
30
- </template>
31
- </SelectComponent>
32
- </ViewContainer>
33
4
  <ResetButton
34
5
  :data-id="componentName + '_reset_filters_button'"
35
6
  :data-qa-id="componentName + '_reset_filters_button'"
@@ -110,10 +81,10 @@
110
81
  :is-searchable="filter.choices.length > 7"
111
82
  :label="filter.label"
112
83
  :label-data-id="filter.dataId"
84
+ lazy-dropdown-content
113
85
  :min-option-length="1"
114
86
  select-height="36px"
115
87
  select-width="100%"
116
- :should-use-teleport="false"
117
88
  >
118
89
  <template #selector>
119
90
  <OptionTitle> {{ filter.selectedText }} </OptionTitle>
@@ -261,9 +232,11 @@
261
232
  :enable-time-picker="false"
262
233
  format="yyyy-MM-dd"
263
234
  :locale="getDatePickerLanguage()"
235
+ menu-class-name="filter-settings-dp-menu"
264
236
  model-type="format"
265
237
  :model-value="filter.range.start"
266
238
  :placeholder="$gettext('Date from')"
239
+ teleport="body"
267
240
  text-input
268
241
  @close="onDatepickerBlur()"
269
242
  @focus="onDatepickerFocus(filter.range)"
@@ -289,9 +262,11 @@
289
262
  :enable-time-picker="false"
290
263
  format="yyyy-MM-dd"
291
264
  :locale="getDatePickerLanguage()"
265
+ menu-class-name="filter-settings-dp-menu"
292
266
  model-type="format"
293
267
  :model-value="filter.range.end"
294
268
  :placeholder="$gettext('Date to')"
269
+ teleport="body"
295
270
  text-input
296
271
  @close="onDatepickerBlur()"
297
272
  @focus="onDatepickerFocus(filter.range)"
@@ -315,9 +290,9 @@
315
290
  font-size="13px"
316
291
  :is-searchable="filter.choices.length > 7"
317
292
  :label="filter.label"
293
+ lazy-dropdown-content
318
294
  select-height="36px"
319
295
  select-width="100%"
320
- :should-use-teleport="false"
321
296
  >
322
297
  <template #selector="{ selectedValue }">
323
298
  <OptionTitle>
@@ -560,7 +535,6 @@
560
535
  display: inline-flex;
561
536
  gap: 16px;
562
537
  width: max-content;
563
- margin-top: 20px;
564
538
  align-self: center;
565
539
  font-size: 13px;
566
540
  color: ${(props) => props.theme.colors.primary};
@@ -745,7 +719,11 @@
745
719
  return type === 'boolean'
746
720
  },
747
721
  isMultipleSelector(type) {
748
- return type === 'multi_select_integer' || type === 'multi_select_string'
722
+ return (
723
+ type === 'multi_select_integer' ||
724
+ type === 'multi_select_string' ||
725
+ type === 'multiple_choice'
726
+ )
749
727
  },
750
728
  isRangeSelector(type) {
751
729
  return type === 'integer_range' || type === 'number_range'
@@ -754,8 +732,16 @@
754
732
  return type === 'integer_range'
755
733
  },
756
734
  isDateSelector(type) {
757
- return type === 'datetime'
735
+ return type === 'datetime' || type === 'date_range'
758
736
  },
759
737
  },
760
738
  }
761
739
  </script>
740
+
741
+ <!-- Teleported menu is under body; unscoped. Expert main.scss also sets z-index so linked package builds pick it up. -->
742
+ <style>
743
+ /* Must exceed app modal stacks (often ~1e7 in eturnity_expert); default dp menu is 99999. */
744
+ body .dp__menu.filter-settings-dp-menu {
745
+ z-index: 10000050 !important;
746
+ }
747
+ </style>
@@ -8,7 +8,8 @@
8
8
  @on-toggle="onToggleDropdown()"
9
9
  />
10
10
  <FilterSettings
11
- v-if="isDropdownOpen"
11
+ v-if="filterSettingsInDOM"
12
+ v-show="isDropdownOpen"
12
13
  :active-language="activeLanguage"
13
14
  :active-view="activeView"
14
15
  :button-text="buttonText"
@@ -82,6 +83,12 @@
82
83
  default: null,
83
84
  required: false,
84
85
  },
86
+ /** Host store slice (e.g. getCurrentFilterData) so the badge tracks live `filters`. */
87
+ currentFilterData: {
88
+ type: Object,
89
+ default: null,
90
+ required: false,
91
+ },
85
92
  componentName: {
86
93
  type: String,
87
94
  required: false,
@@ -92,14 +99,62 @@
92
99
  isDropdownOpen: false,
93
100
  activeFilter: null,
94
101
  preventOutsideClick: false,
102
+ /** Once true, FilterSettings stays mounted; toggled with v-show for instant reopen. */
103
+ filterSettingsInDOM: false,
104
+ _unmounted: false,
105
+ _idlePrewarmId: null,
106
+ _prewarmTimerId: null,
95
107
  }
96
108
  },
97
109
  computed: {
110
+ /** Count applied data filters for the settings-trigger badge (not column visibility). */
98
111
  numberOfFiltersApplied() {
99
- const filterColumns = this.activeFilterView?.columns?.filter(
100
- (column) => column.custom_view_filter !== null
101
- )
102
- return filterColumns?.length > 0 ? filterColumns.length : 0
112
+ const view = this.activeFilterView
113
+ const live = this.currentFilterData
114
+ const resolvedFilters =
115
+ live != null && Array.isArray(live.filters)
116
+ ? live.filters
117
+ : view && Array.isArray(view.filters)
118
+ ? view.filters
119
+ : []
120
+
121
+ const countFromFilterList = (filters) => {
122
+ if (!Array.isArray(filters) || !filters.length) {
123
+ return 0
124
+ }
125
+ const first = filters[0]
126
+ if (
127
+ first &&
128
+ typeof first === 'object' &&
129
+ 'custom_view_filter' in first
130
+ ) {
131
+ return filters.filter((f) => f && f.custom_view_filter).length
132
+ }
133
+ // Flat rows (library / tariffs): multi-select emits one row per value —
134
+ // badge = number of filter *fields* narrowed, not row count.
135
+ if (first && typeof first === 'object' && 'field' in first) {
136
+ return new Set(filters.map((f) => f.field).filter(Boolean)).size
137
+ }
138
+ return filters.length
139
+ }
140
+
141
+ const filtersCount = countFromFilterList(resolvedFilters)
142
+
143
+ if (!view) {
144
+ return filtersCount
145
+ }
146
+
147
+ const cols = view.columns
148
+ if (Array.isArray(cols) && cols.length && typeof cols[0] === 'string') {
149
+ return filtersCount
150
+ }
151
+ if (Array.isArray(cols)) {
152
+ const n = cols.filter(
153
+ (c) => c && typeof c === 'object' && c.custom_view_filter
154
+ ).length
155
+ return n > 0 ? n : filtersCount
156
+ }
157
+ return filtersCount
103
158
  },
104
159
  },
105
160
  watch: {
@@ -111,13 +166,49 @@
111
166
  },
112
167
  mounted() {
113
168
  document.addEventListener('click', this.clickOutside)
169
+ // Build the heavy panel during idle so the first click often only toggles v-show.
170
+ const prewarm = () => {
171
+ if (this._unmounted || this.filterSettingsInDOM) {
172
+ return
173
+ }
174
+ this.filterSettingsInDOM = true
175
+ }
176
+ if (typeof requestIdleCallback !== 'undefined') {
177
+ this._idlePrewarmId = requestIdleCallback(prewarm, { timeout: 2000 })
178
+ } else {
179
+ this._prewarmTimerId = setTimeout(prewarm, 600)
180
+ }
114
181
  },
115
182
  beforeUnmount() {
183
+ this._unmounted = true
184
+ if (
185
+ this._idlePrewarmId != null &&
186
+ typeof cancelIdleCallback !== 'undefined'
187
+ ) {
188
+ cancelIdleCallback(this._idlePrewarmId)
189
+ }
190
+ if (this._prewarmTimerId != null) {
191
+ clearTimeout(this._prewarmTimerId)
192
+ }
116
193
  document.removeEventListener('click', this.clickOutside)
117
194
  },
118
195
  methods: {
196
+ emitFilterPanelOpen() {
197
+ this.$nextTick(() => {
198
+ if (this.isDropdownOpen) {
199
+ this.$emit('on-filter-panel-open')
200
+ }
201
+ })
202
+ },
119
203
  onToggleDropdown() {
204
+ const opening = !this.isDropdownOpen
120
205
  this.isDropdownOpen = !this.isDropdownOpen
206
+ if (opening) {
207
+ if (!this.filterSettingsInDOM) {
208
+ this.filterSettingsInDOM = true
209
+ }
210
+ this.emitFilterPanelOpen()
211
+ }
121
212
  },
122
213
  onContainerClick() {
123
214
  // due to newer versions of Chrome (121), contains() is not always working.
@@ -252,7 +252,10 @@
252
252
  },
253
253
  computed: {
254
254
  hasLabel() {
255
- return !!this.label && !!this.label.length
255
+ if (this.label == null || this.label === '') {
256
+ return false
257
+ }
258
+ return String(this.label).length > 0
256
259
  },
257
260
  },
258
261
  methods: {
@@ -198,7 +198,12 @@
198
198
  @option-hovered="optionHovered"
199
199
  @option-selected="optionSelected"
200
200
  >
201
- <slot name="dropdown"></slot>
201
+ <!-- When lazy, skip building option/checkbox nodes until the user opens
202
+ this select (filter settings can have thousands of options otherwise). -->
203
+ <slot
204
+ v-if="!lazyDropdownContent || isDropdownOpen"
205
+ name="dropdown"
206
+ ></slot>
202
207
  </SelectDropdown>
203
208
  </Component>
204
209
  </DropdownWrapper>
@@ -726,6 +731,12 @@
726
731
  required: false,
727
732
  default: true,
728
733
  },
734
+ /** If true, dropdown slot content is only rendered while the menu is open. */
735
+ lazyDropdownContent: {
736
+ type: Boolean,
737
+ required: false,
738
+ default: false,
739
+ },
729
740
  },
730
741
  setup() {
731
742
  const modalRef = inject('modalRef', null)
@@ -10,7 +10,7 @@
10
10
  >
11
11
  <ArrowIconContainer>
12
12
  <RCIcon
13
- :color="getTheme.colors.brightBlue"
13
+ :color="getTheme.colors.primary"
14
14
  name="arrow_left"
15
15
  size="12px"
16
16
  />
@@ -73,7 +73,7 @@
73
73
  <ArrowText>{{ $gettext('forward') }}</ArrowText>
74
74
  <ArrowIconContainer>
75
75
  <RCIcon
76
- :color="getTheme.colors.brightBlue"
76
+ :color="getTheme.colors.primary"
77
77
  name="arrow_right"
78
78
  size="12px"
79
79
  />
@@ -88,7 +88,7 @@
88
88
  import theme from '@/assets/theme.js'
89
89
 
90
90
  const PaginationWrapper = styled.nav`
91
- color: ${(props) => props.theme.colors.brightBlue};
91
+ color: ${(props) => props.theme.colors.primary};
92
92
  font-size: 13px;
93
93
  display: flex;
94
94
  flex-wrap: wrap;
@@ -103,17 +103,23 @@
103
103
  border-radius: 3px;
104
104
  white-space: nowrap;
105
105
  cursor: pointer;
106
- color: ${(props) => props.theme.colors.brightBlue};
106
+ height: 100%;
107
+ align-items: center;
108
+ color: ${(props) => props.theme.colors.primary};
109
+ &:hover {
110
+ color: ${(props) => props.theme.semanticColors.purple[500]};
111
+ background-color: ${(props) => props.theme.semanticColors.purple[100]};
112
+ }
107
113
 
108
114
  &.active {
109
- color: ${(props) => props.theme.colors.white};
110
- background-color: ${(props) => props.theme.colors.brightBlue};
115
+ color: ${(props) => props.theme.semanticColors.purple[500]};
116
+ background-color: ${(props) => props.theme.semanticColors.purple[50]};
111
117
  padding: 7px 12px;
112
118
  border-radius: 4px;
113
119
  }
114
120
  `
115
121
  const ArrowText = styled.div`
116
- color: ${(props) => props.theme.colors.brightBlue};
122
+ color: ${(props) => props.theme.colors.primary};
117
123
  `
118
124
  const ArrowIconContainer = styled.div`
119
125
  margin: 0 10px;
@@ -8,6 +8,9 @@
8
8
  <ListItem
9
9
  v-if="!item.children"
10
10
  :key="idx"
11
+ :data-active="
12
+ (activeTab === item.key || activeParentTab === item.key).toString()
13
+ "
11
14
  :data-id="`sub_menu_settings_${item.key}`"
12
15
  :data-qa-id="`sub_menu_settings_${item.key}`"
13
16
  :fill-type="item.icon === 'free_technology' ? 'stroke' : 'fill'"
@@ -31,6 +34,7 @@
31
34
  </ListItem>
32
35
  <CollapseWrapper v-else :key="idx + item.key">
33
36
  <CollapseContainer
37
+ :data-active="activeParentTab === item.key"
34
38
  :data-id="`sub_menu_settings_${item.key}`"
35
39
  :data-qa-id="`sub_menu_settings_${item.key}`"
36
40
  :is-active="activeParentTab === item.key"
@@ -53,7 +57,11 @@
53
57
  }}</ListText>
54
58
  <ArrowContainer>
55
59
  <Icon
56
- :color="theme.semanticColors.grey[800]"
60
+ :color="
61
+ activeParentTab === item.key
62
+ ? theme.semanticColors.purple[500]
63
+ : theme.semanticColors.teal[800]
64
+ "
57
65
  :name="
58
66
  activeDropdown === item.key
59
67
  ? 'arrow_up_unfilled'
@@ -67,6 +75,7 @@
67
75
  <SubRouter
68
76
  v-for="subItem in item.children"
69
77
  :key="subItem.key"
78
+ :data-active="activeTab === subItem.key"
70
79
  :data-id="`sub_menu_settings_${subItem.key}`"
71
80
  :data-qa-id="`sub_menu_settings_${subItem.key}`"
72
81
  :is-active="activeTab === subItem.key"
@@ -84,25 +93,15 @@
84
93
  </template>
85
94
  </ListContainer>
86
95
  <BottomSection v-if="hasLogout">
87
- <IconContainer
96
+ <ButtonIcon
88
97
  data-id="button_settings_logout"
89
- data-qa-id="button_settings_logout"
90
- :is-active="false"
91
- :is-button="true"
98
+ icon-name="logout"
99
+ :text="$gettext('Logout')"
100
+ type="ghost"
101
+ variant="tertiary"
92
102
  @click="$emit('on-logout')"
93
- >
94
- <RotateIcon
95
- :color="theme.semanticColors.teal[800]"
96
- cursor="pointer"
97
- name="initial_situation"
98
- size="18px"
99
- />
100
- </IconContainer>
101
- <AppVersion
102
- data-id="app_side_menu_version"
103
- data-qa-id="app_side_menu_version"
104
- >{{ appVersion }}</AppVersion
105
- >
103
+ />
104
+ <AppVersion>{{ appVersion }}</AppVersion>
106
105
  </BottomSection>
107
106
  </PageContainer>
108
107
  </template>
@@ -112,6 +111,7 @@
112
111
  import Icon from '../icon'
113
112
  import Spinner from '../spinner'
114
113
  import theme from '@/assets/theme.js'
114
+ import ButtonIcon from '../buttons/buttonIcon'
115
115
 
116
116
  const PageAttrs = { isLoading: Boolean }
117
117
  const PageContainer = styled('div', PageAttrs)`
@@ -139,13 +139,13 @@
139
139
  padding: 4px;
140
140
  border-radius: 4px;
141
141
  background-color: ${(props) =>
142
- props.isActive ? props.theme.semanticColors.purple[50] : ''};
142
+ props.isActive ? props.theme.semanticColors.purple[100] : ''};
143
143
  color: ${(props) =>
144
144
  props.isActive
145
145
  ? props.theme.semanticColors.purple[500]
146
146
  : props.theme.semanticColors.teal[800]};
147
147
 
148
- :hover {
148
+ &:hover:not([data-active='true']) {
149
149
  background-color: ${(props) => props.theme.semanticColors.purple[100]};
150
150
  color: ${(props) => props.theme.semanticColors.purple[500]};
151
151
  svg path:not(.fix) {
@@ -174,8 +174,7 @@
174
174
  `
175
175
  cursor: pointer;
176
176
  &:hover {
177
- background-color: ${(props) =>
178
- props.theme.semanticColors.purple[100]};
177
+ background-color: ${(props) => props.theme.semanticColors.purple[50]};
179
178
  `}
180
179
  `
181
180
 
@@ -217,10 +216,10 @@
217
216
  font-weight: 400;
218
217
  font-size: 14px;
219
218
  background: ${(props) =>
220
- props.isActive ? props.theme.semanticColors.purple[50] : ''};
219
+ props.isActive ? props.theme.semanticColors.purple[100] : ''};
221
220
 
222
- &:hover {
223
- background: ${(props) => props.theme.semanticColors.purple[100]};
221
+ &:hover:not([data-active='true']) {
222
+ background: ${(props) => props.theme.semanticColors.purple[50]};
224
223
  color: ${(props) => props.theme.semanticColors.purple[500]} !important;
225
224
  }
226
225
  `
@@ -236,15 +235,15 @@
236
235
  align-items: center;
237
236
  cursor: pointer;
238
237
  background: ${(props) =>
239
- props.isActive ? props.theme.semanticColors.purple[50] : ''};
238
+ props.isActive ? props.theme.semanticColors.purple[100] : ''};
240
239
 
241
240
  div {
242
241
  color: ${(props) =>
243
242
  props.isActive ? props.theme.semanticColors.purple[500] : ''};
244
243
  }
245
244
 
246
- &:hover {
247
- background: ${(props) => props.theme.semanticColors.purple[100]};
245
+ &:hover:not([data-active='true']) {
246
+ background: ${(props) => props.theme.semanticColors.purple[50]};
248
247
  color: ${(props) => props.theme.semanticColors.purple[500]};
249
248
  svg path:not(.fix) {
250
249
  fill: ${(props) => props.theme.semanticColors.purple[500]};
@@ -276,12 +275,12 @@
276
275
  Spinner,
277
276
  SpinnerContainer,
278
277
  BottomSection,
279
- RotateIcon,
280
278
  AppVersion,
281
279
  CollapseWrapper,
282
280
  CollapseContainer,
283
281
  SubRouter,
284
282
  ArrowContainer,
283
+ ButtonIcon,
285
284
  },
286
285
  props: {
287
286
  tabsData: {
@@ -54,7 +54,14 @@
54
54
  v-for="(item, index) in options"
55
55
  :key="item.value"
56
56
  :color-theme="colorTheme"
57
- :data-id="item.dataId"
57
+ :data-id="
58
+ item.dataId ||
59
+ 'three_dots_option_item_' + rowIndex + '_' + item.value
60
+ "
61
+ :data-qa-id="
62
+ item.dataId ||
63
+ 'three_dots_option_item_' + rowIndex + '_' + item.value
64
+ "
58
65
  :is-disabled="item.disabled"
59
66
  tabindex="0"
60
67
  :title="item.title"
@@ -359,6 +366,11 @@
359
366
  default: '',
360
367
  type: String,
361
368
  },
369
+ rowIndex: {
370
+ required: false,
371
+ default: 0,
372
+ type: Number,
373
+ },
362
374
  },
363
375
  data() {
364
376
  return {