@nyaruka/temba-components 0.114.1 → 0.117.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 +14 -0
- package/dist/temba-components.js +329 -311
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/button/Button.js +5 -0
- package/out-tsc/src/button/Button.js.map +1 -1
- package/out-tsc/src/chat/Chat.js +5 -1
- package/out-tsc/src/chat/Chat.js.map +1 -1
- package/out-tsc/src/contacts/ContactChat.js +27 -16
- package/out-tsc/src/contacts/ContactChat.js.map +1 -1
- package/out-tsc/src/dropdown/Dropdown.js +1 -1
- package/out-tsc/src/dropdown/Dropdown.js.map +1 -1
- package/out-tsc/src/list/TembaList.js +3 -2
- package/out-tsc/src/list/TembaList.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +17 -5
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/options/Options.js +17 -17
- package/out-tsc/src/options/Options.js.map +1 -1
- package/out-tsc/src/select/Select.js +6 -2
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/select/UserSelect.js +0 -1
- package/out-tsc/src/select/UserSelect.js.map +1 -1
- package/out-tsc/src/select/WorkspaceSelect.js +65 -0
- package/out-tsc/src/select/WorkspaceSelect.js.map +1 -0
- package/out-tsc/src/store/Store.js +3 -1
- package/out-tsc/src/store/Store.js.map +1 -1
- package/out-tsc/src/user/TembaUser.js +27 -11
- package/out-tsc/src/user/TembaUser.js.map +1 -1
- package/out-tsc/temba-modules.js +2 -0
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-contact-chat.test.js +1 -0
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/package.json +1 -1
- 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/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/src/button/Button.ts +5 -0
- package/src/chat/Chat.ts +5 -1
- package/src/contacts/ContactChat.ts +30 -20
- package/src/dropdown/Dropdown.ts +1 -1
- package/src/list/TembaList.ts +3 -6
- package/src/list/TembaMenu.ts +20 -5
- package/src/options/Options.ts +18 -18
- package/src/select/Select.ts +5 -2
- package/src/select/UserSelect.ts +0 -1
- package/src/select/WorkspaceSelect.ts +71 -0
- package/src/store/Store.ts +3 -1
- package/src/user/TembaUser.ts +23 -10
- package/temba-modules.ts +2 -0
- package/test/temba-contact-chat.test.ts +5 -0
package/src/list/TembaMenu.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { Dropdown } from '../dropdown/Dropdown';
|
|
|
8
8
|
import { NotificationList } from './NotificationList';
|
|
9
9
|
import { ResizeElement } from '../ResizeElement';
|
|
10
10
|
import { Store } from '../store/Store';
|
|
11
|
+
|
|
11
12
|
export interface MenuItem {
|
|
12
13
|
id?: string;
|
|
13
14
|
vanity_id?: string;
|
|
@@ -32,6 +33,7 @@ export interface MenuItem {
|
|
|
32
33
|
trigger?: boolean;
|
|
33
34
|
event?: string;
|
|
34
35
|
mobile?: boolean;
|
|
36
|
+
initial?: string;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
interface MenuItemState {
|
|
@@ -587,11 +589,6 @@ export class TembaMenu extends ResizeElement {
|
|
|
587
589
|
margin-right: 0.75em;
|
|
588
590
|
}
|
|
589
591
|
|
|
590
|
-
temba-button[lined] {
|
|
591
|
-
margin: 0.2em 0;
|
|
592
|
-
display: block;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
592
|
.expand-icon {
|
|
596
593
|
transform: rotate(180deg);
|
|
597
594
|
--icon-color: rgba(255, 255, 255, 0.5);
|
|
@@ -653,6 +650,14 @@ export class TembaMenu extends ResizeElement {
|
|
|
653
650
|
.level-0 .icon-wrapper {
|
|
654
651
|
padding: 0.4em 0.9em;
|
|
655
652
|
}
|
|
653
|
+
|
|
654
|
+
temba-workspace-select {
|
|
655
|
+
margin: 0.2em;
|
|
656
|
+
display: block;
|
|
657
|
+
--options-shadow: none;
|
|
658
|
+
--color-widget-border: transparent;
|
|
659
|
+
--widget-box-shadow: none;
|
|
660
|
+
}
|
|
656
661
|
`;
|
|
657
662
|
}
|
|
658
663
|
|
|
@@ -1062,6 +1067,16 @@ export class TembaMenu extends ResizeElement {
|
|
|
1062
1067
|
return html`<div class="divider"></div>`;
|
|
1063
1068
|
}
|
|
1064
1069
|
|
|
1070
|
+
if (menuItem.type === 'temba-workspace-select') {
|
|
1071
|
+
return html`<temba-workspace-select
|
|
1072
|
+
@change=${(event) => {
|
|
1073
|
+
event.stopPropagation();
|
|
1074
|
+
event.preventDefault();
|
|
1075
|
+
}}
|
|
1076
|
+
.values=${[JSON.parse(menuItem.initial)]}
|
|
1077
|
+
></temba-workspace-select>`;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1065
1080
|
if (menuItem.type === 'temba-notification-list') {
|
|
1066
1081
|
return html`<temba-notification-list
|
|
1067
1082
|
endpoint=${menuItem.href}
|
package/src/options/Options.ts
CHANGED
|
@@ -17,16 +17,14 @@ export class Options extends RapidElement {
|
|
|
17
17
|
user-select: none;
|
|
18
18
|
border-radius: var(--curvature-widget);
|
|
19
19
|
overflow: hidden;
|
|
20
|
-
margin-top: var(--options-margin-top);
|
|
21
20
|
display: flex;
|
|
22
21
|
flex-direction: column;
|
|
23
|
-
// transform: scaleY(0.5) translateY(-5em);
|
|
24
22
|
transition: transform var(--transition-speed)
|
|
25
23
|
cubic-bezier(0.71, 0.18, 0.61, 1.33),
|
|
26
24
|
opacity var(--transition-speed) cubic-bezier(0.71, 0.18, 0.61, 1.33);
|
|
27
25
|
opacity: 0;
|
|
28
|
-
border: 1px transparent;
|
|
29
26
|
z-index: 1000;
|
|
27
|
+
pointer-events: none;
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
.shadow {
|
|
@@ -97,10 +95,11 @@ export class Options extends RapidElement {
|
|
|
97
95
|
}
|
|
98
96
|
|
|
99
97
|
.show {
|
|
100
|
-
// transform: scaleY(1) translateY(0);
|
|
101
98
|
border: 1px solid var(--color-widget-border);
|
|
102
99
|
opacity: 1;
|
|
103
100
|
z-index: 1;
|
|
101
|
+
pointer-events: auto;
|
|
102
|
+
margin-top: var(--options-margin-top);
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
.option {
|
|
@@ -351,7 +350,7 @@ export class Options extends RapidElement {
|
|
|
351
350
|
this.tempOptions = changed.get('options');
|
|
352
351
|
window.setTimeout(() => {
|
|
353
352
|
this.tempOptions = [];
|
|
354
|
-
},
|
|
353
|
+
}, 200);
|
|
355
354
|
}
|
|
356
355
|
}
|
|
357
356
|
|
|
@@ -372,7 +371,7 @@ export class Options extends RapidElement {
|
|
|
372
371
|
(previousCount === 0 && newCount > 0 && !changed.has('cursorIndex'))
|
|
373
372
|
) {
|
|
374
373
|
if (!this.internalFocusDisabled) {
|
|
375
|
-
if (!this.block
|
|
374
|
+
if (!this.block) {
|
|
376
375
|
this.cursorIndex = 0;
|
|
377
376
|
} else {
|
|
378
377
|
if (this.cursorIndex >= newCount) {
|
|
@@ -444,6 +443,10 @@ export class Options extends RapidElement {
|
|
|
444
443
|
}
|
|
445
444
|
}
|
|
446
445
|
|
|
446
|
+
if (index === -1) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
|
|
447
450
|
const selected = this.options[index];
|
|
448
451
|
this.fireCustomEvent(CustomEventType.Selection, {
|
|
449
452
|
selected,
|
|
@@ -564,17 +567,12 @@ export class Options extends RapidElement {
|
|
|
564
567
|
.getBoundingClientRect();
|
|
565
568
|
|
|
566
569
|
if (this.anchorTo) {
|
|
567
|
-
this.top = 0;
|
|
568
570
|
const anchorBounds = this.anchorTo.getBoundingClientRect();
|
|
571
|
+
this.top = anchorBounds.bottom;
|
|
569
572
|
if (anchorBounds.bottom + optionsBounds.height > window.innerHeight) {
|
|
570
573
|
this.top = -(optionsBounds.height + anchorBounds.height + 20);
|
|
571
574
|
}
|
|
572
575
|
this.left = anchorBounds.left;
|
|
573
|
-
|
|
574
|
-
// adjust for parent scrolling
|
|
575
|
-
if (this.scrollParent) {
|
|
576
|
-
this.top += -this.scrollParent.scrollTop;
|
|
577
|
-
}
|
|
578
576
|
}
|
|
579
577
|
}
|
|
580
578
|
}
|
|
@@ -627,13 +625,15 @@ export class Options extends RapidElement {
|
|
|
627
625
|
vertical *= -1;
|
|
628
626
|
}
|
|
629
627
|
|
|
630
|
-
const containerStyle =
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
628
|
+
const containerStyle = this.visible
|
|
629
|
+
? {
|
|
630
|
+
'margin-left': `${this.marginHorizontal}px`,
|
|
631
|
+
'margin-top': `${vertical}px`
|
|
632
|
+
}
|
|
633
|
+
: {};
|
|
634
634
|
|
|
635
635
|
if (this.top) {
|
|
636
|
-
containerStyle[
|
|
636
|
+
containerStyle['top'] = `${this.top}px`;
|
|
637
637
|
}
|
|
638
638
|
|
|
639
639
|
if (this.left) {
|
|
@@ -649,7 +649,7 @@ export class Options extends RapidElement {
|
|
|
649
649
|
'options-container': true,
|
|
650
650
|
show: this.visible,
|
|
651
651
|
top: this.poppedTop,
|
|
652
|
-
anchored: !this.block,
|
|
652
|
+
anchored: !this.block && !!this.anchorTo,
|
|
653
653
|
loading: this.loading,
|
|
654
654
|
shadow: !this.hideShadow,
|
|
655
655
|
bordered: this.hideShadow
|
package/src/select/Select.ts
CHANGED
|
@@ -499,6 +499,9 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
499
499
|
@property({ type: Array, attribute: 'options' })
|
|
500
500
|
private staticOptions: any[] = [];
|
|
501
501
|
|
|
502
|
+
@property({ type: Boolean })
|
|
503
|
+
allowAnchor: boolean = true;
|
|
504
|
+
|
|
502
505
|
private alphaSort = (a: any, b: any) => {
|
|
503
506
|
// by default, all endpoint values are sorted by name
|
|
504
507
|
if (this.endpoint) {
|
|
@@ -1510,7 +1513,7 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1510
1513
|
.renderOptionDetail=${this.renderOptionDetail}
|
|
1511
1514
|
.renderOptionName=${this.renderOptionName}
|
|
1512
1515
|
.renderOption=${this.renderOption || this.renderOptionDefault}
|
|
1513
|
-
.anchorTo=${this.anchorElement}
|
|
1516
|
+
.anchorTo=${this.allowAnchor ? this.anchorElement : null}
|
|
1514
1517
|
.options=${this.visibleOptions}
|
|
1515
1518
|
.spaceSelect=${this.spaceSelect}
|
|
1516
1519
|
.nameKey=${this.nameKey}
|
|
@@ -1523,7 +1526,7 @@ export class Select<T extends SelectOption> extends FormElement {
|
|
|
1523
1526
|
<temba-options
|
|
1524
1527
|
@temba-selection=${this.handleExpressionSelection}
|
|
1525
1528
|
@temba-canceled=${() => {}}
|
|
1526
|
-
.anchorTo=${this.anchorExpressions}
|
|
1529
|
+
.anchorTo=${this.allowAnchor ? this.anchorExpressions : null}
|
|
1527
1530
|
.options=${this.completionOptions}
|
|
1528
1531
|
.renderOption=${renderCompletionOption}
|
|
1529
1532
|
?visible=${this.completionOptions.length > 0}
|
package/src/select/UserSelect.ts
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { css, CSSResultArray, html, TemplateResult } from 'lit';
|
|
2
|
+
import { Select, SelectOption } from './Select';
|
|
3
|
+
import { property } from 'lit/decorators.js';
|
|
4
|
+
import { getScrollParent } from '../utils';
|
|
5
|
+
|
|
6
|
+
export interface WorkspaceOption extends SelectOption {
|
|
7
|
+
name: string;
|
|
8
|
+
id: string;
|
|
9
|
+
type: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class WorkspaceSelect extends Select<WorkspaceOption> {
|
|
13
|
+
static get styles(): CSSResultArray {
|
|
14
|
+
return [
|
|
15
|
+
super.styles,
|
|
16
|
+
css`
|
|
17
|
+
:host {
|
|
18
|
+
border: 0px solid blue;
|
|
19
|
+
}
|
|
20
|
+
`
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@property({ type: String })
|
|
25
|
+
endpoint = '/api/internal/orgs.json';
|
|
26
|
+
|
|
27
|
+
@property({ type: String })
|
|
28
|
+
nameKey = 'name';
|
|
29
|
+
|
|
30
|
+
@property({ type: String })
|
|
31
|
+
valueKey = 'id';
|
|
32
|
+
|
|
33
|
+
@property({ type: String })
|
|
34
|
+
placeholder: string = 'Choose Workspace';
|
|
35
|
+
|
|
36
|
+
@property({ type: Boolean })
|
|
37
|
+
sorted: boolean = true;
|
|
38
|
+
|
|
39
|
+
@property({ type: Object })
|
|
40
|
+
workspace: WorkspaceOption;
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
this.shouldExclude = (option: WorkspaceOption) => {
|
|
45
|
+
const selected = this.values[0];
|
|
46
|
+
return option.id === selected?.id;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
this.searchable = true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public firstUpdated(changed: Map<string, any>) {
|
|
53
|
+
super.firstUpdated(changed);
|
|
54
|
+
this.allowAnchor = !!getScrollParent(this);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public prepareOptionsDefault(options: WorkspaceOption[]): WorkspaceOption[] {
|
|
58
|
+
options.forEach((option) => {
|
|
59
|
+
option.type = 'workspace';
|
|
60
|
+
});
|
|
61
|
+
return options;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public renderOptionDefault(option: WorkspaceOption): TemplateResult {
|
|
65
|
+
if (!option) {
|
|
66
|
+
return html``;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return html`<temba-user name=${option.name} showname></temba-user>`;
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/store/Store.ts
CHANGED
|
@@ -519,7 +519,9 @@ export class Store extends RapidElement {
|
|
|
519
519
|
// we don't want to fetch all users at once so we can benefit from caching
|
|
520
520
|
emails.forEach((email) => {
|
|
521
521
|
promises.push(
|
|
522
|
-
this.getUrl(`/api/v2/users.json?email=${encodeURIComponent(email)}
|
|
522
|
+
this.getUrl(`/api/v2/users.json?email=${encodeURIComponent(email)}`, {
|
|
523
|
+
force: true
|
|
524
|
+
})
|
|
523
525
|
);
|
|
524
526
|
});
|
|
525
527
|
|
package/src/user/TembaUser.ts
CHANGED
|
@@ -48,7 +48,10 @@ export class TembaUser extends RapidElement {
|
|
|
48
48
|
system: boolean;
|
|
49
49
|
|
|
50
50
|
@property({ type: String, attribute: false })
|
|
51
|
-
|
|
51
|
+
bgimage: string = null;
|
|
52
|
+
|
|
53
|
+
@property({ type: String, attribute: false })
|
|
54
|
+
bgcolor: string = '#e6e6e6';
|
|
52
55
|
|
|
53
56
|
@property({ type: String, attribute: false })
|
|
54
57
|
initials: string = '';
|
|
@@ -68,16 +71,25 @@ export class TembaUser extends RapidElement {
|
|
|
68
71
|
super.updated(changed);
|
|
69
72
|
|
|
70
73
|
if (changed.has('system') && this.system) {
|
|
71
|
-
this.
|
|
74
|
+
this.bgimage = `url('${DEFAULT_AVATAR}') center / contain no-repeat`;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
if (changed.has('name')
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
if (changed.has('name')) {
|
|
78
|
+
if (this.name) {
|
|
79
|
+
this.bgcolor = colorHash.hex(this.name);
|
|
80
|
+
this.initials = extractInitials(this.name);
|
|
81
|
+
} else {
|
|
82
|
+
this.bgcolor = '#e6e6e6';
|
|
83
|
+
this.initials = '';
|
|
84
|
+
}
|
|
77
85
|
}
|
|
78
86
|
|
|
79
|
-
if (changed.has('avatar')
|
|
80
|
-
|
|
87
|
+
if (changed.has('avatar')) {
|
|
88
|
+
if (this.avatar) {
|
|
89
|
+
this.bgimage = `url('${this.avatar}') center / contain no-repeat`;
|
|
90
|
+
} else if (!this.system) {
|
|
91
|
+
this.bgimage = null;
|
|
92
|
+
}
|
|
81
93
|
}
|
|
82
94
|
}
|
|
83
95
|
|
|
@@ -96,11 +108,12 @@ export class TembaUser extends RapidElement {
|
|
|
96
108
|
border-radius: 100%;
|
|
97
109
|
font-weight: 400;
|
|
98
110
|
overflow: hidden;
|
|
99
|
-
font-size:
|
|
111
|
+
font-size: 0.8em;
|
|
112
|
+
margin-right: 0.75em;
|
|
100
113
|
box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.1);
|
|
101
|
-
background:${this.
|
|
114
|
+
background:${this.bgimage || this.bgcolor};"
|
|
102
115
|
>
|
|
103
|
-
${this.initials && !this.
|
|
116
|
+
${this.initials && !this.bgimage
|
|
104
117
|
? html` <div
|
|
105
118
|
style="border: 0px solid red; display:flex; flex-direction: column; align-items:center;flex-grow:1"
|
|
106
119
|
>
|
package/temba-modules.ts
CHANGED
|
@@ -63,6 +63,7 @@ import { StartProgress } from './src/progress/StartProgress';
|
|
|
63
63
|
import { ShortcutList } from './src/list/ShortcutList';
|
|
64
64
|
import { PopupSelect } from './src/select/PopupSelect';
|
|
65
65
|
import { UserSelect } from './src/select/UserSelect';
|
|
66
|
+
import { WorkspaceSelect } from './src/select/WorkspaceSelect';
|
|
66
67
|
|
|
67
68
|
export function addCustomElement(name: string, comp: any) {
|
|
68
69
|
if (!window.customElements.get(name)) {
|
|
@@ -136,3 +137,4 @@ addCustomElement('temba-start-progress', StartProgress);
|
|
|
136
137
|
addCustomElement('temba-shortcuts', ShortcutList);
|
|
137
138
|
addCustomElement('temba-popup-select', PopupSelect);
|
|
138
139
|
addCustomElement('temba-user-select', UserSelect);
|
|
140
|
+
addCustomElement('temba-workspace-select', WorkspaceSelect);
|
|
@@ -60,6 +60,11 @@ describe('temba-contact-chat', () => {
|
|
|
60
60
|
'/test-assets/contacts/history.json'
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
+
mockGET(
|
|
64
|
+
/\/api\/v2\/users\.json\?email=admin1%40nyaruka\.com/,
|
|
65
|
+
'/test-assets/api/users/admin1.json'
|
|
66
|
+
);
|
|
67
|
+
|
|
63
68
|
mockAPI();
|
|
64
69
|
clock = useFakeTimers();
|
|
65
70
|
});
|