@nyaruka/temba-components 0.113.0 → 0.114.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 +21 -2
- package/demo/index.html +1 -1
- package/dist/temba-components.js +793 -966
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/aliaseditor/AliasEditor.js.map +1 -1
- package/out-tsc/src/button/Button.js +6 -2
- package/out-tsc/src/button/Button.js.map +1 -1
- package/out-tsc/src/chat/Chat.js +29 -7
- package/out-tsc/src/chat/Chat.js.map +1 -1
- package/out-tsc/src/compose/Compose.js +10 -5
- package/out-tsc/src/compose/Compose.js.map +1 -1
- package/out-tsc/src/contacts/ContactChat.js +240 -114
- package/out-tsc/src/contacts/ContactChat.js.map +1 -1
- package/out-tsc/src/contacts/ContactFieldEditor.js.map +1 -1
- package/out-tsc/src/contacts/events.js.map +1 -1
- package/out-tsc/src/contacts/helpers.js +5 -1
- package/out-tsc/src/contacts/helpers.js.map +1 -1
- package/out-tsc/src/contactsearch/ContactSearch.js +1 -1
- package/out-tsc/src/contactsearch/ContactSearch.js.map +1 -1
- package/out-tsc/src/dropdown/Dropdown.js +121 -108
- package/out-tsc/src/dropdown/Dropdown.js.map +1 -1
- package/out-tsc/src/interfaces.js +2 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/list/ContentMenu.js +11 -8
- package/out-tsc/src/list/ContentMenu.js.map +1 -1
- package/out-tsc/src/list/RunList.js.map +1 -1
- package/out-tsc/src/list/TembaList.js +21 -14
- package/out-tsc/src/list/TembaList.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +11 -12
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/list/TicketList.js +10 -0
- package/out-tsc/src/list/TicketList.js.map +1 -1
- package/out-tsc/src/omnibox/Omnibox.js +33 -90
- package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
- package/out-tsc/src/options/Options.js +49 -47
- package/out-tsc/src/options/Options.js.map +1 -1
- package/out-tsc/src/select/PopupSelect.js +57 -0
- package/out-tsc/src/select/PopupSelect.js.map +1 -0
- package/out-tsc/src/select/Select.js +194 -144
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/select/UserSelect.js +67 -0
- package/out-tsc/src/select/UserSelect.js.map +1 -0
- package/out-tsc/src/store/Store.js +65 -14
- package/out-tsc/src/store/Store.js.map +1 -1
- package/out-tsc/src/tabpane/TabPane.js +72 -115
- package/out-tsc/src/tabpane/TabPane.js.map +1 -1
- package/out-tsc/src/textinput/TextInput.js +1 -0
- package/out-tsc/src/textinput/TextInput.js.map +1 -1
- package/out-tsc/src/user/TembaUser.js +24 -37
- package/out-tsc/src/user/TembaUser.js.map +1 -1
- package/out-tsc/src/utils/index.js +13 -6
- package/out-tsc/src/utils/index.js.map +1 -1
- package/out-tsc/temba-modules.js +4 -2
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-omnibox.test.js +43 -4
- package/out-tsc/test/temba-omnibox.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +121 -65
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +4 -0
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/compose/attachments-tab.png +0 -0
- package/screenshots/truth/compose/attachments-with-files-focused.png +0 -0
- package/screenshots/truth/compose/attachments-with-files.png +0 -0
- package/screenshots/truth/compose/intial-text.png +0 -0
- package/screenshots/truth/compose/no-counter.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
- package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/content-menu/item-no-buttons.png +0 -0
- package/screenshots/truth/content-menu/items-and-buttons.png +0 -0
- package/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/select/enabled-multi-selection.png +0 -0
- package/screenshots/truth/select/endpoint-initial-value-updated.png +0 -0
- package/screenshots/truth/select/endpoint-initial-value.png +0 -0
- package/screenshots/truth/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/initial-value.png +0 -0
- package/screenshots/truth/select/multi-with-endpoint.png +0 -0
- package/screenshots/truth/select/multiple-initial-values.png +0 -0
- package/screenshots/truth/select/selected-multi-test.png +0 -0
- package/screenshots/truth/select/static-initial-value.png +0 -0
- package/screenshots/truth/select/static-initial-via-selected.png +0 -0
- package/screenshots/truth/select/value-initial.png +0 -0
- package/src/aliaseditor/AliasEditor.ts +1 -1
- package/src/button/Button.ts +6 -2
- package/src/chat/Chat.ts +28 -6
- package/src/compose/Compose.ts +11 -6
- package/src/contacts/ContactChat.ts +260 -118
- package/src/contacts/ContactFieldEditor.ts +1 -1
- package/src/contacts/events.ts +1 -0
- package/src/contacts/helpers.ts +8 -1
- package/src/contactsearch/ContactSearch.ts +3 -3
- package/src/dropdown/Dropdown.ts +142 -103
- package/src/interfaces.ts +4 -1
- package/src/list/ContentMenu.ts +11 -9
- package/src/list/RunList.ts +3 -1
- package/src/list/TembaList.ts +24 -14
- package/src/list/TembaMenu.ts +14 -15
- package/src/list/TicketList.ts +11 -0
- package/src/omnibox/Omnibox.ts +34 -95
- package/src/options/Options.ts +57 -60
- package/src/select/PopupSelect.ts +53 -0
- package/src/select/Select.ts +182 -112
- package/src/select/UserSelect.ts +71 -0
- package/src/store/Store.ts +70 -21
- package/src/tabpane/TabPane.ts +79 -113
- package/src/textinput/TextInput.ts +1 -0
- package/src/user/TembaUser.ts +30 -41
- package/src/utils/index.ts +12 -8
- package/temba-modules.ts +4 -2
- package/test/temba-omnibox.test.ts +56 -4
- package/test/temba-select.test.ts +170 -56
- package/test/utils.test.ts +5 -0
- package/test-assets/select/omnibox.json +55 -0
- package/web-test-runner.config.mjs +16 -4
- package/out-tsc/src/contacts/ContactTickets.js +0 -462
- package/out-tsc/src/contacts/ContactTickets.js.map +0 -1
- package/out-tsc/test/temba-contact-tickets.test.js +0 -36
- package/out-tsc/test/temba-contact-tickets.test.js.map +0 -1
- package/src/contacts/ContactTickets.ts +0 -490
- package/test/temba-contact-tickets.test.ts +0 -52
package/src/store/Store.ts
CHANGED
|
@@ -28,6 +28,7 @@ import { css, html } from 'lit';
|
|
|
28
28
|
import { configureLocalization } from '@lit/localize';
|
|
29
29
|
import { sourceLocale, targetLocales } from '../locales/locale-codes';
|
|
30
30
|
import { StoreMonitorElement } from './StoreMonitorElement';
|
|
31
|
+
import { getFullName } from '../user/TembaUser';
|
|
31
32
|
|
|
32
33
|
const { setLocale } = configureLocalization({
|
|
33
34
|
sourceLocale,
|
|
@@ -83,9 +84,6 @@ export class Store extends RapidElement {
|
|
|
83
84
|
@property({ type: String, attribute: 'workspace' })
|
|
84
85
|
workspaceEndpoint: string;
|
|
85
86
|
|
|
86
|
-
@property({ type: String, attribute: 'users' })
|
|
87
|
-
usersEndpoint: string;
|
|
88
|
-
|
|
89
87
|
@property({ type: String, attribute: 'shortcuts' })
|
|
90
88
|
shortcutsEndpoint: string;
|
|
91
89
|
|
|
@@ -226,14 +224,6 @@ export class Store extends RapidElement {
|
|
|
226
224
|
);
|
|
227
225
|
}
|
|
228
226
|
|
|
229
|
-
if (this.usersEndpoint) {
|
|
230
|
-
fetches.push(
|
|
231
|
-
getAssets(this.usersEndpoint).then((users: any[]) => {
|
|
232
|
-
this.users = users;
|
|
233
|
-
})
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
227
|
if (this.shortcutsEndpoint) {
|
|
238
228
|
fetches.push(this.refreshShortcuts());
|
|
239
229
|
}
|
|
@@ -249,12 +239,6 @@ export class Store extends RapidElement {
|
|
|
249
239
|
return this.shortcuts || [];
|
|
250
240
|
}
|
|
251
241
|
|
|
252
|
-
public getAssignableUsers() {
|
|
253
|
-
return this.users.filter((user: User) =>
|
|
254
|
-
['administrator', 'editor', 'agent'].includes(user.role)
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
242
|
public firstUpdated() {
|
|
259
243
|
this.reset();
|
|
260
244
|
}
|
|
@@ -397,7 +381,7 @@ export class Store extends RapidElement {
|
|
|
397
381
|
// we treat missing groups as dynamic since the
|
|
398
382
|
// api excludes initializing groups
|
|
399
383
|
if (!group) {
|
|
400
|
-
console.warn('No group for ' + uuid);
|
|
384
|
+
// console.warn('No group for ' + uuid);
|
|
401
385
|
}
|
|
402
386
|
|
|
403
387
|
if (!group || group.query) {
|
|
@@ -510,6 +494,71 @@ export class Store extends RapidElement {
|
|
|
510
494
|
this.cache.delete(url);
|
|
511
495
|
}
|
|
512
496
|
|
|
497
|
+
public resolveUsers(items: any, keys: string[]): Promise<void> {
|
|
498
|
+
return new Promise<void>((resolve) => {
|
|
499
|
+
const emails = new Set<string>();
|
|
500
|
+
|
|
501
|
+
// keys are dot notation paths to user fields
|
|
502
|
+
items.forEach((item) => {
|
|
503
|
+
keys.forEach((key) => {
|
|
504
|
+
const parts = key.split('.');
|
|
505
|
+
let value = item;
|
|
506
|
+
for (let i = 0; i < parts.length; i++) {
|
|
507
|
+
value = value[parts[i]];
|
|
508
|
+
if (!value) {
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (value && value.email) {
|
|
513
|
+
emails.add(value.email);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
const promises = [];
|
|
519
|
+
// we don't want to fetch all users at once so we can benefit from caching
|
|
520
|
+
emails.forEach((email) => {
|
|
521
|
+
promises.push(this.getUrl(`/api/v2/users.json?email=${email}`));
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// wait for all of our user fetches to complete
|
|
525
|
+
Promise.all(promises).then((promises) => {
|
|
526
|
+
promises.forEach((response: WebResponse) => {
|
|
527
|
+
if (response && response.json) {
|
|
528
|
+
const results = response.json.results;
|
|
529
|
+
if (results && results.length === 1) {
|
|
530
|
+
const user = results[0];
|
|
531
|
+
|
|
532
|
+
items.forEach((item) => {
|
|
533
|
+
// replace each key with a matching user
|
|
534
|
+
keys.forEach((key) => {
|
|
535
|
+
const parts = key.split('.');
|
|
536
|
+
let value = item;
|
|
537
|
+
let last = value;
|
|
538
|
+
for (let i = 0; i < parts.length; i++) {
|
|
539
|
+
last = value;
|
|
540
|
+
value = value[parts[i]];
|
|
541
|
+
if (!value) {
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
if (value && value.email === user.email) {
|
|
546
|
+
// only care about avatars for now
|
|
547
|
+
const orginalUser = last[parts[parts.length - 1]];
|
|
548
|
+
orginalUser.avatar = user.avatar;
|
|
549
|
+
orginalUser.name = getFullName(user);
|
|
550
|
+
last[parts[parts.length - 1]].avatar = user.avatar;
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
resolve();
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
|
|
513
562
|
public makeRequest(
|
|
514
563
|
url: string,
|
|
515
564
|
options?: { force?: boolean; prepareData?: (data: any) => any }
|
|
@@ -524,8 +573,9 @@ export class Store extends RapidElement {
|
|
|
524
573
|
return;
|
|
525
574
|
}
|
|
526
575
|
|
|
527
|
-
|
|
576
|
+
let cached = this.cache.get(url);
|
|
528
577
|
if (cached && !options.force) {
|
|
578
|
+
cached = options.prepareData ? options.prepareData(cached) : cached;
|
|
529
579
|
this.fireCustomEvent(CustomEventType.StoreUpdated, { url, data: cached });
|
|
530
580
|
} else {
|
|
531
581
|
options = options || {};
|
|
@@ -535,10 +585,9 @@ export class Store extends RapidElement {
|
|
|
535
585
|
delete this.fetching[url];
|
|
536
586
|
return;
|
|
537
587
|
}
|
|
538
|
-
|
|
539
|
-
data = options.prepareData ? options.prepareData(data) : data;
|
|
540
588
|
this.cache.set(url, data);
|
|
541
589
|
delete this.fetching[url];
|
|
590
|
+
data = options.prepareData ? options.prepareData(data) : data;
|
|
542
591
|
this.fireCustomEvent(CustomEventType.StoreUpdated, { url, data });
|
|
543
592
|
});
|
|
544
593
|
}
|
package/src/tabpane/TabPane.ts
CHANGED
|
@@ -15,12 +15,14 @@ export class TabPane extends RapidElement {
|
|
|
15
15
|
flex-grow: 1;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
.
|
|
18
|
+
.options {
|
|
19
19
|
display: flex;
|
|
20
20
|
align-items: stretch;
|
|
21
|
+
padding: var(--temba-tabs-options-padding, 0);
|
|
22
|
+
border-bottom: none;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
.
|
|
25
|
+
.option {
|
|
24
26
|
user-select: none;
|
|
25
27
|
padding: 0.5em 0.7em;
|
|
26
28
|
margin: 0em 0em;
|
|
@@ -40,22 +42,22 @@ export class TabPane extends RapidElement {
|
|
|
40
42
|
transition: all 100ms linear;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
.focusedname .
|
|
45
|
+
.focusedname .option .name {
|
|
44
46
|
transition: all 0s linear !important;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
.focusedname .
|
|
49
|
+
.focusedname .option.selected .name {
|
|
48
50
|
transition: all 200ms linear !important;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
.
|
|
53
|
+
.option.hidden {
|
|
52
54
|
display: none;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
.
|
|
57
|
+
.option temba-icon {
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
.
|
|
60
|
+
.option .name {
|
|
59
61
|
margin-left: 0.4em;
|
|
60
62
|
max-width: 200px;
|
|
61
63
|
overflow: hidden;
|
|
@@ -64,48 +66,48 @@ export class TabPane extends RapidElement {
|
|
|
64
66
|
text-overflow: ellipsis;
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
.
|
|
69
|
+
.option .badge {
|
|
68
70
|
margin-left: 0.4em;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
@media (max-width: 900px) {
|
|
72
|
-
.collapses .
|
|
74
|
+
.collapses .option .name {
|
|
73
75
|
max-width: 0px;
|
|
74
76
|
margin: 0;
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
@media (max-width: 600px) {
|
|
79
|
-
.collapses .
|
|
81
|
+
.collapses .option .badge {
|
|
80
82
|
display: none;
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
.focusedname .
|
|
86
|
+
.focusedname .option.selected {
|
|
85
87
|
}
|
|
86
88
|
|
|
87
|
-
.focusedname .
|
|
89
|
+
.focusedname .option .name {
|
|
88
90
|
max-width: 0px;
|
|
89
91
|
margin: 0;
|
|
90
92
|
transition: max-width 200ms linear, margin 200ms linear;
|
|
91
93
|
}
|
|
92
94
|
|
|
93
|
-
.focusedname .
|
|
95
|
+
.focusedname .option.selected .name {
|
|
94
96
|
margin-left: 0.4em;
|
|
95
97
|
max-width: 200px;
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
.
|
|
100
|
+
.option {
|
|
99
101
|
transform: scale(0.9) translateY(0em);
|
|
100
102
|
--icon-color: rgba(0, 0, 0, 0.5);
|
|
101
103
|
color: rgba(0, 0, 0, 0.5);
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
.
|
|
106
|
+
.option.selected {
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
.
|
|
108
|
-
.
|
|
109
|
+
.option.selected,
|
|
110
|
+
.option.selected:hover {
|
|
109
111
|
cursor: default;
|
|
110
112
|
box-shadow: 0px -3px 3px 1px rgba(0, 0, 0, 0.02);
|
|
111
113
|
|
|
@@ -117,31 +119,25 @@ export class TabPane extends RapidElement {
|
|
|
117
119
|
border-bottom: 0px;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
|
-
.
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.tab.selected .dot {
|
|
122
|
+
.option.selected .dot {
|
|
124
123
|
display: none;
|
|
125
124
|
}
|
|
126
125
|
|
|
127
|
-
.
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.unselect .tab.selected {
|
|
126
|
+
.unselect .option.selected {
|
|
131
127
|
cursor: pointer;
|
|
132
128
|
}
|
|
133
129
|
|
|
134
|
-
.unselect .
|
|
130
|
+
.unselect .option.selected:hover {
|
|
135
131
|
background: var(--unselect-tab-color, #eee);
|
|
136
132
|
}
|
|
137
133
|
|
|
138
|
-
.
|
|
134
|
+
.option:hover {
|
|
139
135
|
--icon-color: #666;
|
|
140
136
|
color: #666;
|
|
141
137
|
background: rgba(0, 0, 0, 0.02);
|
|
142
138
|
}
|
|
143
139
|
|
|
144
|
-
.
|
|
140
|
+
.option.dirty {
|
|
145
141
|
font-weight: 500;
|
|
146
142
|
}
|
|
147
143
|
|
|
@@ -167,9 +163,6 @@ export class TabPane extends RapidElement {
|
|
|
167
163
|
overflow: hidden;
|
|
168
164
|
}
|
|
169
165
|
|
|
170
|
-
.badge {
|
|
171
|
-
}
|
|
172
|
-
|
|
173
166
|
.count {
|
|
174
167
|
border-radius: 99px;
|
|
175
168
|
background: rgba(0, 0, 0, 0.1);
|
|
@@ -198,22 +191,6 @@ export class TabPane extends RapidElement {
|
|
|
198
191
|
--icon-color: var(--color-alert);
|
|
199
192
|
}
|
|
200
193
|
|
|
201
|
-
.bottom.tabs .tab {
|
|
202
|
-
border-radius: 0em;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.bottom.pane {
|
|
206
|
-
border-radius: 0em;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.bottom.pane.first {
|
|
210
|
-
border-bottom-left-radius: 0px;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.bottom .tab.first {
|
|
214
|
-
border-bottom-left-radius: var(--curvature);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
194
|
.embedded.pane {
|
|
218
195
|
box-shadow: none;
|
|
219
196
|
margin: 0;
|
|
@@ -222,30 +199,22 @@ export class TabPane extends RapidElement {
|
|
|
222
199
|
border-bottom: none !important;
|
|
223
200
|
}
|
|
224
201
|
|
|
225
|
-
.embedded.
|
|
226
|
-
padding-top: 0em;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.embedded .tab {
|
|
202
|
+
.embedded .option {
|
|
230
203
|
border-bottom: none !important;
|
|
231
204
|
border-radius: 0em;
|
|
232
205
|
border-top: none !important;
|
|
233
206
|
}
|
|
234
207
|
|
|
235
|
-
.embedded .
|
|
208
|
+
.embedded .option.first {
|
|
236
209
|
margin-left: 0em;
|
|
237
210
|
border-top: none !important;
|
|
238
211
|
border-left: none;
|
|
239
212
|
}
|
|
240
213
|
|
|
241
|
-
.embedded.
|
|
214
|
+
.embedded.options .option.selected {
|
|
242
215
|
box-shadow: none !important;
|
|
243
216
|
}
|
|
244
217
|
|
|
245
|
-
.embedded.pane {
|
|
246
|
-
// padding: 0.3em;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
218
|
.check {
|
|
250
219
|
margin-left: 0.4em;
|
|
251
220
|
}
|
|
@@ -262,10 +231,6 @@ export class TabPane extends RapidElement {
|
|
|
262
231
|
@property({ type: Boolean })
|
|
263
232
|
collapses = false;
|
|
264
233
|
|
|
265
|
-
// are the tabs on the bottom of the pane?
|
|
266
|
-
@property({ type: Boolean })
|
|
267
|
-
bottom = false;
|
|
268
|
-
|
|
269
234
|
// do we allow unselecting the current tab
|
|
270
235
|
@property({ type: Boolean })
|
|
271
236
|
unselect = false;
|
|
@@ -281,7 +246,7 @@ export class TabPane extends RapidElement {
|
|
|
281
246
|
refresh = '';
|
|
282
247
|
|
|
283
248
|
@property({ type: Array, attribute: false })
|
|
284
|
-
|
|
249
|
+
options: Tab[] = [];
|
|
285
250
|
|
|
286
251
|
private handleTabClick(event: MouseEvent): void {
|
|
287
252
|
const newIndex = parseInt(
|
|
@@ -307,7 +272,7 @@ export class TabPane extends RapidElement {
|
|
|
307
272
|
tabs.push(tab);
|
|
308
273
|
}
|
|
309
274
|
}
|
|
310
|
-
this.
|
|
275
|
+
this.options = tabs;
|
|
311
276
|
this.index = 0;
|
|
312
277
|
}
|
|
313
278
|
|
|
@@ -324,16 +289,16 @@ export class TabPane extends RapidElement {
|
|
|
324
289
|
public updated(changedProperties: Map<string, any>) {
|
|
325
290
|
super.updated(changedProperties);
|
|
326
291
|
|
|
327
|
-
if (changedProperties.has('
|
|
328
|
-
this.
|
|
292
|
+
if (changedProperties.has('options')) {
|
|
293
|
+
this.options.forEach((tab, index) => {
|
|
329
294
|
tab.selected = index == this.index;
|
|
330
295
|
});
|
|
331
296
|
}
|
|
332
297
|
|
|
333
298
|
if (changedProperties.has('index')) {
|
|
334
|
-
if (this.
|
|
299
|
+
if (this.options.length >= 0) {
|
|
335
300
|
if (this.index !== changedProperties.get('index')) {
|
|
336
|
-
this.
|
|
301
|
+
this.options.forEach((tab, index) => {
|
|
337
302
|
tab.selected = index == this.index;
|
|
338
303
|
});
|
|
339
304
|
this.fireEvent(CustomEventType.ContextChanged);
|
|
@@ -342,11 +307,11 @@ export class TabPane extends RapidElement {
|
|
|
342
307
|
}
|
|
343
308
|
|
|
344
309
|
// if our current tab is hidden, select the first visible one
|
|
345
|
-
if (this.index > this.
|
|
346
|
-
const tab = this.
|
|
310
|
+
if (this.index > this.options.length) {
|
|
311
|
+
const tab = this.options[this.index];
|
|
347
312
|
if (tab && tab.hidden) {
|
|
348
|
-
for (let i = 0; i < this.
|
|
349
|
-
const other = this.
|
|
313
|
+
for (let i = 0; i < this.options.length; i++) {
|
|
314
|
+
const other = this.options[i];
|
|
350
315
|
if (other && !other.hidden) {
|
|
351
316
|
this.index = i;
|
|
352
317
|
return;
|
|
@@ -357,7 +322,7 @@ export class TabPane extends RapidElement {
|
|
|
357
322
|
}
|
|
358
323
|
|
|
359
324
|
public focusTab(name: string): Tab {
|
|
360
|
-
const index = this.
|
|
325
|
+
const index = this.options.findIndex((tab) => tab.name === name);
|
|
361
326
|
if (index >= 0) {
|
|
362
327
|
this.index = index;
|
|
363
328
|
return this.getTab(index);
|
|
@@ -368,8 +333,8 @@ export class TabPane extends RapidElement {
|
|
|
368
333
|
index: number,
|
|
369
334
|
details: { count: number; hidden: boolean }
|
|
370
335
|
) {
|
|
371
|
-
if (index < this.
|
|
372
|
-
const tab = this.
|
|
336
|
+
if (index < this.options.length) {
|
|
337
|
+
const tab = this.options[index];
|
|
373
338
|
tab.count = details.count;
|
|
374
339
|
tab.hidden = details.hidden;
|
|
375
340
|
this.requestUpdate();
|
|
@@ -382,11 +347,11 @@ export class TabPane extends RapidElement {
|
|
|
382
347
|
}
|
|
383
348
|
|
|
384
349
|
public getCurrentTab(): Tab {
|
|
385
|
-
return this.
|
|
350
|
+
return this.options[this.index];
|
|
386
351
|
}
|
|
387
352
|
|
|
388
353
|
public getTab(index: number): Tab {
|
|
389
|
-
return this.
|
|
354
|
+
return this.options[index];
|
|
390
355
|
}
|
|
391
356
|
|
|
392
357
|
public handleTabContentChanged() {
|
|
@@ -398,37 +363,24 @@ export class TabPane extends RapidElement {
|
|
|
398
363
|
}
|
|
399
364
|
|
|
400
365
|
public render(): TemplateResult {
|
|
401
|
-
const activeTab = this.
|
|
366
|
+
const activeTab = this.options[this.index];
|
|
402
367
|
return html`
|
|
403
|
-
${this.bottom
|
|
404
|
-
? html`<div
|
|
405
|
-
class="pane ${getClasses({
|
|
406
|
-
first: this.index == 0,
|
|
407
|
-
embedded: this.embedded,
|
|
408
|
-
bottom: this.bottom
|
|
409
|
-
})}"
|
|
410
|
-
>
|
|
411
|
-
<slot></slot>
|
|
412
|
-
</div>`
|
|
413
|
-
: null}
|
|
414
|
-
|
|
415
368
|
<div
|
|
416
|
-
class="
|
|
417
|
-
|
|
418
|
-
bottom: this.bottom,
|
|
369
|
+
class="${getClasses({
|
|
370
|
+
options: true,
|
|
419
371
|
collapses: this.collapses,
|
|
420
372
|
embedded: this.embedded,
|
|
421
373
|
focusedname: this.focusedName,
|
|
422
374
|
unselect: this.unselect
|
|
423
375
|
})}"
|
|
424
376
|
>
|
|
425
|
-
${this.
|
|
377
|
+
${this.options.map(
|
|
426
378
|
(tab, index) => html`
|
|
427
379
|
<div
|
|
428
380
|
@click=${this.handleTabClick}
|
|
429
381
|
data-index=${index}
|
|
430
382
|
class="${getClasses({
|
|
431
|
-
|
|
383
|
+
option: true,
|
|
432
384
|
first: index == 0,
|
|
433
385
|
selected: index == this.index,
|
|
434
386
|
hidden: tab.hidden,
|
|
@@ -473,24 +425,38 @@ export class TabPane extends RapidElement {
|
|
|
473
425
|
<slot name="tab-right"></slot>
|
|
474
426
|
</div>
|
|
475
427
|
</div>
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
428
|
+
<div
|
|
429
|
+
@temba-details-changed=${this.handleTabDetailsChanged}
|
|
430
|
+
style="${activeTab?.borderColor
|
|
431
|
+
? `
|
|
432
|
+
border-top: var(--temba-tabs-border-top, 1px solid ${
|
|
433
|
+
activeTab?.borderColor || 'var(--color-widget-border)'
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
border-left: var(--temba-tabs-border-left, 1px solid ${
|
|
437
|
+
activeTab?.borderColor || 'var(--color-widget-border)'
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
border-bottom: var(--temba-tabs-border-bottom, 1px solid ${
|
|
441
|
+
activeTab?.borderColor || 'var(--color-widget-border)'
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
border-right: var(--temba-tabs-border-right, 1px solid ${
|
|
445
|
+
activeTab?.borderColor || 'var(--color-widget-border)'
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
`
|
|
449
|
+
: ''} ${activeTab?.selectionBackground
|
|
450
|
+
? `background:${activeTab?.selectionBackground};`
|
|
451
|
+
: ``}"
|
|
452
|
+
class="pane ${getClasses({
|
|
453
|
+
first: this.index == 0,
|
|
454
|
+
embedded: this.embedded
|
|
455
|
+
})}"
|
|
456
|
+
>
|
|
457
|
+
<slot></slot>
|
|
458
|
+
<slot name="pane-bottom"></slot>
|
|
459
|
+
</div>
|
|
494
460
|
`;
|
|
495
461
|
}
|
|
496
462
|
}
|
package/src/user/TembaUser.ts
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { PropertyValueMap, TemplateResult, css, html } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { colorHash, extractInitials } from '../utils';
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import { DEFAULT_AVATAR } from '../webchat/assets';
|
|
7
|
+
import { RapidElement } from '../RapidElement';
|
|
7
8
|
|
|
8
|
-
export
|
|
9
|
+
export const getFullName = (user: {
|
|
10
|
+
name?: string;
|
|
11
|
+
first_name?: string;
|
|
12
|
+
last_name?: string;
|
|
13
|
+
}) => {
|
|
14
|
+
return user.name || [user.first_name, user.last_name].join(' ');
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class TembaUser extends RapidElement {
|
|
9
18
|
public static styles = css`
|
|
10
19
|
:host {
|
|
11
20
|
display: flex;
|
|
21
|
+
transform: scale(var(--temba-scale, 1));
|
|
22
|
+
box-sizing: border-box;
|
|
12
23
|
}
|
|
13
24
|
|
|
14
25
|
.wrapper {
|
|
@@ -27,14 +38,11 @@ export class TembaUser extends EndpointMonitorElement {
|
|
|
27
38
|
}
|
|
28
39
|
`;
|
|
29
40
|
|
|
30
|
-
@property({ type: String })
|
|
31
|
-
email: string;
|
|
32
|
-
|
|
33
41
|
@property({ type: Number })
|
|
34
42
|
scale: number;
|
|
35
43
|
|
|
36
44
|
@property({ type: Boolean })
|
|
37
|
-
|
|
45
|
+
showName: boolean;
|
|
38
46
|
|
|
39
47
|
@property({ type: Boolean })
|
|
40
48
|
system: boolean;
|
|
@@ -46,49 +54,30 @@ export class TembaUser extends EndpointMonitorElement {
|
|
|
46
54
|
initials: string = '';
|
|
47
55
|
|
|
48
56
|
@property({ type: String })
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@property({ type: Object, attribute: false })
|
|
52
|
-
data: User;
|
|
57
|
+
name: string;
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return data[0];
|
|
57
|
-
}
|
|
59
|
+
@property({ type: String })
|
|
60
|
+
email: string;
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
+
@property({ type: String })
|
|
63
|
+
avatar: string;
|
|
62
64
|
|
|
63
65
|
public updated(
|
|
64
66
|
changed: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
|
65
67
|
): void {
|
|
66
68
|
super.updated(changed);
|
|
67
69
|
|
|
68
|
-
if (changed.has('email') && this.email) {
|
|
69
|
-
this.url = `/api/v2/users.json?email=${this.email}`;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
70
|
if (changed.has('system') && this.system) {
|
|
73
71
|
this.background = `url('${DEFAULT_AVATAR}') center / contain no-repeat`;
|
|
74
72
|
}
|
|
75
73
|
|
|
76
|
-
if (changed.has('
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
this.background = colorHash.hex(this.fullname);
|
|
80
|
-
this.initials = extractInitials(this.fullname);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (this.data.avatar) {
|
|
84
|
-
this.background = `url('${this.data.avatar}') center / contain no-repeat`;
|
|
85
|
-
this.initials = '';
|
|
86
|
-
}
|
|
74
|
+
if (changed.has('name') && this.name) {
|
|
75
|
+
this.background = colorHash.hex(this.name);
|
|
76
|
+
this.initials = extractInitials(this.name);
|
|
87
77
|
}
|
|
88
78
|
|
|
89
|
-
if (changed.has('
|
|
90
|
-
this.background =
|
|
91
|
-
this.initials = extractInitials(this.fullname);
|
|
79
|
+
if (changed.has('avatar') && this.avatar) {
|
|
80
|
+
this.background = `url('${this.avatar}') center / contain no-repeat`;
|
|
92
81
|
}
|
|
93
82
|
}
|
|
94
83
|
|
|
@@ -99,8 +88,8 @@ export class TembaUser extends EndpointMonitorElement {
|
|
|
99
88
|
style="
|
|
100
89
|
transform:scale(${this.scale || 1});
|
|
101
90
|
display: flex;
|
|
102
|
-
height:
|
|
103
|
-
width:
|
|
91
|
+
min-height: 26px;
|
|
92
|
+
min-width: 26px;
|
|
104
93
|
flex-direction: row;
|
|
105
94
|
align-items: center;
|
|
106
95
|
color: #fff;
|
|
@@ -111,7 +100,7 @@ export class TembaUser extends EndpointMonitorElement {
|
|
|
111
100
|
box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.1);
|
|
112
101
|
background:${this.background}"
|
|
113
102
|
>
|
|
114
|
-
${this.initials
|
|
103
|
+
${this.initials && !this.avatar
|
|
115
104
|
? html` <div
|
|
116
105
|
style="border: 0px solid red; display:flex; flex-direction: column; align-items:center;flex-grow:1"
|
|
117
106
|
>
|
|
@@ -119,13 +108,13 @@ export class TembaUser extends EndpointMonitorElement {
|
|
|
119
108
|
</div>`
|
|
120
109
|
: null}
|
|
121
110
|
</div>
|
|
122
|
-
${this.
|
|
111
|
+
${this.showName
|
|
123
112
|
? html`<div
|
|
124
113
|
class="name"
|
|
125
114
|
style="margin: 0px ${this.scale - 0.5}em;font-size:${this.scale +
|
|
126
115
|
0.2}em"
|
|
127
116
|
>
|
|
128
|
-
${this.
|
|
117
|
+
${this.name}
|
|
129
118
|
</div>`
|
|
130
119
|
: null}
|
|
131
120
|
</div>`;
|