@nyaruka/temba-components 0.54.2 → 0.55.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 +9 -0
- package/dist/{16170315.js → 31b8df84.js} +475 -475
- package/dist/index.js +475 -475
- 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/compose/Compose.js +2 -3
- package/out-tsc/src/compose/Compose.js.map +1 -1
- package/out-tsc/src/contacts/ContactFieldEditor.js +31 -18
- package/out-tsc/src/contacts/ContactFieldEditor.js.map +1 -1
- package/out-tsc/src/contacts/ContactFields.js +27 -33
- package/out-tsc/src/contacts/ContactFields.js.map +1 -1
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/textinput/TextInput.js +4 -3
- package/out-tsc/src/textinput/TextInput.js.map +1 -1
- package/out-tsc/src/utils/index.js +2 -2
- package/out-tsc/src/utils/index.js.map +1 -1
- package/out-tsc/test/temba-compose.test.js +4 -3
- package/out-tsc/test/temba-compose.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/contacts/details.png +0 -0
- package/screenshots/truth/contacts/fields-updated.png +0 -0
- package/screenshots/truth/contacts/fields.png +0 -0
- package/src/compose/Compose.ts +2 -3
- package/src/contacts/ContactFieldEditor.ts +31 -18
- package/src/contacts/ContactFields.ts +34 -37
- package/src/interfaces.ts +1 -0
- package/src/textinput/TextInput.ts +4 -3
- package/src/utils/index.ts +3 -2
- package/test/temba-compose.test.ts +5 -4
|
@@ -34,17 +34,41 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
34
34
|
|
|
35
35
|
static get styles() {
|
|
36
36
|
return css`
|
|
37
|
+
:host {
|
|
38
|
+
--transition-speed: 0ms;
|
|
39
|
+
}
|
|
40
|
+
|
|
37
41
|
.wrapper {
|
|
38
42
|
--temba-textinput-padding: 1.4em 0.8em 0.4em 0.8em;
|
|
39
43
|
--disabled-opacity: 1;
|
|
40
44
|
position: relative;
|
|
45
|
+
--color-widget-bg: transparent;
|
|
46
|
+
--color-widget-bg-focused: #fff;
|
|
47
|
+
--widget-box-shadow: none;
|
|
48
|
+
padding-bottom: 0.6em;
|
|
49
|
+
border-bottom: 1px solid #ececec;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.wrapper.disabled {
|
|
53
|
+
--color-widget-border: transparent;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.wrapper.mutable:hover {
|
|
57
|
+
--color-widget-border: rgb(225, 225, 225);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.wrapper.mutable {
|
|
61
|
+
--color-widget-border: transparent;
|
|
62
|
+
--color-widget-bg: transparent;
|
|
63
|
+
--input-cursor: pointer;
|
|
64
|
+
--color-widget-text-focused: #666;
|
|
65
|
+
--color-widget-text: var(--color-link-primary) !important;
|
|
41
66
|
}
|
|
42
67
|
|
|
43
68
|
.prefix {
|
|
44
69
|
border-top-left-radius: var(--curvature-widget);
|
|
45
70
|
border-bottom-left-radius: var(--curvature-widget);
|
|
46
|
-
|
|
47
|
-
cursor: pointer;
|
|
71
|
+
cursor: pointer !important;
|
|
48
72
|
white-space: nowrap;
|
|
49
73
|
overflow: hidden;
|
|
50
74
|
text-overflow: ellipsis;
|
|
@@ -52,6 +76,7 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
52
76
|
padding: 0em 0.5em;
|
|
53
77
|
position: absolute;
|
|
54
78
|
margin-top: 0.2em;
|
|
79
|
+
pointer-events: none;
|
|
55
80
|
}
|
|
56
81
|
|
|
57
82
|
.wrapper {
|
|
@@ -60,7 +85,7 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
60
85
|
|
|
61
86
|
.prefix .name {
|
|
62
87
|
padding: 0em 0.4em;
|
|
63
|
-
color:
|
|
88
|
+
color: rgba(100, 100, 100, 0.7);
|
|
64
89
|
white-space: nowrap;
|
|
65
90
|
overflow: hidden;
|
|
66
91
|
text-overflow: ellipsis;
|
|
@@ -74,13 +99,12 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
74
99
|
|
|
75
100
|
.popper {
|
|
76
101
|
padding: 0.5em 0.75em;
|
|
77
|
-
background: rgba(
|
|
102
|
+
background: rgba(0, 0, 0, 0.03);
|
|
78
103
|
border-top-right-radius: var(--curvature-widget);
|
|
79
104
|
border-bottom-right-radius: var(--curvature-widget);
|
|
80
105
|
--icon-color: #888;
|
|
81
106
|
opacity: 0;
|
|
82
107
|
cursor: default;
|
|
83
|
-
transform: scale(0.5);
|
|
84
108
|
transition: all var(--transition-speed) ease-in-out;
|
|
85
109
|
display: flex;
|
|
86
110
|
align-items: stretch;
|
|
@@ -100,27 +124,15 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
100
124
|
--icon-color: rgba(0, 0, 0, 0.3);
|
|
101
125
|
}
|
|
102
126
|
|
|
127
|
+
temba-textinput:focus .popper,
|
|
103
128
|
temba-textinput:hover .popper {
|
|
104
129
|
opacity: 1;
|
|
105
|
-
transform: scale(1);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
temba-textinput:focus .popper {
|
|
109
|
-
opacity: 1;
|
|
110
|
-
transform: scale(1);
|
|
111
130
|
}
|
|
112
131
|
|
|
113
132
|
.disabled temba-textinput .postfix {
|
|
114
133
|
display: none;
|
|
115
134
|
}
|
|
116
135
|
|
|
117
|
-
.disabled {
|
|
118
|
-
--widget-box-shadow: none;
|
|
119
|
-
--color-widget-border: transparent;
|
|
120
|
-
padding-bottom: 0.4em;
|
|
121
|
-
border-bottom: 1px solid #e6e6e6;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
136
|
.unset temba-textinput:focus .popper,
|
|
125
137
|
.unset temba-textinput:hover .popper {
|
|
126
138
|
opacity: 0;
|
|
@@ -208,6 +220,7 @@ export class ContactFieldEditor extends RapidElement {
|
|
|
208
220
|
set: !!this.value,
|
|
209
221
|
unset: !this.value,
|
|
210
222
|
disabled: this.disabled,
|
|
223
|
+
mutable: !this.disabled,
|
|
211
224
|
})}
|
|
212
225
|
>
|
|
213
226
|
${this.type === 'datetime'
|
|
@@ -10,12 +10,6 @@ const MIN_FOR_FILTER = 10;
|
|
|
10
10
|
export class ContactFields extends ContactStoreElement {
|
|
11
11
|
static get styles() {
|
|
12
12
|
return css`
|
|
13
|
-
:host {
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.fields {
|
|
17
|
-
}
|
|
18
|
-
|
|
19
13
|
.field {
|
|
20
14
|
display: flex;
|
|
21
15
|
margin: 0.3em 0.3em;
|
|
@@ -25,8 +19,9 @@ export class ContactFields extends ContactStoreElement {
|
|
|
25
19
|
overflow: hidden;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
.show-all .unset
|
|
29
|
-
|
|
22
|
+
.show-all .unset,
|
|
23
|
+
.featured {
|
|
24
|
+
display: block !important;
|
|
30
25
|
}
|
|
31
26
|
|
|
32
27
|
.unset {
|
|
@@ -61,9 +56,6 @@ export class ContactFields extends ContactStoreElement {
|
|
|
61
56
|
font-size: 0.9em;
|
|
62
57
|
}
|
|
63
58
|
|
|
64
|
-
temba-contact-field {
|
|
65
|
-
}
|
|
66
|
-
|
|
67
59
|
.toggle {
|
|
68
60
|
display: flex;
|
|
69
61
|
background: #fff;
|
|
@@ -77,9 +69,6 @@ export class ContactFields extends ContactStoreElement {
|
|
|
77
69
|
`;
|
|
78
70
|
}
|
|
79
71
|
|
|
80
|
-
@property({ type: Boolean })
|
|
81
|
-
featured: boolean;
|
|
82
|
-
|
|
83
72
|
@property({ type: Boolean })
|
|
84
73
|
system: boolean;
|
|
85
74
|
|
|
@@ -92,6 +81,9 @@ export class ContactFields extends ContactStoreElement {
|
|
|
92
81
|
@property({ type: String })
|
|
93
82
|
timezone: string;
|
|
94
83
|
|
|
84
|
+
@property({ type: String })
|
|
85
|
+
role: string;
|
|
86
|
+
|
|
95
87
|
@property({ type: Boolean })
|
|
96
88
|
disabled = false;
|
|
97
89
|
|
|
@@ -100,6 +92,10 @@ export class ContactFields extends ContactStoreElement {
|
|
|
100
92
|
this.handleFieldChanged = this.handleFieldChanged.bind(this);
|
|
101
93
|
}
|
|
102
94
|
|
|
95
|
+
private isAgent(): boolean {
|
|
96
|
+
return this.role === 'T';
|
|
97
|
+
}
|
|
98
|
+
|
|
103
99
|
protected updated(
|
|
104
100
|
changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
|
105
101
|
): void {
|
|
@@ -129,25 +125,29 @@ export class ContactFields extends ContactStoreElement {
|
|
|
129
125
|
|
|
130
126
|
public render(): TemplateResult {
|
|
131
127
|
if (this.data) {
|
|
132
|
-
const fieldsToShow = Object.entries(this.data.fields)
|
|
133
|
-
|
|
134
|
-
return (
|
|
135
|
-
(this.featured && this.store.getContactField(entry[0]).featured) ||
|
|
136
|
-
(!this.featured && !this.store.getContactField(entry[0]).featured)
|
|
137
|
-
);
|
|
138
|
-
})
|
|
139
|
-
.sort((a: [string, string], b: [string, string]) => {
|
|
128
|
+
const fieldsToShow = Object.entries(this.data.fields).sort(
|
|
129
|
+
(a: [string, string], b: [string, string]) => {
|
|
140
130
|
const [ak] = a;
|
|
141
131
|
const [bk] = b;
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
132
|
+
const fieldA = this.store.getContactField(ak);
|
|
133
|
+
const fieldB = this.store.getContactField(bk);
|
|
134
|
+
|
|
135
|
+
if (fieldA.featured && !fieldB.featured) {
|
|
136
|
+
return -1;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (fieldB.featured && !fieldA.featured) {
|
|
140
|
+
return 1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const priority = fieldB.priority - fieldA.priority;
|
|
145
144
|
if (priority !== 0) {
|
|
146
145
|
return priority;
|
|
147
146
|
}
|
|
148
147
|
|
|
149
148
|
return ak.localeCompare(bk);
|
|
150
|
-
}
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
151
|
|
|
152
152
|
if (fieldsToShow.length == 0) {
|
|
153
153
|
return html`<slot name="empty"></slot>`;
|
|
@@ -157,21 +157,24 @@ export class ContactFields extends ContactStoreElement {
|
|
|
157
157
|
const [k, v] = entry;
|
|
158
158
|
const field = this.store.getContactField(k);
|
|
159
159
|
return html`<temba-contact-field
|
|
160
|
-
class=${v
|
|
160
|
+
class=${getClasses({ set: !!v, unset: !v, featured: field.featured })}
|
|
161
161
|
key=${field.key}
|
|
162
162
|
name=${field.label}
|
|
163
163
|
value=${v}
|
|
164
164
|
type=${field.value_type}
|
|
165
165
|
@change=${this.handleFieldChanged}
|
|
166
166
|
timezone=${this.timezone}
|
|
167
|
-
?disabled=${this.
|
|
167
|
+
?disabled=${(this.isAgent() && field.agent_access === 'view') ||
|
|
168
|
+
this.disabled
|
|
169
|
+
? true
|
|
170
|
+
: false}
|
|
168
171
|
></temba-contact-field>`;
|
|
169
172
|
});
|
|
170
173
|
|
|
171
174
|
return html`
|
|
172
175
|
<div class=${getClasses({ disabled: this.disabled })}>
|
|
173
|
-
${
|
|
174
|
-
Object.keys(this.data.fields).length >= MIN_FOR_FILTER
|
|
176
|
+
<div class="fields ${this.showAll ? 'show-all' : ''}">${fields}</div>
|
|
177
|
+
${Object.keys(this.data.fields).length >= MIN_FOR_FILTER
|
|
175
178
|
? html`<div class="toggle">
|
|
176
179
|
<div style="flex-grow: 1"></div>
|
|
177
180
|
<div>
|
|
@@ -179,16 +182,10 @@ export class ContactFields extends ContactStoreElement {
|
|
|
179
182
|
?checked=${this.showAll}
|
|
180
183
|
@change=${this.handleToggle}
|
|
181
184
|
label="Show All"
|
|
182
|
-
|
|
185
|
+
></temba-checkbox>
|
|
183
186
|
</div>
|
|
184
187
|
</div>`
|
|
185
188
|
: null}
|
|
186
|
-
|
|
187
|
-
<div
|
|
188
|
-
class="fields ${this.showAll || this.featured ? 'show-all' : ''}"
|
|
189
|
-
>
|
|
190
|
-
${fields}
|
|
191
|
-
</div>
|
|
192
189
|
</div>
|
|
193
190
|
`;
|
|
194
191
|
}
|
package/src/interfaces.ts
CHANGED
|
@@ -12,7 +12,7 @@ export class TextInput extends FormElement {
|
|
|
12
12
|
return css`
|
|
13
13
|
.input-container {
|
|
14
14
|
border-radius: var(--curvature-widget);
|
|
15
|
-
cursor:
|
|
15
|
+
cursor: var(--input-cursor);
|
|
16
16
|
background: var(--color-widget-bg);
|
|
17
17
|
border: 1px solid var(--color-widget-border);
|
|
18
18
|
transition: all ease-in-out var(--transition-speed);
|
|
@@ -48,7 +48,6 @@ export class TextInput extends FormElement {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
.input-container:hover {
|
|
51
|
-
background: var(--color-widget-bg-focused);
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
textarea {
|
|
@@ -61,11 +60,12 @@ export class TextInput extends FormElement {
|
|
|
61
60
|
flex: 1;
|
|
62
61
|
margin: 0;
|
|
63
62
|
background: none;
|
|
63
|
+
background-color: transparent;
|
|
64
64
|
color: var(--color-widget-text);
|
|
65
65
|
font-family: var(--font-family);
|
|
66
66
|
font-size: var(--temba-textinput-font-size);
|
|
67
67
|
line-height: normal;
|
|
68
|
-
cursor:
|
|
68
|
+
cursor: var(--input-cursor);
|
|
69
69
|
resize: none;
|
|
70
70
|
font-weight: 300;
|
|
71
71
|
width: 100%;
|
|
@@ -75,6 +75,7 @@ export class TextInput extends FormElement {
|
|
|
75
75
|
outline: none;
|
|
76
76
|
box-shadow: none;
|
|
77
77
|
cursor: text;
|
|
78
|
+
color: var(--color-widget-text-focused, var(--color-widget-text));
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
.textinput::placeholder {
|
package/src/utils/index.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-this-alias */
|
|
2
2
|
import { html, TemplateResult } from 'lit-html';
|
|
3
3
|
import { Button } from '../button/Button';
|
|
4
|
-
import { upload_endpoint } from '../compose/Compose';
|
|
5
4
|
import { Dialog } from '../dialog/Dialog';
|
|
6
5
|
import { ContactField, Ticket, User } from '../interfaces';
|
|
7
6
|
import ColorHash from 'color-hash';
|
|
8
7
|
|
|
8
|
+
export const DEFAULT_MEDIA_ENDPOINT = '/api/v2/media.json';
|
|
9
|
+
|
|
9
10
|
const colorHash = new ColorHash();
|
|
10
11
|
|
|
11
12
|
export type Asset = KeyedAsset & Ticket & ContactField;
|
|
@@ -252,7 +253,7 @@ export const postFormData = (
|
|
|
252
253
|
if (response.status >= 200 && response.status < 400) {
|
|
253
254
|
resolve(response);
|
|
254
255
|
} else {
|
|
255
|
-
if (url ===
|
|
256
|
+
if (url === DEFAULT_MEDIA_ENDPOINT) {
|
|
256
257
|
reject(response);
|
|
257
258
|
} else {
|
|
258
259
|
reject('Server failure');
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { assert, expect
|
|
2
|
-
import { Attachment, Compose
|
|
1
|
+
import { assert, expect } from '@open-wc/testing';
|
|
2
|
+
import { Attachment, Compose } from '../src/compose/Compose';
|
|
3
3
|
import { assertScreenshot, getClip, getComponent } from './utils.test';
|
|
4
4
|
import { Button } from '../src/button/Button';
|
|
5
5
|
import { Completion } from '../src/completion/Completion';
|
|
6
|
+
import { DEFAULT_MEDIA_ENDPOINT } from '../src/utils';
|
|
6
7
|
|
|
7
8
|
const TAG = 'temba-compose';
|
|
8
9
|
const getCompose = async (attrs: any = {}, width = 500, height = 500) => {
|
|
@@ -113,7 +114,7 @@ describe('temba-compose chatbox', () => {
|
|
|
113
114
|
it('can be created', async () => {
|
|
114
115
|
const compose: Compose = await getCompose();
|
|
115
116
|
assert.instanceOf(compose, Compose);
|
|
116
|
-
expect(compose.endpoint).equals(
|
|
117
|
+
expect(compose.endpoint).equals(DEFAULT_MEDIA_ENDPOINT);
|
|
117
118
|
});
|
|
118
119
|
|
|
119
120
|
it('cannot be created with a different endpoint', async () => {
|
|
@@ -121,7 +122,7 @@ describe('temba-compose chatbox', () => {
|
|
|
121
122
|
endpoint: '/schmsgmedia/schmupload/',
|
|
122
123
|
});
|
|
123
124
|
assert.instanceOf(compose, Compose);
|
|
124
|
-
expect(compose.endpoint).equals(
|
|
125
|
+
expect(compose.endpoint).equals(DEFAULT_MEDIA_ENDPOINT);
|
|
125
126
|
});
|
|
126
127
|
|
|
127
128
|
it('chatbox no counter no send button', async () => {
|