@nyaruka/temba-components 0.39.0 → 0.40.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{9ac0723e.js → b885f7d6.js} +7 -34
  3. package/dist/index.js +7 -34
  4. package/dist/sw.js +1 -1
  5. package/dist/sw.js.map +1 -1
  6. package/dist/templates/components-body.html +1 -1
  7. package/dist/templates/components-head.html +1 -1
  8. package/out-tsc/src/contacts/ContactBadges.js +5 -5
  9. package/out-tsc/src/contacts/ContactBadges.js.map +1 -1
  10. package/out-tsc/src/list/TembaMenu.js +77 -168
  11. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  12. package/out-tsc/src/utils/index.js +2 -0
  13. package/out-tsc/src/utils/index.js.map +1 -1
  14. package/out-tsc/src/vectoricon/index.js +2 -0
  15. package/out-tsc/src/vectoricon/index.js.map +1 -1
  16. package/out-tsc/test/temba-label.test.js +4 -4
  17. package/out-tsc/test/temba-label.test.js.map +1 -1
  18. package/out-tsc/test/temba-menu.test.js +58 -7
  19. package/out-tsc/test/temba-menu.test.js.map +1 -1
  20. package/package.json +1 -1
  21. package/screenshots/truth/label/custom.png +0 -0
  22. package/screenshots/truth/label/danger.png +0 -0
  23. package/screenshots/truth/label/default-icon.png +0 -0
  24. package/screenshots/truth/label/shadow.png +0 -0
  25. package/screenshots/truth/menu/menu-focus.png +0 -0
  26. package/screenshots/truth/menu/menu-focused-with items.png +0 -0
  27. package/screenshots/truth/menu/menu-refresh-1.png +0 -0
  28. package/screenshots/truth/menu/menu-refresh-2.png +0 -0
  29. package/screenshots/truth/menu/menu-root.png +0 -0
  30. package/screenshots/truth/menu/menu-submenu.png +0 -0
  31. package/screenshots/truth/menu/menu-tasks-nextup.png +0 -0
  32. package/screenshots/truth/menu/menu-tasks.png +0 -0
  33. package/src/contacts/ContactBadges.ts +5 -5
  34. package/src/list/TembaMenu.ts +89 -181
  35. package/src/utils/index.ts +3 -0
  36. package/src/vectoricon/index.ts +2 -0
  37. package/test/temba-label.test.ts +4 -4
  38. package/test/temba-menu.test.ts +73 -7
  39. package/test-assets/menu/menu-root.json +33 -0
  40. package/test-assets/menu/menu-schedule.json +21 -0
  41. package/test-assets/{list → menu}/menu-tasks.json +0 -0
  42. package/screenshots/truth/list/menu-root.png +0 -0
  43. package/screenshots/truth/list/menu-submenu.png +0 -0
  44. package/test-assets/list/menu-root.json +0 -17
package/dist/sw.js CHANGED
@@ -1,2 +1,2 @@
1
- if(!self.define){let e,t={};const o=(o,n)=>(o=new URL(o+".js",n).href,t[o]||new Promise((t=>{if("document"in self){const e=document.createElement("script");e.src=o,e.onload=t,document.head.appendChild(e)}else e=o,importScripts(o),t()})).then((()=>{let e=t[o];if(!e)throw new Error(`Module ${o} didn’t register its module`);return e})));self.define=(n,s)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(t[i])return;let r={};const l=e=>o(e,i),c={module:{uri:i},exports:r,require:l};t[i]=Promise.all(n.map((e=>c[e]||l(e)))).then((e=>(s(...e),r)))}}define(["./workbox-919adfb7"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"9ac0723e.js",revision:"fb9447c01bc44f0e5d14392d90614394"},{url:"templates/components-body.html",revision:"9dd9b0ff4467b05f60de06817c9a688c"},{url:"templates/components-head.html",revision:"67b4db9023b5b889146f73bf36cc84eb"}],{}),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"))),e.registerRoute("polyfills/*.js",new e.CacheFirst,"GET")}));
1
+ if(!self.define){let e,t={};const o=(o,n)=>(o=new URL(o+".js",n).href,t[o]||new Promise((t=>{if("document"in self){const e=document.createElement("script");e.src=o,e.onload=t,document.head.appendChild(e)}else e=o,importScripts(o),t()})).then((()=>{let e=t[o];if(!e)throw new Error(`Module ${o} didn’t register its module`);return e})));self.define=(n,s)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(t[i])return;let r={};const d=e=>o(e,i),l={module:{uri:i},exports:r,require:d};t[i]=Promise.all(n.map((e=>l[e]||d(e)))).then((e=>(s(...e),r)))}}define(["./workbox-919adfb7"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"b885f7d6.js",revision:"4a4f27824f1806ebbd3ea41736e72d71"},{url:"templates/components-body.html",revision:"e20df09bd3338b5803faba488ff25c85"},{url:"templates/components-head.html",revision:"0ec12dae53d7ed76dd9d7a642cf6c8eb"}],{}),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"))),e.registerRoute("polyfills/*.js",new e.CacheFirst,"GET")}));
2
2
  //# sourceMappingURL=sw.js.map
package/dist/sw.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sw.js","sources":["../../../../../tmp/8b0a5762cfabb38535d0e755a79035bd/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"9ac0723e.js\",\n \"revision\": \"fb9447c01bc44f0e5d14392d90614394\"\n },\n {\n \"url\": \"templates/components-body.html\",\n \"revision\": \"9dd9b0ff4467b05f60de06817c9a688c\"\n },\n {\n \"url\": \"templates/components-head.html\",\n \"revision\": \"67b4db9023b5b889146f73bf36cc84eb\"\n }\n], {});\n\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"/index.html\")));\n\n\nworkbox_routing_registerRoute(\"polyfills/*.js\", new workbox_strategies_CacheFirst(), 'GET');\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","url","revision","workbox","registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL","workbox_strategies_CacheFirst"],"mappings":"0nBAwBAA,KAAKC,cAELC,EAAAA,eAQAC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,iCACPC,SAAY,oCAEd,CACED,IAAO,iCACPC,SAAY,qCAEb,CAAE,GAEwBC,EAAAC,cAAC,IAAIC,EAAAA,gBAAgCC,EAAAA,wBAA2C,iBAGhFH,EAAAC,cAAC,iBAAkB,IAAIG,aAAiC"}
1
+ {"version":3,"file":"sw.js","sources":["../../../../../tmp/d0632a26fb72cd69c85046a087ad853b/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-core/clientsClaim.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from '/home/runner/work/temba-components/temba-components/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"b885f7d6.js\",\n \"revision\": \"4a4f27824f1806ebbd3ea41736e72d71\"\n },\n {\n \"url\": \"templates/components-body.html\",\n \"revision\": \"e20df09bd3338b5803faba488ff25c85\"\n },\n {\n \"url\": \"templates/components-head.html\",\n \"revision\": \"0ec12dae53d7ed76dd9d7a642cf6c8eb\"\n }\n], {});\n\nworkbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"/index.html\")));\n\n\nworkbox_routing_registerRoute(\"polyfills/*.js\", new workbox_strategies_CacheFirst(), 'GET');\n\n\n\n\n"],"names":["self","skipWaiting","workbox_core_clientsClaim","workbox_precaching_precacheAndRoute","url","revision","workbox","registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL","workbox_strategies_CacheFirst"],"mappings":"0nBAwBAA,KAAKC,cAELC,EAAAA,eAQAC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,iCACPC,SAAY,oCAEd,CACED,IAAO,iCACPC,SAAY,qCAEb,CAAE,GAEwBC,EAAAC,cAAC,IAAIC,EAAAA,gBAAgCC,EAAAA,wBAA2C,iBAGhFH,EAAAC,cAAC,iBAAkB,IAAIG,aAAiC"}
@@ -1 +1 @@
1
- <script type="module" src="{{STATIC_URL}}@nyaruka/temba-components/dist/9ac0723e.js"></script><script>window.TEMBA_COMPONENTS_VERSION="0.39.0"</script>
1
+ <script type="module" src="{{STATIC_URL}}@nyaruka/temba-components/dist/b885f7d6.js"></script><script>window.TEMBA_COMPONENTS_VERSION="0.40.0"</script>
@@ -1 +1 @@
1
- <link rel="modulepreload" href="{{STATIC_URL}}@nyaruka/temba-components/dist/9ac0723e.js" crossorigin="anonymous">
1
+ <link rel="modulepreload" href="{{STATIC_URL}}@nyaruka/temba-components/dist/b885f7d6.js" crossorigin="anonymous">
@@ -2,9 +2,9 @@ import { css, html } from 'lit';
2
2
  import { Icon } from '../vectoricon';
3
3
  import { ContactStoreElement } from './ContactStoreElement';
4
4
  const STATUS = {
5
- stopped: { name: 'Stopped', icon: 'x-octagon' },
6
- blocked: { name: 'Blocked', icon: 'slash' },
7
- archived: { name: 'Archived', icon: 'archive' },
5
+ stopped: { name: 'Stopped' },
6
+ blocked: { name: 'Blocked' },
7
+ archived: { name: 'Archived' },
8
8
  };
9
9
  export class ContactBadges extends ContactStoreElement {
10
10
  static get styles() {
@@ -27,9 +27,9 @@ export class ContactBadges extends ContactStoreElement {
27
27
  ${status && this.data.status !== 'active'
28
28
  ? html `
29
29
  <temba-label
30
- icon="${status.icon}"
30
+ icon="icon.contact_${this.data.status}"
31
31
  onclick="goto(event)"
32
- href="/contact/${status.name.toLowerCase()}"
32
+ href="/contact/${status.name.toLowerCase()}/"
33
33
  secondary
34
34
  clickable
35
35
  shadow
@@ -1 +1 @@
1
- {"version":3,"file":"ContactBadges.js","sourceRoot":"","sources":["../../../src/contacts/ContactBadges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAkB,MAAM,KAAK,CAAC;AAEhD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,MAAM,GAAG;IACb,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE;IAC/C,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE;IAC3C,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;CAChD,CAAC;AAEF,MAAM,OAAO,aAAc,SAAQ,mBAAmB;IACpD,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;KAST,CAAC;IACJ,CAAC;IAEM,MAAM;QACX,IAAI,IAAI,CAAC,IAAI,EAAE;YACb,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAExC,OAAO,IAAI,CAAA;;YAEL,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ;gBACvC,CAAC,CAAC,IAAI,CAAA;;0BAEQ,MAAM,CAAC,IAAI;;mCAEF,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE;;;;;oBAKxC,MAAM,CAAC,IAAI;;eAEhB;gBACH,CAAC,CAAC,IAAI;YACN,IAAI,CAAC,IAAI,CAAC,IAAI;gBACd,CAAC,CAAC,IAAI,CAAA;;;;oDAIkC,kBAAkB,CAClD,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAChC;;;;;oBAKC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;;eAExB;gBACH,CAAC,CAAC,IAAI;YACN,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAClB,CAAC,CAAC,IAAI,CAAA;;yBAEO,IAAI,CAAC,QAAQ;;wDAEkB,kBAAkB,CACtD,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,GAAG,CAC/B;;;;;oBAKC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;;eAEnD;gBACH,CAAC,CAAC,IAAI;YACN,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAY,EAAE,EAAE;gBACtC,OAAO,IAAI,CAAA;;;;wCAIiB,KAAK,CAAC,IAAI;uBAC3B,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;;;;kBAIrD,KAAK,CAAC,IAAI;;aAEf,CAAC;YACJ,CAAC,CAAC;;OAEL,CAAC;SACH;aAAM;YACL,OAAO,IAAI,CAAC;SACb;IACH,CAAC;CACF","sourcesContent":["import { css, html, TemplateResult } from 'lit';\nimport { Group } from '../interfaces';\nimport { Icon } from '../vectoricon';\nimport { ContactStoreElement } from './ContactStoreElement';\n\nconst STATUS = {\n stopped: { name: 'Stopped', icon: 'x-octagon' },\n blocked: { name: 'Blocked', icon: 'slash' },\n archived: { name: 'Archived', icon: 'archive' },\n};\n\nexport class ContactBadges extends ContactStoreElement {\n static get styles() {\n return css`\n temba-label {\n margin: 0.3em;\n }\n\n .badges {\n display: flex;\n flex-wrap: wrap;\n }\n `;\n }\n\n public render(): TemplateResult {\n if (this.data) {\n const status = STATUS[this.data.status];\n\n return html`\n <div class=\"badges\">\n ${status && this.data.status !== 'active'\n ? html`\n <temba-label\n icon=\"${status.icon}\"\n onclick=\"goto(event)\"\n href=\"/contact/${status.name.toLowerCase()}\"\n secondary\n clickable\n shadow\n >\n ${status.name}\n </temba-label>\n `\n : null}\n ${this.data.flow\n ? html`\n <temba-label\n icon=\"flow\"\n onclick=\"goto(event)\"\n href=\"/contact/?search=flow+%3D+${encodeURIComponent(\n '\"' + this.data.flow.name + '\"'\n )}\"\n clickable\n primary\n shadow\n >\n ${this.data.flow.name}\n </temba-label>\n `\n : null}\n ${this.data.language\n ? html`\n <temba-label\n icon=${Icon.language}\n onclick=\"goto(event)\"\n href=\"/contact/?search=language+%3D+${encodeURIComponent(\n '\"' + this.data.language + '\"'\n )}\"\n clickable\n primary\n shadow\n >\n ${this.store.getLanguageName(this.data.language)}\n </temba-label>\n `\n : null}\n ${this.data.groups.map((group: Group) => {\n return html`\n <temba-label\n class=\"group\"\n onclick=\"goto(event)\"\n href=\"/contact/filter/${group.uuid}/\"\n icon=${group.is_dynamic ? Icon.group_smart : Icon.group}\n clickable\n shadow\n >\n ${group.name}\n </temba-label>\n `;\n })}\n </div>\n `;\n } else {\n return null;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ContactBadges.js","sourceRoot":"","sources":["../../../src/contacts/ContactBadges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAkB,MAAM,KAAK,CAAC;AAEhD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,MAAM,GAAG;IACb,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC5B,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC5B,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;CAC/B,CAAC;AAEF,MAAM,OAAO,aAAc,SAAQ,mBAAmB;IACpD,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;KAST,CAAC;IACJ,CAAC;IAEM,MAAM;QACX,IAAI,IAAI,CAAC,IAAI,EAAE;YACb,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAExC,OAAO,IAAI,CAAA;;YAEL,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ;gBACvC,CAAC,CAAC,IAAI,CAAA;;uCAEqB,IAAI,CAAC,IAAI,CAAC,MAAM;;mCAEpB,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE;;;;;oBAKxC,MAAM,CAAC,IAAI;;eAEhB;gBACH,CAAC,CAAC,IAAI;YACN,IAAI,CAAC,IAAI,CAAC,IAAI;gBACd,CAAC,CAAC,IAAI,CAAA;;;;oDAIkC,kBAAkB,CAClD,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAChC;;;;;oBAKC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;;eAExB;gBACH,CAAC,CAAC,IAAI;YACN,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAClB,CAAC,CAAC,IAAI,CAAA;;yBAEO,IAAI,CAAC,QAAQ;;wDAEkB,kBAAkB,CACtD,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,GAAG,CAC/B;;;;;oBAKC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;;eAEnD;gBACH,CAAC,CAAC,IAAI;YACN,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAY,EAAE,EAAE;gBACtC,OAAO,IAAI,CAAA;;;;wCAIiB,KAAK,CAAC,IAAI;uBAC3B,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;;;;kBAIrD,KAAK,CAAC,IAAI;;aAEf,CAAC;YACJ,CAAC,CAAC;;OAEL,CAAC;SACH;aAAM;YACL,OAAO,IAAI,CAAC;SACb;IACH,CAAC;CACF","sourcesContent":["import { css, html, TemplateResult } from 'lit';\nimport { Group } from '../interfaces';\nimport { Icon } from '../vectoricon';\nimport { ContactStoreElement } from './ContactStoreElement';\n\nconst STATUS = {\n stopped: { name: 'Stopped' },\n blocked: { name: 'Blocked' },\n archived: { name: 'Archived' },\n};\n\nexport class ContactBadges extends ContactStoreElement {\n static get styles() {\n return css`\n temba-label {\n margin: 0.3em;\n }\n\n .badges {\n display: flex;\n flex-wrap: wrap;\n }\n `;\n }\n\n public render(): TemplateResult {\n if (this.data) {\n const status = STATUS[this.data.status];\n\n return html`\n <div class=\"badges\">\n ${status && this.data.status !== 'active'\n ? html`\n <temba-label\n icon=\"icon.contact_${this.data.status}\"\n onclick=\"goto(event)\"\n href=\"/contact/${status.name.toLowerCase()}/\"\n secondary\n clickable\n shadow\n >\n ${status.name}\n </temba-label>\n `\n : null}\n ${this.data.flow\n ? html`\n <temba-label\n icon=\"flow\"\n onclick=\"goto(event)\"\n href=\"/contact/?search=flow+%3D+${encodeURIComponent(\n '\"' + this.data.flow.name + '\"'\n )}\"\n clickable\n primary\n shadow\n >\n ${this.data.flow.name}\n </temba-label>\n `\n : null}\n ${this.data.language\n ? html`\n <temba-label\n icon=${Icon.language}\n onclick=\"goto(event)\"\n href=\"/contact/?search=language+%3D+${encodeURIComponent(\n '\"' + this.data.language + '\"'\n )}\"\n clickable\n primary\n shadow\n >\n ${this.store.getLanguageName(this.data.language)}\n </temba-label>\n `\n : null}\n ${this.data.groups.map((group: Group) => {\n return html`\n <temba-label\n class=\"group\"\n onclick=\"goto(event)\"\n href=\"/contact/filter/${group.uuid}/\"\n icon=${group.is_dynamic ? Icon.group_smart : Icon.group}\n clickable\n shadow\n >\n ${group.name}\n </temba-label>\n `;\n })}\n </div>\n `;\n } else {\n return null;\n }\n }\n}\n"]}
@@ -87,9 +87,6 @@ export class TembaMenu extends RapidElement {
87
87
  display: none;
88
88
  }
89
89
 
90
- .submenu {
91
- }
92
-
93
90
  .level-0 > .item,
94
91
  .level-0 > temba-dropdown > div[slot='toggle'] > .avatar {
95
92
  background: var(--color-primary-dark);
@@ -150,9 +147,6 @@ export class TembaMenu extends RapidElement {
150
147
  font-size: 0.7em;
151
148
  }
152
149
 
153
- .level-0.expanding {
154
- }
155
-
156
150
  .level-0.expanded {
157
151
  background: inherit;
158
152
  }
@@ -183,9 +177,6 @@ export class TembaMenu extends RapidElement {
183
177
  margin-right: 0.5em;
184
178
  }
185
179
 
186
- .item.inline > temba-icon {
187
- }
188
-
189
180
  .item > .details > .name {
190
181
  flex-grow: 1;
191
182
  white-space: nowrap;
@@ -235,9 +226,6 @@ export class TembaMenu extends RapidElement {
235
226
  border-bottom-right-radius: var(--curvature);
236
227
  }
237
228
 
238
- .level-0 > .selected-top {
239
- }
240
-
241
229
  .level-0 > .item:hover {
242
230
  background: rgba(var(--primary-rgb), 0.85);
243
231
  --icon-color: #fff;
@@ -249,12 +237,6 @@ export class TembaMenu extends RapidElement {
249
237
  cursor: default;
250
238
  }
251
239
 
252
- .inline-children {
253
- }
254
-
255
- .inline-children .item {
256
- }
257
-
258
240
  .item.inline {
259
241
  border: 0px solid transparent;
260
242
  }
@@ -295,9 +277,6 @@ export class TembaMenu extends RapidElement {
295
277
  transition: min-width var(--transition-speed) !important;
296
278
  }
297
279
 
298
- .level-1 .item .details {
299
- }
300
-
301
280
  .collapsed .item {
302
281
  overflow: hidden;
303
282
  min-width: 0;
@@ -311,12 +290,6 @@ export class TembaMenu extends RapidElement {
311
290
  align-items: center;
312
291
  }
313
292
 
314
- .item .details .name {
315
- }
316
-
317
- .item temba-icon {
318
- }
319
-
320
293
  .collapsed .item {
321
294
  margin-bottom: 0.5em;
322
295
  }
@@ -477,7 +450,6 @@ export class TembaMenu extends RapidElement {
477
450
  super();
478
451
  this.wraps = false;
479
452
  this.selection = [];
480
- this.pending = [];
481
453
  this.state = {};
482
454
  this.renderMenuItem = (menuItem, parent = null) => {
483
455
  if (menuItem.type === 'divider') {
@@ -625,12 +597,6 @@ export class TembaMenu extends RapidElement {
625
597
  return itemState;
626
598
  }
627
599
  updated(changes) {
628
- if (changes.has('value')) {
629
- this.setSelection((this.value || '').split('/'));
630
- }
631
- if (changes.has('submenu') && !changes.has('value')) {
632
- this.setSelection([this.submenu]);
633
- }
634
600
  if (changes.has('endpoint')) {
635
601
  this.root = {
636
602
  level: -1,
@@ -639,51 +605,43 @@ export class TembaMenu extends RapidElement {
639
605
  if (!this.wait) {
640
606
  this.loadItems(this.root);
641
607
  }
642
- this.fireCustomEvent(CustomEventType.Ready);
608
+ else {
609
+ this.fireCustomEvent(CustomEventType.Ready);
610
+ }
611
+ }
612
+ if (changes.has('root')) {
613
+ if (this.value) {
614
+ this.setFocusedItem(this.value);
615
+ this.value = null;
616
+ }
643
617
  }
644
618
  }
645
619
  reset() {
646
620
  this.loadItems(this.root);
647
621
  }
648
- refresh(path = null) {
649
- if (!path) {
650
- path = [...this.selection];
651
- }
652
- // go up the tree until we find an endpoint
653
- const item = this.getMenuItemForSelection(path);
654
- if (item) {
655
- if (item.endpoint) {
656
- this.loadItems(item, false);
657
- }
658
- else {
659
- path.pop();
660
- this.refresh(path);
661
- }
662
- }
663
- }
664
- fireNoPath(missingId) {
665
- const item = this.getMenuItem();
666
- if (item) {
667
- const details = {
668
- item: item.id,
669
- selection: '/' + this.selection.join('/'),
670
- endpoint: item.endpoint,
671
- path: missingId + '/' + this.pending.join('/') + document.location.search,
672
- };
673
- // remove any excess from our selection
674
- const selection = this.selection.join('/');
675
- selection.replace(details.path, '');
676
- this.selection = selection.split('/');
677
- this.fireCustomEvent(CustomEventType.NoPath, details);
678
- this.pending = [];
679
- this.requestUpdate('root');
622
+ refresh() {
623
+ const path = [...this.selection];
624
+ let item = this.root;
625
+ while (path.length > 0) {
626
+ this.loadItems(item);
627
+ const id = path.shift();
628
+ item = item.items.find(_item => _item.id == id);
680
629
  }
630
+ this.loadItems(item);
681
631
  }
682
632
  // eslint-disable-next-line @typescript-eslint/no-empty-function
683
- loadItems(item, selectFirst = true) {
633
+ loadItems(item, selectFirst = false) {
684
634
  if (item && item.endpoint) {
685
635
  item.loading = true;
686
636
  this.httpComplete = fetchResults(item.endpoint).then((items) => {
637
+ items.forEach(newItem => {
638
+ if (!newItem.items) {
639
+ const prevItem = (item.items || []).find(prev => prev.id == newItem.id);
640
+ if (prevItem && prevItem.items) {
641
+ newItem.items = prevItem.items;
642
+ }
643
+ }
644
+ });
687
645
  // update our item level
688
646
  items.forEach(subItem => {
689
647
  subItem.level = item.level + 1;
@@ -691,53 +649,47 @@ export class TembaMenu extends RapidElement {
691
649
  if (subItem.items) {
692
650
  subItem.items.forEach(inlineItem => {
693
651
  inlineItem.level = item.level + 2;
694
- // inlineItem.parent = subItem;
695
652
  });
696
653
  }
697
654
  });
698
655
  item.items = items;
699
656
  item.loading = false;
700
- this.requestUpdate('root');
701
- this.scrollSelectedIntoView();
702
- if (this.pending && this.pending.length > 0) {
703
- // auto select the next pending click
704
- const nextId = this.pending.shift();
705
- if (nextId && items.length > 0) {
706
- const nextItem = findItem(items, nextId);
707
- if (nextItem.item) {
708
- this.handleItemClicked(null, nextItem.item);
709
- }
710
- else {
711
- this.fireNoPath(nextId);
712
- }
713
- }
657
+ if (this.submenu && this.selection.length == 0) {
658
+ const sub = this.getMenuItemForSelection([this.submenu]);
659
+ this.handleItemClicked(null, sub);
714
660
  }
715
- else {
716
- // auto select the first item
717
- if (selectFirst &&
718
- items.length > 0 &&
719
- this.selection.length >= 1 &&
720
- !item.inline) {
721
- for (const item of items) {
722
- if (!item.type) {
723
- this.handleItemClicked(null, item);
724
- break;
725
- }
726
- }
727
- }
661
+ if (!this.wait) {
662
+ this.fireCustomEvent(CustomEventType.Ready);
663
+ this.wait = true;
728
664
  }
665
+ // once we've set our items check if we need to auto-select
666
+ if (selectFirst && item.items.length > 0) {
667
+ this.handleItemClicked(null, item.items[0]);
668
+ }
669
+ this.requestUpdate('root');
670
+ this.scrollSelectedIntoView();
729
671
  });
730
672
  }
731
673
  }
732
674
  handleItemClicked(event, menuItem, parent = null) {
733
- this.fireCustomEvent(CustomEventType.ButtonClicked, {
734
- item: menuItem,
735
- parent,
736
- });
737
675
  if (parent && parent.popup) {
676
+ if (event) {
677
+ this.fireCustomEvent(CustomEventType.ButtonClicked, {
678
+ item: menuItem,
679
+ selection: this.getSelection(),
680
+ parent,
681
+ });
682
+ }
738
683
  return;
739
684
  }
740
685
  if (menuItem.popup) {
686
+ if (event) {
687
+ this.fireCustomEvent(CustomEventType.ButtonClicked, {
688
+ item: menuItem,
689
+ selection: this.getSelection(),
690
+ parent,
691
+ });
692
+ }
741
693
  return;
742
694
  }
743
695
  if (parent && parent.inline) {
@@ -750,60 +702,31 @@ export class TembaMenu extends RapidElement {
750
702
  event.preventDefault();
751
703
  event.stopPropagation();
752
704
  }
753
- if (menuItem.trigger) {
754
- new Function(menuItem.trigger)();
705
+ // update our selection
706
+ if (menuItem.level >= this.selection.length) {
707
+ this.selection.push(menuItem.vanity_id || menuItem.id);
755
708
  }
756
709
  else {
757
- if (menuItem.level === 0) {
758
- /* this.expanding = menuItem.id;
759
- window.setTimeout(() => {
760
- this.expanding = null;
761
- }, 60);
762
- */
763
- }
764
- // update our selection
765
- if (menuItem.level >= this.selection.length) {
766
- this.selection.push(menuItem.vanity_id || menuItem.id);
767
- }
768
- else {
769
- this.selection.splice(menuItem.level, this.selection.length - menuItem.level, menuItem.vanity_id || menuItem.id);
770
- }
771
- if (menuItem.endpoint) {
772
- this.loadItems(menuItem, this.pending.length == 0);
773
- // make sure change events fire for events with hrefs
774
- if (!menuItem.href) {
775
- return;
776
- }
777
- }
778
- else {
779
- if (this.pending && this.pending.length > 0) {
780
- // auto select the next pending click
781
- const nextId = this.pending.shift();
782
- const item = this.getMenuItem();
783
- if (nextId && item && item.items && item.items.length > 0) {
784
- const nextItem = findItem(item.items, nextId).item;
785
- if (nextItem) {
786
- this.handleItemClicked(null, nextItem);
787
- return;
788
- }
789
- else {
790
- this.fireNoPath(nextId);
791
- this.requestUpdate('root');
792
- return;
793
- }
794
- }
795
- else {
796
- this.fireNoPath(nextId);
797
- this.requestUpdate('root');
798
- return;
799
- }
800
- }
801
- this.requestUpdate('root');
802
- }
803
- if (this.pending.length == 0 || this.getMenuItem().href) {
804
- this.dispatchEvent(new Event('change'));
710
+ this.selection.splice(menuItem.level, this.selection.length - menuItem.level, menuItem.vanity_id || menuItem.id);
711
+ }
712
+ if (menuItem.endpoint) {
713
+ this.loadItems(menuItem, !!event);
714
+ // make sure change events fire for events with hrefs
715
+ if (!menuItem.href) {
716
+ return;
805
717
  }
806
718
  }
719
+ else {
720
+ this.requestUpdate();
721
+ }
722
+ if (menuItem.href) {
723
+ this.dispatchEvent(new Event('change'));
724
+ }
725
+ this.fireCustomEvent(CustomEventType.ButtonClicked, {
726
+ item: menuItem,
727
+ selection: this.getSelection(),
728
+ parent,
729
+ });
807
730
  }
808
731
  scrollSelectedIntoView() {
809
732
  // makes sure we are scrolled into view
@@ -852,23 +775,6 @@ export class TembaMenu extends RapidElement {
852
775
  getSelection() {
853
776
  return this.selection;
854
777
  }
855
- setSelection(path) {
856
- this.pending = [...path];
857
- this.selection = [];
858
- if (this.wait) {
859
- this.wait = false;
860
- this.loadItems(this.root);
861
- }
862
- }
863
- setSelectionPath(path) {
864
- const asPath = path.split('/').filter(step => !!step);
865
- // first try to click in the current space
866
- const clicked = this.clickItem(asPath[asPath.length - 1]);
867
- if (!clicked) {
868
- this.wait = true;
869
- this.setSelection(asPath);
870
- }
871
- }
872
778
  handleExpand() {
873
779
  this.collapsed = false;
874
780
  }
@@ -877,6 +783,9 @@ export class TembaMenu extends RapidElement {
877
783
  }
878
784
  async setFocusedItem(path) {
879
785
  const focusedPath = path.split('/').filter(step => !!step);
786
+ if (!this.root) {
787
+ return;
788
+ }
880
789
  // if we don't match at the first level, we are a noop
881
790
  if (focusedPath.length > 0) {
882
791
  const rootItem = findItem(this.root.items, focusedPath[0]).item;
@@ -890,7 +799,7 @@ export class TembaMenu extends RapidElement {
890
799
  const nextId = focusedPath.shift();
891
800
  if (nextId) {
892
801
  if (!level.items) {
893
- this.loadItems(level, false);
802
+ this.loadItems(level);
894
803
  await this.httpComplete;
895
804
  }
896
805
  level = findItem(level.items, nextId).item;