@nyaruka/temba-components 0.170.1 → 0.172.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/temba-components.js +763 -703
- package/dist/temba-components.js.map +1 -1
- package/package.json +1 -1
- package/src/RapidElement.ts +83 -41
- package/src/events/eventRenderers.ts +4 -0
- package/src/flow/Editor.ts +202 -42
- package/src/flow/FlowSearch.ts +12 -392
- package/src/flow/actions/send_msg.ts +2 -1
- package/src/flow/actions/set_contact_field.ts +1 -0
- package/src/flow/actions/set_contact_name.ts +1 -0
- package/src/flow/dependencies.ts +115 -0
- package/src/flow/nodes/split_by_ticket.ts +1 -0
- package/src/flow/nodes/wait_for_dial.ts +1 -0
- package/src/form/RangePicker.ts +137 -97
- package/src/layout/SearchModal.ts +564 -0
- package/src/list/ContentList.ts +7 -1
- package/src/list/FlowList.ts +82 -0
- package/src/list/TembaMenu.ts +71 -13
- package/src/live/ContactChat.ts +247 -70
- package/src/live/ContactWatch.ts +166 -63
- package/src/live/Realtime.ts +155 -4
- package/src/live/SocketService.ts +115 -10
- package/src/live/TicketSearch.ts +290 -0
- package/src/live/Watchers.ts +93 -0
- package/src/simulator/Simulator.ts +59 -36
- package/src/store/AppState.ts +97 -10
- package/src/store/Store.ts +478 -6
- package/src/store/identity.ts +28 -0
- package/src/utils.ts +10 -8
- package/temba-modules.ts +2 -0
package/src/form/RangePicker.ts
CHANGED
|
@@ -4,107 +4,165 @@ import { DateTime } from 'luxon';
|
|
|
4
4
|
import { html, css, PropertyValues } from 'lit';
|
|
5
5
|
import { DatePicker } from './DatePicker';
|
|
6
6
|
import { CustomEventType } from '../interfaces';
|
|
7
|
+
import { Icon } from '../Icons';
|
|
8
|
+
import { designTokens } from '../styles/designTokens';
|
|
7
9
|
|
|
8
10
|
export class RangePicker extends RapidElement {
|
|
9
11
|
static styles = css`
|
|
12
|
+
${designTokens}
|
|
13
|
+
|
|
14
|
+
:host {
|
|
15
|
+
display: inline-block;
|
|
16
|
+
font-family: var(--font);
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
.range-container {
|
|
11
20
|
display: flex;
|
|
12
|
-
gap:
|
|
21
|
+
gap: 8px;
|
|
13
22
|
align-items: center;
|
|
23
|
+
font-size: 13.5px;
|
|
24
|
+
color: var(--text-1);
|
|
14
25
|
}
|
|
26
|
+
|
|
15
27
|
.date-display {
|
|
16
28
|
cursor: pointer;
|
|
17
|
-
padding:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
padding: 3px 6px;
|
|
30
|
+
border-radius: var(--r-sm);
|
|
31
|
+
transition:
|
|
32
|
+
background 120ms,
|
|
33
|
+
color 120ms;
|
|
22
34
|
}
|
|
23
35
|
|
|
24
36
|
.date-display:hover {
|
|
25
|
-
border: 1px solid var(--color-widget-border);
|
|
26
37
|
background: var(--sunken);
|
|
27
38
|
}
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
padding: 0.2em 0.5em;
|
|
32
|
-
border-radius: var(--curvature-widget);
|
|
33
|
-
border: 1px solid var(--color-widget-border);
|
|
40
|
+
.range-separator {
|
|
41
|
+
color: var(--text-3);
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
.navigation-container {
|
|
37
45
|
display: flex;
|
|
38
46
|
align-items: center;
|
|
39
|
-
gap:
|
|
47
|
+
gap: 4px;
|
|
40
48
|
}
|
|
41
49
|
|
|
50
|
+
/* Chevron-only step buttons, same chrome as the list pager: bare
|
|
51
|
+
glyph at rest, sunken wash on hover. No border of their own, so
|
|
52
|
+
they don't compete with the period track between them. */
|
|
42
53
|
.nav-arrow {
|
|
43
|
-
|
|
44
|
-
border: 1px solid var(--color-widget-border);
|
|
45
|
-
|
|
46
|
-
border-radius: var(--curvature-widget);
|
|
47
|
-
padding: 0em 0em;
|
|
48
|
-
cursor: pointer;
|
|
49
|
-
font-size: 0.6em;
|
|
50
|
-
display: flex;
|
|
54
|
+
display: inline-flex;
|
|
51
55
|
align-items: center;
|
|
52
56
|
justify-content: center;
|
|
53
|
-
width:
|
|
54
|
-
height:
|
|
57
|
+
width: 24px;
|
|
58
|
+
height: 24px;
|
|
59
|
+
padding: 0;
|
|
60
|
+
border: 0;
|
|
61
|
+
background: transparent;
|
|
62
|
+
border-radius: var(--r-sm);
|
|
63
|
+
color: var(--text-3);
|
|
64
|
+
cursor: pointer;
|
|
55
65
|
transition:
|
|
56
|
-
background
|
|
57
|
-
|
|
58
|
-
opacity
|
|
66
|
+
background 120ms,
|
|
67
|
+
color 120ms,
|
|
68
|
+
opacity 120ms;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.nav-arrow temba-icon {
|
|
72
|
+
--icon-color: currentColor;
|
|
59
73
|
}
|
|
60
74
|
|
|
61
75
|
.nav-arrow:hover:not(:disabled) {
|
|
62
|
-
background: var(--
|
|
63
|
-
|
|
76
|
+
background: var(--sunken);
|
|
77
|
+
color: var(--text-1);
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
.nav-arrow:disabled {
|
|
67
|
-
opacity: 0.
|
|
68
|
-
cursor:
|
|
69
|
-
background: var(--sunken);
|
|
81
|
+
opacity: 0.35;
|
|
82
|
+
cursor: default;
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
.nav-arrow.hidden {
|
|
73
86
|
visibility: hidden;
|
|
74
87
|
}
|
|
75
88
|
|
|
89
|
+
/* Segmented control — one bordered sunken track holds every
|
|
90
|
+
period and the selected one lifts out as a surface pill. The
|
|
91
|
+
buttons carry no borders themselves, so there are no
|
|
92
|
+
overlapping 1px edges to clip the selection's outline (the old
|
|
93
|
+
-1px margin stacking left the selected button's left border
|
|
94
|
+
painted over by its neighbor). */
|
|
76
95
|
.button-group {
|
|
77
|
-
display: flex;
|
|
78
|
-
|
|
96
|
+
display: inline-flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
gap: 2px;
|
|
99
|
+
padding: 2px;
|
|
100
|
+
background: var(--sunken);
|
|
101
|
+
border: 1px solid var(--border);
|
|
102
|
+
border-radius: var(--r-sm);
|
|
79
103
|
}
|
|
104
|
+
|
|
80
105
|
.range-btn {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
border
|
|
84
|
-
|
|
85
|
-
|
|
106
|
+
height: 22px;
|
|
107
|
+
padding: 0 10px;
|
|
108
|
+
border: 0;
|
|
109
|
+
background: transparent;
|
|
110
|
+
border-radius: var(--r-xs);
|
|
111
|
+
font-family: inherit;
|
|
112
|
+
font-size: 12.5px;
|
|
113
|
+
font-weight: var(--w-medium);
|
|
114
|
+
line-height: 1;
|
|
115
|
+
color: var(--text-2);
|
|
86
116
|
cursor: pointer;
|
|
87
|
-
font-size: 0.95em;
|
|
88
117
|
transition:
|
|
89
|
-
background
|
|
90
|
-
|
|
118
|
+
background 120ms,
|
|
119
|
+
color 120ms,
|
|
120
|
+
box-shadow 120ms;
|
|
91
121
|
}
|
|
92
122
|
|
|
93
|
-
|
|
94
|
-
|
|
123
|
+
/* The hover wash sits on the sunken track, so --sunken itself
|
|
124
|
+
would be invisible here. Derived from --text-1 rather than a raw
|
|
125
|
+
rgba literal so it follows the palette (the tokens file mixes
|
|
126
|
+
against transparent the same way for --focus-halo). The rgba
|
|
127
|
+
fallback pre-mixes the default --text-1 for browsers without
|
|
128
|
+
color-mix(). */
|
|
129
|
+
.range-btn:hover:not(.selected) {
|
|
130
|
+
background: rgba(26, 31, 38, 0.06);
|
|
131
|
+
color: var(--text-1);
|
|
95
132
|
}
|
|
96
133
|
|
|
97
|
-
|
|
98
|
-
|
|
134
|
+
@supports (color: color-mix(in srgb, red, red)) {
|
|
135
|
+
.range-btn:hover:not(.selected) {
|
|
136
|
+
background: color-mix(in srgb, var(--text-1) 6%, transparent);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.range-btn.selected {
|
|
141
|
+
background: var(--surface);
|
|
142
|
+
color: var(--accent-700);
|
|
143
|
+
box-shadow: var(--shadow-1);
|
|
144
|
+
cursor: default;
|
|
99
145
|
}
|
|
100
146
|
|
|
101
|
-
.range-btn
|
|
102
|
-
.
|
|
103
|
-
|
|
104
|
-
|
|
147
|
+
.range-btn:focus-visible,
|
|
148
|
+
.nav-arrow:focus-visible {
|
|
149
|
+
outline: none;
|
|
150
|
+
box-shadow: var(--focus-halo);
|
|
105
151
|
}
|
|
106
152
|
`;
|
|
107
153
|
|
|
154
|
+
// the periods in the segmented control, in display order
|
|
155
|
+
private static RANGES: {
|
|
156
|
+
type: 'W' | 'M' | 'Y' | 'ALL';
|
|
157
|
+
label: string;
|
|
158
|
+
title: string;
|
|
159
|
+
}[] = [
|
|
160
|
+
{ type: 'W', label: 'W', title: 'Last week' },
|
|
161
|
+
{ type: 'M', label: 'M', title: 'Last month' },
|
|
162
|
+
{ type: 'Y', label: 'Y', title: 'Last year' },
|
|
163
|
+
{ type: 'ALL', label: 'All', title: 'All time' }
|
|
164
|
+
];
|
|
165
|
+
|
|
108
166
|
@property({ type: String, attribute: 'start' })
|
|
109
167
|
startDate = '';
|
|
110
168
|
|
|
@@ -465,6 +523,15 @@ export class RangePicker extends RapidElement {
|
|
|
465
523
|
} ${amount} ${unit}`;
|
|
466
524
|
}
|
|
467
525
|
|
|
526
|
+
private getNavigationTitle(direction: 'previous' | 'next'): string {
|
|
527
|
+
const prefix = direction === 'previous' ? 'Previous' : 'Next';
|
|
528
|
+
if (this.selectedRange === 'W') return `${prefix} week`;
|
|
529
|
+
if (this.selectedRange === 'M') return `${prefix} month`;
|
|
530
|
+
if (this.selectedRange === 'Y') return `${prefix} year`;
|
|
531
|
+
if (this.selectedRange === '') return this.getNavigationLabel(direction);
|
|
532
|
+
return `${prefix} period`;
|
|
533
|
+
}
|
|
534
|
+
|
|
468
535
|
willUpdate(changed: PropertyValues) {
|
|
469
536
|
super.willUpdate(changed);
|
|
470
537
|
|
|
@@ -543,7 +610,7 @@ export class RangePicker extends RapidElement {
|
|
|
543
610
|
>${this.formatDateForDisplay(this.startDate) ||
|
|
544
611
|
'Start date'}</span
|
|
545
612
|
>`}
|
|
546
|
-
<span
|
|
613
|
+
<span class="range-separator">–</span>
|
|
547
614
|
${this.editingEnd
|
|
548
615
|
? html`<temba-datepicker
|
|
549
616
|
.value=${this.endDate}
|
|
@@ -566,61 +633,34 @@ export class RangePicker extends RapidElement {
|
|
|
566
633
|
class="nav-arrow ${this.selectedRange === 'ALL' ? 'hidden' : ''}"
|
|
567
634
|
?disabled=${!this.canNavigatePrevious()}
|
|
568
635
|
@click=${this.navigatePrevious}
|
|
569
|
-
title
|
|
570
|
-
|
|
571
|
-
: this.selectedRange === 'M'
|
|
572
|
-
? 'month'
|
|
573
|
-
: this.selectedRange === 'Y'
|
|
574
|
-
? 'year'
|
|
575
|
-
: this.selectedRange === ''
|
|
576
|
-
? this.getNavigationLabel('previous')
|
|
577
|
-
: 'period'}"
|
|
636
|
+
title=${this.getNavigationTitle('previous')}
|
|
637
|
+
aria-label=${this.getNavigationTitle('previous')}
|
|
578
638
|
>
|
|
579
|
-
|
|
639
|
+
<temba-icon name=${Icon.arrow_left}></temba-icon>
|
|
580
640
|
</button>
|
|
581
|
-
<div class="button-group">
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
class="range-btn ${this.selectedRange === 'Y' ? 'selected' : ''}"
|
|
596
|
-
@click=${() => this.setRange('Y')}
|
|
597
|
-
>
|
|
598
|
-
Y
|
|
599
|
-
</button>
|
|
600
|
-
<button
|
|
601
|
-
class="range-btn ${this.selectedRange === 'ALL'
|
|
602
|
-
? 'selected'
|
|
603
|
-
: ''}"
|
|
604
|
-
@click=${() => this.setRange('ALL')}
|
|
605
|
-
>
|
|
606
|
-
All
|
|
607
|
-
</button>
|
|
641
|
+
<div class="button-group" role="group" aria-label="Period">
|
|
642
|
+
${RangePicker.RANGES.map(
|
|
643
|
+
(range) =>
|
|
644
|
+
html`<button
|
|
645
|
+
class="range-btn ${this.selectedRange === range.type
|
|
646
|
+
? 'selected'
|
|
647
|
+
: ''}"
|
|
648
|
+
title=${range.title}
|
|
649
|
+
aria-pressed=${this.selectedRange === range.type}
|
|
650
|
+
@click=${() => this.setRange(range.type)}
|
|
651
|
+
>
|
|
652
|
+
${range.label}
|
|
653
|
+
</button>`
|
|
654
|
+
)}
|
|
608
655
|
</div>
|
|
609
656
|
<button
|
|
610
657
|
class="nav-arrow ${this.selectedRange === 'ALL' ? 'hidden' : ''}"
|
|
611
658
|
?disabled=${!this.canNavigateNext()}
|
|
612
659
|
@click=${this.navigateNext}
|
|
613
|
-
title
|
|
614
|
-
|
|
615
|
-
: this.selectedRange === 'M'
|
|
616
|
-
? 'month'
|
|
617
|
-
: this.selectedRange === 'Y'
|
|
618
|
-
? 'year'
|
|
619
|
-
: this.selectedRange === ''
|
|
620
|
-
? this.getNavigationLabel('next')
|
|
621
|
-
: 'period'}"
|
|
660
|
+
title=${this.getNavigationTitle('next')}
|
|
661
|
+
aria-label=${this.getNavigationTitle('next')}
|
|
622
662
|
>
|
|
623
|
-
|
|
663
|
+
<temba-icon name=${Icon.arrow_right}></temba-icon>
|
|
624
664
|
</button>
|
|
625
665
|
</div>
|
|
626
666
|
</div>
|