@eturnity/eturnity_reusable_components 8.7.4--EPDM-12729.1 → 8.7.4--EPDM-12729.3

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "8.7.4--EPDM-12729.1",
3
+ "version": "8.7.4--EPDM-12729.3",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -7,7 +7,8 @@
7
7
  :is-active="activeTab === item.id"
8
8
  @click="onTabClick({ id: item.id })"
9
9
  >
10
- {{ item.text }}
10
+ <div>{{ item.text }}</div>
11
+ <RCIcon v-if="item.hasError" name="warning" size="14px" />
11
12
  </TabItem>
12
13
  </TabsContainer>
13
14
  </PageContainer>
@@ -21,15 +22,18 @@
21
22
  // :tabsData="[
22
23
  // {
23
24
  // text: 'Tab 1',
24
- // id: 0
25
+ // id: 0,
26
+ // hasError: true // optional
25
27
  // },
26
28
  // {
27
29
  // text: 'Tab 1',
28
- // id: 1
30
+ // id: 1,
31
+ // hasError: false // optional
29
32
  // }
30
33
  // ]"
31
34
  // />
32
35
  import styled from 'vue3-styled-components'
36
+ import RCIcon from '../icon'
33
37
 
34
38
  const PageContainer = styled.div``
35
39
 
@@ -41,6 +45,10 @@
41
45
 
42
46
  const TabAttrs = { isActive: Boolean }
43
47
  const TabItem = styled('div', TabAttrs)`
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ gap: 8px;
44
52
  padding: 10px 20px;
45
53
  font-size: 14px;
46
54
  font-weight: 600;
@@ -63,6 +71,7 @@
63
71
  PageContainer,
64
72
  TabsContainer,
65
73
  TabItem,
74
+ RCIcon,
66
75
  },
67
76
  props: {
68
77
  tabsData: {
@@ -1,1030 +0,0 @@
1
- <template>
2
- <PageContainer>
3
- <PageTitleContainer data-id="string_design_expand_collapse_section">
4
- <SectionTitleText>{{ $gettext('inverters') }}</SectionTitleText>
5
- <TitleButtonsContainer>
6
- <ButtonIcon
7
- v-if="dataListToDisplay.length > 1"
8
- app-theme="dark"
9
- icon-name="reorder_string"
10
- :is-active="showReorder"
11
- :text="$gettext('reorder')"
12
- @click="toggleShowReorder()"
13
- />
14
- <ButtonIcon
15
- app-theme="dark"
16
- :icon-name="hasExpandedSection ? 'collapse_all' : 'expand_all'"
17
- :text="$gettext(hasExpandedSection ? 'collapse_all' : 'expand_all')"
18
- @click="toggleAllSections"
19
- />
20
- </TitleButtonsContainer>
21
- </PageTitleContainer>
22
- <SectionContainer
23
- v-for="(item, index) in dataListToDisplay"
24
- :key="item.inverterId"
25
- >
26
- <TopContainer>
27
- <LeftContainer>
28
- <TitleContainer>
29
- <IconWrapper
30
- v-if="item.type != 'optimizer'"
31
- size="32px"
32
- @click="toggleSection(item.inverterId)"
33
- >
34
- <RCIcon
35
- v-if="isItemCollapsible(item)"
36
- color="white"
37
- :name="isExpanded(item.inverterId) ? 'arrow_up' : 'arrow_down'"
38
- size="10px"
39
- />
40
- <IconPlaceholder v-else />
41
- </IconWrapper>
42
- <TextContainer
43
- :is-archived="
44
- item.statusActive === false && !!item.companyComponentLibraryId
45
- "
46
- :style="{ marginLeft: item.type == 'optimizer' ? '32px' : '0' }"
47
- >
48
- <TitleText :title="item.model">
49
- {{
50
- (item.type === 'optimizer' || !hasExpandedSection) &&
51
- item.quantity
52
- ? item.quantity + ' x'
53
- : ''
54
- }}
55
- {{ item.model }}
56
- <InfoTextWrapper>
57
- <RCInfoText
58
- v-if="
59
- item.statusActive === false &&
60
- item.companyComponentLibraryId
61
- "
62
- button-type="error"
63
- :text="
64
- $gettext(
65
- `Component has been archived and shouldn't be used`
66
- )
67
- "
68
- />
69
- </InfoTextWrapper>
70
- </TitleText>
71
- <TitleSubText>
72
- <span>{{ item.brandName }}</span>
73
- <template
74
- v-if="itemHasStrings(item) || item.type === 'optimizer'"
75
- >
76
- <ContainerValue
77
- v-if="
78
- item.getkWp() > 1 &&
79
- item.type !== 'optimizer' &&
80
- hasExpandedSection
81
- "
82
- >
83
- |
84
- {{
85
- numberToString({
86
- value: item.getkWp(),
87
- numberPrecision: 2,
88
- })
89
- }}
90
- kWp
91
- </ContainerValue>
92
- <ContainerValue
93
- v-else-if="item.type !== 'optimizer' && hasExpandedSection"
94
- >
95
- |
96
- {{
97
- numberToString({
98
- value: 1000 * item.getkWp(),
99
- numberPrecision: 2,
100
- minDecimals: 2,
101
- })
102
- }}
103
- Wp
104
- </ContainerValue>
105
- </template>
106
- </TitleSubText>
107
- </TextContainer>
108
- </TitleContainer>
109
- <MarkersContainer>
110
- <MarkerItem
111
- v-if="item.mppts.length && hasExpandedSection"
112
- :background-color="isTargetRatioInRange(item) ? 'green' : 'red'"
113
- >{{
114
- numberToString({
115
- value: 100 * item.getTargetRatio(),
116
- numberPrecision: 0,
117
- minDecimals: 0,
118
- })
119
- }}%
120
- </MarkerItem>
121
- <MarkerItem v-if="item.hasTemplate && !item.isLoading">
122
- <span
123
- :title="
124
- item.companyProductTemplateName
125
- ? item.companyProductTemplateName
126
- : $gettext('no_template_selected')
127
- "
128
- >
129
- {{
130
- item.companyProductTemplateName
131
- ? item.companyProductTemplateName
132
- : $gettext('no_template_selected')
133
- }}
134
- </span>
135
- </MarkerItem>
136
- <MarkerItem>
137
- <RCIcon color="white" :name="getIconName(item)" size="14px" />
138
- <MarkerText :title="getTypeName(item.type)">
139
- {{ getTypeName(item.type) }}
140
- </MarkerText>
141
- </MarkerItem>
142
- <MarkerItem
143
- v-if="item.type !== 'optimizer' && item.type !== 'storage'"
144
- :title="$gettext('AC power is the nominal AC output power.')"
145
- >
146
- {{
147
- numberToString({
148
- value: item.pacKw,
149
- numberPrecision: getNumberPrecision(item.pacKw),
150
- minDecimals: 0,
151
- })
152
- }}
153
- {{ $gettext('kWAC') }}
154
- </MarkerItem>
155
- <MarkerItem
156
- v-if="
157
- (!itemHasStrings(item) || !hasExpandedSection) &&
158
- item.type !== 'storage'
159
- "
160
- :title="$gettext('The DC power is the maximum DC input power.')"
161
- >
162
- {{
163
- numberToString({
164
- value: item.inputMaxPowerKw,
165
- numberPrecision: getNumberPrecision(item.inputMaxPowerKw),
166
- minDecimals: 0,
167
- })
168
- }}
169
- {{ $gettext('kWDC') }}
170
- </MarkerItem>
171
- <MarkerItem
172
- v-if="item.type == 'storage'"
173
- :title="$gettext('charging_ac_power_kva_marker_title')"
174
- >
175
- {{
176
- numberToString({
177
- value: item.chargingAcPowerKva,
178
- numberPrecision: getNumberPrecision(item.chargingAcPowerKva),
179
- minDecimals: 0,
180
- })
181
- }}
182
- {{ $gettext('kWAC') }}
183
- </MarkerItem>
184
- </MarkersContainer>
185
- <IconsContainer>
186
- <IconWrapper
187
- v-if="nonOptimizerInverterCount > 1 || item.type === 'optimizer'"
188
- @click="
189
- !item.isLoading && hasGroupedInverters(item)
190
- ? $emit('on-delete-grouped', item)
191
- : $emit('on-delete', item)
192
- "
193
- >
194
- <RCIcon
195
- :color="item.isLoading ? 'grey' : 'red'"
196
- :cursor="item.isLoading ? 'not-allowed' : 'pointer'"
197
- :is-disabled="item.isLoading"
198
- name="delete"
199
- size="14px"
200
- />
201
- </IconWrapper>
202
- <IconWrapper @click="!item.isLoading && $emit('on-edit', item)">
203
- <RCIcon
204
- :color="item.isLoading ? 'grey' : 'white'"
205
- :cursor="item.isLoading ? 'not-allowed' : 'pointer'"
206
- :is-disabled="item.isLoading"
207
- name="edit_button"
208
- size="14px"
209
- />
210
- </IconWrapper>
211
- <IconWrapper @click="$emit('on-datasheet', item)">
212
- <RCIcon
213
- color="white"
214
- cursor="pointer"
215
- name="document"
216
- size="14px"
217
- />
218
- </IconWrapper>
219
- </IconsContainer>
220
- </LeftContainer>
221
- <SortingContainer v-if="dataListToDisplay.length > 1 && showReorder">
222
- <SortingIconWrapper
223
- :data-test-id="'move_up_' + index"
224
- :is-disabled="index === 0"
225
- @click="index > 0 && handleMoveClick('up', index, item)"
226
- >
227
- <RCIcon
228
- :color="index === 0 ? 'grey6' : 'grey3'"
229
- :cursor="index === 0 ? 'not-allowed' : 'pointer'"
230
- name="move_up"
231
- size="14px"
232
- />
233
- </SortingIconWrapper>
234
- <SortingIconWrapper
235
- :data-test-id="'move_down_' + index"
236
- :is-disabled="index === dataListToDisplay.length - 1"
237
- @click="
238
- index < dataListToDisplay.length - 1 &&
239
- handleMoveClick('down', index, item)
240
- "
241
- >
242
- <RCIcon
243
- :color="
244
- index === dataListToDisplay.length - 1 ? 'grey6' : 'grey3'
245
- "
246
- :cursor="
247
- index === dataListToDisplay.length - 1
248
- ? 'not-allowed'
249
- : 'pointer'
250
- "
251
- :is-disabled="index === dataListToDisplay.length - 1"
252
- name="move_down"
253
- size="14px"
254
- />
255
- </SortingIconWrapper>
256
- </SortingContainer>
257
- </TopContainer>
258
- <BoxContainer
259
- v-for="mppt in item.mppts"
260
- v-show="isExpanded(item.inverterId)"
261
- :key="mppt.mpptId"
262
- >
263
- <BoxTitleWrapper>
264
- <IconWrapper
265
- v-if="itemHasStrings(item)"
266
- margin-left="4px"
267
- size="8px"
268
- @click="toggleMppt(mppt.mpptId)"
269
- >
270
- <RCIcon
271
- color="white"
272
- cursor="pointer"
273
- :name="isMpptExpanded(mppt.mpptId) ? 'arrow_up' : 'arrow_down'"
274
- size="10px"
275
- />
276
- </IconWrapper>
277
- <BoxTitleText>{{ mppt.name }}</BoxTitleText>
278
- <BoxIconsContainer>
279
- <BoxIconWrapper>
280
- <RCIcon
281
- color="white"
282
- cursor="pointer"
283
- name="string_design"
284
- size="11px"
285
- />
286
- <div>
287
- {{ mppt.strings.length }}/{{ mppt.getNumberOfTerminals() }}
288
- </div>
289
- </BoxIconWrapper>
290
- <BoxIconWrapper>
291
- <RCIcon
292
- color="white"
293
- cursor="pointer"
294
- name="panels_tool"
295
- size="11px"
296
- />
297
- <div>{{ getNumberOfMpptModules(mppt.strings) }}</div>
298
- </BoxIconWrapper>
299
- </BoxIconsContainer>
300
- </BoxTitleWrapper>
301
-
302
- <div v-show="isMpptExpanded(mppt.mpptId) && itemHasStrings(item)">
303
- <StringBox v-for="string in mppt.strings" :key="string.id">
304
- <StringColorContainer :background-color="string.color" />
305
- <StringContainer>
306
- <div>{{ string.name }}</div>
307
- <StringIconContainer>
308
- <div>{{ string.modules.length }}</div>
309
- <RCIcon color="white" name="module" size="14px" />
310
- </StringIconContainer>
311
- </StringContainer>
312
- </StringBox>
313
- </div>
314
- </BoxContainer>
315
- <template v-if="availableMPPTData(item)">
316
- <BoxContainer
317
- v-for="availableItem in availableMPPTData(item)"
318
- v-show="isExpanded(item.inverterId)"
319
- :key="availableItem.mpptId"
320
- >
321
- <BoxTitleWrapper>
322
- <IconWrapper
323
- v-if="itemHasStrings(item)"
324
- margin-left="4px"
325
- size="8px"
326
- @click="toggleMppt(availableItem.mpptId)"
327
- >
328
- <RCIcon
329
- color="white"
330
- cursor="pointer"
331
- :name="
332
- isMpptExpanded(availableItem.mpptId)
333
- ? 'arrow_up'
334
- : 'arrow_down'
335
- "
336
- size="10px"
337
- />
338
- </IconWrapper>
339
- <BoxTitleText>{{ availableItem.name }}</BoxTitleText>
340
- <BoxIconsContainer>
341
- <BoxIconWrapper>
342
- <RCIcon
343
- color="white"
344
- cursor="pointer"
345
- name="string_design"
346
- size="11px"
347
- />
348
- <div>0/{{ availableItem.numberOfTerminals }}</div>
349
- </BoxIconWrapper>
350
- <BoxIconWrapper>
351
- <RCIcon
352
- color="white"
353
- cursor="pointer"
354
- name="panels_tool"
355
- size="11px"
356
- />
357
- <div>0</div>
358
- </BoxIconWrapper>
359
- </BoxIconsContainer>
360
- </BoxTitleWrapper>
361
- <EmptyStringBox
362
- v-show="
363
- isMpptExpanded(availableItem.mpptId) && itemHasStrings(item)
364
- "
365
- />
366
- </BoxContainer>
367
- </template>
368
- <BoxContainer
369
- v-if="item.storageSystem && Object.keys(item.storageSystem).length > 0"
370
- v-show="isExpanded(item.inverterId)"
371
- :key="item.storageSystem.storage_system_id"
372
- >
373
- <BoxTitleWrapper>
374
- <IconWrapper
375
- margin-left="4px"
376
- size="8px"
377
- @click="toggleMppt(item.storageSystem.storage_system_id)"
378
- >
379
- <RCIcon
380
- color="white"
381
- cursor="pointer"
382
- :name="
383
- isMpptExpanded(item.storageSystem.storage_system_id)
384
- ? 'arrow_up'
385
- : 'arrow_down'
386
- "
387
- size="10px"
388
- />
389
- </IconWrapper>
390
- <BoxTitleText>{{ $gettext('battery') }}</BoxTitleText>
391
- </BoxTitleWrapper>
392
- <div v-show="isMpptExpanded(item.storageSystem.storage_system_id)">
393
- <BatteryBox>
394
- <RCIcon color="white" name="battery" size="14px" />
395
- <BatteryDetailsContainer>
396
- <BatteryType>{{ item.storageSystem.brand_name }}</BatteryType>
397
- <BatteryModel>{{ item.storageSystem.model }}</BatteryModel>
398
- </BatteryDetailsContainer>
399
- <BatteryValue>
400
- {{
401
- numberToString({
402
- value: item.storageSystem.nominal_capacity_kWh,
403
- numberPrecision: 2,
404
- minDecimals: 0,
405
- })
406
- }}
407
- kWh
408
- </BatteryValue>
409
- </BatteryBox>
410
- </div>
411
- </BoxContainer>
412
- </SectionContainer>
413
- <DividerContainer v-if="batteryData.length" />
414
- <UnassignedContainer v-if="batteryData.length">
415
- <SectionTitleText>{{ $gettext('battery_information') }}</SectionTitleText>
416
- <BatteryBox
417
- v-for="battery in batteryData"
418
- :key="battery.id"
419
- :is-unassigned="true"
420
- >
421
- <RCIcon color="black" name="battery" size="14px" />
422
- <BatteryDetailsContainer>
423
- <UnassignedType>{{ battery.brand_name }}</UnassignedType>
424
- <UnassignedModel>{{ battery.model }}</UnassignedModel>
425
- </BatteryDetailsContainer>
426
- <BatteryValue>
427
- {{
428
- numberToString({
429
- value: battery.nominal_capacity_kWh,
430
- numberPrecision: 2,
431
- minDecimals: 0,
432
- })
433
- }}
434
- kWh
435
- </BatteryValue>
436
- </BatteryBox>
437
- </UnassignedContainer>
438
- </PageContainer>
439
- </template>
440
-
441
- <script>
442
- // import DropdownMenu from '@eturnity/eturnity_reusable_components/src/components/stringDesign/DropdownMenu'
443
- import styled from 'vue3-styled-components'
444
- import RCIcon from '../../icon'
445
- import ButtonIcon from '../../buttons/buttonIcon'
446
- import { numberToString } from '../../../helpers/numberConverter'
447
- import RCInfoText from '../../infoText'
448
- const PageContainer = styled.div`
449
- position: relative;
450
- `
451
-
452
- const SectionContainer = styled.div`
453
- &:not(:last-child) {
454
- margin-bottom: 8px;
455
- }
456
- background-color: ${(props) => props.theme.colors.black};
457
- padding: 8px;
458
- border-radius: 4px;
459
- color: ${(props) => props.theme.colors.white};
460
- `
461
-
462
- const TitleContainer = styled.div`
463
- display: flex;
464
- align-items: center;
465
- gap: 4px;
466
- `
467
-
468
- const IconsContainer = styled.div`
469
- display: flex;
470
- align-items: center;
471
- margin-left: 32px;
472
- margin-top: 4px;
473
- `
474
- const textContainerAttr = { isArchived: Boolean }
475
- const TextContainer = styled('div', textContainerAttr)`
476
- display: grid;
477
- color: ${(props) => (props.isArchived ? props.theme.colors.red : 'white')};
478
- `
479
- const InfoTextWrapper = styled.div`
480
- display: flex;
481
- align-items: center;
482
- justify-content: center;
483
- padding-left: 8px;
484
- `
485
- const TitleText = styled.div`
486
- font-size: 14px;
487
- white-space: nowrap;
488
- overflow: hidden;
489
- text-overflow: ellipsis;
490
- display: flex;
491
- `
492
-
493
- const TitleSubText = styled.div`
494
- font-size: 12px;
495
- display: flex;
496
- gap: 4px;
497
- `
498
-
499
- const MarkersContainer = styled.div`
500
- display: flex;
501
- flex-wrap: wrap;
502
- gap: 8px;
503
- margin: 4px 0 2px 32px;
504
- align-items: end;
505
- `
506
-
507
- const MarkerAttrs = { backgroundColor: String }
508
- const MarkerItem = styled('div', MarkerAttrs)`
509
- display: flex;
510
- gap: 5px;
511
- align-items: center;
512
- padding: 2px 7px;
513
- border-radius: 4px;
514
- background-color: ${(props) =>
515
- props.backgroundColor
516
- ? props.theme.colors[props.backgroundColor]
517
- : props.theme.colors.grey6};
518
- font-size: 11px;
519
- color: ${(props) => props.theme.colors.white};
520
- & > span {
521
- overflow: hidden;
522
- white-space: nowrap;
523
- text-overflow: ellipsis;
524
- max-width: 11ch;
525
- }
526
- `
527
-
528
- const MarkerText = styled.div`
529
- max-width: 11ch;
530
- white-space: nowrap;
531
- overflow: hidden;
532
- text-overflow: ellipsis;
533
- `
534
-
535
- const ContainerValue = styled.div`
536
- font-size: 12px;
537
- `
538
-
539
- const IconAttrs = {
540
- size: { type: String, default: '32px' },
541
- marginLeft: String,
542
- }
543
- const IconWrapper = styled('div', IconAttrs)`
544
- display: flex;
545
- align-items: center;
546
- justify-content: center;
547
- border-radius: 4px;
548
- cursor: pointer;
549
- width: ${(props) => props.size};
550
- height: ${(props) => props.size};
551
- margin-left: ${(props) => props.marginLeft};
552
- &:hover {
553
- background: ${(props) =>
554
- props.marginLeft ? 'transparent' : 'rgba(255, 255, 255, 0.1)'};
555
- }
556
-
557
- &:active {
558
- background: rgba(255, 255, 255, 0.2);
559
- }
560
- `
561
-
562
- const BoxContainer = styled.div`
563
- border-radius: 4px;
564
- background: ${(props) => props.theme.colors.grey6};
565
- padding: 8px;
566
- margin-top: 8px;
567
- margin-left: 30px;
568
- `
569
-
570
- const BoxTitleWrapper = styled.div`
571
- display: flex;
572
- align-items: center;
573
- gap: 8px;
574
- `
575
-
576
- const BoxTitleText = styled.div`
577
- font-size: 13px;
578
- `
579
-
580
- const BoxIconsContainer = styled.div`
581
- display: flex;
582
- gap: 8px;
583
- align-items: center;
584
- margin-left: auto;
585
- font-size: 11px;
586
- `
587
-
588
- const BoxIconWrapper = styled.div`
589
- display: flex;
590
- align-items: center;
591
- justify-content: center;
592
- gap: 4px;
593
- padding: 4px;
594
- `
595
-
596
- const StringBox = styled.div`
597
- display: grid;
598
- grid-template-columns: auto 1fr;
599
- margin-top: 8px;
600
- border-radius: 4px;
601
- border: 1px solid ${(props) => props.theme.colors.grey3};
602
- `
603
-
604
- const StringContainer = styled.div`
605
- display: flex;
606
- justify-content: space-between;
607
- gap: 8px;
608
- padding: 8px;
609
- font-size: 11px;
610
- `
611
-
612
- const StringColorAttrs = { backgroundColor: String }
613
- const StringColorContainer = styled('div', StringColorAttrs)`
614
- background-color: ${(props) => props.backgroundColor};
615
- width: 22px;
616
- min-height: 100%;
617
- border-top-left-radius: 2px;
618
- border-bottom-left-radius: 2px;
619
- `
620
-
621
- const StringIconContainer = styled.div`
622
- display: flex;
623
- align-items: center;
624
- justify-content: center;
625
- gap: 2px;
626
- padding: 0 4px;
627
- `
628
-
629
- const PageTitleContainer = styled.div`
630
- position: sticky;
631
- top: 0;
632
- background-color: ${(props) => props.theme.colors.black};
633
- z-index: 99;
634
- padding: 8px;
635
- display: grid;
636
- gap: 6px;
637
- align-items: center;
638
- `
639
-
640
- const TitleButtonsContainer = styled.div`
641
- display: flex;
642
- align-items: center;
643
- gap: 4px;
644
- padding-bottom: 8px;
645
- `
646
-
647
- const SectionTitleText = styled.div`
648
- font-size: 14px;
649
- font-weight: 700;
650
- color: ${(props) => props.theme.colors.white};
651
- `
652
-
653
- const BatteryBoxAttrs = { isUnassigned: Boolean }
654
- const BatteryBox = styled('div', BatteryBoxAttrs)`
655
- display: flex;
656
- align-items: center;
657
- gap: 8px;
658
- border: 1px solid ${(props) => props.theme.colors.white};
659
- border-radius: 4px;
660
- padding: 8px;
661
- margin-top: 8px;
662
- background-color: ${(props) =>
663
- props.isUnassigned ? props.theme.colors.grey2 : ''};
664
- `
665
-
666
- const BatteryDetailsContainer = styled.div`
667
- display: flex;
668
- flex-direction: column;
669
- gap: 4px;
670
- `
671
-
672
- const BatteryType = styled.div`
673
- font-size: 11px;
674
- `
675
-
676
- const BatteryModel = styled.div`
677
- font-size: 10px;
678
- `
679
-
680
- const BatteryValue = styled.div`
681
- font-size: 10px;
682
- align-self: flex-end;
683
- margin-left: auto;
684
- `
685
- const TopContainer = styled.div`
686
- display: flex;
687
- justify-content: space-between;
688
- `
689
-
690
- const LeftContainer = styled.div``
691
-
692
- const SortingContainer = styled.div`
693
- display: flex;
694
- flex-direction: column;
695
- align-items: center;
696
- `
697
-
698
- const SortingIconWrapperAttrs = { isDisabled: Boolean }
699
- const SortingIconWrapper = styled('div', SortingIconWrapperAttrs)`
700
- cursor: ${(props) => (props.isDisabled ? 'not-allowed' : 'pointer')};
701
- width: 30px;
702
- height: 30px;
703
- display: flex;
704
- align-items: center;
705
- justify-content: center;
706
-
707
- &:hover {
708
- background-color: ${(props) =>
709
- props.isDisabled ? 'transparent' : 'rgba(255, 255, 255, 0.1)'};
710
- border-radius: 4px;
711
- }
712
- `
713
-
714
- const UnassignedContainer = styled.div`
715
- margin-top: 8px;
716
- `
717
-
718
- const DividerContainer = styled.div`
719
- height: 0.5px;
720
- width: 100%;
721
- background-color: ${(props) => props.theme.colors.grey4};
722
- opacity: 0.6;
723
- `
724
-
725
- const UnassignedType = styled.div`
726
- font-size: 12px;
727
- line-height: 150%;
728
- `
729
-
730
- const UnassignedModel = styled.div`
731
- font-size: 10px;
732
- line-height: 150%;
733
- `
734
-
735
- const IconPlaceholder = styled.div`
736
- width: 32px;
737
- `
738
-
739
- const EmptyStringBox = styled.div`
740
- border: 0.8px dashed ${(props) => props.theme.colors.black};
741
- border-radius: 4px;
742
- padding: 8px 8px 8px 0;
743
- height: 32px;
744
- width: 233px;
745
- margin-top: 8px;
746
- `
747
-
748
- export default {
749
- name: 'DropdownMenu',
750
- components: {
751
- InfoTextWrapper,
752
- RCInfoText,
753
- SectionContainer,
754
- TitleContainer,
755
- IconsContainer,
756
- TextContainer,
757
- TitleText,
758
- TitleSubText,
759
- RCIcon,
760
- MarkersContainer,
761
- MarkerItem,
762
- ContainerValue,
763
- IconWrapper,
764
- BoxContainer,
765
- BoxTitleWrapper,
766
- BoxTitleText,
767
- BoxIconsContainer,
768
- BoxIconWrapper,
769
- StringBox,
770
- StringContainer,
771
- StringColorContainer,
772
- StringIconContainer,
773
- PageTitleContainer,
774
- TitleButtonsContainer,
775
- SectionTitleText,
776
- ButtonIcon,
777
- PageContainer,
778
- BatteryBox,
779
- BatteryDetailsContainer,
780
- BatteryType,
781
- BatteryModel,
782
- BatteryValue,
783
- TopContainer,
784
- LeftContainer,
785
- SortingContainer,
786
- SortingIconWrapper,
787
- UnassignedContainer,
788
- DividerContainer,
789
- UnassignedType,
790
- UnassignedModel,
791
- IconPlaceholder,
792
- EmptyStringBox,
793
- MarkerText,
794
- },
795
- props: {
796
- dataList: {
797
- required: true,
798
- type: Array,
799
- },
800
- batteryData: {
801
- required: true,
802
- type: Array,
803
- },
804
- inverterParameters: {
805
- required: true,
806
- type: Object,
807
- },
808
- isPvAndBatteryActive: {
809
- required: false,
810
- type: Boolean,
811
- },
812
- },
813
- emits: ['on-edit', 'on-move', 'on-delete', 'on-delete-grouped'],
814
- data() {
815
- return {
816
- expandedInverters: [],
817
- expandedMppts: [],
818
- showReorder: false,
819
- numberToString,
820
- }
821
- },
822
- computed: {
823
- dataListToDisplay() {
824
- let data = this.hasExpandedSection
825
- ? this.dataList
826
- : this.compressedDataList
827
- return data.sort((a, b) => a.lineNr - b.lineNr)
828
- },
829
- hasExpandedSection() {
830
- return this.expandedInverters.length > 0
831
- },
832
- hasStringsOrStorage() {
833
- return this.dataList.some((item) => {
834
- return (
835
- item.mppts.some((mppt) => mppt.strings.length > 0) ||
836
- (item.storageSystem && Object.keys(item.storageSystem).length > 0)
837
- )
838
- })
839
- },
840
- nonOptimizerInverterCount() {
841
- return this.dataList.filter((item) => item.type !== 'optimizer').length
842
- },
843
- compressedDataList() {
844
- return this.dataList.reduce((acc, item) => {
845
- if (item.type == 'optimizer') {
846
- acc.push(item)
847
- return acc
848
- }
849
- const existingInverter = acc.find((inverter) => {
850
- return inverter.componentId == item.componentId
851
- })
852
- if (!existingInverter) {
853
- acc.push(item)
854
- item.quantity = 1
855
- } else {
856
- existingInverter.quantity++
857
- }
858
- return acc
859
- }, [])
860
- },
861
- },
862
- created() {
863
- // Expand all items on creation
864
- if (this.hasStringsOrStorage) {
865
- this.expandedInverters = this.dataList.map((item) => item.inverterId)
866
- this.expandedMppts = this.dataList.flatMap((item) => {
867
- const availableMppts = this.availableMPPTData(item)
868
- return [
869
- ...item.mppts.map((mppt) => mppt.mpptId),
870
- ...(item.storageSystem
871
- ? [item.storageSystem.storage_system_id]
872
- : []),
873
- ...(availableMppts?.map((mppt) => mppt.mpptId) || []),
874
- ]
875
- })
876
- }
877
- },
878
- methods: {
879
- hasGroupedInverters(item) {
880
- return item.type != 'optimizer' && item.quantity > 1
881
- },
882
- toggleShowReorder() {
883
- this.showReorder = !this.showReorder
884
- },
885
- isTargetRatioInRange(inverter) {
886
- const currentTargetRatio = inverter.getTargetRatio()
887
- return (
888
- this.inverterParameters.target_power_ratio - 20 <=
889
- 100 * currentTargetRatio &&
890
- this.inverterParameters.target_power_ratio + 20 >=
891
- 100 * currentTargetRatio
892
- )
893
- },
894
- getNumberPrecision(value) {
895
- if (typeof value === 'string') {
896
- value = Number(value)
897
- }
898
- if (value < 10) {
899
- return 2
900
- } else if (value >= 10 && value < 100) {
901
- return 1
902
- } else {
903
- return 0
904
- }
905
- },
906
- getNumberOfMpptModules(strings) {
907
- return strings.reduce((acc, curr) => acc + curr.modules.length, 0)
908
- },
909
- availableMPPTData(item) {
910
- if (item.type === 'optimizer' || item.type === 'storage') {
911
- return []
912
- }
913
- const existingTrackerNumbers = item.mppts.map(
914
- (mppt) => mppt.trackerNumber
915
- )
916
- const filteredAvailableMPPTs = item.availableMPPTs.filter(
917
- (mppt) => !existingTrackerNumbers.includes(mppt.tracker_number)
918
- )
919
-
920
- let mpptData = []
921
- filteredAvailableMPPTs.forEach((mppt) => {
922
- mpptData.push({
923
- mpptId:
924
- 'available_mppt_' +
925
- item.companyComponentLibraryId +
926
- '_' +
927
- mppt.tracker_number,
928
- numberOfTerminals: mppt.number_of_terminals,
929
- name:
930
- 'MPPT ' +
931
- (item.mppts.length + filteredAvailableMPPTs.indexOf(mppt) + 1),
932
- })
933
- })
934
- return mpptData
935
- },
936
- isExpanded(id) {
937
- return this.expandedInverters.includes(id)
938
- },
939
- isMpptExpanded(id) {
940
- return this.expandedMppts.includes(id)
941
- },
942
- toggleSection(id) {
943
- const index = this.expandedInverters.indexOf(id)
944
- if (index === -1) {
945
- this.expandedInverters.push(id)
946
- } else {
947
- this.expandedInverters.splice(index, 1)
948
- }
949
- },
950
- toggleMppt(id) {
951
- const index = this.expandedMppts.indexOf(id)
952
- if (index === -1) {
953
- this.expandedMppts.push(id)
954
- } else {
955
- this.expandedMppts.splice(index, 1)
956
- }
957
- },
958
- toggleAllSections() {
959
- if (this.hasExpandedSection) {
960
- this.expandedInverters = []
961
- this.expandedMppts = []
962
- } else {
963
- this.expandedInverters = this.dataList.map((item) => item.inverterId)
964
- this.expandedMppts = this.dataList.flatMap((item) => {
965
- const hasStrings = !!item.getStrings().length
966
- return [
967
- ...(hasStrings ? item.mppts.map((mppt) => mppt.mpptId) : []),
968
- ...(item.storageSystem
969
- ? [item.storageSystem.storage_system_id]
970
- : []),
971
- ]
972
- })
973
- }
974
- },
975
- isItemCollapsible(item) {
976
- return (
977
- item.mppts.some((mppt) => mppt.strings.length > 0) ||
978
- (item.storageSystem && Object.keys(item.storageSystem).length > 0) ||
979
- item.availableMPPTs.length
980
- )
981
- },
982
- itemHasStrings(item) {
983
- return item.mppts.some((mppt) => mppt.strings.length > 0)
984
- },
985
- getTypeName(type) {
986
- const value = type.toLowerCase()
987
- switch (value) {
988
- case 'pv':
989
- return this.$gettext('PV')
990
- case 'pv_storage':
991
- return this.$gettext('hybrid')
992
- case 'storage':
993
- return this.$gettext('battery')
994
- case 'optimizer':
995
- return this.$gettext('inverter_type_optimizer')
996
- default:
997
- return this.$gettext('PV')
998
- }
999
- },
1000
- getIconName(item) {
1001
- const value =
1002
- item.type === 'pv_storage'
1003
- ? item.iconName.technology_choice
1004
- : item.type
1005
- switch (value) {
1006
- case 'photovoltaics':
1007
- return 'pv'
1008
- case 'pv':
1009
- return 'pv'
1010
- case 'storage':
1011
- return 'battery'
1012
- case 'battery':
1013
- return 'battery'
1014
- case 'optimizer':
1015
- return 'optimizer'
1016
- default:
1017
- return 'pv'
1018
- }
1019
- },
1020
- handleMoveClick(direction, index, item) {
1021
- this.$emit('on-move', {
1022
- direction: direction,
1023
- index: index,
1024
- item: item,
1025
- isExpanded: this.hasExpandedSection,
1026
- })
1027
- },
1028
- },
1029
- }
1030
- </script>