@nyaruka/temba-components 0.123.0 → 0.124.1
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/.github/copilot-instructions.md +22 -4
- package/CHANGELOG.md +21 -0
- package/TEST_OPTIMIZATION.md +158 -0
- package/demo/alert/example.html +65 -0
- package/demo/button/example.html +71 -0
- package/demo/chart/example.html +56 -0
- package/demo/checkbox/example.html +72 -0
- package/demo/compose/example.html +72 -0
- package/demo/data/images/gus.png +0 -0
- package/demo/data/images/purrington.jpg +0 -0
- package/demo/data/server/opened-tickets.json +40 -0
- package/demo/data/server/response-time.json +27 -0
- package/demo/datepicker/example.html +69 -0
- package/demo/dialog/example.html +107 -0
- package/demo/dropdown/example.html +99 -0
- package/demo/index.html +152 -430
- package/demo/misc/example.html +72 -0
- package/demo/progress/example.html +59 -0
- package/demo/select/drag-and-drop.html +142 -0
- package/demo/select/example.html +82 -0
- package/demo/select/multi.html +73 -0
- package/demo/slider/example.html +59 -0
- package/demo/sortable-list/example.html +99 -0
- package/demo/styles.css +183 -0
- package/demo/tabs/example.html +91 -0
- package/demo/textinput/completion.html +56 -0
- package/demo/textinput/example.html +61 -0
- package/dist/temba-components.js +323 -191
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/chart/TembaChart.js +19 -16
- package/out-tsc/src/chart/TembaChart.js.map +1 -1
- package/out-tsc/src/fields/FieldManager.js +27 -34
- package/out-tsc/src/fields/FieldManager.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +1 -1
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/list/SortableList.js +257 -60
- package/out-tsc/src/list/SortableList.js.map +1 -1
- package/out-tsc/src/omnibox/Omnibox.js +1 -1
- package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
- package/out-tsc/src/select/Select.js +198 -38
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/thumbnail/Thumbnail.js +1 -1
- package/out-tsc/src/thumbnail/Thumbnail.js.map +1 -1
- package/out-tsc/src/webchat/WebChat.js +5 -2
- package/out-tsc/src/webchat/WebChat.js.map +1 -1
- package/out-tsc/test/temba-chart.test.js +1 -1
- package/out-tsc/test/temba-chart.test.js.map +1 -1
- package/out-tsc/test/temba-compose.test.js +6 -30
- package/out-tsc/test/temba-compose.test.js.map +1 -1
- package/out-tsc/test/temba-contact-chat.test.js +1 -2
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-dropdown.test.js +1 -1
- package/out-tsc/test/temba-dropdown.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-node.test.js +273 -0
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor.test.js +244 -0
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -0
- package/out-tsc/test/temba-flow-plumber.test.js +145 -0
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -0
- package/out-tsc/test/temba-flow-render.test.js +171 -0
- package/out-tsc/test/temba-flow-render.test.js.map +1 -0
- package/out-tsc/test/temba-omnibox.test.js +6 -3
- package/out-tsc/test/temba-omnibox.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +183 -53
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/temba-sortable-list.test.js +91 -15
- package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
- package/out-tsc/test/temba-toast.test.js +1 -2
- package/out-tsc/test/temba-toast.test.js.map +1 -1
- package/out-tsc/test/temba-utils-index.test.js +2 -2
- package/out-tsc/test/temba-utils-index.test.js.map +1 -1
- package/out-tsc/test/temba-webchat-lightbox-fix.test.js +42 -0
- package/out-tsc/test/temba-webchat-lightbox-fix.test.js.map +1 -0
- package/out-tsc/test/utils.test.js +58 -0
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +2 -3
- package/screenshots/truth/flow/editor-basic.png +0 -0
- package/screenshots/truth/list/fields-dragging.png +0 -0
- package/screenshots/truth/list/sortable-dragging.png +0 -0
- package/screenshots/truth/list/sortable-dropped.png +0 -0
- package/screenshots/truth/list/sortable.png +0 -0
- package/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/select/disabled-multi-selection.png +0 -0
- package/screenshots/truth/select/disabled-selection.png +0 -0
- package/screenshots/truth/select/disabled.png +0 -0
- package/screenshots/truth/select/embedded.png +0 -0
- package/screenshots/truth/select/empty-options.png +0 -0
- package/screenshots/truth/select/expression-selected.png +0 -0
- package/screenshots/truth/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/local-options.png +0 -0
- package/screenshots/truth/select/multi-reorder-final.png +0 -0
- package/screenshots/truth/select/multi-reorder-initial.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/remote-options.png +0 -0
- package/screenshots/truth/select/search-enabled.png +0 -0
- package/screenshots/truth/select/search-multi-no-matches.png +0 -0
- package/screenshots/truth/select/search-selected-focus.png +0 -0
- package/screenshots/truth/select/search-selected.png +0 -0
- package/screenshots/truth/select/search-with-selected.png +0 -0
- package/screenshots/truth/select/searching.png +0 -0
- package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
- package/screenshots/truth/select/selected-multi.png +0 -0
- package/screenshots/truth/select/selected-single.png +0 -0
- package/screenshots/truth/select/selection-clearable.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/truncated-selection.png +0 -0
- package/screenshots/truth/select/with-placeholder.png +0 -0
- package/screenshots/truth/select/without-placeholder.png +0 -0
- package/screenshots/truth/templates/default.png +0 -0
- package/screenshots/truth/templates/unapproved.png +0 -0
- package/screenshots/truth/webchat/connected-state.png +0 -0
- package/src/chart/TembaChart.ts +20 -16
- package/src/fields/FieldManager.ts +30 -38
- package/src/flow/Editor.ts +1 -1
- package/src/list/SortableList.ts +291 -67
- package/src/omnibox/Omnibox.ts +1 -1
- package/src/select/Select.ts +213 -42
- package/src/thumbnail/Thumbnail.ts +1 -1
- package/src/webchat/WebChat.ts +5 -2
- package/test/temba-chart.test.ts +1 -1
- package/test/temba-compose.test.ts +11 -38
- package/test/temba-contact-chat.test.ts +4 -6
- package/test/temba-dropdown.test.ts +1 -1
- package/test/temba-flow-editor-node.test.ts +344 -0
- package/test/temba-flow-editor.test.ts +301 -0
- package/test/temba-flow-plumber.test.ts +189 -0
- package/test/temba-flow-render.test.ts +220 -0
- package/test/temba-omnibox.test.ts +7 -3
- package/test/temba-select.test.ts +247 -79
- package/test/temba-sortable-list.test.ts +108 -15
- package/test/temba-toast.test.ts +2 -2
- package/test/temba-utils-index.test.ts +2 -2
- package/test/temba-webchat-lightbox-fix.test.ts +57 -0
- package/test/utils.test.ts +88 -0
- package/web-test-runner.config.mjs +4 -2
- package/.storybook/main.js +0 -14
- package/.storybook/preview-head.html +0 -1
- package/.storybook/preview.js +0 -17
- package/demo/agents.html +0 -147
- package/demo/old.html +0 -573
- package/demo/remote.html +0 -3
- package/screenshots/truth/compose/attachments-with-files-focused.png +0 -0
- package/stories/temba-checkbox.stories.md +0 -37
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { WebChat } from '../src/webchat/WebChat';
|
|
3
|
+
import { getComponent } from './utils.test';
|
|
4
|
+
|
|
5
|
+
const getWebChat = async (attrs: any = {}) => {
|
|
6
|
+
const webChat = (await getComponent(
|
|
7
|
+
'temba-webchat',
|
|
8
|
+
attrs,
|
|
9
|
+
'',
|
|
10
|
+
400,
|
|
11
|
+
600
|
|
12
|
+
)) as WebChat;
|
|
13
|
+
return webChat;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
describe('WebChat Lightbox Fix', () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
// Clean up any lightbox elements after each test
|
|
19
|
+
const lightboxes = document.querySelectorAll('temba-lightbox');
|
|
20
|
+
lightboxes.forEach((lightbox) => lightbox.remove());
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should only create one lightbox element even with multiple WebChat instances', async () => {
|
|
24
|
+
// Create first WebChat instance
|
|
25
|
+
await getWebChat({
|
|
26
|
+
channel: 'test-channel-1'
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Verify lightbox was created
|
|
30
|
+
let lightboxes = document.querySelectorAll('temba-lightbox');
|
|
31
|
+
expect(lightboxes.length).to.equal(1);
|
|
32
|
+
|
|
33
|
+
// Create second WebChat instance
|
|
34
|
+
await getWebChat({
|
|
35
|
+
channel: 'test-channel-2'
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Verify still only one lightbox exists
|
|
39
|
+
lightboxes = document.querySelectorAll('temba-lightbox');
|
|
40
|
+
expect(lightboxes.length).to.equal(1);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should not create lightbox if one already exists', async () => {
|
|
44
|
+
// Manually create a lightbox first
|
|
45
|
+
const existingLightbox = document.createElement('temba-lightbox');
|
|
46
|
+
document.body.appendChild(existingLightbox);
|
|
47
|
+
|
|
48
|
+
// Create WebChat instance
|
|
49
|
+
await getWebChat({
|
|
50
|
+
channel: 'test-channel'
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Verify still only one lightbox exists
|
|
54
|
+
const lightboxes = document.querySelectorAll('temba-lightbox');
|
|
55
|
+
expect(lightboxes.length).to.equal(1);
|
|
56
|
+
});
|
|
57
|
+
});
|
package/test/utils.test.ts
CHANGED
|
@@ -11,6 +11,10 @@ import { expect, fixture, html, assert, waitUntil } from '@open-wc/testing';
|
|
|
11
11
|
import MouseHelper from './MouseHelper';
|
|
12
12
|
import { Store } from '../src/store/Store';
|
|
13
13
|
import { replace, stub } from 'sinon';
|
|
14
|
+
import { Select, SelectOption } from '../src/select/Select';
|
|
15
|
+
import { Options } from '../src/options/Options';
|
|
16
|
+
import { Attachment } from '../src/interfaces';
|
|
17
|
+
import { Compose } from '../src/compose/Compose';
|
|
14
18
|
|
|
15
19
|
export interface CodeMock {
|
|
16
20
|
endpoint: RegExp;
|
|
@@ -279,3 +283,87 @@ export const mockNow = (isodate: string) => {
|
|
|
279
283
|
return now;
|
|
280
284
|
});
|
|
281
285
|
};
|
|
286
|
+
|
|
287
|
+
export const getOptions = (select: Select<SelectOption>): Options => {
|
|
288
|
+
return select.shadowRoot.querySelector('temba-options[visible]');
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
export const clickOption = async (
|
|
292
|
+
clock: any,
|
|
293
|
+
select: Select<SelectOption>,
|
|
294
|
+
index: number
|
|
295
|
+
) => {
|
|
296
|
+
const options = getOptions(select);
|
|
297
|
+
const option = options.shadowRoot.querySelector(
|
|
298
|
+
`[data-option-index="${index}"]`
|
|
299
|
+
) as HTMLDivElement;
|
|
300
|
+
|
|
301
|
+
await mouseClickElement(option);
|
|
302
|
+
await options.updateComplete;
|
|
303
|
+
await select.updateComplete;
|
|
304
|
+
await clock.runAll();
|
|
305
|
+
|
|
306
|
+
checkTimers(clock);
|
|
307
|
+
};
|
|
308
|
+
export const openSelect = async (clock: any, select: Select<SelectOption>) => {
|
|
309
|
+
const container = select.shadowRoot.querySelector('.select-container');
|
|
310
|
+
container.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
311
|
+
|
|
312
|
+
clock.runAll();
|
|
313
|
+
|
|
314
|
+
// add more explicit waiting and clock ticks
|
|
315
|
+
await select.updateComplete;
|
|
316
|
+
clock.runAll();
|
|
317
|
+
|
|
318
|
+
// reduce wait time for options to become visible
|
|
319
|
+
await waitFor(25);
|
|
320
|
+
clock.runAll();
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
export const openAndClick = async (
|
|
324
|
+
clock: any,
|
|
325
|
+
select: Select<SelectOption>,
|
|
326
|
+
idx: number
|
|
327
|
+
) => {
|
|
328
|
+
await openSelect(clock, select);
|
|
329
|
+
|
|
330
|
+
// Add this line to ensure proper timing when running as part of a test suite
|
|
331
|
+
await select.updateComplete;
|
|
332
|
+
clock.tick(25); // Reduced from 50 to give minimum time for options to render
|
|
333
|
+
|
|
334
|
+
await clickOption(clock, select, idx);
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// valid = attachments that are uploaded sent to the server when the user clicks send
|
|
338
|
+
export const getValidAttachments = (numFiles = 2): Attachment[] => {
|
|
339
|
+
const attachments = [];
|
|
340
|
+
let index = 1;
|
|
341
|
+
while (index <= numFiles) {
|
|
342
|
+
const s = 's' + index;
|
|
343
|
+
const attachment = {
|
|
344
|
+
uuid: s,
|
|
345
|
+
content_type: 'image/png',
|
|
346
|
+
type: 'image/png',
|
|
347
|
+
filename: 'name_' + s,
|
|
348
|
+
url: 'url_' + s,
|
|
349
|
+
size: 1024,
|
|
350
|
+
error: null
|
|
351
|
+
} as Attachment;
|
|
352
|
+
attachments.push(attachment);
|
|
353
|
+
index++;
|
|
354
|
+
}
|
|
355
|
+
return attachments;
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
export const updateComponent = async (
|
|
359
|
+
compose: Compose,
|
|
360
|
+
text?: string,
|
|
361
|
+
attachments?: Attachment[]
|
|
362
|
+
): Promise<void> => {
|
|
363
|
+
compose.initialText = text ? text : '';
|
|
364
|
+
compose.currentAttachments = attachments ? attachments : [];
|
|
365
|
+
await compose.updateComplete;
|
|
366
|
+
};
|
|
367
|
+
export const getValidText = () => {
|
|
368
|
+
return 'sà-wàd-dee!';
|
|
369
|
+
};
|
|
@@ -150,8 +150,9 @@ const wireScreenshots = async (page, context, wait, replaceScreenshots) => {
|
|
|
150
150
|
const testFile = await getPath(TEST, filename);
|
|
151
151
|
const truthFile = await getPath(TRUTH, filename);
|
|
152
152
|
|
|
153
|
+
// Only wait for network idle if explicitly requested
|
|
153
154
|
if (wait) {
|
|
154
|
-
await page.waitForNetworkIdle();
|
|
155
|
+
await page.waitForNetworkIdle({ idleTime: 100, timeout: 1000 });
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
if (!(await fileExists(truthFile))) {
|
|
@@ -302,9 +303,10 @@ export default {
|
|
|
302
303
|
files: '**/test/**/*.test.ts',
|
|
303
304
|
nodeResolve: true,
|
|
304
305
|
setupFiles: ['./test-setup.js'],
|
|
306
|
+
concurrency: 4,
|
|
305
307
|
testFramework: {
|
|
306
308
|
config: {
|
|
307
|
-
timeout: '
|
|
309
|
+
timeout: '5000',
|
|
308
310
|
},
|
|
309
311
|
},
|
|
310
312
|
|
package/.storybook/main.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
stories: ['../stories/**/*.stories.{js,md,mdx}'],
|
|
3
|
-
addons: [
|
|
4
|
-
'storybook-prebuilt/addon-knobs/register.js',
|
|
5
|
-
'storybook-prebuilt/addon-docs/register.js',
|
|
6
|
-
'storybook-prebuilt/addon-viewport/register.js'
|
|
7
|
-
],
|
|
8
|
-
esDevServer: {
|
|
9
|
-
// custom es-dev-server options
|
|
10
|
-
nodeResolve: true,
|
|
11
|
-
watch: true,
|
|
12
|
-
open: true
|
|
13
|
-
}
|
|
14
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<link type="text/css" rel="stylesheet" href="https://textit.com/sitestatic/css/temba-components.css"/>
|
package/.storybook/preview.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { addParameters, setCustomElements } from '@open-wc/demoing-storybook';
|
|
2
|
-
|
|
3
|
-
addParameters({
|
|
4
|
-
docs: {
|
|
5
|
-
iframeHeight: '200px'
|
|
6
|
-
}
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
async function run() {
|
|
10
|
-
const customElements = await (
|
|
11
|
-
await fetch(new URL('../custom-elements.json', import.meta.url))
|
|
12
|
-
).json();
|
|
13
|
-
|
|
14
|
-
setCustomElements(customElements);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
run();
|
package/demo/agents.html
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<link
|
|
6
|
-
href="/sitestatic/css/temba-components.css"
|
|
7
|
-
rel="stylesheet"
|
|
8
|
-
type="text/css"
|
|
9
|
-
/>
|
|
10
|
-
|
|
11
|
-
<link
|
|
12
|
-
href="/sitestatic/css/tailwind.css"
|
|
13
|
-
rel="stylesheet"
|
|
14
|
-
type="text/css"
|
|
15
|
-
/>
|
|
16
|
-
|
|
17
|
-
<link
|
|
18
|
-
href="https://fonts.googleapis.com/css?family=Roboto+Mono:300|Roboto:300,400,500"
|
|
19
|
-
rel="stylesheet"
|
|
20
|
-
/>
|
|
21
|
-
|
|
22
|
-
<style>
|
|
23
|
-
html {
|
|
24
|
-
--color-text-dark: #555 !important;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
temba-select[name='ticket-filter'] {
|
|
28
|
-
margin-bottom: 0.5em;
|
|
29
|
-
margin-top: -0.4em;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.ticket-list {
|
|
33
|
-
flex-basis: 300px;
|
|
34
|
-
flex-grow: 0;
|
|
35
|
-
flex-shrink: 0;
|
|
36
|
-
transition: all 200ms ease-in;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@media only screen and (max-width: 1024px) {
|
|
40
|
-
.ticket-list {
|
|
41
|
-
flex-basis: 200px;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@media only screen and (max-width: 768px) {
|
|
46
|
-
.ticket-list {
|
|
47
|
-
flex-basis: 125px;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
</style>
|
|
52
|
-
<script type="module">
|
|
53
|
-
import '../out-tsc/temba-modules.js';
|
|
54
|
-
</script>
|
|
55
|
-
|
|
56
|
-
<script language="javascript">
|
|
57
|
-
|
|
58
|
-
function handleContactChange(event) {
|
|
59
|
-
const ticket = event.target.value;
|
|
60
|
-
const chat = document.querySelector("temba-contact-chat");
|
|
61
|
-
chat.ticket = ticket;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function handleContactHistoryUpdate(event) {
|
|
65
|
-
// tell our list to refresh since we know things happened
|
|
66
|
-
const tickets = document.querySelector("temba-tickets");
|
|
67
|
-
tickets.refresh();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function handleTicketsRefreshed(event) {
|
|
71
|
-
// tell our chat to refresh since we know things are new in our list
|
|
72
|
-
const chat = document.querySelector("temba-contact-chat");
|
|
73
|
-
chat.refresh();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function handleFilterChanged(event) {
|
|
77
|
-
const tickets = document.querySelector("temba-tickets");
|
|
78
|
-
const chat = document.querySelector("temba-contact-chat");
|
|
79
|
-
|
|
80
|
-
// if we have auto selecting, don't clear the chat
|
|
81
|
-
if (!tickets.nextSelection) {
|
|
82
|
-
chat.ticket = null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const filter = event.target.values[0].value;
|
|
86
|
-
if (filter === "O") {
|
|
87
|
-
tickets.endpoint = "/contact/tickets/?_format=json&folder=open"
|
|
88
|
-
} else {
|
|
89
|
-
tickets.endpoint = "/contact/tickets/?_format=json&folder=closed"
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function handleTicketChanged(event) {
|
|
94
|
-
const ticket = event.detail.ticket;
|
|
95
|
-
const focus = event.detail.focus;
|
|
96
|
-
|
|
97
|
-
const filter = document.querySelector('temba-select[name="ticket-filter"]');
|
|
98
|
-
const tickets = document.querySelector("temba-tickets");
|
|
99
|
-
|
|
100
|
-
if (focus) {
|
|
101
|
-
tickets.setNextSelection(ticket.uuid);
|
|
102
|
-
filter.setSelection(ticket.status);
|
|
103
|
-
} else {
|
|
104
|
-
// no focus, just refresh
|
|
105
|
-
tickets.refresh();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
</script>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
</head>
|
|
113
|
-
<body>
|
|
114
|
-
|
|
115
|
-
<temba-store
|
|
116
|
-
completions="/mr/docs/en-us/completion.json"
|
|
117
|
-
functions="/mr/docs/en-us/functions.json"
|
|
118
|
-
fields="/api/v2/fields.json"
|
|
119
|
-
globals="/api/v2/globals.json"
|
|
120
|
-
groups="/api/v2/groups.json"
|
|
121
|
-
></temba-store>
|
|
122
|
-
|
|
123
|
-
<div class="flex-col">
|
|
124
|
-
<div class="flex" style="height:100vh">
|
|
125
|
-
|
|
126
|
-
<div class="ticket-list m-4 mr-2 flex flex-col">
|
|
127
|
-
|
|
128
|
-
<temba-select name="ticket-filter" onchange="handleFilterChanged(event)">
|
|
129
|
-
<temba-option name="Open" value="O" icon="inbox"></temba-option>
|
|
130
|
-
<temba-option name="Closed" value="C" icon="check"></temba-option>
|
|
131
|
-
</temba-select>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<div class="flex flex-grow">
|
|
135
|
-
<temba-tickets endpoint="/contact/tickets/?_format=json&folder=open" @temba-refreshed="handleTicketsRefreshed(event)" onchange="handleContactChange(event)"></temba-tickets>
|
|
136
|
-
</div>
|
|
137
|
-
|
|
138
|
-
</div>
|
|
139
|
-
|
|
140
|
-
<div class="flex-grow flex-col h-full py-4 pb-4 pr-4">
|
|
141
|
-
<temba-contact-chat @temba-refreshed="handleContactHistoryUpdate(event)" @temba-content-changed="handleTicketChanged(event)"></temba-contact-chat>
|
|
142
|
-
</div>
|
|
143
|
-
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
</body>
|
|
147
|
-
</html>
|