@nyaruka/temba-components 0.26.9 → 0.26.10
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 +9 -0
- package/dist/{d0cc86be.js → cbffa348.js} +213 -109
- package/dist/index.js +213 -109
- package/dist/static/icons/symbol-defs.svg +35 -4
- package/dist/sw.js +1 -1
- package/dist/sw.js.map +1 -1
- package/dist/templates/components-body.html +1 -1
- package/dist/templates/components-head.html +1 -1
- package/out-tsc/src/contacts/ContactBadges.js +97 -0
- package/out-tsc/src/contacts/ContactBadges.js.map +1 -0
- package/out-tsc/src/contacts/ContactFieldEditor.js +53 -41
- package/out-tsc/src/contacts/ContactFieldEditor.js.map +1 -1
- package/out-tsc/src/contacts/ContactFields.js +86 -29
- package/out-tsc/src/contacts/ContactFields.js.map +1 -1
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/label/Label.js +25 -0
- package/out-tsc/src/label/Label.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +8 -6
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/store/Store.js +16 -0
- package/out-tsc/src/store/Store.js.map +1 -1
- package/out-tsc/src/tabpane/Tab.js +14 -1
- package/out-tsc/src/tabpane/Tab.js.map +1 -1
- package/out-tsc/src/tabpane/TabPane.js +35 -0
- package/out-tsc/src/tabpane/TabPane.js.map +1 -1
- package/out-tsc/src/textinput/TextInput.js +2 -2
- package/out-tsc/src/textinput/TextInput.js.map +1 -1
- package/out-tsc/src/vectoricon/VectorIcon.js +13 -2
- package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
- package/out-tsc/temba-modules.js +6 -6
- package/out-tsc/temba-modules.js.map +1 -1
- package/package.json +1 -1
- package/src/contacts/ContactBadges.ts +104 -0
- package/src/contacts/ContactFieldEditor.ts +55 -41
- package/src/contacts/ContactFields.ts +99 -33
- package/src/interfaces.ts +3 -1
- package/src/label/Label.ts +25 -0
- package/src/list/TembaMenu.ts +7 -5
- package/src/store/Store.ts +24 -1
- package/src/tabpane/Tab.ts +14 -1
- package/src/tabpane/TabPane.ts +36 -0
- package/src/textinput/TextInput.ts +2 -2
- package/src/vectoricon/VectorIcon.ts +15 -2
- package/static/css/temba-components.css +3 -0
- package/static/icons/Read Me.txt +1 -1
- package/static/icons/SVG/bookmark-filled.svg +5 -0
- package/static/icons/SVG/bookmark.svg +1 -1
- package/static/icons/SVG/external-link1.svg +5 -0
- package/static/icons/SVG/globe.svg +5 -0
- package/static/icons/SVG/language.svg +5 -0
- package/static/icons/SVG/search.svg +5 -0
- package/static/icons/demo-external-svg.html +218 -165
- package/static/icons/demo-files/demo.css +6 -3
- package/static/icons/demo.html +253 -169
- package/static/icons/selection.json +318 -184
- package/static/icons/style.css +4 -0
- package/static/icons/symbol-defs.svg +35 -4
- package/temba-modules.ts +7 -6
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { css, html, TemplateResult } from 'lit';
|
|
2
|
+
import { Group } from '../interfaces';
|
|
3
|
+
import { ContactStoreElement } from './ContactStoreElement';
|
|
4
|
+
|
|
5
|
+
const STATUS = {
|
|
6
|
+
S: { name: 'Stopped', icon: 'x-octagon' },
|
|
7
|
+
B: { name: 'Blocked', icon: 'slash' },
|
|
8
|
+
V: { name: 'Archived', icon: 'archive' },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export class ContactBadges extends ContactStoreElement {
|
|
12
|
+
static get styles() {
|
|
13
|
+
return css`
|
|
14
|
+
temba-label {
|
|
15
|
+
margin: 0.3em;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.badges {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-wrap: wrap;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.flow {
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public render(): TemplateResult {
|
|
29
|
+
if (this.data) {
|
|
30
|
+
const status = STATUS[this.data.status];
|
|
31
|
+
|
|
32
|
+
return html`
|
|
33
|
+
<div class="badges">
|
|
34
|
+
${status && this.data.status !== 'A'
|
|
35
|
+
? html`
|
|
36
|
+
<temba-label
|
|
37
|
+
class="status"
|
|
38
|
+
icon="${status.icon}"
|
|
39
|
+
onclick="goto(event)"
|
|
40
|
+
href="/contact/${status.name.toLowerCase()}"
|
|
41
|
+
clickable
|
|
42
|
+
secondary
|
|
43
|
+
shadow
|
|
44
|
+
>
|
|
45
|
+
${status.name}
|
|
46
|
+
</temba-label>
|
|
47
|
+
`
|
|
48
|
+
: null}
|
|
49
|
+
${this.data.flow
|
|
50
|
+
? html`
|
|
51
|
+
<temba-label
|
|
52
|
+
class="flow"
|
|
53
|
+
icon="flow"
|
|
54
|
+
onclick="goto(event)"
|
|
55
|
+
href="/contact/?search=flow+%3D+${encodeURIComponent(
|
|
56
|
+
'"' + this.data.flow.name + '"'
|
|
57
|
+
)}"
|
|
58
|
+
clickable
|
|
59
|
+
tertiary
|
|
60
|
+
shadow
|
|
61
|
+
>
|
|
62
|
+
${this.data.flow.name}
|
|
63
|
+
</temba-label>
|
|
64
|
+
`
|
|
65
|
+
: null}
|
|
66
|
+
${this.data.language
|
|
67
|
+
? html`
|
|
68
|
+
<temba-label
|
|
69
|
+
class="language"
|
|
70
|
+
icon="globe"
|
|
71
|
+
onclick="goto(event)"
|
|
72
|
+
href="/contact/?search=language+%3D+${encodeURIComponent(
|
|
73
|
+
'"' + this.data.language + '"'
|
|
74
|
+
)}"
|
|
75
|
+
clickable
|
|
76
|
+
primary
|
|
77
|
+
shadow
|
|
78
|
+
>
|
|
79
|
+
${this.store.getLanguageName(this.data.language)}
|
|
80
|
+
</temba-label>
|
|
81
|
+
`
|
|
82
|
+
: null}
|
|
83
|
+
${this.data.groups.map((group: Group) => {
|
|
84
|
+
return html`
|
|
85
|
+
<temba-label
|
|
86
|
+
class="group"
|
|
87
|
+
onclick="goto(event)"
|
|
88
|
+
href="/contact/filter/${group.uuid}/"
|
|
89
|
+
icon=${group.is_dynamic ? 'atom' : 'users'}
|
|
90
|
+
clickable
|
|
91
|
+
light
|
|
92
|
+
shadow
|
|
93
|
+
>
|
|
94
|
+
${group.name}
|
|
95
|
+
</temba-label>
|
|
96
|
+
`;
|
|
97
|
+
})}
|
|
98
|
+
</div>
|
|
99
|
+
`;
|
|
100
|
+
} else {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { css, html, TemplateResult } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators';
|
|
3
|
+
import { CustomEventType } from '../interfaces';
|
|
3
4
|
import { RapidElement } from '../RapidElement';
|
|
4
5
|
import { TextInput } from '../textinput/TextInput';
|
|
5
6
|
|
|
@@ -26,11 +27,11 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
26
27
|
return css`
|
|
27
28
|
.prefix {
|
|
28
29
|
background: rgba(0, 0, 0, 0.05);
|
|
29
|
-
border-top-left-radius:
|
|
30
|
-
border-bottom-left-radius:
|
|
30
|
+
border-top-left-radius: var(--curvature-widget);
|
|
31
|
+
border-bottom-left-radius: var(--curvature-widget);
|
|
31
32
|
color: #888;
|
|
32
33
|
cursor: pointer;
|
|
33
|
-
width:
|
|
34
|
+
width: 200px;
|
|
34
35
|
white-space: nowrap;
|
|
35
36
|
overflow: hidden;
|
|
36
37
|
text-overflow: ellipsis;
|
|
@@ -38,10 +39,14 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
38
39
|
padding: 0em 0.5em;
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
.wrapper {
|
|
43
|
+
margin-bottom: -1px;
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
.prefix .name {
|
|
42
47
|
padding: 0.5em 0em;
|
|
43
48
|
color: #888;
|
|
44
|
-
width:
|
|
49
|
+
width: 200px;
|
|
45
50
|
white-space: nowrap;
|
|
46
51
|
overflow: hidden;
|
|
47
52
|
text-overflow: ellipsis;
|
|
@@ -55,8 +60,8 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
55
60
|
.popper {
|
|
56
61
|
padding: 0.5em 0.75em;
|
|
57
62
|
background: rgba(240, 240, 240, 1);
|
|
58
|
-
border-top-right-radius:
|
|
59
|
-
border-bottom-right-radius:
|
|
63
|
+
border-top-right-radius: var(--curvature-widget);
|
|
64
|
+
border-bottom-right-radius: var(--curvature-widget);
|
|
60
65
|
--icon-color: #888;
|
|
61
66
|
opacity: 0;
|
|
62
67
|
cursor: default;
|
|
@@ -67,47 +72,34 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
67
72
|
z-index: 1000;
|
|
68
73
|
}
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
--icon-color:
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.popper.check {
|
|
75
|
-
background: rgba(90, 145, 86, 0.15);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.popper.none {
|
|
79
|
-
opacity: 0;
|
|
75
|
+
temba-icon[name='calendar'] {
|
|
76
|
+
--icon-color: rgba(0, 0, 0, 0.2);
|
|
80
77
|
}
|
|
81
78
|
|
|
82
|
-
|
|
83
|
-
--icon-color:
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.popper.corner-down-left {
|
|
87
|
-
// background: var(--color-primary-dark);
|
|
88
|
-
// --icon-color: var(--color-text-light);
|
|
89
|
-
opacity: 1;
|
|
90
|
-
transform: scale(1);
|
|
79
|
+
temba-icon:hover {
|
|
80
|
+
--icon-color: rgba(0, 0, 0, 0.5);
|
|
91
81
|
}
|
|
92
82
|
|
|
93
83
|
temba-icon {
|
|
94
84
|
cursor: pointer;
|
|
85
|
+
--icon-color: rgba(0, 0, 0, 0.3);
|
|
95
86
|
}
|
|
96
87
|
|
|
97
|
-
temba-
|
|
98
|
-
--icon-color: rgb(90, 145, 86);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
temba-textinput:hover .popper.copy {
|
|
88
|
+
temba-textinput:hover .popper {
|
|
102
89
|
opacity: 1;
|
|
103
90
|
transform: scale(1);
|
|
104
91
|
}
|
|
105
92
|
|
|
106
|
-
temba-textinput:focus .popper
|
|
93
|
+
temba-textinput:focus .popper {
|
|
107
94
|
opacity: 1;
|
|
108
95
|
transform: scale(1);
|
|
109
96
|
}
|
|
110
97
|
|
|
98
|
+
.unset temba-textinput:focus .popper,
|
|
99
|
+
.unset temba-textinput:hover .popper {
|
|
100
|
+
opacity: 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
111
103
|
.copy.clicked temba-icon {
|
|
112
104
|
transform: scale(1.2);
|
|
113
105
|
}
|
|
@@ -115,6 +107,10 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
115
107
|
temba-icon {
|
|
116
108
|
transition: all 200ms ease-in-out;
|
|
117
109
|
}
|
|
110
|
+
|
|
111
|
+
temba-icon[name='search'] {
|
|
112
|
+
margin-right: 1em;
|
|
113
|
+
}
|
|
118
114
|
`;
|
|
119
115
|
}
|
|
120
116
|
|
|
@@ -139,6 +135,14 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
139
135
|
});
|
|
140
136
|
}
|
|
141
137
|
}
|
|
138
|
+
|
|
139
|
+
if (icon === 'search') {
|
|
140
|
+
this.fireCustomEvent(CustomEventType.ButtonClicked, {
|
|
141
|
+
key: this.key,
|
|
142
|
+
value: this.value,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
142
146
|
evt.preventDefault();
|
|
143
147
|
evt.stopPropagation();
|
|
144
148
|
}
|
|
@@ -166,7 +170,7 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
166
170
|
|
|
167
171
|
public render(): TemplateResult {
|
|
168
172
|
return html`
|
|
169
|
-
<div>
|
|
173
|
+
<div class="wrapper ${this.value ? 'set' : 'unset'}">
|
|
170
174
|
<temba-textinput
|
|
171
175
|
value="${this.value ? this.value : ''}"
|
|
172
176
|
?datetimepicker=${this.type === 'datetime'}
|
|
@@ -176,22 +180,32 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
176
180
|
>
|
|
177
181
|
<div class="prefix" slot="prefix">
|
|
178
182
|
<div class="name">${this.name}</div>
|
|
179
|
-
</div>
|
|
180
|
-
|
|
181
|
-
<div class="postfix">
|
|
182
183
|
${this.type === 'datetime'
|
|
183
|
-
? html`<div
|
|
184
|
-
|
|
185
|
-
>
|
|
186
|
-
<temba-icon name="calendar" />
|
|
184
|
+
? html`<div style="position: relative; padding-top: .75em;">
|
|
185
|
+
<temba-icon name="calendar" animateclick="pulse" />
|
|
187
186
|
</div>`
|
|
188
187
|
: null}
|
|
188
|
+
</div>
|
|
189
189
|
|
|
190
|
+
<div class="postfix">
|
|
190
191
|
<div
|
|
191
|
-
class="popper ${this.iconClass}
|
|
192
|
+
class="popper ${this.iconClass}"
|
|
192
193
|
@click=${this.handleIconClick}
|
|
193
194
|
>
|
|
194
|
-
|
|
195
|
+
${this.value
|
|
196
|
+
? html`
|
|
197
|
+
<temba-icon
|
|
198
|
+
name="search"
|
|
199
|
+
animateclick="pulse"
|
|
200
|
+
></temba-icon>
|
|
201
|
+
</div>
|
|
202
|
+
`
|
|
203
|
+
: null}
|
|
204
|
+
<temba-icon
|
|
205
|
+
name="${this.icon}"
|
|
206
|
+
animatechange="spin"
|
|
207
|
+
animateclick="pulse"
|
|
208
|
+
></temba-icon>
|
|
195
209
|
</div>
|
|
196
210
|
</div>
|
|
197
211
|
</temba-textinput>
|
|
@@ -1,40 +1,35 @@
|
|
|
1
|
-
import { css, html, TemplateResult } from 'lit';
|
|
1
|
+
import { css, html, PropertyValueMap, TemplateResult } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators';
|
|
3
|
-
import { ContactField } from '../interfaces';
|
|
4
3
|
import { postJSON } from '../utils';
|
|
5
4
|
import { ContactFieldEditor } from './ContactFieldEditor';
|
|
6
5
|
import { ContactStoreElement } from './ContactStoreElement';
|
|
6
|
+
import { Checkbox } from '../checkbox/Checkbox';
|
|
7
|
+
|
|
8
|
+
const MIN_FOR_FILTER = 10;
|
|
7
9
|
|
|
8
10
|
export class ContactFields extends ContactStoreElement {
|
|
9
11
|
static get styles() {
|
|
10
12
|
return css`
|
|
11
13
|
:host {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
flex-shrink: 1;
|
|
14
|
+
--curvature-widget: 0px;
|
|
15
|
+
border-radius: 6px;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
.field {
|
|
18
19
|
display: flex;
|
|
19
20
|
margin: 0.3em 0.3em;
|
|
20
21
|
box-shadow: 0 0 0.2em rgba(0, 0, 0, 0.15);
|
|
21
|
-
border-radius:
|
|
22
|
+
border-radius: 0px;
|
|
22
23
|
align-items: center;
|
|
23
24
|
overflow: hidden;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
.
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.field.unset {
|
|
31
|
-
opacity: 0.4;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.field.unset .label {
|
|
27
|
+
.show-all .unset {
|
|
28
|
+
display: block;
|
|
35
29
|
}
|
|
36
30
|
|
|
37
|
-
.
|
|
31
|
+
.unset {
|
|
32
|
+
display: none;
|
|
38
33
|
}
|
|
39
34
|
|
|
40
35
|
.field:hover {
|
|
@@ -45,8 +40,8 @@ export class ContactFields extends ContactStoreElement {
|
|
|
45
40
|
|
|
46
41
|
.label {
|
|
47
42
|
padding: 0.25em 1em;
|
|
48
|
-
border-top-left-radius:
|
|
49
|
-
border-bottom-left-radius:
|
|
43
|
+
border-top-left-radius: 0px;
|
|
44
|
+
border-bottom-left-radius: 0px;
|
|
50
45
|
color: #777;
|
|
51
46
|
font-size: 0.9em;
|
|
52
47
|
font-weight: 400;
|
|
@@ -60,27 +55,52 @@ export class ContactFields extends ContactStoreElement {
|
|
|
60
55
|
overflow: hidden;
|
|
61
56
|
text-overflow: ellipsis;
|
|
62
57
|
padding: 0.25em 1em;
|
|
63
|
-
border-top-right-radius:
|
|
64
|
-
border-bottom-right-radius:
|
|
58
|
+
border-top-right-radius: 0px;
|
|
59
|
+
border-bottom-right-radius: 0px;
|
|
65
60
|
font-size: 0.9em;
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
temba-contact-field {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.footer {
|
|
67
|
+
margin-bottom: 0;
|
|
68
|
+
display: flex;
|
|
69
|
+
background: #fff;
|
|
70
|
+
align-items: center;
|
|
71
|
+
margin-top: 0.5em;
|
|
72
72
|
}
|
|
73
73
|
`;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
@property({ type: Boolean })
|
|
77
|
+
pinned: boolean;
|
|
78
|
+
|
|
79
|
+
@property({ type: Boolean })
|
|
80
|
+
system: boolean;
|
|
81
|
+
|
|
76
82
|
@property({ type: Boolean })
|
|
77
83
|
dirty: boolean;
|
|
78
84
|
|
|
85
|
+
@property({ type: Boolean })
|
|
86
|
+
showAll: boolean;
|
|
87
|
+
|
|
79
88
|
connectedCallback(): void {
|
|
80
89
|
super.connectedCallback();
|
|
81
90
|
this.handleFieldChanged = this.handleFieldChanged.bind(this);
|
|
82
91
|
}
|
|
83
92
|
|
|
93
|
+
protected updated(
|
|
94
|
+
changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
|
95
|
+
): void {
|
|
96
|
+
super.updated(changes);
|
|
97
|
+
if (changes.has('data')) {
|
|
98
|
+
if (Object.keys(this.data.fields).length <= MIN_FOR_FILTER) {
|
|
99
|
+
this.showAll = true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
84
104
|
public handleFieldChanged(evt: InputEvent) {
|
|
85
105
|
const field = evt.currentTarget as ContactFieldEditor;
|
|
86
106
|
this.data.fields[field.key] = field.value;
|
|
@@ -91,22 +111,68 @@ export class ContactFields extends ContactStoreElement {
|
|
|
91
111
|
});
|
|
92
112
|
}
|
|
93
113
|
|
|
94
|
-
public
|
|
95
|
-
const
|
|
114
|
+
public handleToggle(evt: Event) {
|
|
115
|
+
const checkbox = evt.currentTarget as Checkbox;
|
|
116
|
+
console.log(checkbox.checked);
|
|
117
|
+
this.showAll = checkbox.checked;
|
|
118
|
+
}
|
|
96
119
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
120
|
+
public render(): TemplateResult {
|
|
121
|
+
if (this.data) {
|
|
122
|
+
const fieldsToShow = Object.entries(this.data.fields)
|
|
123
|
+
.filter((entry: [string, string]) => {
|
|
124
|
+
return (
|
|
125
|
+
(this.pinned && this.store.getContactField(entry[0]).pinned) ||
|
|
126
|
+
(!this.pinned && !this.store.getContactField(entry[0]).pinned)
|
|
127
|
+
);
|
|
128
|
+
})
|
|
129
|
+
.sort((a: [string, string], b: [string, string]) => {
|
|
130
|
+
const [ak] = a;
|
|
131
|
+
const [bk] = b;
|
|
132
|
+
/* if (av && !bv) {
|
|
133
|
+
return -1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (bv && !av) {
|
|
137
|
+
return 1;
|
|
138
|
+
}*/
|
|
139
|
+
|
|
140
|
+
return ak.localeCompare(bk);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const fields = fieldsToShow.map((entry: [string, string]) => {
|
|
144
|
+
const [k, v] = entry;
|
|
145
|
+
const field = this.store.getContactField(k);
|
|
100
146
|
return html`<temba-contact-field
|
|
147
|
+
class=${v ? 'set' : 'unset'}
|
|
101
148
|
key=${field.key}
|
|
102
149
|
name=${field.label}
|
|
103
|
-
value=${
|
|
150
|
+
value=${v}
|
|
104
151
|
type=${field.value_type}
|
|
105
152
|
@change=${this.handleFieldChanged}
|
|
106
153
|
></temba-contact-field>`;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return html`
|
|
157
|
+
<div class="${this.showAll || this.pinned ? 'show-all' : ''}">
|
|
158
|
+
${fields}
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
${!this.pinned && Object.keys(this.data.fields).length >= MIN_FOR_FILTER
|
|
162
|
+
? html` <div class="footer">
|
|
163
|
+
<div style="flex-grow: 1"></div>
|
|
164
|
+
<div>
|
|
165
|
+
<temba-checkbox
|
|
166
|
+
?checked=${this.showAll}
|
|
167
|
+
@change=${this.handleToggle}
|
|
168
|
+
label="Show All"
|
|
169
|
+
/>
|
|
170
|
+
</div>
|
|
171
|
+
</div>`
|
|
172
|
+
: null}
|
|
173
|
+
`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return null;
|
|
111
177
|
}
|
|
112
178
|
}
|
package/src/interfaces.ts
CHANGED
|
@@ -84,13 +84,15 @@ export interface Contact {
|
|
|
84
84
|
stopped: boolean;
|
|
85
85
|
blocked: boolean;
|
|
86
86
|
urns: string[];
|
|
87
|
-
|
|
87
|
+
language?: string;
|
|
88
88
|
fields: { [key: string]: string };
|
|
89
89
|
groups: Group[];
|
|
90
90
|
modified_on: string;
|
|
91
91
|
created_on: string;
|
|
92
92
|
last_seen_on: string;
|
|
93
|
+
status: string;
|
|
93
94
|
|
|
95
|
+
flow?: ObjectReference;
|
|
94
96
|
last_msg?: Msg;
|
|
95
97
|
direction?: string;
|
|
96
98
|
ticket: {
|
package/src/label/Label.ts
CHANGED
|
@@ -50,6 +50,27 @@ export default class Label extends LitElement {
|
|
|
50
50
|
text-shadow: none;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
.tertiary {
|
|
54
|
+
background: var(--color-label-tertiary);
|
|
55
|
+
color: var(--color-label-tertiary-text);
|
|
56
|
+
--icon-color: var(--color-label-tertiary-text);
|
|
57
|
+
text-shadow: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.tertiary {
|
|
61
|
+
background: var(--color-label-tertiary);
|
|
62
|
+
color: var(--color-label-tertiary-text);
|
|
63
|
+
--icon-color: var(--color-label-tertiary-text);
|
|
64
|
+
text-shadow: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.tertiary {
|
|
68
|
+
background: var(--color-label-tertiary);
|
|
69
|
+
color: var(--color-label-tertiary-text);
|
|
70
|
+
--icon-color: var(--color-label-tertiary-text);
|
|
71
|
+
text-shadow: none;
|
|
72
|
+
}
|
|
73
|
+
|
|
53
74
|
.light {
|
|
54
75
|
background: var(--color-overlay-light);
|
|
55
76
|
color: var(--color-overlay-light-text);
|
|
@@ -83,6 +104,9 @@ export default class Label extends LitElement {
|
|
|
83
104
|
@property({ type: Boolean })
|
|
84
105
|
secondary: boolean;
|
|
85
106
|
|
|
107
|
+
@property({ type: Boolean })
|
|
108
|
+
tertiary: boolean;
|
|
109
|
+
|
|
86
110
|
@property({ type: Boolean })
|
|
87
111
|
light: boolean;
|
|
88
112
|
|
|
@@ -116,6 +140,7 @@ export default class Label extends LitElement {
|
|
|
116
140
|
clickable: this.clickable,
|
|
117
141
|
primary: this.primary,
|
|
118
142
|
secondary: this.secondary,
|
|
143
|
+
tertiary: this.tertiary,
|
|
119
144
|
light: this.light,
|
|
120
145
|
dark: this.dark,
|
|
121
146
|
shadow: this.shadow,
|
package/src/list/TembaMenu.ts
CHANGED
|
@@ -503,11 +503,13 @@ export class TembaMenu extends RapidElement {
|
|
|
503
503
|
// go up the tree until we find an endpoint
|
|
504
504
|
const item = this.getMenuItemForSelection(path);
|
|
505
505
|
|
|
506
|
-
if (item
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
506
|
+
if (item) {
|
|
507
|
+
if (item.endpoint) {
|
|
508
|
+
this.loadItems(item, false);
|
|
509
|
+
} else {
|
|
510
|
+
path.pop();
|
|
511
|
+
this.refresh(path);
|
|
512
|
+
}
|
|
511
513
|
}
|
|
512
514
|
}
|
|
513
515
|
|
package/src/store/Store.ts
CHANGED
|
@@ -30,6 +30,9 @@ export class Store extends RapidElement {
|
|
|
30
30
|
@property({ type: String, attribute: 'globals' })
|
|
31
31
|
globalsEndpoint: string;
|
|
32
32
|
|
|
33
|
+
@property({ type: String, attribute: 'languages' })
|
|
34
|
+
languagesEndpoint: string;
|
|
35
|
+
|
|
33
36
|
@property({ type: Object, attribute: false })
|
|
34
37
|
private schema: CompletionSchema;
|
|
35
38
|
|
|
@@ -41,7 +44,7 @@ export class Store extends RapidElement {
|
|
|
41
44
|
|
|
42
45
|
private fields: { [key: string]: ContactField } = {};
|
|
43
46
|
private groups: { [uuid: string]: ContactGroup } = {};
|
|
44
|
-
|
|
47
|
+
private languages: any = {};
|
|
45
48
|
private pinnedFields: ContactField[] = [];
|
|
46
49
|
|
|
47
50
|
// http promise to monitor for completeness
|
|
@@ -91,6 +94,22 @@ export class Store extends RapidElement {
|
|
|
91
94
|
);
|
|
92
95
|
}
|
|
93
96
|
|
|
97
|
+
if (this.languagesEndpoint) {
|
|
98
|
+
fetches.push(
|
|
99
|
+
getAssets(this.languagesEndpoint).then((results: any[]) => {
|
|
100
|
+
// convert array of objects to lookup
|
|
101
|
+
this.languages = results.reduce(function (
|
|
102
|
+
languages: any,
|
|
103
|
+
result: any
|
|
104
|
+
) {
|
|
105
|
+
languages[result.value] = result.name;
|
|
106
|
+
return languages;
|
|
107
|
+
},
|
|
108
|
+
{});
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
94
113
|
if (this.groupsEndpoint) {
|
|
95
114
|
fetches.push(
|
|
96
115
|
getAssets(this.groupsEndpoint).then((groups: any[]) => {
|
|
@@ -132,6 +151,10 @@ export class Store extends RapidElement {
|
|
|
132
151
|
return this.pinnedFields;
|
|
133
152
|
}
|
|
134
153
|
|
|
154
|
+
public getLanguageName(iso: string) {
|
|
155
|
+
return this.languages[iso];
|
|
156
|
+
}
|
|
157
|
+
|
|
135
158
|
public isDynamicGroup(uuid: string): boolean {
|
|
136
159
|
const group = this.groups[uuid];
|
|
137
160
|
if (group && group.query) {
|
package/src/tabpane/Tab.ts
CHANGED
|
@@ -31,12 +31,25 @@ export class Tab extends RapidElement {
|
|
|
31
31
|
@property({ type: String })
|
|
32
32
|
icon: string;
|
|
33
33
|
|
|
34
|
+
@property({ type: String })
|
|
35
|
+
selectionColor: string;
|
|
36
|
+
|
|
37
|
+
@property({ type: String })
|
|
38
|
+
selectionBackground: string;
|
|
39
|
+
|
|
34
40
|
@property({ type: Boolean })
|
|
35
41
|
selected = false;
|
|
36
42
|
|
|
43
|
+
@property({ type: Number })
|
|
44
|
+
count = 0;
|
|
45
|
+
|
|
46
|
+
public hasBadge() {
|
|
47
|
+
return this.count > 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
37
50
|
public render(): TemplateResult {
|
|
38
51
|
return html`<slot
|
|
39
52
|
class="${getClasses({ selected: this.selected })}"
|
|
40
|
-
></slot
|
|
53
|
+
></slot> `;
|
|
41
54
|
}
|
|
42
55
|
}
|