@nyaruka/temba-components 0.156.8 → 0.156.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 +17 -0
- package/dist/temba-components.js +678 -631
- package/dist/temba-components.js.map +1 -1
- package/package.json +1 -1
- package/src/display/Chat.ts +8 -8
- package/src/display/FloatingTab.ts +2 -2
- package/src/display/Options.ts +8 -2
- package/src/flow/CanvasMenu.ts +20 -25
- package/src/flow/CanvasNode.ts +16 -12
- package/src/flow/DragManager.ts +93 -33
- package/src/flow/Editor.ts +64 -59
- package/src/flow/EditorToolbar.ts +19 -20
- package/src/flow/FlowSearch.ts +9 -7
- package/src/flow/MessageTable.ts +181 -74
- package/src/flow/NodeEditor.ts +55 -72
- package/src/flow/RevisionsWindow.ts +2 -4
- package/src/flow/ZoomManager.ts +1 -2
- package/src/flow/actions/play_audio.ts +1 -28
- package/src/flow/actions/say_msg.ts +1 -40
- package/src/flow/actions/send_broadcast.ts +1 -2
- package/src/flow/actions/send_email.ts +5 -56
- package/src/flow/actions/send_msg.ts +10 -2
- package/src/flow/actions/start_session.ts +1 -2
- package/src/flow/categoryLocalization.ts +1 -5
- package/src/flow/categoryUtils.ts +139 -0
- package/src/flow/nodes/shared-rules.ts +6 -16
- package/src/flow/nodes/shared.ts +113 -6
- package/src/flow/nodes/split_by_airtime.ts +41 -63
- package/src/flow/nodes/split_by_contact_field.ts +8 -17
- package/src/flow/nodes/split_by_expression.ts +8 -17
- package/src/flow/nodes/split_by_groups.ts +34 -112
- package/src/flow/nodes/split_by_llm.ts +1 -7
- package/src/flow/nodes/split_by_llm_categorize.ts +27 -43
- package/src/flow/nodes/split_by_random.ts +39 -99
- package/src/flow/nodes/split_by_resthook.ts +5 -19
- package/src/flow/nodes/split_by_run_result.ts +8 -17
- package/src/flow/nodes/split_by_scheme.ts +39 -124
- package/src/flow/nodes/split_by_subflow.ts +1 -7
- package/src/flow/nodes/split_by_ticket.ts +1 -7
- package/src/flow/nodes/split_by_webhook.ts +2 -8
- package/src/flow/nodes/wait_for_audio.ts +1 -7
- package/src/flow/nodes/wait_for_dial.ts +2 -8
- package/src/flow/nodes/wait_for_digits.ts +5 -7
- package/src/flow/nodes/wait_for_menu.ts +5 -7
- package/src/flow/nodes/wait_for_response.ts +10 -18
- package/src/flow/types.ts +27 -0
- package/src/flow/utils.ts +111 -3
- package/src/form/Compose.ts +11 -4
- package/src/form/MessageEditor.ts +5 -3
- package/src/form/RichEditor.ts +3 -1
- package/src/form/TemplateEditor.ts +5 -1
- package/src/form/select/Select.ts +11 -9
- package/src/layout/AccordionSection.ts +9 -3
- package/src/layout/Modax.ts +1 -3
- package/src/live/ContactChat.ts +54 -46
- package/src/simulator/Simulator.ts +9 -3
- package/src/store/AppState.ts +1 -1
- package/src/store/Store.ts +6 -1
- package/src/utils.ts +21 -16
package/src/form/Compose.ts
CHANGED
|
@@ -41,7 +41,10 @@ export class Compose extends FieldElement {
|
|
|
41
41
|
|
|
42
42
|
.container:focus-within {
|
|
43
43
|
border-color: var(--color-focus);
|
|
44
|
-
box-shadow: var(
|
|
44
|
+
box-shadow: var(
|
|
45
|
+
--widget-box-shadow-focused,
|
|
46
|
+
0 0 0 3px rgba(0, 123, 255, 0.25)
|
|
47
|
+
);
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
.editor-wrapper {
|
|
@@ -115,14 +118,15 @@ export class Compose extends FieldElement {
|
|
|
115
118
|
color: #888;
|
|
116
119
|
background: rgba(0, 0, 0, 0.04);
|
|
117
120
|
border-radius: 8px;
|
|
118
|
-
transition:
|
|
121
|
+
transition:
|
|
122
|
+
background-color 0.2s ease-in-out,
|
|
123
|
+
color 0.2s ease-in-out;
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
.shortcut-icon:hover {
|
|
122
127
|
color: var(--color-text-dark);
|
|
123
128
|
background: rgba(0, 0, 0, 0.08);
|
|
124
129
|
}
|
|
125
|
-
|
|
126
130
|
`;
|
|
127
131
|
}
|
|
128
132
|
|
|
@@ -347,7 +351,10 @@ export class Compose extends FieldElement {
|
|
|
347
351
|
|
|
348
352
|
disconnectedCallback() {
|
|
349
353
|
super.disconnectedCallback();
|
|
350
|
-
this.removeEventListener(
|
|
354
|
+
this.removeEventListener(
|
|
355
|
+
'keydown',
|
|
356
|
+
this.handleHostKeyDown as EventListener
|
|
357
|
+
);
|
|
351
358
|
}
|
|
352
359
|
|
|
353
360
|
private handleShortcutIconClick() {
|
|
@@ -59,7 +59,7 @@ export class MessageEditor extends FieldElement {
|
|
|
59
59
|
position: relative;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
::slotted([slot=
|
|
62
|
+
::slotted([slot='icons']) {
|
|
63
63
|
position: absolute;
|
|
64
64
|
bottom: 4px;
|
|
65
65
|
left: 36px;
|
|
@@ -69,7 +69,7 @@ export class MessageEditor extends FieldElement {
|
|
|
69
69
|
z-index: 1;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
.has-attachments ::slotted([slot=
|
|
72
|
+
.has-attachments ::slotted([slot='icons']) {
|
|
73
73
|
left: 4px;
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -155,7 +155,9 @@ export class MessageEditor extends FieldElement {
|
|
|
155
155
|
padding: 6px;
|
|
156
156
|
border-radius: 8px;
|
|
157
157
|
background: rgba(0, 0, 0, 0.04);
|
|
158
|
-
transition:
|
|
158
|
+
transition:
|
|
159
|
+
background-color 0.2s ease-in-out,
|
|
160
|
+
color 0.2s ease-in-out;
|
|
159
161
|
}
|
|
160
162
|
|
|
161
163
|
.attachment-icon:hover {
|
package/src/form/RichEditor.ts
CHANGED
|
@@ -678,7 +678,9 @@ export class RichEditor extends FieldElement {
|
|
|
678
678
|
<div class="comp-container">
|
|
679
679
|
<div id="anchor" style=${styleMap(anchorStyles)}></div>
|
|
680
680
|
<div
|
|
681
|
-
class="input-container ${this.flavor !== 'default'
|
|
681
|
+
class="input-container ${this.flavor !== 'default'
|
|
682
|
+
? this.flavor
|
|
683
|
+
: ''}"
|
|
682
684
|
style=${this.minHeight
|
|
683
685
|
? `--textarea-min-height: ${this.minHeight}px`
|
|
684
686
|
: ''}
|
|
@@ -491,7 +491,11 @@ export class TemplateEditor extends FieldElement {
|
|
|
491
491
|
>
|
|
492
492
|
</temba-select>
|
|
493
493
|
${this.templateWarning && this.selectedTemplate
|
|
494
|
-
? html`<temba-alert
|
|
494
|
+
? html`<temba-alert
|
|
495
|
+
level="warning"
|
|
496
|
+
style="margin-bottom: 0.5em; display: block;"
|
|
497
|
+
>${this.templateWarning}</temba-alert
|
|
498
|
+
>`
|
|
495
499
|
: null}
|
|
496
500
|
${content ? html` <div class="template">${content}</div>` : null}
|
|
497
501
|
</div>
|
|
@@ -866,9 +866,7 @@ export class Select<T extends SelectOption> extends FieldElement {
|
|
|
866
866
|
}
|
|
867
867
|
|
|
868
868
|
private updateEnterHintPosition() {
|
|
869
|
-
const hint = this.shadowRoot.querySelector(
|
|
870
|
-
'.enter-hint'
|
|
871
|
-
) as HTMLElement;
|
|
869
|
+
const hint = this.shadowRoot.querySelector('.enter-hint') as HTMLElement;
|
|
872
870
|
if (!hint) {
|
|
873
871
|
this.removeHintRepositionListeners();
|
|
874
872
|
return;
|
|
@@ -2346,7 +2344,9 @@ export class Select<T extends SelectOption> extends FieldElement {
|
|
|
2346
2344
|
: null
|
|
2347
2345
|
}</slot>
|
|
2348
2346
|
${
|
|
2349
|
-
!this.tags &&
|
|
2347
|
+
!this.tags &&
|
|
2348
|
+
!this.emails &&
|
|
2349
|
+
!(this.clearable && this.values.length > 0 && !this.isMultiMode)
|
|
2350
2350
|
? html`<div
|
|
2351
2351
|
class="right-side arrow"
|
|
2352
2352
|
style="display:block;margin-right:5px"
|
|
@@ -2412,11 +2412,13 @@ export class Select<T extends SelectOption> extends FieldElement {
|
|
|
2412
2412
|
: null
|
|
2413
2413
|
}
|
|
2414
2414
|
</temba-options>
|
|
2415
|
-
${
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2415
|
+
${
|
|
2416
|
+
showEnterHint
|
|
2417
|
+
? html`<div class="enter-hint">
|
|
2418
|
+
<span style="position:relative;top:3px">↵</span> ${msg('to add')}
|
|
2419
|
+
</div>`
|
|
2420
|
+
: null
|
|
2421
|
+
}
|
|
2420
2422
|
`;
|
|
2421
2423
|
}
|
|
2422
2424
|
|
|
@@ -194,9 +194,15 @@ export class AccordionSection extends LitElement {
|
|
|
194
194
|
@mouseenter=${this.handleMouseEnter}
|
|
195
195
|
@mouseleave=${this.handleMouseLeave}
|
|
196
196
|
>
|
|
197
|
-
<div class="accordion-title"
|
|
198
|
-
|
|
199
|
-
|
|
197
|
+
<div class="accordion-title">
|
|
198
|
+
${this.icon
|
|
199
|
+
? html`<temba-icon
|
|
200
|
+
name=${this.icon}
|
|
201
|
+
size="1"
|
|
202
|
+
style="margin-right:6px;color:#999;"
|
|
203
|
+
></temba-icon>`
|
|
204
|
+
: ''}${this.label}
|
|
205
|
+
</div>
|
|
200
206
|
${this.hasError
|
|
201
207
|
? html`<temba-icon
|
|
202
208
|
name="alert_warning"
|
package/src/layout/Modax.ts
CHANGED
|
@@ -312,9 +312,7 @@ export class Modax extends RapidElement {
|
|
|
312
312
|
} else {
|
|
313
313
|
// apply or clear header colors from response
|
|
314
314
|
const headerBg = response.headers.get('X-Temba-Header-Bg');
|
|
315
|
-
const headerText = response.headers.get(
|
|
316
|
-
'X-Temba-Header-Text'
|
|
317
|
-
);
|
|
315
|
+
const headerText = response.headers.get('X-Temba-Header-Text');
|
|
318
316
|
if (headerBg) {
|
|
319
317
|
this.style.setProperty('--header-bg', headerBg);
|
|
320
318
|
} else {
|
package/src/live/ContactChat.ts
CHANGED
|
@@ -68,8 +68,6 @@ export class ContactChat extends ContactStoreElement {
|
|
|
68
68
|
--compose-padding: 3px;
|
|
69
69
|
--compose-curvature: none;
|
|
70
70
|
border-top: 1px inset rgba(0, 0, 0, 0.05);
|
|
71
|
-
|
|
72
|
-
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
.chat-wrapper {
|
|
@@ -612,9 +610,7 @@ export class ContactChat extends ContactStoreElement {
|
|
|
612
610
|
this.refreshId = null;
|
|
613
611
|
}
|
|
614
612
|
window.setTimeout(() => {
|
|
615
|
-
const input = this.shadowRoot.querySelector(
|
|
616
|
-
'.search-input'
|
|
617
|
-
) as any;
|
|
613
|
+
const input = this.shadowRoot.querySelector('.search-input') as any;
|
|
618
614
|
if (input) {
|
|
619
615
|
input.focus();
|
|
620
616
|
}
|
|
@@ -1125,7 +1121,13 @@ export class ContactChat extends ContactStoreElement {
|
|
|
1125
1121
|
private fetchingNewer = false;
|
|
1126
1122
|
|
|
1127
1123
|
private fetchNewerMessages() {
|
|
1128
|
-
if (
|
|
1124
|
+
if (
|
|
1125
|
+
!this.searchMode ||
|
|
1126
|
+
!this.afterUUID ||
|
|
1127
|
+
!this.chat ||
|
|
1128
|
+
this.fetchingNewer ||
|
|
1129
|
+
this.blockFetchingNewer
|
|
1130
|
+
) {
|
|
1129
1131
|
return;
|
|
1130
1132
|
}
|
|
1131
1133
|
|
|
@@ -1141,28 +1143,30 @@ export class ContactChat extends ContactStoreElement {
|
|
|
1141
1143
|
this.currentTicket?.uuid,
|
|
1142
1144
|
null,
|
|
1143
1145
|
this.afterUUID
|
|
1144
|
-
)
|
|
1145
|
-
|
|
1146
|
-
this.
|
|
1147
|
-
|
|
1148
|
-
|
|
1146
|
+
)
|
|
1147
|
+
.then((page: ContactHistoryPage) => {
|
|
1148
|
+
if (!this.chat) {
|
|
1149
|
+
this.fetchingNewer = false;
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1149
1152
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1153
|
+
const messages = this.createMessages(page);
|
|
1154
|
+
messages.reverse();
|
|
1152
1155
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1156
|
+
if (messages.length === 0) {
|
|
1157
|
+
this.blockFetchingNewer = true;
|
|
1158
|
+
this.fetchingNewer = false;
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1158
1161
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1162
|
+
// maintainScroll=true keeps the user's visual position stable
|
|
1163
|
+
// so they must actively scroll down to trigger the next fetch
|
|
1164
|
+
// fetchingNewer is reset in fetchComplete after scroll settles
|
|
1165
|
+
this.chat.addMessages(messages, null, true, true);
|
|
1166
|
+
})
|
|
1167
|
+
.catch(() => {
|
|
1168
|
+
this.fetchingNewer = false;
|
|
1169
|
+
});
|
|
1166
1170
|
}
|
|
1167
1171
|
|
|
1168
1172
|
private getTembaCompose(): TemplateResult {
|
|
@@ -1330,7 +1334,11 @@ export class ContactChat extends ContactStoreElement {
|
|
|
1330
1334
|
${this.currentContact
|
|
1331
1335
|
? html`<div class="chat-container">
|
|
1332
1336
|
${this.showSearch && this.searchMode
|
|
1333
|
-
? html`<div
|
|
1337
|
+
? html`<div
|
|
1338
|
+
class="search-overlay ${this.searchClosing
|
|
1339
|
+
? 'closing'
|
|
1340
|
+
: ''}"
|
|
1341
|
+
>
|
|
1334
1342
|
<div class="search-input-wrapper">
|
|
1335
1343
|
<temba-textinput
|
|
1336
1344
|
class="search-input"
|
|
@@ -1350,10 +1358,7 @@ export class ContactChat extends ContactStoreElement {
|
|
|
1350
1358
|
this.searchLoading}
|
|
1351
1359
|
title="Search (Enter)"
|
|
1352
1360
|
>
|
|
1353
|
-
<temba-icon
|
|
1354
|
-
name="search"
|
|
1355
|
-
size="0.8"
|
|
1356
|
-
></temba-icon>
|
|
1361
|
+
<temba-icon name="search" size="0.8"></temba-icon>
|
|
1357
1362
|
</button>
|
|
1358
1363
|
</div>
|
|
1359
1364
|
${this.searchLoading
|
|
@@ -1362,22 +1367,25 @@ export class ContactChat extends ContactStoreElement {
|
|
|
1362
1367
|
></span>`
|
|
1363
1368
|
: this.searchResults.length > 0
|
|
1364
1369
|
? html`<span class="search-counter"
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1370
|
+
>${this.searchIndex + 1} /
|
|
1371
|
+
${this.searchResults.length}</span
|
|
1372
|
+
><button
|
|
1373
|
+
class="search-btn ${this.searchFocused &&
|
|
1374
|
+
this.searchQuery.trim() === this.lastSearchedQuery
|
|
1375
|
+
? 'enter-target'
|
|
1376
|
+
: ''}"
|
|
1377
|
+
@click=${this.handleSearchNext}
|
|
1378
|
+
title="Older match (Enter)"
|
|
1379
|
+
>
|
|
1380
|
+
▲
|
|
1381
|
+
</button>
|
|
1382
|
+
<button
|
|
1383
|
+
class="search-btn"
|
|
1384
|
+
@click=${this.handleSearchPrev}
|
|
1385
|
+
title="Newer match (Shift+Enter)"
|
|
1386
|
+
>
|
|
1387
|
+
▼
|
|
1388
|
+
</button>`
|
|
1381
1389
|
: null}
|
|
1382
1390
|
<button
|
|
1383
1391
|
class="search-btn"
|
|
@@ -1947,13 +1947,19 @@ export class Simulator extends RapidElement {
|
|
|
1947
1947
|
totalElapsedMs === null
|
|
1948
1948
|
? 'n/a'
|
|
1949
1949
|
: this.formatWebhookDuration(totalElapsedMs);
|
|
1950
|
-
const renderWebhookLogContent = (
|
|
1950
|
+
const renderWebhookLogContent = (
|
|
1951
|
+
log: WebhookLog,
|
|
1952
|
+
singleAttempt = false
|
|
1953
|
+
) => {
|
|
1951
1954
|
const request = this.formatWebhookValue(log.request) || 'No request body';
|
|
1952
|
-
const response =
|
|
1955
|
+
const response =
|
|
1956
|
+
this.formatWebhookValue(log.response) || 'No response body';
|
|
1953
1957
|
|
|
1954
1958
|
return html`
|
|
1955
1959
|
<div
|
|
1956
|
-
class="webhook-log-content ${singleAttempt
|
|
1960
|
+
class="webhook-log-content ${singleAttempt
|
|
1961
|
+
? 'webhook-single-log'
|
|
1962
|
+
: ''}"
|
|
1957
1963
|
>
|
|
1958
1964
|
<div class="webhook-log-section">
|
|
1959
1965
|
<h4>Request</h4>
|
package/src/store/AppState.ts
CHANGED
|
@@ -192,7 +192,7 @@ export interface AppState {
|
|
|
192
192
|
issuesByAction: Map<string, FlowIssue[]>;
|
|
193
193
|
|
|
194
194
|
languageCode: string;
|
|
195
|
-
languageNames: { [code: string]:
|
|
195
|
+
languageNames: { [code: string]: string };
|
|
196
196
|
workspace: Workspace;
|
|
197
197
|
isTranslating: boolean;
|
|
198
198
|
viewingRevision: boolean;
|
package/src/store/Store.ts
CHANGED
|
@@ -30,6 +30,7 @@ import { sourceLocale, targetLocales } from '../locales/locale-codes';
|
|
|
30
30
|
import { getFullName } from '../display/TembaUser';
|
|
31
31
|
import { AppState, zustand } from './AppState';
|
|
32
32
|
import { StoreApi } from 'zustand/vanilla';
|
|
33
|
+
import { getLanguageDisplayName } from '../flow/utils';
|
|
33
34
|
|
|
34
35
|
const { setLocale } = configureLocalization({
|
|
35
36
|
sourceLocale,
|
|
@@ -379,7 +380,11 @@ export class Store extends RapidElement {
|
|
|
379
380
|
}
|
|
380
381
|
|
|
381
382
|
public getLanguageName(iso: string) {
|
|
382
|
-
|
|
383
|
+
const name = this.languages[iso];
|
|
384
|
+
if (!name || name === 'und' || iso === 'und') {
|
|
385
|
+
return getLanguageDisplayName(iso);
|
|
386
|
+
}
|
|
387
|
+
return name;
|
|
383
388
|
}
|
|
384
389
|
|
|
385
390
|
public isDynamicGroup(uuid: string): boolean {
|
package/src/utils.ts
CHANGED
|
@@ -7,6 +7,13 @@ import { Attachment, ContactField, Shortcut, Ticket, User } from './interfaces';
|
|
|
7
7
|
import ColorHash from 'color-hash';
|
|
8
8
|
import { Toast } from './display/Toast';
|
|
9
9
|
import { v4 as generateUUID, v7 as generateUUIDv7 } from 'uuid';
|
|
10
|
+
import {
|
|
11
|
+
categoryNamesEqual,
|
|
12
|
+
findCategoryByName,
|
|
13
|
+
isSystemCategory
|
|
14
|
+
} from './flow/categoryUtils';
|
|
15
|
+
|
|
16
|
+
export { isSystemCategory } from './flow/categoryUtils';
|
|
10
17
|
|
|
11
18
|
export const DEFAULT_MEDIA_ENDPOINT = '/api/v2/media.json';
|
|
12
19
|
|
|
@@ -1096,8 +1103,9 @@ export const createOrPreserveCategory = (
|
|
|
1096
1103
|
const { name, existingCategories, existingExits, existingCases, caseConfig } =
|
|
1097
1104
|
params;
|
|
1098
1105
|
|
|
1099
|
-
// Find existing category
|
|
1100
|
-
|
|
1106
|
+
// Find existing category (case-insensitive so renames that only change
|
|
1107
|
+
// casing preserve UUIDs and destinations)
|
|
1108
|
+
const existingCategory = findCategoryByName(existingCategories, name);
|
|
1101
1109
|
const existingExit = existingCategory
|
|
1102
1110
|
? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)
|
|
1103
1111
|
: null;
|
|
@@ -1247,13 +1255,6 @@ export const createMultiCategoryRouter = (
|
|
|
1247
1255
|
};
|
|
1248
1256
|
};
|
|
1249
1257
|
|
|
1250
|
-
// Helper function to check if a category is a system category
|
|
1251
|
-
export const isSystemCategory = (categoryName: string): boolean => {
|
|
1252
|
-
return ['No Response', 'Other', 'All Responses', 'Timeout'].includes(
|
|
1253
|
-
categoryName
|
|
1254
|
-
);
|
|
1255
|
-
};
|
|
1256
|
-
|
|
1257
1258
|
// Helper function to check if a UUID belongs to a system category
|
|
1258
1259
|
export const isSystemCategoryUuid = (
|
|
1259
1260
|
uuid: string,
|
|
@@ -1529,16 +1530,18 @@ export const createRulesRouter = (
|
|
|
1529
1530
|
// Name is "Other" if there are user rules, "All Responses" if there are no user rules
|
|
1530
1531
|
const defaultCategoryName = userRules.length > 0 ? 'Other' : 'All Responses';
|
|
1531
1532
|
|
|
1532
|
-
// Try to find existing default category by name (
|
|
1533
|
-
let existingDefaultCategory =
|
|
1534
|
-
|
|
1533
|
+
// Try to find existing default category by name (case-insensitive)
|
|
1534
|
+
let existingDefaultCategory = findCategoryByName(
|
|
1535
|
+
existingCategories,
|
|
1536
|
+
defaultCategoryName
|
|
1535
1537
|
);
|
|
1536
1538
|
|
|
1537
|
-
// If no
|
|
1539
|
+
// If no match, try the other possible default category name
|
|
1538
1540
|
if (!existingDefaultCategory) {
|
|
1539
1541
|
const alternateName = userRules.length > 0 ? 'All Responses' : 'Other';
|
|
1540
|
-
existingDefaultCategory =
|
|
1541
|
-
|
|
1542
|
+
existingDefaultCategory = findCategoryByName(
|
|
1543
|
+
existingCategories,
|
|
1544
|
+
alternateName
|
|
1542
1545
|
);
|
|
1543
1546
|
}
|
|
1544
1547
|
|
|
@@ -1564,7 +1567,9 @@ export const createRulesRouter = (
|
|
|
1564
1567
|
|
|
1565
1568
|
// Find the default category (either "Other" or "All Responses")
|
|
1566
1569
|
const defaultCategory = categories.find(
|
|
1567
|
-
(cat) =>
|
|
1570
|
+
(cat) =>
|
|
1571
|
+
categoryNamesEqual(cat.name, 'Other') ||
|
|
1572
|
+
categoryNamesEqual(cat.name, 'All Responses')
|
|
1568
1573
|
);
|
|
1569
1574
|
|
|
1570
1575
|
return {
|