@nyaruka/temba-components 0.164.0 → 0.165.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 (49) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/DEV_DATA.md +11 -11
  3. package/README.md +4 -4
  4. package/TEST_OPTIMIZATION.md +8 -11
  5. package/dist/locales/es.js +4 -0
  6. package/dist/locales/es.js.map +1 -1
  7. package/dist/locales/fr.js +4 -0
  8. package/dist/locales/fr.js.map +1 -1
  9. package/dist/locales/pt.js +4 -0
  10. package/dist/locales/pt.js.map +1 -1
  11. package/dist/static/svg/index.svg +1 -1
  12. package/dist/temba-components.js +1555 -484
  13. package/dist/temba-components.js.map +1 -1
  14. package/orca/setup.sh +2 -2
  15. package/package.json +13 -18
  16. package/scripts/dev-data-sync.mjs +4 -4
  17. package/src/Icons.ts +3 -2
  18. package/src/display/ProgressBar.ts +15 -2
  19. package/src/form/Compose.ts +31 -1
  20. package/src/form/ContactSearch.ts +229 -126
  21. package/src/interfaces.ts +52 -0
  22. package/src/layout/Card.ts +25 -0
  23. package/src/layout/CardLayout.ts +3 -3
  24. package/src/layout/HeaderBar.ts +4 -1
  25. package/src/list/BroadcastList.ts +912 -0
  26. package/src/list/ContentList.ts +46 -10
  27. package/src/list/FieldList.ts +1057 -0
  28. package/src/list/SortableList.ts +7 -2
  29. package/src/list/TembaList.ts +8 -0
  30. package/src/list/TembaMenu.ts +5 -38
  31. package/src/live/CampaignEvents.ts +33 -19
  32. package/src/live/ContactChat.ts +7 -1
  33. package/src/live/ContactDetails.ts +20 -13
  34. package/src/live/ContactFieldEditor.ts +7 -3
  35. package/src/live/ContactStoreElement.ts +3 -1
  36. package/src/live/ContactTimeline.ts +28 -7
  37. package/src/locales/es.ts +4 -0
  38. package/src/locales/fr.ts +4 -0
  39. package/src/locales/pt.ts +4 -0
  40. package/static/svg/index.svg +1 -1
  41. package/static/svg/packs/2-temba/star-filled.svg +3 -0
  42. package/static/svg/work/traced/star-filled.svg +1 -0
  43. package/static/svg/work/used/star-filled.svg +3 -0
  44. package/stress-test.js +3 -3
  45. package/temba-modules.ts +4 -0
  46. package/web-test-runner.config.mjs +1 -1
  47. package/xliff/es.xlf +12 -0
  48. package/xliff/fr.xlf +12 -0
  49. package/xliff/pt.xlf +12 -0
package/src/interfaces.ts CHANGED
@@ -192,6 +192,58 @@ export interface Trigger {
192
192
  created_on?: string;
193
193
  }
194
194
 
195
+ /** A single row in the broadcast CRUDL lists — both the scheduled
196
+ * list (`msgs/broadcast_scheduled.html`) and the sent list
197
+ * (`msgs/broadcast_list.html`). Broadcasts key off the numeric id;
198
+ * content fields carry the base-language translation. */
199
+ export interface Broadcast {
200
+ id: number;
201
+ /** Server status slug — `pending`, `queued`, `started`,
202
+ * `completed`, `failed` or `interrupted`. Scheduled broadcasts
203
+ * that haven't fired yet sit at `pending`. */
204
+ status?: string;
205
+ /** Send progress for an in-flight broadcast — total recipients
206
+ * (-1 until the org's contact count resolves) and messages
207
+ * created so far. */
208
+ progress?: { total: number; started: number };
209
+ /** Base-language message text. */
210
+ text?: string;
211
+ /** Base-language attachments (`{content_type, url}` objects or
212
+ * `contentType:url` strings). */
213
+ attachments?: (string | Attachment)[];
214
+ /** Base-language quick replies. */
215
+ quick_replies?: string[];
216
+ /** The opt-in the broadcast requests, when it is one. */
217
+ optin?: ObjectReference | null;
218
+ /** The WhatsApp template the broadcast sends, when it uses one. */
219
+ template?: ObjectReference | null;
220
+ /** Recipient groups. */
221
+ groups?: ObjectReference[];
222
+ /** Recipient contacts. */
223
+ contacts?: ObjectReference[];
224
+ /** Raw recipient URNs (editors/admins only). */
225
+ urns?: string[];
226
+ /** Recipient contact query, for query-addressed broadcasts. */
227
+ query?: string | null;
228
+ /** Human-readable exclusion descriptions ("Skip inactive
229
+ * contacts", ...) rendered in the detail view. */
230
+ exclusions?: string[];
231
+ /** Scheduled broadcasts only — `display` is the server-rendered
232
+ * human repeat ("each week on Monday, Wednesday"); `next_fire` is
233
+ * null once the schedule is exhausted or paused. */
234
+ schedule?: {
235
+ repeat_period?: string;
236
+ display?: string;
237
+ next_fire?: string | null;
238
+ } | null;
239
+ /** Messages created by a sent broadcast. */
240
+ msg_count?: number;
241
+ created_on?: string;
242
+ /** Email of the user who created the broadcast. */
243
+ created_by?: string | null;
244
+ modified_on?: string;
245
+ }
246
+
195
247
  export interface Msg {
196
248
  /** Numeric id — present on persisted messages (the CRUDL list
197
249
  * keys rows off it); absent on outbound drafts. */
@@ -20,6 +20,12 @@ export class Card extends RapidElement {
20
20
  display: block;
21
21
  }
22
22
 
23
+ /* an empty panel drops its card entirely — in tab (plain) mode the
24
+ pane still renders so the tab keeps working */
25
+ :host([empty]:not([plain])) {
26
+ display: none;
27
+ }
28
+
23
29
  /* The chrome lives on an inner frame rather than the host so
24
30
  document-level universal rules (e.g. tailwind's preflight
25
31
  border-color) can't override it. */
@@ -130,6 +136,16 @@ export class Card extends RapidElement {
130
136
  padding: 0 10px 10px;
131
137
  }
132
138
 
139
+ /* card chrome bounds the panel tightly — slotted panels scale their
140
+ empty-state treatment down from the roomy tab-pane default to a
141
+ single quiet line */
142
+ :host(:not([plain])) .content ::slotted(*) {
143
+ --empty-padding: 1em;
144
+ --empty-extras-display: none;
145
+ --empty-title-size: 0.9em;
146
+ --empty-title-color: var(--text-3);
147
+ }
148
+
133
149
  /* bleed mode: the body content runs edge-to-edge so a panel with its
134
150
  own surface (e.g. the notepad) fills the card, clipped to the card
135
151
  radius. The footer of such content sits on the card's bottom edge. */
@@ -210,6 +226,12 @@ export class Card extends RapidElement {
210
226
  @property({ type: Boolean, reflect: true })
211
227
  bleed = false;
212
228
 
229
+ // the slotted panel reported (via temba-details-changed) that it has
230
+ // nothing to show — the card hides entirely in card mode, though its
231
+ // tab remains available in narrow mode
232
+ @property({ type: Boolean, reflect: true })
233
+ empty = false;
234
+
213
235
  // named surface treatments, e.g. "note" for the sticky-note look
214
236
  @property({ type: String, reflect: true })
215
237
  variant = '';
@@ -252,6 +274,9 @@ export class Card extends RapidElement {
252
274
  if ('count' in event.detail) {
253
275
  this.count = event.detail.count;
254
276
  }
277
+ if ('empty' in event.detail) {
278
+ this.empty = event.detail.empty;
279
+ }
255
280
  }
256
281
 
257
282
  public render(): TemplateResult {
@@ -88,13 +88,13 @@ export class CardLayout extends RapidElement {
88
88
  /* the column soaks up whatever the main view doesn't take. Its
89
89
  scrollport runs the full height (the host supplies no vertical
90
90
  padding) so the scrollbar bleeds top to bottom, while the inner
91
- padding aligns the first card with the main view and doubles as
92
- room for card shadows. */
91
+ padding aligns the cards with the main view including below,
92
+ so the last card scrolls to rest level with the bottom of the
93
+ main view — and doubles as room for card shadows. */
93
94
  flex: 1 0 var(--card-column-width, 360px);
94
95
  min-height: 0;
95
96
  overflow-y: auto;
96
97
  padding: var(--layout-spacing, 8px);
97
- padding-bottom: 0;
98
98
  }
99
99
 
100
100
  temba-tabs {
@@ -22,7 +22,10 @@ export class HeaderBar extends RapidElement {
22
22
  box-sizing: border-box;
23
23
  padding: 0 8px;
24
24
  background: var(--surface);
25
- border-bottom: 1px solid var(--border);
25
+ /* the rule is a box-shadow, not a border — host pages (tailwind
26
+ preflight) reset border-width on every element, and outer-scope
27
+ element styles beat :host */
28
+ box-shadow: inset 0 -1px 0 0 var(--border);
26
29
  }
27
30
 
28
31
  ::slotted(*) {